From 6c439d81080231e51ea2f76c9753f09f3e7078d1 Mon Sep 17 00:00:00 2001 From: Mickael Kerjean Date: Tue, 14 Mar 2023 17:32:08 +1100 Subject: [PATCH] maintain (deps): golang deps --- go.mod | 9 +- go.sum | 52 + vendor/github.com/beevik/etree/.travis.yml | 14 + vendor/github.com/beevik/etree/CONTRIBUTORS | 10 + vendor/github.com/beevik/etree/LICENSE | 24 + vendor/github.com/beevik/etree/README.md | 205 + .../github.com/beevik/etree/RELEASE_NOTES.md | 109 + vendor/github.com/beevik/etree/etree.go | 1453 +++++ vendor/github.com/beevik/etree/helpers.go | 276 + vendor/github.com/beevik/etree/path.go | 582 ++ .../github.com/crewjam/httperr/.golangci.yml | 78 + vendor/github.com/crewjam/httperr/.travis.yml | 13 + vendor/github.com/crewjam/httperr/LICENSE | 23 + vendor/github.com/crewjam/httperr/README.md | 152 + vendor/github.com/crewjam/httperr/client.go | 120 + vendor/github.com/crewjam/httperr/codes.go | 73 + vendor/github.com/crewjam/httperr/go.mod | 8 + vendor/github.com/crewjam/httperr/go.sum | 13 + vendor/github.com/crewjam/httperr/handler.go | 20 + vendor/github.com/crewjam/httperr/httperr.go | 56 + .../github.com/crewjam/httperr/middleware.go | 62 + vendor/github.com/crewjam/httperr/response.go | 42 + vendor/github.com/crewjam/httperr/value.go | 67 + vendor/github.com/crewjam/httperr/writer.go | 119 + vendor/github.com/davecgh/go-spew/LICENSE | 15 + .../github.com/davecgh/go-spew/spew/bypass.go | 145 + .../davecgh/go-spew/spew/bypasssafe.go | 38 + .../github.com/davecgh/go-spew/spew/common.go | 341 ++ .../github.com/davecgh/go-spew/spew/config.go | 306 + vendor/github.com/davecgh/go-spew/spew/doc.go | 211 + .../github.com/davecgh/go-spew/spew/dump.go | 509 ++ .../github.com/davecgh/go-spew/spew/format.go | 419 ++ .../github.com/davecgh/go-spew/spew/spew.go | 148 + .../decred/dcrd/dcrec/secp256k1/v3/LICENSE | 17 + .../decred/dcrd/dcrec/secp256k1/v3/README.md | 73 + .../secp256k1/v3/compressedbytepoints.go | 11 + .../decred/dcrd/dcrec/secp256k1/v3/curve.go | 880 +++ .../decred/dcrd/dcrec/secp256k1/v3/doc.go | 58 + .../decred/dcrd/dcrec/secp256k1/v3/ecdh.go | 21 + .../dcrec/secp256k1/v3/ellipticadaptor.go | 276 + .../decred/dcrd/dcrec/secp256k1/v3/error.go | 126 + .../decred/dcrd/dcrec/secp256k1/v3/field.go | 1680 ++++++ .../dcrd/dcrec/secp256k1/v3/genstatics.go | 203 + .../decred/dcrd/dcrec/secp256k1/v3/go.mod | 8 + .../decred/dcrd/dcrec/secp256k1/v3/go.sum | 4 + .../dcrec/secp256k1/v3/loadprecomputed.go | 68 + .../dcrd/dcrec/secp256k1/v3/modnscalar.go | 1090 ++++ .../decred/dcrd/dcrec/secp256k1/v3/nonce.go | 263 + .../decred/dcrd/dcrec/secp256k1/v3/privkey.go | 78 + .../decred/dcrd/dcrec/secp256k1/v3/pubkey.go | 232 + .../duosecurity/duo_universal_golang/LICENSE | 25 + .../duouniversal/client.go | 705 +++ .../duouniversal/duo_jwt.go | 100 + vendor/github.com/goccy/go-json/.codecov.yml | 32 + vendor/github.com/goccy/go-json/.gitignore | 2 + vendor/github.com/goccy/go-json/.golangci.yml | 75 + vendor/github.com/goccy/go-json/CHANGELOG.md | 236 + vendor/github.com/goccy/go-json/LICENSE | 21 + vendor/github.com/goccy/go-json/Makefile | 39 + vendor/github.com/goccy/go-json/README.md | 529 ++ vendor/github.com/goccy/go-json/color.go | 68 + vendor/github.com/goccy/go-json/decode.go | 232 + .../goccy/go-json/docker-compose.yml | 13 + vendor/github.com/goccy/go-json/encode.go | 323 ++ vendor/github.com/goccy/go-json/error.go | 39 + vendor/github.com/goccy/go-json/go.mod | 3 + vendor/github.com/goccy/go-json/go.sum | 0 .../internal/decoder/anonymous_field.go | 37 + .../goccy/go-json/internal/decoder/array.go | 169 + .../goccy/go-json/internal/decoder/bool.go | 78 + .../goccy/go-json/internal/decoder/bytes.go | 177 + .../goccy/go-json/internal/decoder/compile.go | 510 ++ .../internal/decoder/compile_norace.go | 28 + .../go-json/internal/decoder/compile_race.go | 36 + .../goccy/go-json/internal/decoder/context.go | 254 + .../goccy/go-json/internal/decoder/float.go | 158 + .../goccy/go-json/internal/decoder/func.go | 141 + .../goccy/go-json/internal/decoder/int.go | 242 + .../go-json/internal/decoder/interface.go | 458 ++ .../goccy/go-json/internal/decoder/map.go | 173 + .../goccy/go-json/internal/decoder/number.go | 108 + .../goccy/go-json/internal/decoder/option.go | 15 + .../goccy/go-json/internal/decoder/ptr.go | 87 + .../goccy/go-json/internal/decoder/slice.go | 294 + .../goccy/go-json/internal/decoder/stream.go | 554 ++ .../goccy/go-json/internal/decoder/string.go | 361 ++ .../goccy/go-json/internal/decoder/struct.go | 819 +++ .../goccy/go-json/internal/decoder/type.go | 29 + .../goccy/go-json/internal/decoder/uint.go | 190 + .../internal/decoder/unmarshal_json.go | 91 + .../internal/decoder/unmarshal_text.go | 280 + .../internal/decoder/wrapped_string.go | 68 + .../goccy/go-json/internal/encoder/compact.go | 286 + .../go-json/internal/encoder/compiler.go | 1569 +++++ .../internal/encoder/compiler_norace.go | 56 + .../go-json/internal/encoder/compiler_race.go | 65 + .../goccy/go-json/internal/encoder/context.go | 141 + .../goccy/go-json/internal/encoder/encoder.go | 551 ++ .../goccy/go-json/internal/encoder/indent.go | 211 + .../goccy/go-json/internal/encoder/int.go | 130 + .../goccy/go-json/internal/encoder/map112.go | 8 + .../goccy/go-json/internal/encoder/map113.go | 8 + .../goccy/go-json/internal/encoder/opcode.go | 766 +++ .../goccy/go-json/internal/encoder/option.go | 41 + .../goccy/go-json/internal/encoder/optype.go | 934 +++ .../goccy/go-json/internal/encoder/string.go | 640 +++ .../go-json/internal/encoder/vm/debug_vm.go | 34 + .../goccy/go-json/internal/encoder/vm/hack.go | 9 + .../goccy/go-json/internal/encoder/vm/util.go | 182 + .../goccy/go-json/internal/encoder/vm/vm.go | 5041 +++++++++++++++++ .../internal/encoder/vm_color/debug_vm.go | 34 + .../go-json/internal/encoder/vm_color/hack.go | 9 + .../go-json/internal/encoder/vm_color/util.go | 246 + .../go-json/internal/encoder/vm_color/vm.go | 5041 +++++++++++++++++ .../encoder/vm_color_indent/debug_vm.go | 34 + .../internal/encoder/vm_color_indent/util.go | 267 + .../internal/encoder/vm_color_indent/vm.go | 5041 +++++++++++++++++ .../internal/encoder/vm_indent/debug_vm.go | 34 + .../internal/encoder/vm_indent/hack.go | 9 + .../internal/encoder/vm_indent/util.go | 204 + .../go-json/internal/encoder/vm_indent/vm.go | 5041 +++++++++++++++++ .../goccy/go-json/internal/errors/error.go | 157 + .../goccy/go-json/internal/runtime/rtype.go | 263 + .../go-json/internal/runtime/struct_field.go | 87 + .../goccy/go-json/internal/runtime/type.go | 100 + vendor/github.com/goccy/go-json/json.go | 366 ++ vendor/github.com/goccy/go-json/option.go | 46 + .../github.com/golang-jwt/jwt/v4/.gitignore | 4 + vendor/github.com/golang-jwt/jwt/v4/LICENSE | 9 + .../golang-jwt/jwt/v4/MIGRATION_GUIDE.md | 22 + vendor/github.com/golang-jwt/jwt/v4/README.md | 138 + .../github.com/golang-jwt/jwt/v4/SECURITY.md | 19 + .../golang-jwt/jwt/v4/VERSION_HISTORY.md | 135 + vendor/github.com/golang-jwt/jwt/v4/claims.go | 273 + vendor/github.com/golang-jwt/jwt/v4/doc.go | 4 + vendor/github.com/golang-jwt/jwt/v4/ecdsa.go | 142 + .../golang-jwt/jwt/v4/ecdsa_utils.go | 69 + .../github.com/golang-jwt/jwt/v4/ed25519.go | 85 + .../golang-jwt/jwt/v4/ed25519_utils.go | 64 + vendor/github.com/golang-jwt/jwt/v4/errors.go | 112 + vendor/github.com/golang-jwt/jwt/v4/go.mod | 7 + vendor/github.com/golang-jwt/jwt/v4/go.sum | 0 vendor/github.com/golang-jwt/jwt/v4/hmac.go | 95 + .../golang-jwt/jwt/v4/map_claims.go | 151 + vendor/github.com/golang-jwt/jwt/v4/none.go | 52 + vendor/github.com/golang-jwt/jwt/v4/parser.go | 170 + .../golang-jwt/jwt/v4/parser_option.go | 29 + vendor/github.com/golang-jwt/jwt/v4/rsa.go | 101 + .../github.com/golang-jwt/jwt/v4/rsa_pss.go | 143 + .../github.com/golang-jwt/jwt/v4/rsa_utils.go | 105 + .../golang-jwt/jwt/v4/signing_method.go | 46 + .../golang-jwt/jwt/v4/staticcheck.conf | 1 + vendor/github.com/golang-jwt/jwt/v4/token.go | 127 + vendor/github.com/golang-jwt/jwt/v4/types.go | 145 + .../jonboulle/clockwork/.editorconfig | 12 + .../github.com/jonboulle/clockwork/.gitignore | 27 + vendor/github.com/jonboulle/clockwork/LICENSE | 201 + .../github.com/jonboulle/clockwork/README.md | 80 + .../jonboulle/clockwork/clockwork.go | 195 + vendor/github.com/jonboulle/clockwork/go.mod | 3 + .../github.com/jonboulle/clockwork/ticker.go | 72 + .../lestrrat-go/backoff/v2/.gitignore | 14 + .../lestrrat-go/backoff/v2/.golangci.yml | 7 + .../github.com/lestrrat-go/backoff/v2/Changes | 5 + .../github.com/lestrrat-go/backoff/v2/LICENSE | 21 + .../lestrrat-go/backoff/v2/README.md | 112 + .../lestrrat-go/backoff/v2/backoff.go | 31 + .../lestrrat-go/backoff/v2/constant.go | 66 + .../lestrrat-go/backoff/v2/controller.go | 95 + .../github.com/lestrrat-go/backoff/v2/doc.go | 6 + .../lestrrat-go/backoff/v2/exponential.go | 107 + .../github.com/lestrrat-go/backoff/v2/go.mod | 8 + .../github.com/lestrrat-go/backoff/v2/go.sum | 13 + .../lestrrat-go/backoff/v2/interface.go | 30 + .../lestrrat-go/backoff/v2/jitter.go | 59 + .../github.com/lestrrat-go/backoff/v2/null.go | 51 + .../lestrrat-go/backoff/v2/options.go | 127 + .../lestrrat-go/blackmagic/.gitignore | 15 + .../github.com/lestrrat-go/blackmagic/LICENSE | 21 + .../lestrrat-go/blackmagic/README.md | 3 + .../lestrrat-go/blackmagic/blackmagic.go | 55 + .../github.com/lestrrat-go/blackmagic/go.mod | 8 + .../github.com/lestrrat-go/blackmagic/go.sum | 13 + .../github.com/lestrrat-go/httpcc/.gitignore | 15 + vendor/github.com/lestrrat-go/httpcc/LICENSE | 21 + .../github.com/lestrrat-go/httpcc/README.md | 35 + .../lestrrat-go/httpcc/directives.go | 117 + vendor/github.com/lestrrat-go/httpcc/go.mod | 8 + .../github.com/lestrrat-go/httpcc/httpcc.go | 311 + vendor/github.com/lestrrat-go/iter/LICENSE | 21 + .../lestrrat-go/iter/arrayiter/arrayiter.go | 193 + .../lestrrat-go/iter/mapiter/mapiter.go | 196 + vendor/github.com/lestrrat-go/jwx/.gitignore | 35 + .../github.com/lestrrat-go/jwx/.golangci.yml | 77 + vendor/github.com/lestrrat-go/jwx/Changes | 490 ++ vendor/github.com/lestrrat-go/jwx/LICENSE | 22 + vendor/github.com/lestrrat-go/jwx/Makefile | 86 + vendor/github.com/lestrrat-go/jwx/README.md | 327 ++ vendor/github.com/lestrrat-go/jwx/format.go | 94 + .../lestrrat-go/jwx/formatkind_string_gen.go | 28 + vendor/github.com/lestrrat-go/jwx/go.mod | 20 + vendor/github.com/lestrrat-go/jwx/go.sum | 70 + .../lestrrat-go/jwx/internal/base64/base64.go | 66 + .../lestrrat-go/jwx/internal/ecutil/ecutil.go | 109 + .../lestrrat-go/jwx/internal/iter/mapiter.go | 35 + .../lestrrat-go/jwx/internal/json/goccy.go | 50 + .../lestrrat-go/jwx/internal/json/json.go | 105 + .../lestrrat-go/jwx/internal/json/registry.go | 53 + .../lestrrat-go/jwx/internal/json/stdlib.go | 48 + .../jwx/internal/keyconv/keyconv.go | 177 + .../lestrrat-go/jwx/internal/pool/pool.go | 40 + .../lestrrat-go/jwx/jwa/compression_gen.go | 73 + .../jwx/jwa/content_encryption_gen.go | 81 + .../lestrrat-go/jwx/jwa/elliptic_gen.go | 84 + vendor/github.com/lestrrat-go/jwx/jwa/jwa.go | 4 + .../lestrrat-go/jwx/jwa/key_encryption_gen.go | 112 + .../lestrrat-go/jwx/jwa/key_type_gen.go | 78 + .../lestrrat-go/jwx/jwa/secp2561k.go | 10 + .../lestrrat-go/jwx/jwa/signature_gen.go | 99 + .../github.com/lestrrat-go/jwx/jwe/README.md | 90 + .../lestrrat-go/jwx/jwe/compress.go | 41 + .../github.com/lestrrat-go/jwx/jwe/decrypt.go | 335 ++ .../github.com/lestrrat-go/jwx/jwe/encrypt.go | 174 + .../github.com/lestrrat-go/jwx/jwe/headers.go | 121 + .../lestrrat-go/jwx/jwe/headers_gen.go | 717 +++ .../lestrrat-go/jwx/jwe/interface.go | 101 + .../jwx/jwe/internal/aescbc/aescbc.go | 244 + .../jwx/jwe/internal/cipher/cipher.go | 218 + .../jwx/jwe/internal/cipher/interface.go | 34 + .../jwx/jwe/internal/concatkdf/concatkdf.go | 77 + .../internal/content_crypt/content_crypt.go | 61 + .../jwe/internal/content_crypt/interface.go | 20 + .../jwx/jwe/internal/keyenc/interface.go | 104 + .../jwx/jwe/internal/keyenc/keyenc.go | 667 +++ .../jwx/jwe/internal/keygen/interface.go | 73 + .../jwx/jwe/internal/keygen/keygen.go | 192 + vendor/github.com/lestrrat-go/jwx/jwe/io.go | 23 + vendor/github.com/lestrrat-go/jwx/jwe/jwe.go | 391 ++ .../github.com/lestrrat-go/jwx/jwe/message.go | 680 +++ .../github.com/lestrrat-go/jwx/jwe/options.go | 87 + .../lestrrat-go/jwx/jwe/serializer.go | 94 + .../github.com/lestrrat-go/jwx/jwk/README.md | 272 + .../lestrrat-go/jwx/jwk/certchain.go | 85 + .../github.com/lestrrat-go/jwx/jwk/ecdsa.go | 229 + .../lestrrat-go/jwx/jwk/ecdsa_gen.go | 1184 ++++ .../github.com/lestrrat-go/jwx/jwk/es256k.go | 13 + .../lestrrat-go/jwx/jwk/interface.go | 113 + .../lestrrat-go/jwx/jwk/interface_gen.go | 94 + vendor/github.com/lestrrat-go/jwx/jwk/io.go | 29 + vendor/github.com/lestrrat-go/jwx/jwk/jwk.go | 665 +++ .../github.com/lestrrat-go/jwx/jwk/key_ops.go | 58 + vendor/github.com/lestrrat-go/jwx/jwk/okp.go | 182 + .../github.com/lestrrat-go/jwx/jwk/okp_gen.go | 1122 ++++ .../github.com/lestrrat-go/jwx/jwk/option.go | 161 + .../github.com/lestrrat-go/jwx/jwk/refresh.go | 553 ++ vendor/github.com/lestrrat-go/jwx/jwk/rsa.go | 237 + .../github.com/lestrrat-go/jwx/jwk/rsa_gen.go | 1259 ++++ vendor/github.com/lestrrat-go/jwx/jwk/set.go | 208 + .../lestrrat-go/jwx/jwk/symmetric.go | 61 + .../lestrrat-go/jwx/jwk/symmetric_gen.go | 522 ++ .../github.com/lestrrat-go/jwx/jwk/usage.go | 30 + .../github.com/lestrrat-go/jwx/jws/README.md | 106 + .../github.com/lestrrat-go/jwx/jws/ecdsa.go | 125 + .../github.com/lestrrat-go/jwx/jws/eddsa.go | 48 + .../github.com/lestrrat-go/jwx/jws/headers.go | 70 + .../lestrrat-go/jwx/jws/headers_gen.go | 559 ++ vendor/github.com/lestrrat-go/jwx/jws/hmac.go | 77 + .../lestrrat-go/jwx/jws/interface.go | 135 + vendor/github.com/lestrrat-go/jwx/jws/io.go | 23 + vendor/github.com/lestrrat-go/jwx/jws/jws.go | 581 ++ .../github.com/lestrrat-go/jwx/jws/message.go | 341 ++ .../github.com/lestrrat-go/jwx/jws/option.go | 55 + vendor/github.com/lestrrat-go/jwx/jws/rsa.go | 146 + .../github.com/lestrrat-go/jwx/jws/signer.go | 68 + .../lestrrat-go/jwx/jws/verifier.go | 68 + .../github.com/lestrrat-go/jwx/jwt/README.md | 221 + vendor/github.com/lestrrat-go/jwx/jwt/http.go | 129 + .../lestrrat-go/jwx/jwt/interface.go | 14 + .../jwx/jwt/internal/types/date.go | 98 + .../jwx/jwt/internal/types/string.go | 43 + vendor/github.com/lestrrat-go/jwx/jwt/io.go | 29 + vendor/github.com/lestrrat-go/jwx/jwt/jwt.go | 445 ++ .../github.com/lestrrat-go/jwx/jwt/options.go | 418 ++ .../lestrrat-go/jwx/jwt/serialize.go | 229 + .../lestrrat-go/jwx/jwt/token_gen.go | 506 ++ .../lestrrat-go/jwx/jwt/validate.go | 188 + vendor/github.com/lestrrat-go/jwx/jwx.go | 48 + vendor/github.com/lestrrat-go/jwx/options.go | 30 + .../lestrrat-go/jwx/x25519/x25519.go | 116 + .../github.com/lestrrat-go/option/.gitignore | 15 + vendor/github.com/lestrrat-go/option/LICENSE | 21 + .../github.com/lestrrat-go/option/README.md | 136 + vendor/github.com/lestrrat-go/option/go.mod | 5 + vendor/github.com/lestrrat-go/option/go.sum | 11 + .../github.com/lestrrat-go/option/option.go | 32 + .../lestrrat-go/pdebug/v3/.gitignore | 24 + .../lestrrat-go/pdebug/v3/.golangci.yml | 7 + .../github.com/lestrrat-go/pdebug/v3/LICENSE | 21 + .../lestrrat-go/pdebug/v3/README.md | 83 + .../github.com/lestrrat-go/pdebug/v3/go.mod | 8 + .../github.com/lestrrat-go/pdebug/v3/go.sum | 13 + .../lestrrat-go/pdebug/v3/interface.go | 18 + .../lestrrat-go/pdebug/v3/options.go | 20 + .../lestrrat-go/pdebug/v3/pdebug.go | 231 + .../lestrrat-go/pdebug/v3/pdebug_off.go | 15 + .../xml-roundtrip-validator/LICENSE.txt | 201 + .../xml-roundtrip-validator/README.md | 73 + .../xml-roundtrip-validator/SECURITY.md | 25 + .../mattermost/xml-roundtrip-validator/go.mod | 5 + .../mattermost/xml-roundtrip-validator/go.sum | 12 + .../xml-roundtrip-validator/validator.go | 292 + .../mickael-kerjean/saml/.gitignore | 7 + .../mickael-kerjean/saml/.golangci.yml | 78 + .../github.com/mickael-kerjean/saml/LICENSE | 23 + .../github.com/mickael-kerjean/saml/README.md | 157 + .../mickael-kerjean/saml/duration.go | 128 + vendor/github.com/mickael-kerjean/saml/go.mod | 16 + vendor/github.com/mickael-kerjean/saml/go.sum | 59 + .../mickael-kerjean/saml/identity_provider.go | 1050 ++++ .../mickael-kerjean/saml/logger/logger.go | 31 + .../mickael-kerjean/saml/metadata.go | 303 + .../github.com/mickael-kerjean/saml/saml.go | 177 + .../mickael-kerjean/saml/saml_gen.go | 3 + .../mickael-kerjean/saml/samlsp/error.go | 25 + .../saml/samlsp/fetch_metadata.go | 75 + .../mickael-kerjean/saml/samlsp/middleware.go | 233 + .../mickael-kerjean/saml/samlsp/new.go | 149 + .../saml/samlsp/request_tracker.go | 46 + .../saml/samlsp/request_tracker_cookie.go | 111 + .../saml/samlsp/request_tracker_jwt.go | 75 + .../mickael-kerjean/saml/samlsp/session.go | 89 + .../saml/samlsp/session_cookie.go | 99 + .../saml/samlsp/session_jwt.go | 143 + .../mickael-kerjean/saml/samlsp/util.go | 16 + .../github.com/mickael-kerjean/saml/schema.go | 1321 +++++ .../mickael-kerjean/saml/service_provider.go | 1676 ++++++ .../github.com/mickael-kerjean/saml/time.go | 52 + .../github.com/mickael-kerjean/saml/util.go | 31 + .../mickael-kerjean/saml/xmlenc/cbc.go | 187 + .../mickael-kerjean/saml/xmlenc/decrypt.go | 115 + .../mickael-kerjean/saml/xmlenc/digest.go | 56 + .../mickael-kerjean/saml/xmlenc/fuzz.go | 49 + .../mickael-kerjean/saml/xmlenc/gcm.go | 143 + .../mickael-kerjean/saml/xmlenc/pubkey.go | 162 + .../mickael-kerjean/saml/xmlenc/xmlenc.go | 62 + vendor/github.com/pmezard/go-difflib/LICENSE | 27 + .../pmezard/go-difflib/difflib/difflib.go | 772 +++ .../russellhaering/goxmldsig/.gitignore | 1 + .../russellhaering/goxmldsig/.travis.yml | 11 + .../russellhaering/goxmldsig/LICENSE | 175 + .../russellhaering/goxmldsig/README.md | 90 + .../russellhaering/goxmldsig/canonicalize.go | 178 + .../russellhaering/goxmldsig/clock.go | 55 + .../goxmldsig/etreeutils/canonicalize.go | 98 + .../goxmldsig/etreeutils/namespace.go | 407 ++ .../goxmldsig/etreeutils/sort.go | 66 + .../goxmldsig/etreeutils/unmarshal.go | 43 + .../russellhaering/goxmldsig/go.mod | 13 + .../russellhaering/goxmldsig/go.sum | 34 + .../russellhaering/goxmldsig/keystore.go | 67 + .../russellhaering/goxmldsig/run_test.sh | 12 + .../russellhaering/goxmldsig/sign.go | 257 + .../russellhaering/goxmldsig/tls_keystore.go | 39 + .../goxmldsig/types/signature.go | 93 + .../russellhaering/goxmldsig/validate.go | 491 ++ .../russellhaering/goxmldsig/xml_constants.go | 81 + vendor/github.com/stretchr/testify/LICENSE | 21 + .../testify/assert/assertion_compare.go | 394 ++ .../testify/assert/assertion_format.go | 741 +++ .../testify/assert/assertion_format.go.tmpl | 5 + .../testify/assert/assertion_forward.go | 1470 +++++ .../testify/assert/assertion_forward.go.tmpl | 5 + .../testify/assert/assertion_order.go | 81 + .../stretchr/testify/assert/assertions.go | 1774 ++++++ .../github.com/stretchr/testify/assert/doc.go | 45 + .../stretchr/testify/assert/errors.go | 10 + .../testify/assert/forward_assertions.go | 16 + .../testify/assert/http_assertions.go | 162 + vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go | 77 + .../x/crypto/ripemd160/ripemd160.go | 124 + .../x/crypto/ripemd160/ripemd160block.go | 165 + vendor/gopkg.in/ldap.v2/.gitignore | 0 vendor/gopkg.in/ldap.v2/.travis.yml | 31 + vendor/gopkg.in/ldap.v2/LICENSE | 22 + vendor/gopkg.in/ldap.v2/Makefile | 52 + vendor/gopkg.in/ldap.v2/README.md | 53 + vendor/gopkg.in/ldap.v2/add.go | 113 + vendor/gopkg.in/ldap.v2/atomic_value.go | 13 + vendor/gopkg.in/ldap.v2/atomic_value_go13.go | 28 + vendor/gopkg.in/ldap.v2/bind.go | 143 + vendor/gopkg.in/ldap.v2/client.go | 27 + vendor/gopkg.in/ldap.v2/compare.go | 85 + vendor/gopkg.in/ldap.v2/conn.go | 470 ++ vendor/gopkg.in/ldap.v2/control.go | 420 ++ vendor/gopkg.in/ldap.v2/debug.go | 24 + vendor/gopkg.in/ldap.v2/del.go | 84 + vendor/gopkg.in/ldap.v2/dn.go | 247 + vendor/gopkg.in/ldap.v2/doc.go | 4 + vendor/gopkg.in/ldap.v2/error.go | 155 + vendor/gopkg.in/ldap.v2/filter.go | 469 ++ vendor/gopkg.in/ldap.v2/ldap.go | 320 ++ vendor/gopkg.in/ldap.v2/modify.go | 170 + vendor/gopkg.in/ldap.v2/passwdmodify.go | 148 + vendor/gopkg.in/ldap.v2/search.go | 450 ++ vendor/gopkg.in/yaml.v3/LICENSE | 50 + vendor/gopkg.in/yaml.v3/NOTICE | 13 + vendor/gopkg.in/yaml.v3/README.md | 150 + vendor/gopkg.in/yaml.v3/apic.go | 747 +++ vendor/gopkg.in/yaml.v3/decode.go | 950 ++++ vendor/gopkg.in/yaml.v3/emitterc.go | 2020 +++++++ vendor/gopkg.in/yaml.v3/encode.go | 577 ++ vendor/gopkg.in/yaml.v3/go.mod | 5 + vendor/gopkg.in/yaml.v3/parserc.go | 1249 ++++ vendor/gopkg.in/yaml.v3/readerc.go | 434 ++ vendor/gopkg.in/yaml.v3/resolve.go | 326 ++ vendor/gopkg.in/yaml.v3/scannerc.go | 3038 ++++++++++ vendor/gopkg.in/yaml.v3/sorter.go | 134 + vendor/gopkg.in/yaml.v3/writerc.go | 48 + vendor/gopkg.in/yaml.v3/yaml.go | 698 +++ vendor/gopkg.in/yaml.v3/yamlh.go | 807 +++ vendor/gopkg.in/yaml.v3/yamlprivateh.go | 198 + vendor/modules.txt | 91 +- 422 files changed, 101246 insertions(+), 14 deletions(-) create mode 100644 vendor/github.com/beevik/etree/.travis.yml create mode 100644 vendor/github.com/beevik/etree/CONTRIBUTORS create mode 100644 vendor/github.com/beevik/etree/LICENSE create mode 100644 vendor/github.com/beevik/etree/README.md create mode 100644 vendor/github.com/beevik/etree/RELEASE_NOTES.md create mode 100644 vendor/github.com/beevik/etree/etree.go create mode 100644 vendor/github.com/beevik/etree/helpers.go create mode 100644 vendor/github.com/beevik/etree/path.go create mode 100644 vendor/github.com/crewjam/httperr/.golangci.yml create mode 100644 vendor/github.com/crewjam/httperr/.travis.yml create mode 100644 vendor/github.com/crewjam/httperr/LICENSE create mode 100644 vendor/github.com/crewjam/httperr/README.md create mode 100644 vendor/github.com/crewjam/httperr/client.go create mode 100644 vendor/github.com/crewjam/httperr/codes.go create mode 100644 vendor/github.com/crewjam/httperr/go.mod create mode 100644 vendor/github.com/crewjam/httperr/go.sum create mode 100644 vendor/github.com/crewjam/httperr/handler.go create mode 100644 vendor/github.com/crewjam/httperr/httperr.go create mode 100644 vendor/github.com/crewjam/httperr/middleware.go create mode 100644 vendor/github.com/crewjam/httperr/response.go create mode 100644 vendor/github.com/crewjam/httperr/value.go create mode 100644 vendor/github.com/crewjam/httperr/writer.go create mode 100644 vendor/github.com/davecgh/go-spew/LICENSE create mode 100644 vendor/github.com/davecgh/go-spew/spew/bypass.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/bypasssafe.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/common.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/config.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/doc.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/dump.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/format.go create mode 100644 vendor/github.com/davecgh/go-spew/spew/spew.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/LICENSE create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/README.md create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/compressedbytepoints.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/curve.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/doc.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/ecdh.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/ellipticadaptor.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/error.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/field.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/genstatics.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/go.mod create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/go.sum create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/loadprecomputed.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/modnscalar.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/nonce.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/privkey.go create mode 100644 vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/pubkey.go create mode 100644 vendor/github.com/duosecurity/duo_universal_golang/LICENSE create mode 100644 vendor/github.com/duosecurity/duo_universal_golang/duouniversal/client.go create mode 100644 vendor/github.com/duosecurity/duo_universal_golang/duouniversal/duo_jwt.go create mode 100644 vendor/github.com/goccy/go-json/.codecov.yml create mode 100644 vendor/github.com/goccy/go-json/.gitignore create mode 100644 vendor/github.com/goccy/go-json/.golangci.yml create mode 100644 vendor/github.com/goccy/go-json/CHANGELOG.md create mode 100644 vendor/github.com/goccy/go-json/LICENSE create mode 100644 vendor/github.com/goccy/go-json/Makefile create mode 100644 vendor/github.com/goccy/go-json/README.md create mode 100644 vendor/github.com/goccy/go-json/color.go create mode 100644 vendor/github.com/goccy/go-json/decode.go create mode 100644 vendor/github.com/goccy/go-json/docker-compose.yml create mode 100644 vendor/github.com/goccy/go-json/encode.go create mode 100644 vendor/github.com/goccy/go-json/error.go create mode 100644 vendor/github.com/goccy/go-json/go.mod create mode 100644 vendor/github.com/goccy/go-json/go.sum create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/array.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/bool.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/bytes.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/compile.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/compile_norace.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/compile_race.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/context.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/float.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/func.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/int.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/interface.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/map.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/number.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/option.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/ptr.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/slice.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/stream.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/string.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/struct.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/type.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/uint.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go create mode 100644 vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/compact.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/compiler.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/compiler_norace.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/compiler_race.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/context.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/encoder.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/indent.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/int.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/map112.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/map113.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/opcode.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/option.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/optype.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/string.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm/hack.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm/util.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_color/debug_vm.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_color/hack.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/debug_vm.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_indent/debug_vm.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_indent/hack.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go create mode 100644 vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go create mode 100644 vendor/github.com/goccy/go-json/internal/errors/error.go create mode 100644 vendor/github.com/goccy/go-json/internal/runtime/rtype.go create mode 100644 vendor/github.com/goccy/go-json/internal/runtime/struct_field.go create mode 100644 vendor/github.com/goccy/go-json/internal/runtime/type.go create mode 100644 vendor/github.com/goccy/go-json/json.go create mode 100644 vendor/github.com/goccy/go-json/option.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/.gitignore create mode 100644 vendor/github.com/golang-jwt/jwt/v4/LICENSE create mode 100644 vendor/github.com/golang-jwt/jwt/v4/MIGRATION_GUIDE.md create mode 100644 vendor/github.com/golang-jwt/jwt/v4/README.md create mode 100644 vendor/github.com/golang-jwt/jwt/v4/SECURITY.md create mode 100644 vendor/github.com/golang-jwt/jwt/v4/VERSION_HISTORY.md create mode 100644 vendor/github.com/golang-jwt/jwt/v4/claims.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/doc.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/ecdsa.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/ecdsa_utils.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/ed25519.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/ed25519_utils.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/errors.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/go.mod create mode 100644 vendor/github.com/golang-jwt/jwt/v4/go.sum create mode 100644 vendor/github.com/golang-jwt/jwt/v4/hmac.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/map_claims.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/none.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/parser.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/parser_option.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/rsa.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/rsa_pss.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/rsa_utils.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/signing_method.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/staticcheck.conf create mode 100644 vendor/github.com/golang-jwt/jwt/v4/token.go create mode 100644 vendor/github.com/golang-jwt/jwt/v4/types.go create mode 100644 vendor/github.com/jonboulle/clockwork/.editorconfig create mode 100644 vendor/github.com/jonboulle/clockwork/.gitignore create mode 100644 vendor/github.com/jonboulle/clockwork/LICENSE create mode 100644 vendor/github.com/jonboulle/clockwork/README.md create mode 100644 vendor/github.com/jonboulle/clockwork/clockwork.go create mode 100644 vendor/github.com/jonboulle/clockwork/go.mod create mode 100644 vendor/github.com/jonboulle/clockwork/ticker.go create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/.gitignore create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/.golangci.yml create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/Changes create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/LICENSE create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/README.md create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/backoff.go create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/constant.go create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/controller.go create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/doc.go create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/exponential.go create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/go.mod create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/go.sum create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/interface.go create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/jitter.go create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/null.go create mode 100644 vendor/github.com/lestrrat-go/backoff/v2/options.go create mode 100644 vendor/github.com/lestrrat-go/blackmagic/.gitignore create mode 100644 vendor/github.com/lestrrat-go/blackmagic/LICENSE create mode 100644 vendor/github.com/lestrrat-go/blackmagic/README.md create mode 100644 vendor/github.com/lestrrat-go/blackmagic/blackmagic.go create mode 100644 vendor/github.com/lestrrat-go/blackmagic/go.mod create mode 100644 vendor/github.com/lestrrat-go/blackmagic/go.sum create mode 100644 vendor/github.com/lestrrat-go/httpcc/.gitignore create mode 100644 vendor/github.com/lestrrat-go/httpcc/LICENSE create mode 100644 vendor/github.com/lestrrat-go/httpcc/README.md create mode 100644 vendor/github.com/lestrrat-go/httpcc/directives.go create mode 100644 vendor/github.com/lestrrat-go/httpcc/go.mod create mode 100644 vendor/github.com/lestrrat-go/httpcc/httpcc.go create mode 100644 vendor/github.com/lestrrat-go/iter/LICENSE create mode 100644 vendor/github.com/lestrrat-go/iter/arrayiter/arrayiter.go create mode 100644 vendor/github.com/lestrrat-go/iter/mapiter/mapiter.go create mode 100644 vendor/github.com/lestrrat-go/jwx/.gitignore create mode 100644 vendor/github.com/lestrrat-go/jwx/.golangci.yml create mode 100644 vendor/github.com/lestrrat-go/jwx/Changes create mode 100644 vendor/github.com/lestrrat-go/jwx/LICENSE create mode 100644 vendor/github.com/lestrrat-go/jwx/Makefile create mode 100644 vendor/github.com/lestrrat-go/jwx/README.md create mode 100644 vendor/github.com/lestrrat-go/jwx/format.go create mode 100644 vendor/github.com/lestrrat-go/jwx/formatkind_string_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/go.mod create mode 100644 vendor/github.com/lestrrat-go/jwx/go.sum create mode 100644 vendor/github.com/lestrrat-go/jwx/internal/base64/base64.go create mode 100644 vendor/github.com/lestrrat-go/jwx/internal/ecutil/ecutil.go create mode 100644 vendor/github.com/lestrrat-go/jwx/internal/iter/mapiter.go create mode 100644 vendor/github.com/lestrrat-go/jwx/internal/json/goccy.go create mode 100644 vendor/github.com/lestrrat-go/jwx/internal/json/json.go create mode 100644 vendor/github.com/lestrrat-go/jwx/internal/json/registry.go create mode 100644 vendor/github.com/lestrrat-go/jwx/internal/json/stdlib.go create mode 100644 vendor/github.com/lestrrat-go/jwx/internal/keyconv/keyconv.go create mode 100644 vendor/github.com/lestrrat-go/jwx/internal/pool/pool.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwa/compression_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwa/content_encryption_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwa/elliptic_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwa/jwa.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwa/key_encryption_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwa/key_type_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwa/secp2561k.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwa/signature_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/README.md create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/compress.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/decrypt.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/encrypt.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/headers.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/headers_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/interface.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/aescbc/aescbc.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/cipher/cipher.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/cipher/interface.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/concatkdf/concatkdf.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/content_crypt/content_crypt.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/content_crypt/interface.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/keyenc/interface.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/keyenc/keyenc.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/keygen/interface.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/internal/keygen/keygen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/io.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/jwe.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/message.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/options.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwe/serializer.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/README.md create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/certchain.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/ecdsa.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/ecdsa_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/es256k.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/interface.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/interface_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/io.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/jwk.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/key_ops.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/okp.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/okp_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/option.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/refresh.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/rsa.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/rsa_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/set.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/symmetric.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/symmetric_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwk/usage.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/README.md create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/ecdsa.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/eddsa.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/headers.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/headers_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/hmac.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/interface.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/io.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/jws.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/message.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/option.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/rsa.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/signer.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jws/verifier.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/README.md create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/http.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/interface.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/internal/types/date.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/internal/types/string.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/io.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/jwt.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/options.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/serialize.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/token_gen.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwt/validate.go create mode 100644 vendor/github.com/lestrrat-go/jwx/jwx.go create mode 100644 vendor/github.com/lestrrat-go/jwx/options.go create mode 100644 vendor/github.com/lestrrat-go/jwx/x25519/x25519.go create mode 100644 vendor/github.com/lestrrat-go/option/.gitignore create mode 100644 vendor/github.com/lestrrat-go/option/LICENSE create mode 100644 vendor/github.com/lestrrat-go/option/README.md create mode 100644 vendor/github.com/lestrrat-go/option/go.mod create mode 100644 vendor/github.com/lestrrat-go/option/go.sum create mode 100644 vendor/github.com/lestrrat-go/option/option.go create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/.gitignore create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/.golangci.yml create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/LICENSE create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/README.md create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/go.mod create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/go.sum create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/interface.go create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/options.go create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/pdebug.go create mode 100644 vendor/github.com/lestrrat-go/pdebug/v3/pdebug_off.go create mode 100644 vendor/github.com/mattermost/xml-roundtrip-validator/LICENSE.txt create mode 100644 vendor/github.com/mattermost/xml-roundtrip-validator/README.md create mode 100644 vendor/github.com/mattermost/xml-roundtrip-validator/SECURITY.md create mode 100644 vendor/github.com/mattermost/xml-roundtrip-validator/go.mod create mode 100644 vendor/github.com/mattermost/xml-roundtrip-validator/go.sum create mode 100644 vendor/github.com/mattermost/xml-roundtrip-validator/validator.go create mode 100644 vendor/github.com/mickael-kerjean/saml/.gitignore create mode 100644 vendor/github.com/mickael-kerjean/saml/.golangci.yml create mode 100644 vendor/github.com/mickael-kerjean/saml/LICENSE create mode 100644 vendor/github.com/mickael-kerjean/saml/README.md create mode 100644 vendor/github.com/mickael-kerjean/saml/duration.go create mode 100644 vendor/github.com/mickael-kerjean/saml/go.mod create mode 100644 vendor/github.com/mickael-kerjean/saml/go.sum create mode 100644 vendor/github.com/mickael-kerjean/saml/identity_provider.go create mode 100644 vendor/github.com/mickael-kerjean/saml/logger/logger.go create mode 100644 vendor/github.com/mickael-kerjean/saml/metadata.go create mode 100644 vendor/github.com/mickael-kerjean/saml/saml.go create mode 100644 vendor/github.com/mickael-kerjean/saml/saml_gen.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/error.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/fetch_metadata.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/middleware.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/new.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker_cookie.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker_jwt.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/session.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/session_cookie.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/session_jwt.go create mode 100644 vendor/github.com/mickael-kerjean/saml/samlsp/util.go create mode 100644 vendor/github.com/mickael-kerjean/saml/schema.go create mode 100644 vendor/github.com/mickael-kerjean/saml/service_provider.go create mode 100644 vendor/github.com/mickael-kerjean/saml/time.go create mode 100644 vendor/github.com/mickael-kerjean/saml/util.go create mode 100644 vendor/github.com/mickael-kerjean/saml/xmlenc/cbc.go create mode 100644 vendor/github.com/mickael-kerjean/saml/xmlenc/decrypt.go create mode 100644 vendor/github.com/mickael-kerjean/saml/xmlenc/digest.go create mode 100644 vendor/github.com/mickael-kerjean/saml/xmlenc/fuzz.go create mode 100644 vendor/github.com/mickael-kerjean/saml/xmlenc/gcm.go create mode 100644 vendor/github.com/mickael-kerjean/saml/xmlenc/pubkey.go create mode 100644 vendor/github.com/mickael-kerjean/saml/xmlenc/xmlenc.go create mode 100644 vendor/github.com/pmezard/go-difflib/LICENSE create mode 100644 vendor/github.com/pmezard/go-difflib/difflib/difflib.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/.gitignore create mode 100644 vendor/github.com/russellhaering/goxmldsig/.travis.yml create mode 100644 vendor/github.com/russellhaering/goxmldsig/LICENSE create mode 100644 vendor/github.com/russellhaering/goxmldsig/README.md create mode 100644 vendor/github.com/russellhaering/goxmldsig/canonicalize.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/clock.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/etreeutils/unmarshal.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/go.mod create mode 100644 vendor/github.com/russellhaering/goxmldsig/go.sum create mode 100644 vendor/github.com/russellhaering/goxmldsig/keystore.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/run_test.sh create mode 100644 vendor/github.com/russellhaering/goxmldsig/sign.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/tls_keystore.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/types/signature.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/validate.go create mode 100644 vendor/github.com/russellhaering/goxmldsig/xml_constants.go create mode 100644 vendor/github.com/stretchr/testify/LICENSE create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_compare.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_format.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_forward.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_order.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertions.go create mode 100644 vendor/github.com/stretchr/testify/assert/doc.go create mode 100644 vendor/github.com/stretchr/testify/assert/errors.go create mode 100644 vendor/github.com/stretchr/testify/assert/forward_assertions.go create mode 100644 vendor/github.com/stretchr/testify/assert/http_assertions.go create mode 100644 vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go create mode 100644 vendor/golang.org/x/crypto/ripemd160/ripemd160.go create mode 100644 vendor/golang.org/x/crypto/ripemd160/ripemd160block.go create mode 100644 vendor/gopkg.in/ldap.v2/.gitignore create mode 100644 vendor/gopkg.in/ldap.v2/.travis.yml create mode 100644 vendor/gopkg.in/ldap.v2/LICENSE create mode 100644 vendor/gopkg.in/ldap.v2/Makefile create mode 100644 vendor/gopkg.in/ldap.v2/README.md create mode 100644 vendor/gopkg.in/ldap.v2/add.go create mode 100644 vendor/gopkg.in/ldap.v2/atomic_value.go create mode 100644 vendor/gopkg.in/ldap.v2/atomic_value_go13.go create mode 100644 vendor/gopkg.in/ldap.v2/bind.go create mode 100644 vendor/gopkg.in/ldap.v2/client.go create mode 100644 vendor/gopkg.in/ldap.v2/compare.go create mode 100644 vendor/gopkg.in/ldap.v2/conn.go create mode 100644 vendor/gopkg.in/ldap.v2/control.go create mode 100644 vendor/gopkg.in/ldap.v2/debug.go create mode 100644 vendor/gopkg.in/ldap.v2/del.go create mode 100644 vendor/gopkg.in/ldap.v2/dn.go create mode 100644 vendor/gopkg.in/ldap.v2/doc.go create mode 100644 vendor/gopkg.in/ldap.v2/error.go create mode 100644 vendor/gopkg.in/ldap.v2/filter.go create mode 100644 vendor/gopkg.in/ldap.v2/ldap.go create mode 100644 vendor/gopkg.in/ldap.v2/modify.go create mode 100644 vendor/gopkg.in/ldap.v2/passwdmodify.go create mode 100644 vendor/gopkg.in/ldap.v2/search.go create mode 100644 vendor/gopkg.in/yaml.v3/LICENSE create mode 100644 vendor/gopkg.in/yaml.v3/NOTICE create mode 100644 vendor/gopkg.in/yaml.v3/README.md create mode 100644 vendor/gopkg.in/yaml.v3/apic.go create mode 100644 vendor/gopkg.in/yaml.v3/decode.go create mode 100644 vendor/gopkg.in/yaml.v3/emitterc.go create mode 100644 vendor/gopkg.in/yaml.v3/encode.go create mode 100644 vendor/gopkg.in/yaml.v3/go.mod create mode 100644 vendor/gopkg.in/yaml.v3/parserc.go create mode 100644 vendor/gopkg.in/yaml.v3/readerc.go create mode 100644 vendor/gopkg.in/yaml.v3/resolve.go create mode 100644 vendor/gopkg.in/yaml.v3/scannerc.go create mode 100644 vendor/gopkg.in/yaml.v3/sorter.go create mode 100644 vendor/gopkg.in/yaml.v3/writerc.go create mode 100644 vendor/gopkg.in/yaml.v3/yaml.go create mode 100644 vendor/gopkg.in/yaml.v3/yamlh.go create mode 100644 vendor/gopkg.in/yaml.v3/yamlprivateh.go diff --git a/go.mod b/go.mod index fa75d9c1..d79336bf 100644 --- a/go.mod +++ b/go.mod @@ -7,15 +7,15 @@ require ( github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // indirect github.com/creack/pty v1.1.18 github.com/cretz/bine v0.1.0 + github.com/duosecurity/duo_universal_golang v1.0.3 github.com/go-sql-driver/mysql v1.5.0 - github.com/google/go-cmp v0.5.8 // indirect github.com/gorilla/mux v1.7.3 github.com/gorilla/websocket v1.4.1 github.com/h2non/bimg v1.1.5 github.com/hirochachacha/go-smb2 v1.0.2 - github.com/kr/pretty v0.3.0 // indirect github.com/mattn/go-sqlite3 v2.0.2+incompatible github.com/mickael-kerjean/net v0.0.0-20191120063050-2457c043ba06 + github.com/mickael-kerjean/saml v0.0.0-20221221152539-19783715740c github.com/mitchellh/hashstructure v1.0.0 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible @@ -23,10 +23,10 @@ require ( github.com/prasad83/goftp v0.0.0-20210325080443-f57aaed46a32 github.com/qeesung/image2ascii v1.0.1 github.com/rasky/go-xdr v0.0.0-20170124162913-1a41d1a06c93 // indirect - github.com/rogpeppe/go-internal v1.8.0 // indirect github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 // indirect github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef + github.com/stretchr/testify v1.7.0 github.com/suyashkumar/dicom v1.0.5 github.com/tidwall/gjson v1.13.0 github.com/tidwall/sjson v1.0.4 @@ -41,11 +41,10 @@ require ( golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 google.golang.org/api v0.15.0 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df + gopkg.in/ldap.v2 v2.5.1 gopkg.in/ldap.v3 v3.1.0 gopkg.in/src-d/go-git.v4 v4.13.1 - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect modernc.org/sqlite v1.19.1 storj.io/uplink v1.9.0 ) diff --git a/go.sum b/go.sum index d72e6e5d..b15faebf 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,8 @@ github.com/aws/aws-sdk-go v1.40.41 h1:v/Y4bB8+wHCONtKV+fuHTzLiqC08lk8e9HqYhRB9PB github.com/aws/aws-sdk-go v1.40.41/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= +github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= +github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= @@ -37,9 +39,17 @@ github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cretz/bine v0.1.0 h1:1/fvhLE+fk0bPzjdO5Ci+0ComYxEMuB1JhM4X5skT3g= github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw= +github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo= +github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 h1:sgNeV1VRMDzs6rzyPpxyM0jp317hnwiq58Filgag2xw= +github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0/go.mod h1:J70FGZSbzsjecRTiTzER+3f1KZLNaXkuv+yeFTKoxM8= +github.com/duosecurity/duo_universal_golang v1.0.3 h1:Cbetr591IkwhBmGPdblwC1YfekekwUu7PqYhc67keZo= +github.com/duosecurity/duo_universal_golang v1.0.3/go.mod h1:F2HspmxSKfoqV7oaaevguP2Ng8qpEgpWg0X39aV0b0A= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= @@ -56,9 +66,13 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/goccy/go-json v0.7.4 h1:B44qRUFwz/vxPKPISQ1KhvzRi9kZ28RAf6YtjriBZ5k= +github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= @@ -125,6 +139,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= @@ -145,6 +161,22 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lestrrat-go/backoff/v2 v2.0.7 h1:i2SeK33aOFJlUNJZzf2IpXRBvqBBnaGXfY5Xaop/GsE= +github.com/lestrrat-go/backoff/v2 v2.0.7/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0 h1:XzdxDbuQTz0RZZEmdU7cnQxUtFUzgCSPq8RCz4BxIi4= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/codegen v1.0.0/go.mod h1:JhJw6OQAuPEfVKUCLItpaVLumDGWQznd1VaXrBk9TdM= +github.com/lestrrat-go/httpcc v1.0.0 h1:FszVC6cKfDvBKcJv646+lkh4GydQg2Z29scgUfkOpYc= +github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE= +github.com/lestrrat-go/iter v1.0.1 h1:q8faalr2dY6o8bV45uwrxq12bRa1ezKrB6oM9FUgN4A= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.4 h1:EuVGI/hPUSRstxWpWjVcklOe1odJLVrFY9zt4k1pa30= +github.com/lestrrat-go/jwx v1.2.4/go.mod h1:CAe9Z479rJwIYDR2DqWwMm9c+gCNoYB6+0wBxPkEh0Q= +github.com/lestrrat-go/option v0.0.0-20210103042652-6f1ecfceda35/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lestrrat-go/pdebug/v3 v3.0.1 h1:3G5sX/aw/TbMTtVc9U7IHBWRZtMvwvBziF1e4HoQtv8= +github.com/lestrrat-go/pdebug/v3 v3.0.1/go.mod h1:za+m+Ve24yCxTEhR59N7UlnJomWwCiIqbJRmKeiADU4= github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -153,6 +185,8 @@ github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1j github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= +github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= +github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -162,6 +196,8 @@ github.com/mattn/go-sqlite3 v2.0.2+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mickael-kerjean/net v0.0.0-20191120063050-2457c043ba06 h1:427Mpu5edwuFuDBdqOm6EgRohYqZ9Oomd+87ryW2Uls= github.com/mickael-kerjean/net v0.0.0-20191120063050-2457c043ba06/go.mod h1:K5atEXcXMSGE5O2cPGjggOqCb5lKRaieqgNJHEwS/IE= +github.com/mickael-kerjean/saml v0.0.0-20221221152539-19783715740c h1:BywEyUDqL4Igi3BjEP0IYcITl6KHkoa9zxX+FMeLbyM= +github.com/mickael-kerjean/saml v0.0.0-20221221152539-19783715740c/go.mod h1:T3cV0zW4ocnA2MxG38wwYPCmJ9OXo8NbTOCY6RFnLBc= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -210,6 +246,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qq github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/russellhaering/goxmldsig v1.1.1 h1:vI0r2osGF1A9PLvsGdPUAGwEIrKa4Pj5sesSBsebIxM= +github.com/russellhaering/goxmldsig v1.1.1/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 h1:PT+ElG/UUFMfqy5HrxJxNzj3QBOf7dZwupeVC+mG1Lo= github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4/go.mod h1:MnkX001NG75g3p8bhFycnyIjeQoOjGL6CEIsdE/nKSY= @@ -257,6 +295,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/suyashkumar/dicom v1.0.5 h1:2b2pdEhGoKrHYHTQjNBXGsRbv8Py5AX/9QNPJJqiIpw= @@ -311,7 +350,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= @@ -326,6 +367,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -346,6 +388,7 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -370,6 +413,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= @@ -385,6 +429,7 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -405,6 +450,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= @@ -433,9 +479,11 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -493,6 +541,8 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU= +gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk= gopkg.in/ldap.v3 v3.1.0 h1:DIDWEjI7vQWREh0S8X5/NFPCZ3MCVd55LmXKPW4XLGE= gopkg.in/ldap.v3 v3.1.0/go.mod h1:dQjCc0R0kfyFjIlWNMH1DORwUASZyDxo2Ry1B51dXaQ= gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= @@ -514,6 +564,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/github.com/beevik/etree/.travis.yml b/vendor/github.com/beevik/etree/.travis.yml new file mode 100644 index 00000000..f4cb25d4 --- /dev/null +++ b/vendor/github.com/beevik/etree/.travis.yml @@ -0,0 +1,14 @@ +language: go +sudo: false + +go: + - 1.11.x + - tip + +matrix: + allow_failures: + - go: tip + +script: + - go vet ./... + - go test -v ./... diff --git a/vendor/github.com/beevik/etree/CONTRIBUTORS b/vendor/github.com/beevik/etree/CONTRIBUTORS new file mode 100644 index 00000000..03211a85 --- /dev/null +++ b/vendor/github.com/beevik/etree/CONTRIBUTORS @@ -0,0 +1,10 @@ +Brett Vickers (beevik) +Felix Geisendörfer (felixge) +Kamil Kisiel (kisielk) +Graham King (grahamking) +Matt Smith (ma314smith) +Michal Jemala (michaljemala) +Nicolas Piganeau (npiganeau) +Chris Brown (ccbrown) +Earncef Sequeira (earncef) +Gabriel de Labachelerie (wuzuf) diff --git a/vendor/github.com/beevik/etree/LICENSE b/vendor/github.com/beevik/etree/LICENSE new file mode 100644 index 00000000..26f1f775 --- /dev/null +++ b/vendor/github.com/beevik/etree/LICENSE @@ -0,0 +1,24 @@ +Copyright 2015-2019 Brett Vickers. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/beevik/etree/README.md b/vendor/github.com/beevik/etree/README.md new file mode 100644 index 00000000..08ec26b0 --- /dev/null +++ b/vendor/github.com/beevik/etree/README.md @@ -0,0 +1,205 @@ +[![Build Status](https://travis-ci.org/beevik/etree.svg?branch=master)](https://travis-ci.org/beevik/etree) +[![GoDoc](https://godoc.org/github.com/beevik/etree?status.svg)](https://godoc.org/github.com/beevik/etree) + +etree +===== + +The etree package is a lightweight, pure go package that expresses XML in +the form of an element tree. Its design was inspired by the Python +[ElementTree](http://docs.python.org/2/library/xml.etree.elementtree.html) +module. + +Some of the package's capabilities and features: + +* Represents XML documents as trees of elements for easy traversal. +* Imports, serializes, modifies or creates XML documents from scratch. +* Writes and reads XML to/from files, byte slices, strings and io interfaces. +* Performs simple or complex searches with lightweight XPath-like query APIs. +* Auto-indents XML using spaces or tabs for better readability. +* Implemented in pure go; depends only on standard go libraries. +* Built on top of the go [encoding/xml](http://golang.org/pkg/encoding/xml) + package. + +### Creating an XML document + +The following example creates an XML document from scratch using the etree +package and outputs its indented contents to stdout. +```go +doc := etree.NewDocument() +doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`) +doc.CreateProcInst("xml-stylesheet", `type="text/xsl" href="style.xsl"`) + +people := doc.CreateElement("People") +people.CreateComment("These are all known people") + +jon := people.CreateElement("Person") +jon.CreateAttr("name", "Jon") + +sally := people.CreateElement("Person") +sally.CreateAttr("name", "Sally") + +doc.Indent(2) +doc.WriteTo(os.Stdout) +``` + +Output: +```xml + + + + + + + +``` + +### Reading an XML file + +Suppose you have a file on disk called `bookstore.xml` containing the +following data: + +```xml + + + + Everyday Italian + Giada De Laurentiis + 2005 + 30.00 + + + + Harry Potter + J K. Rowling + 2005 + 29.99 + + + + XQuery Kick Start + James McGovern + Per Bothner + Kurt Cagle + James Linn + Vaidyanathan Nagarajan + 2003 + 49.99 + + + + Learning XML + Erik T. Ray + 2003 + 39.95 + + + +``` + +This code reads the file's contents into an etree document. +```go +doc := etree.NewDocument() +if err := doc.ReadFromFile("bookstore.xml"); err != nil { + panic(err) +} +``` + +You can also read XML from a string, a byte slice, or an `io.Reader`. + +### Processing elements and attributes + +This example illustrates several ways to access elements and attributes using +etree selection queries. +```go +root := doc.SelectElement("bookstore") +fmt.Println("ROOT element:", root.Tag) + +for _, book := range root.SelectElements("book") { + fmt.Println("CHILD element:", book.Tag) + if title := book.SelectElement("title"); title != nil { + lang := title.SelectAttrValue("lang", "unknown") + fmt.Printf(" TITLE: %s (%s)\n", title.Text(), lang) + } + for _, attr := range book.Attr { + fmt.Printf(" ATTR: %s=%s\n", attr.Key, attr.Value) + } +} +``` +Output: +``` +ROOT element: bookstore +CHILD element: book + TITLE: Everyday Italian (en) + ATTR: category=COOKING +CHILD element: book + TITLE: Harry Potter (en) + ATTR: category=CHILDREN +CHILD element: book + TITLE: XQuery Kick Start (en) + ATTR: category=WEB +CHILD element: book + TITLE: Learning XML (en) + ATTR: category=WEB +``` + +### Path queries + +This example uses etree's path functions to select all book titles that fall +into the category of 'WEB'. The double-slash prefix in the path causes the +search for book elements to occur recursively; book elements may appear at any +level of the XML hierarchy. +```go +for _, t := range doc.FindElements("//book[@category='WEB']/title") { + fmt.Println("Title:", t.Text()) +} +``` + +Output: +``` +Title: XQuery Kick Start +Title: Learning XML +``` + +This example finds the first book element under the root bookstore element and +outputs the tag and text of each of its child elements. +```go +for _, e := range doc.FindElements("./bookstore/book[1]/*") { + fmt.Printf("%s: %s\n", e.Tag, e.Text()) +} +``` + +Output: +``` +title: Everyday Italian +author: Giada De Laurentiis +year: 2005 +price: 30.00 +``` + +This example finds all books with a price of 49.99 and outputs their titles. +```go +path := etree.MustCompilePath("./bookstore/book[p:price='49.99']/title") +for _, e := range doc.FindElementsPath(path) { + fmt.Println(e.Text()) +} +``` + +Output: +``` +XQuery Kick Start +``` + +Note that this example uses the FindElementsPath function, which takes as an +argument a pre-compiled path object. Use precompiled paths when you plan to +search with the same path more than once. + +### Other features + +These are just a few examples of the things the etree package can do. See the +[documentation](http://godoc.org/github.com/beevik/etree) for a complete +description of its capabilities. + +### Contributing + +This project accepts contributions. Just fork the repo and submit a pull +request! diff --git a/vendor/github.com/beevik/etree/RELEASE_NOTES.md b/vendor/github.com/beevik/etree/RELEASE_NOTES.md new file mode 100644 index 00000000..ee59d7ab --- /dev/null +++ b/vendor/github.com/beevik/etree/RELEASE_NOTES.md @@ -0,0 +1,109 @@ +Release v1.1.0 +============== + +**New Features** + +* New attribute helpers. + * Added the `Element.SortAttrs` method, which lexicographically sorts an + element's attributes by key. +* New `ReadSettings` properties. + * Added `Entity` for the support of custom entity maps. +* New `WriteSettings` properties. + * Added `UseCRLF` to allow the output of CR-LF newlines instead of the + default LF newlines. This is useful on Windows systems. +* Additional support for text and CDATA sections. + * The `Element.Text` method now returns the concatenation of all consecutive + character data tokens immediately following an element's opening tag. + * Added `Element.SetCData` to replace the character data immediately + following an element's opening tag with a CDATA section. + * Added `Element.CreateCData` to create and add a CDATA section child + `CharData` token to an element. + * Added `Element.CreateText` to create and add a child text `CharData` token + to an element. + * Added `NewCData` to create a parentless CDATA section `CharData` token. + * Added `NewText` to create a parentless text `CharData` + token. + * Added `CharData.IsCData` to detect if the token contains a CDATA section. + * Added `CharData.IsWhitespace` to detect if the token contains whitespace + inserted by one of the document Indent functions. + * Modified `Element.SetText` so that it replaces a run of consecutive + character data tokens following the element's opening tag (instead of just + the first one). +* New "tail text" support. + * Added the `Element.Tail` method, which returns the text immediately + following an element's closing tag. + * Added the `Element.SetTail` method, which modifies the text immediately + following an element's closing tag. +* New element child insertion and removal methods. + * Added the `Element.InsertChildAt` method, which inserts a new child token + before the specified child token index. + * Added the `Element.RemoveChildAt` method, which removes the child token at + the specified child token index. +* New element and attribute queries. + * Added the `Element.Index` method, which returns the element's index within + its parent element's child token list. + * Added the `Element.NamespaceURI` method to return the namespace URI + associated with an element. + * Added the `Attr.NamespaceURI` method to return the namespace URI + associated with an element. + * Added the `Attr.Element` method to return the element that an attribute + belongs to. +* New Path filter functions. + * Added `[local-name()='val']` to keep elements whose unprefixed tag matches + the desired value. + * Added `[name()='val']` to keep elements whose full tag matches the desired + value. + * Added `[namespace-prefix()='val']` to keep elements whose namespace prefix + matches the desired value. + * Added `[namespace-uri()='val']` to keep elements whose namespace URI + matches the desired value. + +**Bug Fixes** + +* A default XML `CharSetReader` is now used to prevent failed parsing of XML + documents using certain encodings. + ([Issue](https://github.com/beevik/etree/issues/53)). +* All characters are now properly escaped according to XML parsing rules. + ([Issue](https://github.com/beevik/etree/issues/55)). +* The `Document.Indent` and `Document.IndentTabs` functions no longer insert + empty string `CharData` tokens. + +**Deprecated** + +* `Element` + * The `InsertChild` method is deprecated. Use `InsertChildAt` instead. + * The `CreateCharData` method is deprecated. Use `CreateText` instead. +* `CharData` + * The `NewCharData` method is deprecated. Use `NewText` instead. + + +Release v1.0.1 +============== + +**Changes** + +* Added support for absolute etree Path queries. An absolute path begins with + `/` or `//` and begins its search from the element's document root. +* Added [`GetPath`](https://godoc.org/github.com/beevik/etree#Element.GetPath) + and [`GetRelativePath`](https://godoc.org/github.com/beevik/etree#Element.GetRelativePath) + functions to the [`Element`](https://godoc.org/github.com/beevik/etree#Element) + type. + +**Breaking changes** + +* A path starting with `//` is now interpreted as an absolute path. + Previously, it was interpreted as a relative path starting from the element + whose + [`FindElement`](https://godoc.org/github.com/beevik/etree#Element.FindElement) + method was called. To remain compatible with this release, all paths + prefixed with `//` should be prefixed with `.//` when called from any + element other than the document's root. +* [**edit 2/1/2019**]: Minor releases should not contain breaking changes. + Even though this breaking change was very minor, it was a mistake to include + it in this minor release. In the future, all breaking changes will be + limited to major releases (e.g., version 2.0.0). + +Release v1.0.0 +============== + +Initial release. diff --git a/vendor/github.com/beevik/etree/etree.go b/vendor/github.com/beevik/etree/etree.go new file mode 100644 index 00000000..9e24f901 --- /dev/null +++ b/vendor/github.com/beevik/etree/etree.go @@ -0,0 +1,1453 @@ +// Copyright 2015-2019 Brett Vickers. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package etree provides XML services through an Element Tree +// abstraction. +package etree + +import ( + "bufio" + "bytes" + "encoding/xml" + "errors" + "io" + "os" + "sort" + "strings" +) + +const ( + // NoIndent is used with Indent to disable all indenting. + NoIndent = -1 +) + +// ErrXML is returned when XML parsing fails due to incorrect formatting. +var ErrXML = errors.New("etree: invalid XML format") + +// ReadSettings allow for changing the default behavior of the ReadFrom* +// methods. +type ReadSettings struct { + // CharsetReader to be passed to standard xml.Decoder. Default: nil. + CharsetReader func(charset string, input io.Reader) (io.Reader, error) + + // Permissive allows input containing common mistakes such as missing tags + // or attribute values. Default: false. + Permissive bool + + // Entity to be passed to standard xml.Decoder. Default: nil. + Entity map[string]string +} + +// newReadSettings creates a default ReadSettings record. +func newReadSettings() ReadSettings { + return ReadSettings{ + CharsetReader: func(label string, input io.Reader) (io.Reader, error) { + return input, nil + }, + Permissive: false, + } +} + +// WriteSettings allow for changing the serialization behavior of the WriteTo* +// methods. +type WriteSettings struct { + // CanonicalEndTags forces the production of XML end tags, even for + // elements that have no child elements. Default: false. + CanonicalEndTags bool + + // CanonicalText forces the production of XML character references for + // text data characters &, <, and >. If false, XML character references + // are also produced for " and '. Default: false. + CanonicalText bool + + // CanonicalAttrVal forces the production of XML character references for + // attribute value characters &, < and ". If false, XML character + // references are also produced for > and '. Default: false. + CanonicalAttrVal bool + + // When outputting indented XML, use a carriage return and linefeed + // ("\r\n") as a new-line delimiter instead of just a linefeed ("\n"). + // This is useful on Windows-based systems. + UseCRLF bool +} + +// newWriteSettings creates a default WriteSettings record. +func newWriteSettings() WriteSettings { + return WriteSettings{ + CanonicalEndTags: false, + CanonicalText: false, + CanonicalAttrVal: false, + UseCRLF: false, + } +} + +// A Token is an empty interface that represents an Element, CharData, +// Comment, Directive, or ProcInst. +type Token interface { + Parent() *Element + Index() int + dup(parent *Element) Token + setParent(parent *Element) + setIndex(index int) + writeTo(w *bufio.Writer, s *WriteSettings) +} + +// A Document is a container holding a complete XML hierarchy. Its embedded +// element contains zero or more children, one of which is usually the root +// element. The embedded element may include other children such as +// processing instructions or BOM CharData tokens. +type Document struct { + Element + ReadSettings ReadSettings + WriteSettings WriteSettings +} + +// An Element represents an XML element, its attributes, and its child tokens. +type Element struct { + Space, Tag string // namespace prefix and tag + Attr []Attr // key-value attribute pairs + Child []Token // child tokens (elements, comments, etc.) + parent *Element // parent element + index int // token index in parent's children +} + +// An Attr represents a key-value attribute of an XML element. +type Attr struct { + Space, Key string // The attribute's namespace prefix and key + Value string // The attribute value string + element *Element // element containing the attribute +} + +// charDataFlags are used with CharData tokens to store additional settings. +type charDataFlags uint8 + +const ( + // The CharData was created by an indent function as whitespace. + whitespaceFlag charDataFlags = 1 << iota + + // The CharData contains a CDATA section. + cdataFlag +) + +// CharData can be used to represent character data or a CDATA section within +// an XML document. +type CharData struct { + Data string + parent *Element + index int + flags charDataFlags +} + +// A Comment represents an XML comment. +type Comment struct { + Data string + parent *Element + index int +} + +// A Directive represents an XML directive. +type Directive struct { + Data string + parent *Element + index int +} + +// A ProcInst represents an XML processing instruction. +type ProcInst struct { + Target string + Inst string + parent *Element + index int +} + +// NewDocument creates an XML document without a root element. +func NewDocument() *Document { + return &Document{ + Element{Child: make([]Token, 0)}, + newReadSettings(), + newWriteSettings(), + } +} + +// Copy returns a recursive, deep copy of the document. +func (d *Document) Copy() *Document { + return &Document{*(d.dup(nil).(*Element)), d.ReadSettings, d.WriteSettings} +} + +// Root returns the root element of the document, or nil if there is no root +// element. +func (d *Document) Root() *Element { + for _, t := range d.Child { + if c, ok := t.(*Element); ok { + return c + } + } + return nil +} + +// SetRoot replaces the document's root element with e. If the document +// already has a root when this function is called, then the document's +// original root is unbound first. If the element e is bound to another +// document (or to another element within a document), then it is unbound +// first. +func (d *Document) SetRoot(e *Element) { + if e.parent != nil { + e.parent.RemoveChild(e) + } + + p := &d.Element + e.setParent(p) + + // If there is already a root element, replace it. + for i, t := range p.Child { + if _, ok := t.(*Element); ok { + t.setParent(nil) + t.setIndex(-1) + p.Child[i] = e + e.setIndex(i) + return + } + } + + // No existing root element, so add it. + p.addChild(e) +} + +// ReadFrom reads XML from the reader r into the document d. It returns the +// number of bytes read and any error encountered. +func (d *Document) ReadFrom(r io.Reader) (n int64, err error) { + return d.Element.readFrom(r, d.ReadSettings) +} + +// ReadFromFile reads XML from the string s into the document d. +func (d *Document) ReadFromFile(filename string) error { + f, err := os.Open(filename) + if err != nil { + return err + } + defer f.Close() + _, err = d.ReadFrom(f) + return err +} + +// ReadFromBytes reads XML from the byte slice b into the document d. +func (d *Document) ReadFromBytes(b []byte) error { + _, err := d.ReadFrom(bytes.NewReader(b)) + return err +} + +// ReadFromString reads XML from the string s into the document d. +func (d *Document) ReadFromString(s string) error { + _, err := d.ReadFrom(strings.NewReader(s)) + return err +} + +// WriteTo serializes an XML document into the writer w. It +// returns the number of bytes written and any error encountered. +func (d *Document) WriteTo(w io.Writer) (n int64, err error) { + cw := newCountWriter(w) + b := bufio.NewWriter(cw) + for _, c := range d.Child { + c.writeTo(b, &d.WriteSettings) + } + err, n = b.Flush(), cw.bytes + return +} + +// WriteToFile serializes an XML document into the file named +// filename. +func (d *Document) WriteToFile(filename string) error { + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + _, err = d.WriteTo(f) + return err +} + +// WriteToBytes serializes the XML document into a slice of +// bytes. +func (d *Document) WriteToBytes() (b []byte, err error) { + var buf bytes.Buffer + if _, err = d.WriteTo(&buf); err != nil { + return + } + return buf.Bytes(), nil +} + +// WriteToString serializes the XML document into a string. +func (d *Document) WriteToString() (s string, err error) { + var b []byte + if b, err = d.WriteToBytes(); err != nil { + return + } + return string(b), nil +} + +type indentFunc func(depth int) string + +// Indent modifies the document's element tree by inserting character data +// tokens containing newlines and indentation. The amount of indentation per +// depth level is given as spaces. Pass etree.NoIndent for spaces if you want +// no indentation at all. +func (d *Document) Indent(spaces int) { + var indent indentFunc + switch { + case spaces < 0: + indent = func(depth int) string { return "" } + case d.WriteSettings.UseCRLF == true: + indent = func(depth int) string { return indentCRLF(depth*spaces, indentSpaces) } + default: + indent = func(depth int) string { return indentLF(depth*spaces, indentSpaces) } + } + d.Element.indent(0, indent) +} + +// IndentTabs modifies the document's element tree by inserting CharData +// tokens containing newlines and tabs for indentation. One tab is used per +// indentation level. +func (d *Document) IndentTabs() { + var indent indentFunc + switch d.WriteSettings.UseCRLF { + case true: + indent = func(depth int) string { return indentCRLF(depth, indentTabs) } + default: + indent = func(depth int) string { return indentLF(depth, indentTabs) } + } + d.Element.indent(0, indent) +} + +// NewElement creates an unparented element with the specified tag. The tag +// may be prefixed by a namespace prefix and a colon. +func NewElement(tag string) *Element { + space, stag := spaceDecompose(tag) + return newElement(space, stag, nil) +} + +// newElement is a helper function that creates an element and binds it to +// a parent element if possible. +func newElement(space, tag string, parent *Element) *Element { + e := &Element{ + Space: space, + Tag: tag, + Attr: make([]Attr, 0), + Child: make([]Token, 0), + parent: parent, + index: -1, + } + if parent != nil { + parent.addChild(e) + } + return e +} + +// Copy creates a recursive, deep copy of the element and all its attributes +// and children. The returned element has no parent but can be parented to a +// another element using AddElement, or to a document using SetRoot. +func (e *Element) Copy() *Element { + return e.dup(nil).(*Element) +} + +// FullTag returns the element e's complete tag, including namespace prefix if +// present. +func (e *Element) FullTag() string { + if e.Space == "" { + return e.Tag + } + return e.Space + ":" + e.Tag +} + +// NamespaceURI returns the XML namespace URI associated with the element. If +// the element is part of the XML default namespace, NamespaceURI returns the +// empty string. +func (e *Element) NamespaceURI() string { + if e.Space == "" { + return e.findDefaultNamespaceURI() + } + return e.findLocalNamespaceURI(e.Space) +} + +// findLocalNamespaceURI finds the namespace URI corresponding to the +// requested prefix. +func (e *Element) findLocalNamespaceURI(prefix string) string { + for _, a := range e.Attr { + if a.Space == "xmlns" && a.Key == prefix { + return a.Value + } + } + + if e.parent == nil { + return "" + } + + return e.parent.findLocalNamespaceURI(prefix) +} + +// findDefaultNamespaceURI finds the default namespace URI of the element. +func (e *Element) findDefaultNamespaceURI() string { + for _, a := range e.Attr { + if a.Space == "" && a.Key == "xmlns" { + return a.Value + } + } + + if e.parent == nil { + return "" + } + + return e.parent.findDefaultNamespaceURI() +} + +// hasText returns true if the element has character data immediately +// folllowing the element's opening tag. +func (e *Element) hasText() bool { + if len(e.Child) == 0 { + return false + } + _, ok := e.Child[0].(*CharData) + return ok +} + +// namespacePrefix returns the namespace prefix associated with the element. +func (e *Element) namespacePrefix() string { + return e.Space +} + +// name returns the tag associated with the element. +func (e *Element) name() string { + return e.Tag +} + +// Text returns all character data immediately following the element's opening +// tag. +func (e *Element) Text() string { + if len(e.Child) == 0 { + return "" + } + + text := "" + for _, ch := range e.Child { + if cd, ok := ch.(*CharData); ok { + if text == "" { + text = cd.Data + } else { + text = text + cd.Data + } + } else { + break + } + } + return text +} + +// SetText replaces all character data immediately following an element's +// opening tag with the requested string. +func (e *Element) SetText(text string) { + e.replaceText(0, text, 0) +} + +// SetCData replaces all character data immediately following an element's +// opening tag with a CDATA section. +func (e *Element) SetCData(text string) { + e.replaceText(0, text, cdataFlag) +} + +// Tail returns all character data immediately following the element's end +// tag. +func (e *Element) Tail() string { + if e.Parent() == nil { + return "" + } + + p := e.Parent() + i := e.Index() + + text := "" + for _, ch := range p.Child[i+1:] { + if cd, ok := ch.(*CharData); ok { + if text == "" { + text = cd.Data + } else { + text = text + cd.Data + } + } else { + break + } + } + return text +} + +// SetTail replaces all character data immediately following the element's end +// tag with the requested string. +func (e *Element) SetTail(text string) { + if e.Parent() == nil { + return + } + + p := e.Parent() + p.replaceText(e.Index()+1, text, 0) +} + +// replaceText is a helper function that replaces a series of chardata tokens +// starting at index i with the requested text. +func (e *Element) replaceText(i int, text string, flags charDataFlags) { + end := e.findTermCharDataIndex(i) + + switch { + case end == i: + if text != "" { + // insert a new chardata token at index i + cd := newCharData(text, flags, nil) + e.InsertChildAt(i, cd) + } + + case end == i+1: + if text == "" { + // remove the chardata token at index i + e.RemoveChildAt(i) + } else { + // replace the first and only character token at index i + cd := e.Child[i].(*CharData) + cd.Data, cd.flags = text, flags + } + + default: + if text == "" { + // remove all chardata tokens starting from index i + copy(e.Child[i:], e.Child[end:]) + removed := end - i + e.Child = e.Child[:len(e.Child)-removed] + for j := i; j < len(e.Child); j++ { + e.Child[j].setIndex(j) + } + } else { + // replace the first chardata token at index i and remove all + // subsequent chardata tokens + cd := e.Child[i].(*CharData) + cd.Data, cd.flags = text, flags + copy(e.Child[i+1:], e.Child[end:]) + removed := end - (i + 1) + e.Child = e.Child[:len(e.Child)-removed] + for j := i + 1; j < len(e.Child); j++ { + e.Child[j].setIndex(j) + } + } + } +} + +// findTermCharDataIndex finds the index of the first child token that isn't +// a CharData token. It starts from the requested start index. +func (e *Element) findTermCharDataIndex(start int) int { + for i := start; i < len(e.Child); i++ { + if _, ok := e.Child[i].(*CharData); !ok { + return i + } + } + return len(e.Child) +} + +// CreateElement creates an element with the specified tag and adds it as the +// last child element of the element e. The tag may be prefixed by a namespace +// prefix and a colon. +func (e *Element) CreateElement(tag string) *Element { + space, stag := spaceDecompose(tag) + return newElement(space, stag, e) +} + +// AddChild adds the token t as the last child of element e. If token t was +// already the child of another element, it is first removed from its current +// parent element. +func (e *Element) AddChild(t Token) { + if t.Parent() != nil { + t.Parent().RemoveChild(t) + } + + t.setParent(e) + e.addChild(t) +} + +// InsertChild inserts the token t before e's existing child token ex. If ex +// is nil or ex is not a child of e, then t is added to the end of e's child +// token list. If token t was already the child of another element, it is +// first removed from its current parent element. +// +// Deprecated: InsertChild is deprecated. Use InsertChildAt instead. +func (e *Element) InsertChild(ex Token, t Token) { + if ex == nil || ex.Parent() != e { + e.AddChild(t) + return + } + + if t.Parent() != nil { + t.Parent().RemoveChild(t) + } + + t.setParent(e) + + i := ex.Index() + e.Child = append(e.Child, nil) + copy(e.Child[i+1:], e.Child[i:]) + e.Child[i] = t + + for j := i; j < len(e.Child); j++ { + e.Child[j].setIndex(j) + } +} + +// InsertChildAt inserts the token t into the element e's list of child tokens +// just before the requested index. If the index is greater than or equal to +// the length of the list of child tokens, the token t is added to the end of +// the list. +func (e *Element) InsertChildAt(index int, t Token) { + if index >= len(e.Child) { + e.AddChild(t) + return + } + + if t.Parent() != nil { + if t.Parent() == e && t.Index() > index { + index-- + } + t.Parent().RemoveChild(t) + } + + t.setParent(e) + + e.Child = append(e.Child, nil) + copy(e.Child[index+1:], e.Child[index:]) + e.Child[index] = t + + for j := index; j < len(e.Child); j++ { + e.Child[j].setIndex(j) + } +} + +// RemoveChild attempts to remove the token t from element e's list of +// children. If the token t is a child of e, then it is returned. Otherwise, +// nil is returned. +func (e *Element) RemoveChild(t Token) Token { + if t.Parent() != e { + return nil + } + return e.RemoveChildAt(t.Index()) +} + +// RemoveChildAt removes the index-th child token from the element e. The +// removed child token is returned. If the index is out of bounds, no child is +// removed and nil is returned. +func (e *Element) RemoveChildAt(index int) Token { + if index >= len(e.Child) { + return nil + } + + t := e.Child[index] + for j := index + 1; j < len(e.Child); j++ { + e.Child[j].setIndex(j - 1) + } + e.Child = append(e.Child[:index], e.Child[index+1:]...) + t.setIndex(-1) + t.setParent(nil) + return t +} + +// ReadFrom reads XML from the reader r and stores the result as a new child +// of element e. +func (e *Element) readFrom(ri io.Reader, settings ReadSettings) (n int64, err error) { + r := newCountReader(ri) + dec := xml.NewDecoder(r) + dec.CharsetReader = settings.CharsetReader + dec.Strict = !settings.Permissive + dec.Entity = settings.Entity + var stack stack + stack.push(e) + for { + t, err := dec.RawToken() + switch { + case err == io.EOF: + return r.bytes, nil + case err != nil: + return r.bytes, err + case stack.empty(): + return r.bytes, ErrXML + } + + top := stack.peek().(*Element) + + switch t := t.(type) { + case xml.StartElement: + e := newElement(t.Name.Space, t.Name.Local, top) + for _, a := range t.Attr { + e.createAttr(a.Name.Space, a.Name.Local, a.Value, e) + } + stack.push(e) + case xml.EndElement: + stack.pop() + case xml.CharData: + data := string(t) + var flags charDataFlags + if isWhitespace(data) { + flags = whitespaceFlag + } + newCharData(data, flags, top) + case xml.Comment: + newComment(string(t), top) + case xml.Directive: + newDirective(string(t), top) + case xml.ProcInst: + newProcInst(t.Target, string(t.Inst), top) + } + } +} + +// SelectAttr finds an element attribute matching the requested key and +// returns it if found. Returns nil if no matching attribute is found. The key +// may be prefixed by a namespace prefix and a colon. +func (e *Element) SelectAttr(key string) *Attr { + space, skey := spaceDecompose(key) + for i, a := range e.Attr { + if spaceMatch(space, a.Space) && skey == a.Key { + return &e.Attr[i] + } + } + return nil +} + +// SelectAttrValue finds an element attribute matching the requested key and +// returns its value if found. The key may be prefixed by a namespace prefix +// and a colon. If the key is not found, the dflt value is returned instead. +func (e *Element) SelectAttrValue(key, dflt string) string { + space, skey := spaceDecompose(key) + for _, a := range e.Attr { + if spaceMatch(space, a.Space) && skey == a.Key { + return a.Value + } + } + return dflt +} + +// ChildElements returns all elements that are children of element e. +func (e *Element) ChildElements() []*Element { + var elements []*Element + for _, t := range e.Child { + if c, ok := t.(*Element); ok { + elements = append(elements, c) + } + } + return elements +} + +// SelectElement returns the first child element with the given tag. The tag +// may be prefixed by a namespace prefix and a colon. Returns nil if no +// element with a matching tag was found. +func (e *Element) SelectElement(tag string) *Element { + space, stag := spaceDecompose(tag) + for _, t := range e.Child { + if c, ok := t.(*Element); ok && spaceMatch(space, c.Space) && stag == c.Tag { + return c + } + } + return nil +} + +// SelectElements returns a slice of all child elements with the given tag. +// The tag may be prefixed by a namespace prefix and a colon. +func (e *Element) SelectElements(tag string) []*Element { + space, stag := spaceDecompose(tag) + var elements []*Element + for _, t := range e.Child { + if c, ok := t.(*Element); ok && spaceMatch(space, c.Space) && stag == c.Tag { + elements = append(elements, c) + } + } + return elements +} + +// FindElement returns the first element matched by the XPath-like path +// string. Returns nil if no element is found using the path. Panics if an +// invalid path string is supplied. +func (e *Element) FindElement(path string) *Element { + return e.FindElementPath(MustCompilePath(path)) +} + +// FindElementPath returns the first element matched by the XPath-like path +// string. Returns nil if no element is found using the path. +func (e *Element) FindElementPath(path Path) *Element { + p := newPather() + elements := p.traverse(e, path) + switch { + case len(elements) > 0: + return elements[0] + default: + return nil + } +} + +// FindElements returns a slice of elements matched by the XPath-like path +// string. Panics if an invalid path string is supplied. +func (e *Element) FindElements(path string) []*Element { + return e.FindElementsPath(MustCompilePath(path)) +} + +// FindElementsPath returns a slice of elements matched by the Path object. +func (e *Element) FindElementsPath(path Path) []*Element { + p := newPather() + return p.traverse(e, path) +} + +// GetPath returns the absolute path of the element. +func (e *Element) GetPath() string { + path := []string{} + for seg := e; seg != nil; seg = seg.Parent() { + if seg.Tag != "" { + path = append(path, seg.Tag) + } + } + + // Reverse the path. + for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 { + path[i], path[j] = path[j], path[i] + } + + return "/" + strings.Join(path, "/") +} + +// GetRelativePath returns the path of the element relative to the source +// element. If the two elements are not part of the same element tree, then +// GetRelativePath returns the empty string. +func (e *Element) GetRelativePath(source *Element) string { + var path []*Element + + if source == nil { + return "" + } + + // Build a reverse path from the element toward the root. Stop if the + // source element is encountered. + var seg *Element + for seg = e; seg != nil && seg != source; seg = seg.Parent() { + path = append(path, seg) + } + + // If we found the source element, reverse the path and compose the + // string. + if seg == source { + if len(path) == 0 { + return "." + } + parts := []string{} + for i := len(path) - 1; i >= 0; i-- { + parts = append(parts, path[i].Tag) + } + return "./" + strings.Join(parts, "/") + } + + // The source wasn't encountered, so climb from the source element toward + // the root of the tree until an element in the reversed path is + // encountered. + + findPathIndex := func(e *Element, path []*Element) int { + for i, ee := range path { + if e == ee { + return i + } + } + return -1 + } + + climb := 0 + for seg = source; seg != nil; seg = seg.Parent() { + i := findPathIndex(seg, path) + if i >= 0 { + path = path[:i] // truncate at found segment + break + } + climb++ + } + + // No element in the reversed path was encountered, so the two elements + // must not be part of the same tree. + if seg == nil { + return "" + } + + // Reverse the (possibly truncated) path and prepend ".." segments to + // climb. + parts := []string{} + for i := 0; i < climb; i++ { + parts = append(parts, "..") + } + for i := len(path) - 1; i >= 0; i-- { + parts = append(parts, path[i].Tag) + } + return strings.Join(parts, "/") +} + +// indent recursively inserts proper indentation between an +// XML element's child tokens. +func (e *Element) indent(depth int, indent indentFunc) { + e.stripIndent() + n := len(e.Child) + if n == 0 { + return + } + + oldChild := e.Child + e.Child = make([]Token, 0, n*2+1) + isCharData, firstNonCharData := false, true + for _, c := range oldChild { + // Insert NL+indent before child if it's not character data. + // Exceptions: when it's the first non-character-data child, or when + // the child is at root depth. + _, isCharData = c.(*CharData) + if !isCharData { + if !firstNonCharData || depth > 0 { + s := indent(depth) + if s != "" { + newCharData(s, whitespaceFlag, e) + } + } + firstNonCharData = false + } + + e.addChild(c) + + // Recursively process child elements. + if ce, ok := c.(*Element); ok { + ce.indent(depth+1, indent) + } + } + + // Insert NL+indent before the last child. + if !isCharData { + if !firstNonCharData || depth > 0 { + s := indent(depth - 1) + if s != "" { + newCharData(s, whitespaceFlag, e) + } + } + } +} + +// stripIndent removes any previously inserted indentation. +func (e *Element) stripIndent() { + // Count the number of non-indent child tokens + n := len(e.Child) + for _, c := range e.Child { + if cd, ok := c.(*CharData); ok && cd.IsWhitespace() { + n-- + } + } + if n == len(e.Child) { + return + } + + // Strip out indent CharData + newChild := make([]Token, n) + j := 0 + for _, c := range e.Child { + if cd, ok := c.(*CharData); ok && cd.IsWhitespace() { + continue + } + newChild[j] = c + newChild[j].setIndex(j) + j++ + } + e.Child = newChild +} + +// dup duplicates the element. +func (e *Element) dup(parent *Element) Token { + ne := &Element{ + Space: e.Space, + Tag: e.Tag, + Attr: make([]Attr, len(e.Attr)), + Child: make([]Token, len(e.Child)), + parent: parent, + index: e.index, + } + for i, t := range e.Child { + ne.Child[i] = t.dup(ne) + } + for i, a := range e.Attr { + ne.Attr[i] = a + } + return ne +} + +// Parent returns the element token's parent element, or nil if it has no +// parent. +func (e *Element) Parent() *Element { + return e.parent +} + +// Index returns the index of this element within its parent element's +// list of child tokens. If this element has no parent element, the index +// is -1. +func (e *Element) Index() int { + return e.index +} + +// setParent replaces the element token's parent. +func (e *Element) setParent(parent *Element) { + e.parent = parent +} + +// setIndex sets the element token's index within its parent's Child slice. +func (e *Element) setIndex(index int) { + e.index = index +} + +// writeTo serializes the element to the writer w. +func (e *Element) writeTo(w *bufio.Writer, s *WriteSettings) { + w.WriteByte('<') + w.WriteString(e.FullTag()) + for _, a := range e.Attr { + w.WriteByte(' ') + a.writeTo(w, s) + } + if len(e.Child) > 0 { + w.WriteString(">") + for _, c := range e.Child { + c.writeTo(w, s) + } + w.Write([]byte{'<', '/'}) + w.WriteString(e.FullTag()) + w.WriteByte('>') + } else { + if s.CanonicalEndTags { + w.Write([]byte{'>', '<', '/'}) + w.WriteString(e.FullTag()) + w.WriteByte('>') + } else { + w.Write([]byte{'/', '>'}) + } + } +} + +// addChild adds a child token to the element e. +func (e *Element) addChild(t Token) { + t.setIndex(len(e.Child)) + e.Child = append(e.Child, t) +} + +// CreateAttr creates an attribute and adds it to element e. The key may be +// prefixed by a namespace prefix and a colon. If an attribute with the key +// already exists, its value is replaced. +func (e *Element) CreateAttr(key, value string) *Attr { + space, skey := spaceDecompose(key) + return e.createAttr(space, skey, value, e) +} + +// createAttr is a helper function that creates attributes. +func (e *Element) createAttr(space, key, value string, parent *Element) *Attr { + for i, a := range e.Attr { + if space == a.Space && key == a.Key { + e.Attr[i].Value = value + return &e.Attr[i] + } + } + a := Attr{ + Space: space, + Key: key, + Value: value, + element: parent, + } + e.Attr = append(e.Attr, a) + return &e.Attr[len(e.Attr)-1] +} + +// RemoveAttr removes and returns a copy of the first attribute of the element +// whose key matches the given key. The key may be prefixed by a namespace +// prefix and a colon. If a matching attribute does not exist, nil is +// returned. +func (e *Element) RemoveAttr(key string) *Attr { + space, skey := spaceDecompose(key) + for i, a := range e.Attr { + if space == a.Space && skey == a.Key { + e.Attr = append(e.Attr[0:i], e.Attr[i+1:]...) + return &Attr{ + Space: a.Space, + Key: a.Key, + Value: a.Value, + element: nil, + } + } + } + return nil +} + +// SortAttrs sorts the element's attributes lexicographically by key. +func (e *Element) SortAttrs() { + sort.Sort(byAttr(e.Attr)) +} + +type byAttr []Attr + +func (a byAttr) Len() int { + return len(a) +} + +func (a byAttr) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +func (a byAttr) Less(i, j int) bool { + sp := strings.Compare(a[i].Space, a[j].Space) + if sp == 0 { + return strings.Compare(a[i].Key, a[j].Key) < 0 + } + return sp < 0 +} + +// FullKey returns the attribute a's complete key, including namespace prefix +// if present. +func (a *Attr) FullKey() string { + if a.Space == "" { + return a.Key + } + return a.Space + ":" + a.Key +} + +// Element returns the element containing the attribute. +func (a *Attr) Element() *Element { + return a.element +} + +// NamespaceURI returns the XML namespace URI associated with the attribute. +// If the element is part of the XML default namespace, NamespaceURI returns +// the empty string. +func (a *Attr) NamespaceURI() string { + return a.element.NamespaceURI() +} + +// writeTo serializes the attribute to the writer. +func (a *Attr) writeTo(w *bufio.Writer, s *WriteSettings) { + w.WriteString(a.FullKey()) + w.WriteString(`="`) + var m escapeMode + if s.CanonicalAttrVal { + m = escapeCanonicalAttr + } else { + m = escapeNormal + } + escapeString(w, a.Value, m) + w.WriteByte('"') +} + +// NewText creates a parentless CharData token containing character data. +func NewText(text string) *CharData { + return newCharData(text, 0, nil) +} + +// NewCData creates a parentless XML character CDATA section. +func NewCData(data string) *CharData { + return newCharData(data, cdataFlag, nil) +} + +// NewCharData creates a parentless CharData token containing character data. +// +// Deprecated: NewCharData is deprecated. Instead, use NewText, which does the +// same thing. +func NewCharData(data string) *CharData { + return newCharData(data, 0, nil) +} + +// newCharData creates a character data token and binds it to a parent +// element. If parent is nil, the CharData token remains unbound. +func newCharData(data string, flags charDataFlags, parent *Element) *CharData { + c := &CharData{ + Data: data, + parent: parent, + index: -1, + flags: flags, + } + if parent != nil { + parent.addChild(c) + } + return c +} + +// CreateText creates a CharData token containing character data and adds it +// as a child of element e. +func (e *Element) CreateText(text string) *CharData { + return newCharData(text, 0, e) +} + +// CreateCData creates a CharData token containing a CDATA section and adds it +// as a child of element e. +func (e *Element) CreateCData(data string) *CharData { + return newCharData(data, cdataFlag, e) +} + +// CreateCharData creates a CharData token containing character data and adds +// it as a child of element e. +// +// Deprecated: CreateCharData is deprecated. Instead, use CreateText, which +// does the same thing. +func (e *Element) CreateCharData(data string) *CharData { + return newCharData(data, 0, e) +} + +// dup duplicates the character data. +func (c *CharData) dup(parent *Element) Token { + return &CharData{ + Data: c.Data, + flags: c.flags, + parent: parent, + index: c.index, + } +} + +// IsCData returns true if the character data token is to be encoded as a +// CDATA section. +func (c *CharData) IsCData() bool { + return (c.flags & cdataFlag) != 0 +} + +// IsWhitespace returns true if the character data token was created by one of +// the document Indent methods to contain only whitespace. +func (c *CharData) IsWhitespace() bool { + return (c.flags & whitespaceFlag) != 0 +} + +// Parent returns the character data token's parent element, or nil if it has +// no parent. +func (c *CharData) Parent() *Element { + return c.parent +} + +// Index returns the index of this CharData token within its parent element's +// list of child tokens. If this CharData token has no parent element, the +// index is -1. +func (c *CharData) Index() int { + return c.index +} + +// setParent replaces the character data token's parent. +func (c *CharData) setParent(parent *Element) { + c.parent = parent +} + +// setIndex sets the CharData token's index within its parent element's Child +// slice. +func (c *CharData) setIndex(index int) { + c.index = index +} + +// writeTo serializes character data to the writer. +func (c *CharData) writeTo(w *bufio.Writer, s *WriteSettings) { + if c.IsCData() { + w.WriteString(``) + } else { + var m escapeMode + if s.CanonicalText { + m = escapeCanonicalText + } else { + m = escapeNormal + } + escapeString(w, c.Data, m) + } +} + +// NewComment creates a parentless XML comment. +func NewComment(comment string) *Comment { + return newComment(comment, nil) +} + +// NewComment creates an XML comment and binds it to a parent element. If +// parent is nil, the Comment remains unbound. +func newComment(comment string, parent *Element) *Comment { + c := &Comment{ + Data: comment, + parent: parent, + index: -1, + } + if parent != nil { + parent.addChild(c) + } + return c +} + +// CreateComment creates an XML comment and adds it as a child of element e. +func (e *Element) CreateComment(comment string) *Comment { + return newComment(comment, e) +} + +// dup duplicates the comment. +func (c *Comment) dup(parent *Element) Token { + return &Comment{ + Data: c.Data, + parent: parent, + index: c.index, + } +} + +// Parent returns comment token's parent element, or nil if it has no parent. +func (c *Comment) Parent() *Element { + return c.parent +} + +// Index returns the index of this Comment token within its parent element's +// list of child tokens. If this Comment token has no parent element, the +// index is -1. +func (c *Comment) Index() int { + return c.index +} + +// setParent replaces the comment token's parent. +func (c *Comment) setParent(parent *Element) { + c.parent = parent +} + +// setIndex sets the Comment token's index within its parent element's Child +// slice. +func (c *Comment) setIndex(index int) { + c.index = index +} + +// writeTo serialies the comment to the writer. +func (c *Comment) writeTo(w *bufio.Writer, s *WriteSettings) { + w.WriteString("") +} + +// NewDirective creates a parentless XML directive. +func NewDirective(data string) *Directive { + return newDirective(data, nil) +} + +// newDirective creates an XML directive and binds it to a parent element. If +// parent is nil, the Directive remains unbound. +func newDirective(data string, parent *Element) *Directive { + d := &Directive{ + Data: data, + parent: parent, + index: -1, + } + if parent != nil { + parent.addChild(d) + } + return d +} + +// CreateDirective creates an XML directive and adds it as the last child of +// element e. +func (e *Element) CreateDirective(data string) *Directive { + return newDirective(data, e) +} + +// dup duplicates the directive. +func (d *Directive) dup(parent *Element) Token { + return &Directive{ + Data: d.Data, + parent: parent, + index: d.index, + } +} + +// Parent returns directive token's parent element, or nil if it has no +// parent. +func (d *Directive) Parent() *Element { + return d.parent +} + +// Index returns the index of this Directive token within its parent element's +// list of child tokens. If this Directive token has no parent element, the +// index is -1. +func (d *Directive) Index() int { + return d.index +} + +// setParent replaces the directive token's parent. +func (d *Directive) setParent(parent *Element) { + d.parent = parent +} + +// setIndex sets the Directive token's index within its parent element's Child +// slice. +func (d *Directive) setIndex(index int) { + d.index = index +} + +// writeTo serializes the XML directive to the writer. +func (d *Directive) writeTo(w *bufio.Writer, s *WriteSettings) { + w.WriteString("") +} + +// NewProcInst creates a parentless XML processing instruction. +func NewProcInst(target, inst string) *ProcInst { + return newProcInst(target, inst, nil) +} + +// newProcInst creates an XML processing instruction and binds it to a parent +// element. If parent is nil, the ProcInst remains unbound. +func newProcInst(target, inst string, parent *Element) *ProcInst { + p := &ProcInst{ + Target: target, + Inst: inst, + parent: parent, + index: -1, + } + if parent != nil { + parent.addChild(p) + } + return p +} + +// CreateProcInst creates a processing instruction and adds it as a child of +// element e. +func (e *Element) CreateProcInst(target, inst string) *ProcInst { + return newProcInst(target, inst, e) +} + +// dup duplicates the procinst. +func (p *ProcInst) dup(parent *Element) Token { + return &ProcInst{ + Target: p.Target, + Inst: p.Inst, + parent: parent, + index: p.index, + } +} + +// Parent returns processing instruction token's parent element, or nil if it +// has no parent. +func (p *ProcInst) Parent() *Element { + return p.parent +} + +// Index returns the index of this ProcInst token within its parent element's +// list of child tokens. If this ProcInst token has no parent element, the +// index is -1. +func (p *ProcInst) Index() int { + return p.index +} + +// setParent replaces the processing instruction token's parent. +func (p *ProcInst) setParent(parent *Element) { + p.parent = parent +} + +// setIndex sets the processing instruction token's index within its parent +// element's Child slice. +func (p *ProcInst) setIndex(index int) { + p.index = index +} + +// writeTo serializes the processing instruction to the writer. +func (p *ProcInst) writeTo(w *bufio.Writer, s *WriteSettings) { + w.WriteString("") +} diff --git a/vendor/github.com/beevik/etree/helpers.go b/vendor/github.com/beevik/etree/helpers.go new file mode 100644 index 00000000..825e14e9 --- /dev/null +++ b/vendor/github.com/beevik/etree/helpers.go @@ -0,0 +1,276 @@ +// Copyright 2015-2019 Brett Vickers. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package etree + +import ( + "bufio" + "io" + "strings" + "unicode/utf8" +) + +// A simple stack +type stack struct { + data []interface{} +} + +func (s *stack) empty() bool { + return len(s.data) == 0 +} + +func (s *stack) push(value interface{}) { + s.data = append(s.data, value) +} + +func (s *stack) pop() interface{} { + value := s.data[len(s.data)-1] + s.data[len(s.data)-1] = nil + s.data = s.data[:len(s.data)-1] + return value +} + +func (s *stack) peek() interface{} { + return s.data[len(s.data)-1] +} + +// A fifo is a simple first-in-first-out queue. +type fifo struct { + data []interface{} + head, tail int +} + +func (f *fifo) add(value interface{}) { + if f.len()+1 >= len(f.data) { + f.grow() + } + f.data[f.tail] = value + if f.tail++; f.tail == len(f.data) { + f.tail = 0 + } +} + +func (f *fifo) remove() interface{} { + value := f.data[f.head] + f.data[f.head] = nil + if f.head++; f.head == len(f.data) { + f.head = 0 + } + return value +} + +func (f *fifo) len() int { + if f.tail >= f.head { + return f.tail - f.head + } + return len(f.data) - f.head + f.tail +} + +func (f *fifo) grow() { + c := len(f.data) * 2 + if c == 0 { + c = 4 + } + buf, count := make([]interface{}, c), f.len() + if f.tail >= f.head { + copy(buf[0:count], f.data[f.head:f.tail]) + } else { + hindex := len(f.data) - f.head + copy(buf[0:hindex], f.data[f.head:]) + copy(buf[hindex:count], f.data[:f.tail]) + } + f.data, f.head, f.tail = buf, 0, count +} + +// countReader implements a proxy reader that counts the number of +// bytes read from its encapsulated reader. +type countReader struct { + r io.Reader + bytes int64 +} + +func newCountReader(r io.Reader) *countReader { + return &countReader{r: r} +} + +func (cr *countReader) Read(p []byte) (n int, err error) { + b, err := cr.r.Read(p) + cr.bytes += int64(b) + return b, err +} + +// countWriter implements a proxy writer that counts the number of +// bytes written by its encapsulated writer. +type countWriter struct { + w io.Writer + bytes int64 +} + +func newCountWriter(w io.Writer) *countWriter { + return &countWriter{w: w} +} + +func (cw *countWriter) Write(p []byte) (n int, err error) { + b, err := cw.w.Write(p) + cw.bytes += int64(b) + return b, err +} + +// isWhitespace returns true if the byte slice contains only +// whitespace characters. +func isWhitespace(s string) bool { + for i := 0; i < len(s); i++ { + if c := s[i]; c != ' ' && c != '\t' && c != '\n' && c != '\r' { + return false + } + } + return true +} + +// spaceMatch returns true if namespace a is the empty string +// or if namespace a equals namespace b. +func spaceMatch(a, b string) bool { + switch { + case a == "": + return true + default: + return a == b + } +} + +// spaceDecompose breaks a namespace:tag identifier at the ':' +// and returns the two parts. +func spaceDecompose(str string) (space, key string) { + colon := strings.IndexByte(str, ':') + if colon == -1 { + return "", str + } + return str[:colon], str[colon+1:] +} + +// Strings used by indentCRLF and indentLF +const ( + indentSpaces = "\r\n " + indentTabs = "\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" +) + +// indentCRLF returns a CRLF newline followed by n copies of the first +// non-CRLF character in the source string. +func indentCRLF(n int, source string) string { + switch { + case n < 0: + return source[:2] + case n < len(source)-1: + return source[:n+2] + default: + return source + strings.Repeat(source[2:3], n-len(source)+2) + } +} + +// indentLF returns a LF newline followed by n copies of the first non-LF +// character in the source string. +func indentLF(n int, source string) string { + switch { + case n < 0: + return source[1:2] + case n < len(source)-1: + return source[1 : n+2] + default: + return source[1:] + strings.Repeat(source[2:3], n-len(source)+2) + } +} + +// nextIndex returns the index of the next occurrence of sep in s, +// starting from offset. It returns -1 if the sep string is not found. +func nextIndex(s, sep string, offset int) int { + switch i := strings.Index(s[offset:], sep); i { + case -1: + return -1 + default: + return offset + i + } +} + +// isInteger returns true if the string s contains an integer. +func isInteger(s string) bool { + for i := 0; i < len(s); i++ { + if (s[i] < '0' || s[i] > '9') && !(i == 0 && s[i] == '-') { + return false + } + } + return true +} + +type escapeMode byte + +const ( + escapeNormal escapeMode = iota + escapeCanonicalText + escapeCanonicalAttr +) + +// escapeString writes an escaped version of a string to the writer. +func escapeString(w *bufio.Writer, s string, m escapeMode) { + var esc []byte + last := 0 + for i := 0; i < len(s); { + r, width := utf8.DecodeRuneInString(s[i:]) + i += width + switch r { + case '&': + esc = []byte("&") + case '<': + esc = []byte("<") + case '>': + if m == escapeCanonicalAttr { + continue + } + esc = []byte(">") + case '\'': + if m != escapeNormal { + continue + } + esc = []byte("'") + case '"': + if m == escapeCanonicalText { + continue + } + esc = []byte(""") + case '\t': + if m != escapeCanonicalAttr { + continue + } + esc = []byte(" ") + case '\n': + if m != escapeCanonicalAttr { + continue + } + esc = []byte(" ") + case '\r': + if m == escapeNormal { + continue + } + esc = []byte(" ") + default: + if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) { + esc = []byte("\uFFFD") + break + } + continue + } + w.WriteString(s[last : i-width]) + w.Write(esc) + last = i + } + w.WriteString(s[last:]) +} + +func isInCharacterRange(r rune) bool { + return r == 0x09 || + r == 0x0A || + r == 0x0D || + r >= 0x20 && r <= 0xD7FF || + r >= 0xE000 && r <= 0xFFFD || + r >= 0x10000 && r <= 0x10FFFF +} diff --git a/vendor/github.com/beevik/etree/path.go b/vendor/github.com/beevik/etree/path.go new file mode 100644 index 00000000..82db0ac5 --- /dev/null +++ b/vendor/github.com/beevik/etree/path.go @@ -0,0 +1,582 @@ +// Copyright 2015-2019 Brett Vickers. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package etree + +import ( + "strconv" + "strings" +) + +/* +A Path is a string that represents a search path through an etree starting +from the document root or an arbitrary element. Paths are used with the +Element object's Find* methods to locate and return desired elements. + +A Path consists of a series of slash-separated "selectors", each of which may +be modified by one or more bracket-enclosed "filters". Selectors are used to +traverse the etree from element to element, while filters are used to narrow +the list of candidate elements at each node. + +Although etree Path strings are similar to XPath strings +(https://www.w3.org/TR/1999/REC-xpath-19991116/), they have a more limited set +of selectors and filtering options. + +The following selectors are supported by etree Path strings: + + . Select the current element. + .. Select the parent of the current element. + * Select all child elements of the current element. + / Select the root element when used at the start of a path. + // Select all descendants of the current element. + tag Select all child elements with a name matching the tag. + +The following basic filters are supported by etree Path strings: + + [@attrib] Keep elements with an attribute named attrib. + [@attrib='val'] Keep elements with an attribute named attrib and value matching val. + [tag] Keep elements with a child element named tag. + [tag='val'] Keep elements with a child element named tag and text matching val. + [n] Keep the n-th element, where n is a numeric index starting from 1. + +The following function filters are also supported: + + [text()] Keep elements with non-empty text. + [text()='val'] Keep elements whose text matches val. + [local-name()='val'] Keep elements whose un-prefixed tag matches val. + [name()='val'] Keep elements whose full tag exactly matches val. + [namespace-prefix()='val'] Keep elements whose namespace prefix matches val. + [namespace-uri()='val'] Keep elements whose namespace URI matches val. + +Here are some examples of Path strings: + +- Select the bookstore child element of the root element: + /bookstore + +- Beginning from the root element, select the title elements of all +descendant book elements having a 'category' attribute of 'WEB': + //book[@category='WEB']/title + +- Beginning from the current element, select the first descendant +book element with a title child element containing the text 'Great +Expectations': + .//book[title='Great Expectations'][1] + +- Beginning from the current element, select all child elements of +book elements with an attribute 'language' set to 'english': + ./book/*[@language='english'] + +- Beginning from the current element, select all child elements of +book elements containing the text 'special': + ./book/*[text()='special'] + +- Beginning from the current element, select all descendant book +elements whose title child element has a 'language' attribute of 'french': + .//book/title[@language='french']/.. + +- Beginning from the current element, select all book elements +belonging to the http://www.w3.org/TR/html4/ namespace: + .//book[namespace-uri()='http://www.w3.org/TR/html4/'] + +*/ +type Path struct { + segments []segment +} + +// ErrPath is returned by path functions when an invalid etree path is provided. +type ErrPath string + +// Error returns the string describing a path error. +func (err ErrPath) Error() string { + return "etree: " + string(err) +} + +// CompilePath creates an optimized version of an XPath-like string that +// can be used to query elements in an element tree. +func CompilePath(path string) (Path, error) { + var comp compiler + segments := comp.parsePath(path) + if comp.err != ErrPath("") { + return Path{nil}, comp.err + } + return Path{segments}, nil +} + +// MustCompilePath creates an optimized version of an XPath-like string that +// can be used to query elements in an element tree. Panics if an error +// occurs. Use this function to create Paths when you know the path is +// valid (i.e., if it's hard-coded). +func MustCompilePath(path string) Path { + p, err := CompilePath(path) + if err != nil { + panic(err) + } + return p +} + +// A segment is a portion of a path between "/" characters. +// It contains one selector and zero or more [filters]. +type segment struct { + sel selector + filters []filter +} + +func (seg *segment) apply(e *Element, p *pather) { + seg.sel.apply(e, p) + for _, f := range seg.filters { + f.apply(p) + } +} + +// A selector selects XML elements for consideration by the +// path traversal. +type selector interface { + apply(e *Element, p *pather) +} + +// A filter pares down a list of candidate XML elements based +// on a path filter in [brackets]. +type filter interface { + apply(p *pather) +} + +// A pather is helper object that traverses an element tree using +// a Path object. It collects and deduplicates all elements matching +// the path query. +type pather struct { + queue fifo + results []*Element + inResults map[*Element]bool + candidates []*Element + scratch []*Element // used by filters +} + +// A node represents an element and the remaining path segments that +// should be applied against it by the pather. +type node struct { + e *Element + segments []segment +} + +func newPather() *pather { + return &pather{ + results: make([]*Element, 0), + inResults: make(map[*Element]bool), + candidates: make([]*Element, 0), + scratch: make([]*Element, 0), + } +} + +// traverse follows the path from the element e, collecting +// and then returning all elements that match the path's selectors +// and filters. +func (p *pather) traverse(e *Element, path Path) []*Element { + for p.queue.add(node{e, path.segments}); p.queue.len() > 0; { + p.eval(p.queue.remove().(node)) + } + return p.results +} + +// eval evalutes the current path node by applying the remaining +// path's selector rules against the node's element. +func (p *pather) eval(n node) { + p.candidates = p.candidates[0:0] + seg, remain := n.segments[0], n.segments[1:] + seg.apply(n.e, p) + + if len(remain) == 0 { + for _, c := range p.candidates { + if in := p.inResults[c]; !in { + p.inResults[c] = true + p.results = append(p.results, c) + } + } + } else { + for _, c := range p.candidates { + p.queue.add(node{c, remain}) + } + } +} + +// A compiler generates a compiled path from a path string. +type compiler struct { + err ErrPath +} + +// parsePath parses an XPath-like string describing a path +// through an element tree and returns a slice of segment +// descriptors. +func (c *compiler) parsePath(path string) []segment { + // If path ends with //, fix it + if strings.HasSuffix(path, "//") { + path = path + "*" + } + + var segments []segment + + // Check for an absolute path + if strings.HasPrefix(path, "/") { + segments = append(segments, segment{new(selectRoot), []filter{}}) + path = path[1:] + } + + // Split path into segments + for _, s := range splitPath(path) { + segments = append(segments, c.parseSegment(s)) + if c.err != ErrPath("") { + break + } + } + return segments +} + +func splitPath(path string) []string { + pieces := make([]string, 0) + start := 0 + inquote := false + for i := 0; i+1 <= len(path); i++ { + if path[i] == '\'' { + inquote = !inquote + } else if path[i] == '/' && !inquote { + pieces = append(pieces, path[start:i]) + start = i + 1 + } + } + return append(pieces, path[start:]) +} + +// parseSegment parses a path segment between / characters. +func (c *compiler) parseSegment(path string) segment { + pieces := strings.Split(path, "[") + seg := segment{ + sel: c.parseSelector(pieces[0]), + filters: []filter{}, + } + for i := 1; i < len(pieces); i++ { + fpath := pieces[i] + if fpath[len(fpath)-1] != ']' { + c.err = ErrPath("path has invalid filter [brackets].") + break + } + seg.filters = append(seg.filters, c.parseFilter(fpath[:len(fpath)-1])) + } + return seg +} + +// parseSelector parses a selector at the start of a path segment. +func (c *compiler) parseSelector(path string) selector { + switch path { + case ".": + return new(selectSelf) + case "..": + return new(selectParent) + case "*": + return new(selectChildren) + case "": + return new(selectDescendants) + default: + return newSelectChildrenByTag(path) + } +} + +var fnTable = map[string]struct { + hasFn func(e *Element) bool + getValFn func(e *Element) string +}{ + "local-name": {nil, (*Element).name}, + "name": {nil, (*Element).FullTag}, + "namespace-prefix": {nil, (*Element).namespacePrefix}, + "namespace-uri": {nil, (*Element).NamespaceURI}, + "text": {(*Element).hasText, (*Element).Text}, +} + +// parseFilter parses a path filter contained within [brackets]. +func (c *compiler) parseFilter(path string) filter { + if len(path) == 0 { + c.err = ErrPath("path contains an empty filter expression.") + return nil + } + + // Filter contains [@attr='val'], [fn()='val'], or [tag='val']? + eqindex := strings.Index(path, "='") + if eqindex >= 0 { + rindex := nextIndex(path, "'", eqindex+2) + if rindex != len(path)-1 { + c.err = ErrPath("path has mismatched filter quotes.") + return nil + } + + key := path[:eqindex] + value := path[eqindex+2 : rindex] + + switch { + case key[0] == '@': + return newFilterAttrVal(key[1:], value) + case strings.HasSuffix(key, "()"): + fn := key[:len(key)-2] + if t, ok := fnTable[fn]; ok && t.getValFn != nil { + return newFilterFuncVal(t.getValFn, value) + } + c.err = ErrPath("path has unknown function " + fn) + return nil + default: + return newFilterChildText(key, value) + } + } + + // Filter contains [@attr], [N], [tag] or [fn()] + switch { + case path[0] == '@': + return newFilterAttr(path[1:]) + case strings.HasSuffix(path, "()"): + fn := path[:len(path)-2] + if t, ok := fnTable[fn]; ok && t.hasFn != nil { + return newFilterFunc(t.hasFn) + } + c.err = ErrPath("path has unknown function " + fn) + return nil + case isInteger(path): + pos, _ := strconv.Atoi(path) + switch { + case pos > 0: + return newFilterPos(pos - 1) + default: + return newFilterPos(pos) + } + default: + return newFilterChild(path) + } +} + +// selectSelf selects the current element into the candidate list. +type selectSelf struct{} + +func (s *selectSelf) apply(e *Element, p *pather) { + p.candidates = append(p.candidates, e) +} + +// selectRoot selects the element's root node. +type selectRoot struct{} + +func (s *selectRoot) apply(e *Element, p *pather) { + root := e + for root.parent != nil { + root = root.parent + } + p.candidates = append(p.candidates, root) +} + +// selectParent selects the element's parent into the candidate list. +type selectParent struct{} + +func (s *selectParent) apply(e *Element, p *pather) { + if e.parent != nil { + p.candidates = append(p.candidates, e.parent) + } +} + +// selectChildren selects the element's child elements into the +// candidate list. +type selectChildren struct{} + +func (s *selectChildren) apply(e *Element, p *pather) { + for _, c := range e.Child { + if c, ok := c.(*Element); ok { + p.candidates = append(p.candidates, c) + } + } +} + +// selectDescendants selects all descendant child elements +// of the element into the candidate list. +type selectDescendants struct{} + +func (s *selectDescendants) apply(e *Element, p *pather) { + var queue fifo + for queue.add(e); queue.len() > 0; { + e := queue.remove().(*Element) + p.candidates = append(p.candidates, e) + for _, c := range e.Child { + if c, ok := c.(*Element); ok { + queue.add(c) + } + } + } +} + +// selectChildrenByTag selects into the candidate list all child +// elements of the element having the specified tag. +type selectChildrenByTag struct { + space, tag string +} + +func newSelectChildrenByTag(path string) *selectChildrenByTag { + s, l := spaceDecompose(path) + return &selectChildrenByTag{s, l} +} + +func (s *selectChildrenByTag) apply(e *Element, p *pather) { + for _, c := range e.Child { + if c, ok := c.(*Element); ok && spaceMatch(s.space, c.Space) && s.tag == c.Tag { + p.candidates = append(p.candidates, c) + } + } +} + +// filterPos filters the candidate list, keeping only the +// candidate at the specified index. +type filterPos struct { + index int +} + +func newFilterPos(pos int) *filterPos { + return &filterPos{pos} +} + +func (f *filterPos) apply(p *pather) { + if f.index >= 0 { + if f.index < len(p.candidates) { + p.scratch = append(p.scratch, p.candidates[f.index]) + } + } else { + if -f.index <= len(p.candidates) { + p.scratch = append(p.scratch, p.candidates[len(p.candidates)+f.index]) + } + } + p.candidates, p.scratch = p.scratch, p.candidates[0:0] +} + +// filterAttr filters the candidate list for elements having +// the specified attribute. +type filterAttr struct { + space, key string +} + +func newFilterAttr(str string) *filterAttr { + s, l := spaceDecompose(str) + return &filterAttr{s, l} +} + +func (f *filterAttr) apply(p *pather) { + for _, c := range p.candidates { + for _, a := range c.Attr { + if spaceMatch(f.space, a.Space) && f.key == a.Key { + p.scratch = append(p.scratch, c) + break + } + } + } + p.candidates, p.scratch = p.scratch, p.candidates[0:0] +} + +// filterAttrVal filters the candidate list for elements having +// the specified attribute with the specified value. +type filterAttrVal struct { + space, key, val string +} + +func newFilterAttrVal(str, value string) *filterAttrVal { + s, l := spaceDecompose(str) + return &filterAttrVal{s, l, value} +} + +func (f *filterAttrVal) apply(p *pather) { + for _, c := range p.candidates { + for _, a := range c.Attr { + if spaceMatch(f.space, a.Space) && f.key == a.Key && f.val == a.Value { + p.scratch = append(p.scratch, c) + break + } + } + } + p.candidates, p.scratch = p.scratch, p.candidates[0:0] +} + +// filterFunc filters the candidate list for elements satisfying a custom +// boolean function. +type filterFunc struct { + fn func(e *Element) bool +} + +func newFilterFunc(fn func(e *Element) bool) *filterFunc { + return &filterFunc{fn} +} + +func (f *filterFunc) apply(p *pather) { + for _, c := range p.candidates { + if f.fn(c) { + p.scratch = append(p.scratch, c) + } + } + p.candidates, p.scratch = p.scratch, p.candidates[0:0] +} + +// filterFuncVal filters the candidate list for elements containing a value +// matching the result of a custom function. +type filterFuncVal struct { + fn func(e *Element) string + val string +} + +func newFilterFuncVal(fn func(e *Element) string, value string) *filterFuncVal { + return &filterFuncVal{fn, value} +} + +func (f *filterFuncVal) apply(p *pather) { + for _, c := range p.candidates { + if f.fn(c) == f.val { + p.scratch = append(p.scratch, c) + } + } + p.candidates, p.scratch = p.scratch, p.candidates[0:0] +} + +// filterChild filters the candidate list for elements having +// a child element with the specified tag. +type filterChild struct { + space, tag string +} + +func newFilterChild(str string) *filterChild { + s, l := spaceDecompose(str) + return &filterChild{s, l} +} + +func (f *filterChild) apply(p *pather) { + for _, c := range p.candidates { + for _, cc := range c.Child { + if cc, ok := cc.(*Element); ok && + spaceMatch(f.space, cc.Space) && + f.tag == cc.Tag { + p.scratch = append(p.scratch, c) + } + } + } + p.candidates, p.scratch = p.scratch, p.candidates[0:0] +} + +// filterChildText filters the candidate list for elements having +// a child element with the specified tag and text. +type filterChildText struct { + space, tag, text string +} + +func newFilterChildText(str, text string) *filterChildText { + s, l := spaceDecompose(str) + return &filterChildText{s, l, text} +} + +func (f *filterChildText) apply(p *pather) { + for _, c := range p.candidates { + for _, cc := range c.Child { + if cc, ok := cc.(*Element); ok && + spaceMatch(f.space, cc.Space) && + f.tag == cc.Tag && + f.text == cc.Text() { + p.scratch = append(p.scratch, c) + } + } + } + p.candidates, p.scratch = p.scratch, p.candidates[0:0] +} diff --git a/vendor/github.com/crewjam/httperr/.golangci.yml b/vendor/github.com/crewjam/httperr/.golangci.yml new file mode 100644 index 00000000..3cbb0ab3 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/.golangci.yml @@ -0,0 +1,78 @@ +# Configuration file for golangci-lint +# +# https://github.com/golangci/golangci-lint +# +# fighting with false positives? +# https://github.com/golangci/golangci-lint#nolint + +linters: + enable: + - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification [fast: true, auto-fix: true] + - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports [fast: true, auto-fix: true] + - gosec # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases [fast: true, auto-fix: false] + - misspell # Finds commonly misspelled English words in comments [fast: true, auto-fix: true] + - deadcode # Finds unused code [fast: true, auto-fix: false] + - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes [fast: true, auto-fix: false] + + disable: + # TODO(ross): fix errors reported by these checkers and enable them + - bodyclose # checks whether HTTP response body is closed successfully [fast: false, auto-fix: false] + - depguard # Go linter that checks if package imports are in a list of acceptable packages [fast: true, auto-fix: false] + - dupl # Tool for code clone detection [fast: true, auto-fix: false] + - errcheck # Inspects source code for security problems [fast: true, auto-fix: false] + - gochecknoglobals # Checks that no globals are present in Go code [fast: true, auto-fix: false] + - gochecknoinits # Checks that no init functions are present in Go code [fast: true, auto-fix: false] + - goconst # Finds repeated strings that could be replaced by a constant [fast: true, auto-fix: false] + - gocritic # The most opinionated Go source code linter [fast: true, auto-fix: false] + - gocyclo # Computes and checks the cyclomatic complexity of functions [fast: true, auto-fix: false] + - gosimple # Linter for Go source code that specializes in simplifying a code [fast: false, auto-fix: false] + - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string [fast: false, auto-fix: false] + - ineffassign # Detects when assignments to existing variables are not used [fast: true, auto-fix: false] + - interfacer # Linter that suggests narrower interface types [fast: false, auto-fix: false] + - lll # Reports long lines [fast: true, auto-fix: false] + - maligned # Tool to detect Go structs that would take less memory if their fields were sorted [fast: true, auto-fix: false] + - nakedret # Finds naked returns in functions greater than a specified function length [fast: true, auto-fix: false] + - prealloc # Finds slice declarations that could potentially be preallocated [fast: true, auto-fix: false] + - scopelint # Scopelint checks for unpinned variables in go programs [fast: true, auto-fix: false] + - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks [fast: false, auto-fix: false] + - structcheck # Finds unused struct fields [fast: true, auto-fix: false] + - stylecheck # Stylecheck is a replacement for golint [fast: false, auto-fix: false] + - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code [fast: true, auto-fix: false] + - unconvert # Remove unnecessary type conversions [fast: true, auto-fix: false] + - unparam # Reports unused function parameters [fast: false, auto-fix: false] + - unused # Checks Go code for unused constants, variables, functions and types [fast: false, auto-fix: false] + - varcheck # Finds unused global variables and constants [fast: true, auto-fix: false] +linters-settings: + goimports: + local-prefixes: github.com/crewjam/saml + govet: + disable: + - shadow + enable: + - asmdecl + - assign + - atomic + - bools + - buildtag + - cgocall + - composites + - copylocks + - errorsas + - httpresponse + - loopclosure + - lostcancel + - nilfunc + - printf + - shift + - stdmethods + - structtag + - tests + - unmarshal + - unreachable + - unsafeptr + - unusedresult +issues: + exclude-use-default: false + exclude: + - G104 # 'Errors unhandled. (gosec) + diff --git a/vendor/github.com/crewjam/httperr/.travis.yml b/vendor/github.com/crewjam/httperr/.travis.yml new file mode 100644 index 00000000..a5411315 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/.travis.yml @@ -0,0 +1,13 @@ +language: go + +env: GO111MODULE=on + +before_script: + - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(go env GOPATH)/bin v1.21.0 + +script: + - golangci-lint run + - go test -v ./... + +go: + - tip diff --git a/vendor/github.com/crewjam/httperr/LICENSE b/vendor/github.com/crewjam/httperr/LICENSE new file mode 100644 index 00000000..2bbd8619 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2016, Ross Kinder +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/crewjam/httperr/README.md b/vendor/github.com/crewjam/httperr/README.md new file mode 100644 index 00000000..97d7f570 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/README.md @@ -0,0 +1,152 @@ +# httperr + +[![GoDoc](https://godoc.org/github.com/crewjam/httperr?status.svg)](https://godoc.org/github.com/crewjam/httperr) + +[![Build Status](https://travis-ci.org/crewjam/httperr.svg?branch=master)](https://travis-ci.org/crewjam/httperr) + +Package httperr provides utilities for handling error conditions in http +clients and servers. + +## Client + +This package provides an http.Client that returns errors for requests that return +a status code >= 400. It lets you turn code like this: + +```golang +func GetFoo() { + req, _ := http.NewRequest("GET", "https://api.example.com/foo", nil) + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + if resp.StatusCode >= 400 { + return nil, fmt.Errorf("api call failed: %d", resp.StatusCode) + } + // .... +} +``` + +Into code like this: + +```golang +func GetFoo() { + req, _ := http.NewRequest("GET", "https://api.example.com/foo", nil) + resp, err := httperr.Client().Do(req) + if err != nil { + return nil, err + } + // .... +} +``` + +Wow, three whole lines. Life changing, eh? But wait, there's more! + +You can have the client parse structured errors returned from an API: + +```golang + +type APIError struct { + Message string `json:"message"` + Code string `json:"code"` +} + +func (a APIError) Error() string { + // APIError must implement the Error interface + return fmt.Sprintf("%s (code %d)", a.Message, a.Code) +} + +func GetFoo() { + client := httperr.Client(http.DefaultClient, httperr.JSON(APIError{})) + + req, _ := http.NewRequest("GET", "https://api.example.com/foo", nil) + resp, err := client.Do(req) + if err != nil { + // If the server returned a status code >= 400, and the response was valid + // JSON for APIError, then err is an *APIErr. + return nil, err + } + // .... +} +``` + +## Server + +Error handling in Go's http.Handler and http.HandlerFunc can be tricky. I often found myself wishing that we could just return an `err` and be done with things. + +This package provides an adapter function which turns: + +```golang +func (s *Server) getUser(w http.ResponseWriter, r *http.Request) { + remoteUser, err := s.Auth.RequireUser(w, r) + if err != nil { + http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + return + } + + user, err := s.Storage.Get(remoteUser.Name) + if err != nil { + log.Printf("ERROR: cannot fetch user: %s", err) + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return + } + json.NewEncoder(w).Encode(user) +} +``` + +Into this: + +```golang +func (s *Server) getUser(w http.ResponseWriter, r *http.Request) error { + remoteUser, err := s.Auth.RequireUser(w, r) + if err != nil { + return httperr.Unauthorized + } + + user, err := s.Storage.Get(remoteUser.Name) + if err != nil { + return err + } + return json.NewEncoder(w).Encode(user) +} +``` + +Life changing? Probably not, but it seems to remove a lot of redundancy and make control flow in web servers simpler. + +You can also wrap your calls with middleware that allow you to provide custom handling of errors that are returned from your handlers, but also >= 400 status codes issued by handlers that don't return errors. + +```golang +htmlErrorTmpl := template.Must(template.New("err").Parse(errorTemplate)) +handler := httperr.Middleware{ + OnError: func(w http.ResponseWriter, r *http.Request, err error) error { + log.Printf("REQUEST ERROR: %s", err) + if acceptHeaderContainsTextHTML(r) { + htmlErrorTmpl.Execute(w, struct{ Error error }{Error: err}) + return nil // nil means we've handled the error + } + return err // fall back to the default + }, + Handler: httperr.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { + if r.Method != "POST" { + return httperr.MethodNotAllowed + } + var reqBody RequestBody + if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil { + return httperr.Public{ + StatusCode: http.StatusBadRequest, + Err: err, + } + } + + if reqBody.Count <= 0 { + // The client won't see this, instead OnError will be called with a httperr.Response containing + // the response. The OnError function can decide to write the error, or replace it with it's own. + w.WriteHeader(http.StatusConflict) + fmt.Fprintln(w, "an obscure internal error happened, but the user doesn't want to see this.") + return nil + } + + // ... + return nil + }), +} +``` diff --git a/vendor/github.com/crewjam/httperr/client.go b/vendor/github.com/crewjam/httperr/client.go new file mode 100644 index 00000000..64002cc2 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/client.go @@ -0,0 +1,120 @@ +package httperr + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http" + "reflect" +) + +// ClientArg is an argument to Client +type ClientArg func(xport *Transport) + +// Client returns an http.Client that wraps client with +// an error handling transport. +func Client(next *http.Client, args ...ClientArg) *http.Client { + xport := Transport{Next: next.Transport} + for _, arg := range args { + arg(&xport) + } + + rv := *next + rv.Transport = xport + return &rv +} + +// DefaultClient returns an http.Client that wraps the default +// http.Client with an error handling transport. +func DefaultClient() *http.Client { + return Client(http.DefaultClient) +} + +var _ http.RoundTripper = Transport{} + +// Transport is an http.RoundTripper that intercepts responses where +// the StatusCode >= 400 and returns a Response{}. +// +// If ErrorFactory is specified it should return an error that can be used +// to unmarshal a JSON error response. This is useful when a web service +// offers structured error information. If the error structure cannot be +// unmarshalled, then a regular Response error is returned. +// +// type APIError struct { +// Code string `json:"code"` +// Message string `json:"message"` +// } +// +// func (a APIError) Error() string { +// return fmt.Sprintf("%s (%d)", a.Message, a.Code) +// } +// +// t := Transport{ +// ErrorFactory: func() error { +// return &APIError{} +// }, +// } +// +type Transport struct { + Next http.RoundTripper + OnError func(req *http.Request, resp *http.Response) error +} + +// RoundTrip implements http.RoundTripper. +func (t Transport) RoundTrip(req *http.Request) (*http.Response, error) { + next := t.Next + if next == nil { + next = http.DefaultTransport + } + + resp, err := next.RoundTrip(req) + if err != nil { + return nil, err + } + if resp.StatusCode < 400 { + return resp, nil + } + + if t.OnError != nil { + if err := t.OnError(req, resp); err != nil { + return nil, err + } + } + + return nil, Response(*resp) +} + +// JSON returns a ClientArg that specifies a function that +// handles errors structured as a JSON object. +func JSON(errStruct error) ClientArg { + typ := reflect.TypeOf(errStruct) + if typ.Kind() != reflect.Struct { + panic("JSON() argument must be a structure") + } + + e := reflect.New(typ).Interface() + _ = e.(error) // panic if errStruct + + return func(xport *Transport) { + xport.OnError = func(req *http.Request, resp *http.Response) error { + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + resp.Body = ioutil.NopCloser(bytes.NewReader(body)) + + jsonErrValue := reflect.New(typ) + + unmarshalErr := json.Unmarshal(body, jsonErrValue.Interface()) + if unmarshalErr == nil { + // jsonErrValue is a *Foo if errStruct == Foo{} + return jsonErrValue.Elem().Interface().(error) + } + + // we failed to unmarshal the response body, so ignore the + // JSON error and proceed as if ErrorFactory was not provided. + return Response(*resp) + } + } +} diff --git a/vendor/github.com/crewjam/httperr/codes.go b/vendor/github.com/crewjam/httperr/codes.go new file mode 100644 index 00000000..145f5e92 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/codes.go @@ -0,0 +1,73 @@ +package httperr + +var ( + // BadRequest is an error that represents a static http.StatusBadRequest error + BadRequest = Value{StatusCode: 400} + // Unauthorized is an error that represents a static http.StatusUnauthorized error + Unauthorized = Value{StatusCode: 401} + // PaymentRequired is an error that represents a static http.StatusPaymentRequired error + PaymentRequired = Value{StatusCode: 402} + // Forbidden is an error that represents a static http.StatusForbidden error + Forbidden = Value{StatusCode: 403} + // NotFound is an error that represents a static http.StatusNotFound error + NotFound = Value{StatusCode: 404} + // MethodNotAllowed is an error that represents a static http.StatusMethodNotAllowed error + MethodNotAllowed = Value{StatusCode: 405} + // NotAcceptable is an error that represents a static http.StatusNotAcceptable error + NotAcceptable = Value{StatusCode: 406} + // ProxyAuthRequired is an error that represents a static http.StatusProxyAuthRequired error + ProxyAuthRequired = Value{StatusCode: 407} + // RequestTimeout is an error that represents a static http.StatusRequestTimeout error + RequestTimeout = Value{StatusCode: 408} + // Conflict is an error that represents a static http.StatusConflict error + Conflict = Value{StatusCode: 409} + // Gone is an error that represents a static http.StatusGone error + Gone = Value{StatusCode: 410} + // LengthRequired is an error that represents a static http.StatusLengthRequired error + LengthRequired = Value{StatusCode: 411} + // PreconditionFailed is an error that represents a static http.StatusPreconditionFailed error + PreconditionFailed = Value{StatusCode: 412} + // RequestEntityTooLarge is an error that represents a static http.StatusRequestEntityTooLarge error + RequestEntityTooLarge = Value{StatusCode: 413} + // RequestURITooLong is an error that represents a static http.StatusRequestURITooLong error + RequestURITooLong = Value{StatusCode: 414} + // UnsupportedMediaType is an error that represents a static http.StatusUnsupportedMediaType error + UnsupportedMediaType = Value{StatusCode: 415} + // RequestedRangeNotSatisfiable is an error that represents a static http.StatusRequestedRangeNotSatisfiable error + RequestedRangeNotSatisfiable = Value{StatusCode: 416} + // ExpectationFailed is an error that represents a static http.StatusExpectationFailed error + ExpectationFailed = Value{StatusCode: 417} + // Teapot is an error that represents a static http.StatusTeapot error + Teapot = Value{StatusCode: 418} + // TooManyRequests is an error that represents a static http.StatusTooManyRequests error + TooManyRequests = Value{StatusCode: 429} + // InternalServerError is an error that represents a static http.StatusInternalServerError error + InternalServerError = Value{StatusCode: 500} + // NotImplemented is an error that represents a static http.StatusNotImplemented error + NotImplemented = Value{StatusCode: 501} + // BadGateway is an error that represents a static http.StatusBadGateway error + BadGateway = Value{StatusCode: 502} + // ServiceUnavailable is an error that represents a static http.StatusServiceUnavailable error + ServiceUnavailable = Value{StatusCode: 503} + // GatewayTimeout is an error that represents a static http.StatusGatewayTimeout error + GatewayTimeout = Value{StatusCode: 504} + // HTTPVersionNotSupported is an error that represents a static http.StatusHTTPVersionNotSupported error + HTTPVersionNotSupported = Value{StatusCode: 505} +) + +// New returns a new http error wrapping err with status statusCode. +func New(statusCode int, err error) error { + return Value{ + StatusCode: statusCode, + Err: err, + } +} + +// Public returns a new public http error wrapping err with status statusCode. +func Public(statusCode int, err error) error { + return Value{ + Public: true, + StatusCode: statusCode, + Err: err, + } +} diff --git a/vendor/github.com/crewjam/httperr/go.mod b/vendor/github.com/crewjam/httperr/go.mod new file mode 100644 index 00000000..a6d7114f --- /dev/null +++ b/vendor/github.com/crewjam/httperr/go.mod @@ -0,0 +1,8 @@ +module github.com/crewjam/httperr + +go 1.13 + +require ( + github.com/pkg/errors v0.8.1 + github.com/stretchr/testify v1.4.0 +) diff --git a/vendor/github.com/crewjam/httperr/go.sum b/vendor/github.com/crewjam/httperr/go.sum new file mode 100644 index 00000000..3086d129 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/go.sum @@ -0,0 +1,13 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/crewjam/httperr/handler.go b/vendor/github.com/crewjam/httperr/handler.go new file mode 100644 index 00000000..7ab1208b --- /dev/null +++ b/vendor/github.com/crewjam/httperr/handler.go @@ -0,0 +1,20 @@ +package httperr + +import "net/http" + +// The HandlerFunc type is an adapter to allow the use of +// ordinary functions as HTTP handlers. If f is a function +// with the appropriate signature, HandlerFunc(f) is a +// Handler object that calls f. +type HandlerFunc func(http.ResponseWriter, *http.Request) error + +// ServeHTTP calls f(w, r). +func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if err := f(w, r); err != nil { + if v := r.Context().Value(onErrorIndex); v != nil { + v.(func(error))(err) + } else { + Write(w, r, err) + } + } +} diff --git a/vendor/github.com/crewjam/httperr/httperr.go b/vendor/github.com/crewjam/httperr/httperr.go new file mode 100644 index 00000000..78efa0fb --- /dev/null +++ b/vendor/github.com/crewjam/httperr/httperr.go @@ -0,0 +1,56 @@ +// Package httperr implements an error object that speaks HTTP. +package httperr + +import ( + "errors" + "net/http" + + pkgerrors "github.com/pkg/errors" +) + +type statusCodeAndTexter interface { + StatusCodeAndText() (int, string) +} + +// StatusCodeAndText returns the status code and text of the error +func StatusCodeAndText(err error) (int, string) { + if err == nil { + return http.StatusOK, http.StatusText(http.StatusOK) + } + + err = pkgerrors.Cause(err) + + var scater statusCodeAndTexter + if errors.As(err, &scater) { + return scater.StatusCodeAndText() + } + + return http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError) +} + +// Writer is an interface for things that know how to write themselves +// to an error response. This interface is implemented by Private and +// Public to provide default error pages. +type Writer interface { + error + WriteError(w http.ResponseWriter, r *http.Request) +} + +// Write writes the specified error to w. If err is a Writer, then +// it's WriteError method is invoked to produce the response. +// Otherwise a generic "500 Internal Server Error" is written. +func Write(w http.ResponseWriter, r *http.Request, err error) { + err = pkgerrors.Cause(err) + + var errWriter Writer + if errors.As(err, &errWriter) { + errWriter.WriteError(w, r) + return + } + + genericErr := Value{ + Err: err, + StatusCode: http.StatusInternalServerError, + } + genericErr.WriteError(w, r) +} diff --git a/vendor/github.com/crewjam/httperr/middleware.go b/vendor/github.com/crewjam/httperr/middleware.go new file mode 100644 index 00000000..c86dedb1 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/middleware.go @@ -0,0 +1,62 @@ +package httperr + +import ( + "context" + "net/http" +) + +type onErrorIndexType int + +const onErrorIndex onErrorIndexType = iota + +// Middleware wraps the provided handler with middleware that captures errors which +// are returned from HandlerFunc, or reported via ReportError, and invokes the provided +// callback to render them. If the handler returns a status code >= 400, the response is +// captured and passed to OnError as a Response. +// +type Middleware struct { + // OnError is a function that is called then a request fails with an error. If this function + // returns nil, then the error is assumed to be handled. If it returns a non-nil error, then + // that error is written to the client with Write() + OnError func(w http.ResponseWriter, r *http.Request, err error) error + + // Handler is the next handler + Handler http.Handler +} + +func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { + var unwrappedWriter = w + var wrappedWriter *basicWriter + if m.OnError != nil { + wrappedWriter, w = wrapWriter(w) + } + + var didCallOnError bool + r = r.WithContext(context.WithValue(r.Context(), onErrorIndex, func(err error) { + if m.OnError != nil { + didCallOnError = true + handlerErr := m.OnError(unwrappedWriter, r, err) + if handlerErr != nil { + Write(unwrappedWriter, r, handlerErr) + } + } + })) + + m.Handler.ServeHTTP(w, r) + + if wrappedWriter != nil && wrappedWriter.statusCode >= 400 && !didCallOnError { + err := Response(*wrappedWriter.copy) + handlerErr := m.OnError(unwrappedWriter, r, err) + if handlerErr != nil { + Write(unwrappedWriter, r, handlerErr) + } + } +} + +// ReportError reports the error to the function given in +// OnError. +func ReportError(r *http.Request, err error) { + if v := r.Context().Value(onErrorIndex); v != nil { + v.(func(error))(err) + } +} diff --git a/vendor/github.com/crewjam/httperr/response.go b/vendor/github.com/crewjam/httperr/response.go new file mode 100644 index 00000000..b37b5e87 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/response.go @@ -0,0 +1,42 @@ +package httperr + +import ( + "io" + "net/http" +) + +// Response is an alias for http.Response that implements +// the error interface. Example: +// +// resp, err := http.Get("http://www.example.com") +// if err != nil { +// return err +// } +// if resp.StatusCode != http.StatusOK { +// return httperr.Response(*resp) +// } +// // ... +// +type Response http.Response + +func (re Response) Error() string { + statusText := re.Status + if statusText == "" { + statusText = http.StatusText(re.StatusCode) + } + return statusText +} + +// WriteError copies the Response to the ResponseWriter. +func (re Response) WriteError(w http.ResponseWriter, r *http.Request) { + for k, vv := range re.Header { + for _, v := range vv { + w.Header().Add(k, v) + } + } + w.WriteHeader(re.StatusCode) + io.Copy(w, re.Body) +} + +var _ error = Response{} +var _ Writer = Response{} diff --git a/vendor/github.com/crewjam/httperr/value.go b/vendor/github.com/crewjam/httperr/value.go new file mode 100644 index 00000000..ac00a381 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/value.go @@ -0,0 +1,67 @@ +// Package httperr implements an error object that speaks HTTP. +package httperr + +import ( + "fmt" + "net/http" +) + +// Value is an Error that returns that status and code +// provided, and reveals the underlying wrapper error to +// the caller. The text of the error is rendered to the +// client in the body of the response, as well as in +// the X-Error header. +type Value struct { + Err error // the underlying error + StatusCode int // the HTTP status code. If not supplied, http.StatusInternalServerError is used. + Status string // the HTTP status text. If not supplied, http.StatusText(http.StatusCode) is used. + Public bool + Header http.Header // extra headers to add to the response (optional) +} + +// StatusCodeAndText returns the status code and text of the error +func (e Value) StatusCodeAndText() (int, string) { + if e.StatusCode == 0 { + e.StatusCode = http.StatusInternalServerError + } + + if e.Status == "" { + if e.Err != nil && e.Public { + e.Status = e.Err.Error() + } else { + e.Status = http.StatusText(e.StatusCode) + } + } + + return e.StatusCode, e.Status +} + +func (e Value) Error() string { + statusCode, statusText := StatusCodeAndText(e) + if e.Public { + return fmt.Sprintf("%d %s", statusCode, statusText) + } + return fmt.Sprintf("%d %s: %s", statusCode, statusText, e.Err.Error()) +} + +// WriteError writes an error response to w using the specified status code. +func (e Value) WriteError(w http.ResponseWriter, r *http.Request) { + for key, values := range e.Header { + w.Header().Del(key) // overwrite headers already in the response with the ones specified + for _, value := range values { + w.Header().Add(key, value) + } + } + + code, message := e.StatusCodeAndText() + http.Error(w, message, code) +} + +// Unwrap unwraps the Value error and returns the underlying error` +func (e Value) Unwrap() error { + return e.Err +} + +var _ error = Value{} +var _ Writer = Value{} +var _ statusCodeAndTexter = Value{} diff --git a/vendor/github.com/crewjam/httperr/writer.go b/vendor/github.com/crewjam/httperr/writer.go new file mode 100644 index 00000000..afc0c119 --- /dev/null +++ b/vendor/github.com/crewjam/httperr/writer.go @@ -0,0 +1,119 @@ +package httperr + +// Note: The writer proxies in this file are a heavily modified version of +// code bearing the following message: +// +// Copyright (c) 2014, 2015, 2016 Carl Jackson (carl@avtok.com) +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import ( + "bufio" + "bytes" + "io/ioutil" + "net" + "net/http" +) + +// wrapWriter wraps an http.ResponseWriter, returning a proxy that +// tracks the response. +func wrapWriter(w http.ResponseWriter) (*basicWriter, http.ResponseWriter) { + _, isCloseNotifier := w.(http.CloseNotifier) + _, isFlusher := w.(http.Flusher) + _, isHijacker := w.(http.Hijacker) + + bw := basicWriter{ResponseWriter: w} + if isCloseNotifier && isFlusher && isHijacker { + rv := fancyWriter{bw} + return &rv.basicWriter, &rv + } + if isFlusher { + rv := flushWriter{bw} + return &rv.basicWriter, &rv + } + return &bw, &bw +} + +type basicWriter struct { + http.ResponseWriter + + statusCode int + copy *http.Response + body *bytes.Buffer +} + +func (b *basicWriter) WriteHeader(code int) { + b.statusCode = code + if code < 400 { + b.ResponseWriter.WriteHeader(code) + return + } + + b.copy = &http.Response{ + StatusCode: code, + Header: b.ResponseWriter.Header(), + } +} + +func (b *basicWriter) Write(buf []byte) (int, error) { + if b.copy == nil { + return b.ResponseWriter.Write(buf) + } + + if b.body == nil { + b.body = &bytes.Buffer{} + b.copy.Body = ioutil.NopCloser(b.body) + } + return b.body.Write(buf) +} + +type fancyWriter struct { + basicWriter +} + +func (f *fancyWriter) CloseNotify() <-chan bool { + cn := f.basicWriter.ResponseWriter.(http.CloseNotifier) + return cn.CloseNotify() +} + +func (f *fancyWriter) Flush() { + fl := f.basicWriter.ResponseWriter.(http.Flusher) + fl.Flush() +} + +func (f *fancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + hj := f.basicWriter.ResponseWriter.(http.Hijacker) + return hj.Hijack() +} + +var _ http.CloseNotifier = &fancyWriter{} +var _ http.Flusher = &fancyWriter{} +var _ http.Hijacker = &fancyWriter{} + +type flushWriter struct { + basicWriter +} + +func (f *flushWriter) Flush() { + fl := f.basicWriter.ResponseWriter.(http.Flusher) + fl.Flush() +} + +var _ http.Flusher = &flushWriter{} diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE new file mode 100644 index 00000000..bc52e96f --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2012-2016 Dave Collins + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go new file mode 100644 index 00000000..79299478 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/bypass.go @@ -0,0 +1,145 @@ +// Copyright (c) 2015-2016 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when the code is not running on Google App Engine, compiled by GopherJS, and +// "-tags safe" is not added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +// Go versions prior to 1.4 are disabled because they use a different layout +// for interfaces which make the implementation of unsafeReflectValue more complex. +// +build !js,!appengine,!safe,!disableunsafe,go1.4 + +package spew + +import ( + "reflect" + "unsafe" +) + +const ( + // UnsafeDisabled is a build-time constant which specifies whether or + // not access to the unsafe package is available. + UnsafeDisabled = false + + // ptrSize is the size of a pointer on the current arch. + ptrSize = unsafe.Sizeof((*byte)(nil)) +) + +type flag uintptr + +var ( + // flagRO indicates whether the value field of a reflect.Value + // is read-only. + flagRO flag + + // flagAddr indicates whether the address of the reflect.Value's + // value may be taken. + flagAddr flag +) + +// flagKindMask holds the bits that make up the kind +// part of the flags field. In all the supported versions, +// it is in the lower 5 bits. +const flagKindMask = flag(0x1f) + +// Different versions of Go have used different +// bit layouts for the flags type. This table +// records the known combinations. +var okFlags = []struct { + ro, addr flag +}{{ + // From Go 1.4 to 1.5 + ro: 1 << 5, + addr: 1 << 7, +}, { + // Up to Go tip. + ro: 1<<5 | 1<<6, + addr: 1 << 8, +}} + +var flagValOffset = func() uintptr { + field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") + if !ok { + panic("reflect.Value has no flag field") + } + return field.Offset +}() + +// flagField returns a pointer to the flag field of a reflect.Value. +func flagField(v *reflect.Value) *flag { + return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset)) +} + +// unsafeReflectValue converts the passed reflect.Value into a one that bypasses +// the typical safety restrictions preventing access to unaddressable and +// unexported data. It works by digging the raw pointer to the underlying +// value out of the protected value and generating a new unprotected (unsafe) +// reflect.Value to it. +// +// This allows us to check for implementations of the Stringer and error +// interfaces to be used for pretty printing ordinarily unaddressable and +// inaccessible values such as unexported struct fields. +func unsafeReflectValue(v reflect.Value) reflect.Value { + if !v.IsValid() || (v.CanInterface() && v.CanAddr()) { + return v + } + flagFieldPtr := flagField(&v) + *flagFieldPtr &^= flagRO + *flagFieldPtr |= flagAddr + return v +} + +// Sanity checks against future reflect package changes +// to the type or semantics of the Value.flag field. +func init() { + field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") + if !ok { + panic("reflect.Value has no flag field") + } + if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() { + panic("reflect.Value flag field has changed kind") + } + type t0 int + var t struct { + A t0 + // t0 will have flagEmbedRO set. + t0 + // a will have flagStickyRO set + a t0 + } + vA := reflect.ValueOf(t).FieldByName("A") + va := reflect.ValueOf(t).FieldByName("a") + vt0 := reflect.ValueOf(t).FieldByName("t0") + + // Infer flagRO from the difference between the flags + // for the (otherwise identical) fields in t. + flagPublic := *flagField(&vA) + flagWithRO := *flagField(&va) | *flagField(&vt0) + flagRO = flagPublic ^ flagWithRO + + // Infer flagAddr from the difference between a value + // taken from a pointer and not. + vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A") + flagNoPtr := *flagField(&vA) + flagPtr := *flagField(&vPtrA) + flagAddr = flagNoPtr ^ flagPtr + + // Check that the inferred flags tally with one of the known versions. + for _, f := range okFlags { + if flagRO == f.ro && flagAddr == f.addr { + return + } + } + panic("reflect.Value read-only flag has changed semantics") +} diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go new file mode 100644 index 00000000..205c28d6 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go @@ -0,0 +1,38 @@ +// Copyright (c) 2015-2016 Dave Collins +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// NOTE: Due to the following build constraints, this file will only be compiled +// when the code is running on Google App Engine, compiled by GopherJS, or +// "-tags safe" is added to the go build command line. The "disableunsafe" +// tag is deprecated and thus should not be used. +// +build js appengine safe disableunsafe !go1.4 + +package spew + +import "reflect" + +const ( + // UnsafeDisabled is a build-time constant which specifies whether or + // not access to the unsafe package is available. + UnsafeDisabled = true +) + +// unsafeReflectValue typically converts the passed reflect.Value into a one +// that bypasses the typical safety restrictions preventing access to +// unaddressable and unexported data. However, doing this relies on access to +// the unsafe package. This is a stub version which simply returns the passed +// reflect.Value when the unsafe package is not available. +func unsafeReflectValue(v reflect.Value) reflect.Value { + return v +} diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go new file mode 100644 index 00000000..1be8ce94 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/common.go @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "reflect" + "sort" + "strconv" +) + +// Some constants in the form of bytes to avoid string overhead. This mirrors +// the technique used in the fmt package. +var ( + panicBytes = []byte("(PANIC=") + plusBytes = []byte("+") + iBytes = []byte("i") + trueBytes = []byte("true") + falseBytes = []byte("false") + interfaceBytes = []byte("(interface {})") + commaNewlineBytes = []byte(",\n") + newlineBytes = []byte("\n") + openBraceBytes = []byte("{") + openBraceNewlineBytes = []byte("{\n") + closeBraceBytes = []byte("}") + asteriskBytes = []byte("*") + colonBytes = []byte(":") + colonSpaceBytes = []byte(": ") + openParenBytes = []byte("(") + closeParenBytes = []byte(")") + spaceBytes = []byte(" ") + pointerChainBytes = []byte("->") + nilAngleBytes = []byte("") + maxNewlineBytes = []byte("\n") + maxShortBytes = []byte("") + circularBytes = []byte("") + circularShortBytes = []byte("") + invalidAngleBytes = []byte("") + openBracketBytes = []byte("[") + closeBracketBytes = []byte("]") + percentBytes = []byte("%") + precisionBytes = []byte(".") + openAngleBytes = []byte("<") + closeAngleBytes = []byte(">") + openMapBytes = []byte("map[") + closeMapBytes = []byte("]") + lenEqualsBytes = []byte("len=") + capEqualsBytes = []byte("cap=") +) + +// hexDigits is used to map a decimal value to a hex digit. +var hexDigits = "0123456789abcdef" + +// catchPanic handles any panics that might occur during the handleMethods +// calls. +func catchPanic(w io.Writer, v reflect.Value) { + if err := recover(); err != nil { + w.Write(panicBytes) + fmt.Fprintf(w, "%v", err) + w.Write(closeParenBytes) + } +} + +// handleMethods attempts to call the Error and String methods on the underlying +// type the passed reflect.Value represents and outputes the result to Writer w. +// +// It handles panics in any called methods by catching and displaying the error +// as the formatted value. +func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { + // We need an interface to check if the type implements the error or + // Stringer interface. However, the reflect package won't give us an + // interface on certain things like unexported struct fields in order + // to enforce visibility rules. We use unsafe, when it's available, + // to bypass these restrictions since this package does not mutate the + // values. + if !v.CanInterface() { + if UnsafeDisabled { + return false + } + + v = unsafeReflectValue(v) + } + + // Choose whether or not to do error and Stringer interface lookups against + // the base type or a pointer to the base type depending on settings. + // Technically calling one of these methods with a pointer receiver can + // mutate the value, however, types which choose to satisify an error or + // Stringer interface with a pointer receiver should not be mutating their + // state inside these interface methods. + if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { + v = unsafeReflectValue(v) + } + if v.CanAddr() { + v = v.Addr() + } + + // Is it an error or Stringer? + switch iface := v.Interface().(type) { + case error: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.Error())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + + w.Write([]byte(iface.Error())) + return true + + case fmt.Stringer: + defer catchPanic(w, v) + if cs.ContinueOnMethod { + w.Write(openParenBytes) + w.Write([]byte(iface.String())) + w.Write(closeParenBytes) + w.Write(spaceBytes) + return false + } + w.Write([]byte(iface.String())) + return true + } + return false +} + +// printBool outputs a boolean value as true or false to Writer w. +func printBool(w io.Writer, val bool) { + if val { + w.Write(trueBytes) + } else { + w.Write(falseBytes) + } +} + +// printInt outputs a signed integer value to Writer w. +func printInt(w io.Writer, val int64, base int) { + w.Write([]byte(strconv.FormatInt(val, base))) +} + +// printUint outputs an unsigned integer value to Writer w. +func printUint(w io.Writer, val uint64, base int) { + w.Write([]byte(strconv.FormatUint(val, base))) +} + +// printFloat outputs a floating point value using the specified precision, +// which is expected to be 32 or 64bit, to Writer w. +func printFloat(w io.Writer, val float64, precision int) { + w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) +} + +// printComplex outputs a complex value using the specified float precision +// for the real and imaginary parts to Writer w. +func printComplex(w io.Writer, c complex128, floatPrecision int) { + r := real(c) + w.Write(openParenBytes) + w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) + i := imag(c) + if i >= 0 { + w.Write(plusBytes) + } + w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) + w.Write(iBytes) + w.Write(closeParenBytes) +} + +// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x' +// prefix to Writer w. +func printHexPtr(w io.Writer, p uintptr) { + // Null pointer. + num := uint64(p) + if num == 0 { + w.Write(nilAngleBytes) + return + } + + // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix + buf := make([]byte, 18) + + // It's simpler to construct the hex string right to left. + base := uint64(16) + i := len(buf) - 1 + for num >= base { + buf[i] = hexDigits[num%base] + num /= base + i-- + } + buf[i] = hexDigits[num] + + // Add '0x' prefix. + i-- + buf[i] = 'x' + i-- + buf[i] = '0' + + // Strip unused leading bytes. + buf = buf[i:] + w.Write(buf) +} + +// valuesSorter implements sort.Interface to allow a slice of reflect.Value +// elements to be sorted. +type valuesSorter struct { + values []reflect.Value + strings []string // either nil or same len and values + cs *ConfigState +} + +// newValuesSorter initializes a valuesSorter instance, which holds a set of +// surrogate keys on which the data should be sorted. It uses flags in +// ConfigState to decide if and how to populate those surrogate keys. +func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { + vs := &valuesSorter{values: values, cs: cs} + if canSortSimply(vs.values[0].Kind()) { + return vs + } + if !cs.DisableMethods { + vs.strings = make([]string, len(values)) + for i := range vs.values { + b := bytes.Buffer{} + if !handleMethods(cs, &b, vs.values[i]) { + vs.strings = nil + break + } + vs.strings[i] = b.String() + } + } + if vs.strings == nil && cs.SpewKeys { + vs.strings = make([]string, len(values)) + for i := range vs.values { + vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) + } + } + return vs +} + +// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted +// directly, or whether it should be considered for sorting by surrogate keys +// (if the ConfigState allows it). +func canSortSimply(kind reflect.Kind) bool { + // This switch parallels valueSortLess, except for the default case. + switch kind { + case reflect.Bool: + return true + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return true + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return true + case reflect.Float32, reflect.Float64: + return true + case reflect.String: + return true + case reflect.Uintptr: + return true + case reflect.Array: + return true + } + return false +} + +// Len returns the number of values in the slice. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Len() int { + return len(s.values) +} + +// Swap swaps the values at the passed indices. It is part of the +// sort.Interface implementation. +func (s *valuesSorter) Swap(i, j int) { + s.values[i], s.values[j] = s.values[j], s.values[i] + if s.strings != nil { + s.strings[i], s.strings[j] = s.strings[j], s.strings[i] + } +} + +// valueSortLess returns whether the first value should sort before the second +// value. It is used by valueSorter.Less as part of the sort.Interface +// implementation. +func valueSortLess(a, b reflect.Value) bool { + switch a.Kind() { + case reflect.Bool: + return !a.Bool() && b.Bool() + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + return a.Int() < b.Int() + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + return a.Uint() < b.Uint() + case reflect.Float32, reflect.Float64: + return a.Float() < b.Float() + case reflect.String: + return a.String() < b.String() + case reflect.Uintptr: + return a.Uint() < b.Uint() + case reflect.Array: + // Compare the contents of both arrays. + l := a.Len() + for i := 0; i < l; i++ { + av := a.Index(i) + bv := b.Index(i) + if av.Interface() == bv.Interface() { + continue + } + return valueSortLess(av, bv) + } + } + return a.String() < b.String() +} + +// Less returns whether the value at index i should sort before the +// value at index j. It is part of the sort.Interface implementation. +func (s *valuesSorter) Less(i, j int) bool { + if s.strings == nil { + return valueSortLess(s.values[i], s.values[j]) + } + return s.strings[i] < s.strings[j] +} + +// sortValues is a sort function that handles both native types and any type that +// can be converted to error or Stringer. Other inputs are sorted according to +// their Value.String() value to ensure display stability. +func sortValues(values []reflect.Value, cs *ConfigState) { + if len(values) == 0 { + return + } + sort.Sort(newValuesSorter(values, cs)) +} diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go new file mode 100644 index 00000000..2e3d22f3 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/config.go @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "io" + "os" +) + +// ConfigState houses the configuration options used by spew to format and +// display values. There is a global instance, Config, that is used to control +// all top-level Formatter and Dump functionality. Each ConfigState instance +// provides methods equivalent to the top-level functions. +// +// The zero value for ConfigState provides no indentation. You would typically +// want to set it to a space or a tab. +// +// Alternatively, you can use NewDefaultConfig to get a ConfigState instance +// with default settings. See the documentation of NewDefaultConfig for default +// values. +type ConfigState struct { + // Indent specifies the string to use for each indentation level. The + // global config instance that all top-level functions use set this to a + // single space by default. If you would like more indentation, you might + // set this to a tab with "\t" or perhaps two spaces with " ". + Indent string + + // MaxDepth controls the maximum number of levels to descend into nested + // data structures. The default, 0, means there is no limit. + // + // NOTE: Circular data structures are properly detected, so it is not + // necessary to set this value unless you specifically want to limit deeply + // nested data structures. + MaxDepth int + + // DisableMethods specifies whether or not error and Stringer interfaces are + // invoked for types that implement them. + DisableMethods bool + + // DisablePointerMethods specifies whether or not to check for and invoke + // error and Stringer interfaces on types which only accept a pointer + // receiver when the current type is not a pointer. + // + // NOTE: This might be an unsafe action since calling one of these methods + // with a pointer receiver could technically mutate the value, however, + // in practice, types which choose to satisify an error or Stringer + // interface with a pointer receiver should not be mutating their state + // inside these interface methods. As a result, this option relies on + // access to the unsafe package, so it will not have any effect when + // running in environments without access to the unsafe package such as + // Google App Engine or with the "safe" build tag specified. + DisablePointerMethods bool + + // DisablePointerAddresses specifies whether to disable the printing of + // pointer addresses. This is useful when diffing data structures in tests. + DisablePointerAddresses bool + + // DisableCapacities specifies whether to disable the printing of capacities + // for arrays, slices, maps and channels. This is useful when diffing + // data structures in tests. + DisableCapacities bool + + // ContinueOnMethod specifies whether or not recursion should continue once + // a custom error or Stringer interface is invoked. The default, false, + // means it will print the results of invoking the custom error or Stringer + // interface and return immediately instead of continuing to recurse into + // the internals of the data type. + // + // NOTE: This flag does not have any effect if method invocation is disabled + // via the DisableMethods or DisablePointerMethods options. + ContinueOnMethod bool + + // SortKeys specifies map keys should be sorted before being printed. Use + // this to have a more deterministic, diffable output. Note that only + // native types (bool, int, uint, floats, uintptr and string) and types + // that support the error or Stringer interfaces (if methods are + // enabled) are supported, with other types sorted according to the + // reflect.Value.String() output which guarantees display stability. + SortKeys bool + + // SpewKeys specifies that, as a last resort attempt, map keys should + // be spewed to strings and sorted by those strings. This is only + // considered if SortKeys is true. + SpewKeys bool +} + +// Config is the active configuration of the top-level functions. +// The configuration can be changed by modifying the contents of spew.Config. +var Config = ConfigState{Indent: " "} + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the formatted string as a value that satisfies error. See NewFormatter +// for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, c.convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, c.convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, c.convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a Formatter interface returned by c.NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, c.convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Print(a ...interface{}) (n int, err error) { + return fmt.Print(c.convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, c.convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Println(a ...interface{}) (n int, err error) { + return fmt.Println(c.convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprint(a ...interface{}) string { + return fmt.Sprint(c.convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a Formatter interface returned by c.NewFormatter. It returns +// the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, c.convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a Formatter interface returned by c.NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) +func (c *ConfigState) Sprintln(a ...interface{}) string { + return fmt.Sprintln(c.convertArgs(a)...) +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +c.Printf, c.Println, or c.Printf. +*/ +func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(c, v) +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { + fdump(c, w, a...) +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by modifying the public members +of c. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func (c *ConfigState) Dump(a ...interface{}) { + fdump(c, os.Stdout, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func (c *ConfigState) Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(c, &buf, a...) + return buf.String() +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a spew Formatter interface using +// the ConfigState associated with s. +func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = newFormatter(c, arg) + } + return formatters +} + +// NewDefaultConfig returns a ConfigState with the following default settings. +// +// Indent: " " +// MaxDepth: 0 +// DisableMethods: false +// DisablePointerMethods: false +// ContinueOnMethod: false +// SortKeys: false +func NewDefaultConfig() *ConfigState { + return &ConfigState{Indent: " "} +} diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go new file mode 100644 index 00000000..aacaac6f --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/doc.go @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* +Package spew implements a deep pretty printer for Go data structures to aid in +debugging. + +A quick overview of the additional features spew provides over the built-in +printing facilities for Go data types are as follows: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output (only when using + Dump style) + +There are two different approaches spew allows for dumping Go data structures: + + * Dump style which prints with newlines, customizable indentation, + and additional debug information such as types and all pointer addresses + used to indirect to the final value + * A custom Formatter interface that integrates cleanly with the standard fmt + package and replaces %v, %+v, %#v, and %#+v to provide inline printing + similar to the default %v while providing the additional functionality + outlined above and passing unsupported format verbs such as %x and %q + along to fmt + +Quick Start + +This section demonstrates how to quickly get started with spew. See the +sections below for further details on formatting and configuration options. + +To dump a variable with full newlines, indentation, type, and pointer +information use Dump, Fdump, or Sdump: + spew.Dump(myVar1, myVar2, ...) + spew.Fdump(someWriter, myVar1, myVar2, ...) + str := spew.Sdump(myVar1, myVar2, ...) + +Alternatively, if you would prefer to use format strings with a compacted inline +printing style, use the convenience wrappers Printf, Fprintf, etc with +%v (most compact), %+v (adds pointer addresses), %#v (adds types), or +%#+v (adds types and pointer addresses): + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +Configuration Options + +Configuration of spew is handled by fields in the ConfigState type. For +convenience, all of the top-level functions use a global state available +via the spew.Config global. + +It is also possible to create a ConfigState instance that provides methods +equivalent to the top-level functions. This allows concurrent configuration +options. See the ConfigState documentation for more details. + +The following configuration options are available: + * Indent + String to use for each indentation level for Dump functions. + It is a single space by default. A popular alternative is "\t". + + * MaxDepth + Maximum number of levels to descend into nested data structures. + There is no limit by default. + + * DisableMethods + Disables invocation of error and Stringer interface methods. + Method invocation is enabled by default. + + * DisablePointerMethods + Disables invocation of error and Stringer interface methods on types + which only accept pointer receivers from non-pointer variables. + Pointer method invocation is enabled by default. + + * DisablePointerAddresses + DisablePointerAddresses specifies whether to disable the printing of + pointer addresses. This is useful when diffing data structures in tests. + + * DisableCapacities + DisableCapacities specifies whether to disable the printing of + capacities for arrays, slices, maps and channels. This is useful when + diffing data structures in tests. + + * ContinueOnMethod + Enables recursion into types after invoking error and Stringer interface + methods. Recursion after method invocation is disabled by default. + + * SortKeys + Specifies map keys should be sorted before being printed. Use + this to have a more deterministic, diffable output. Note that + only native types (bool, int, uint, floats, uintptr and string) + and types which implement error or Stringer interfaces are + supported with other types sorted according to the + reflect.Value.String() output which guarantees display + stability. Natural map order is used by default. + + * SpewKeys + Specifies that, as a last resort attempt, map keys should be + spewed to strings and sorted by those strings. This is only + considered if SortKeys is true. + +Dump Usage + +Simply call spew.Dump with a list of variables you want to dump: + + spew.Dump(myVar1, myVar2, ...) + +You may also call spew.Fdump if you would prefer to output to an arbitrary +io.Writer. For example, to dump to standard error: + + spew.Fdump(os.Stderr, myVar1, myVar2, ...) + +A third option is to call spew.Sdump to get the formatted output as a string: + + str := spew.Sdump(myVar1, myVar2, ...) + +Sample Dump Output + +See the Dump example for details on the setup of the types and variables being +shown here. + + (main.Foo) { + unexportedField: (*main.Bar)(0xf84002e210)({ + flag: (main.Flag) flagTwo, + data: (uintptr) + }), + ExportedField: (map[interface {}]interface {}) (len=1) { + (string) (len=3) "one": (bool) true + } + } + +Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C +command as shown. + ([]uint8) (len=32 cap=32) { + 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | + 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| + 00000020 31 32 |12| + } + +Custom Formatter + +Spew provides a custom formatter that implements the fmt.Formatter interface +so that it integrates cleanly with standard fmt package printing functions. The +formatter is useful for inline printing of smaller data types similar to the +standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Custom Formatter Usage + +The simplest way to make use of the spew custom formatter is to call one of the +convenience functions such as spew.Printf, spew.Println, or spew.Printf. The +functions have syntax you are most likely already familiar with: + + spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + spew.Println(myVar, myVar2) + spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) + spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) + +See the Index for the full list convenience functions. + +Sample Formatter Output + +Double pointer to a uint8: + %v: <**>5 + %+v: <**>(0xf8400420d0->0xf8400420c8)5 + %#v: (**uint8)5 + %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 + +Pointer to circular struct with a uint8 field and a pointer to itself: + %v: <*>{1 <*>} + %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} + %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} + %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} + +See the Printf example for details on the setup of variables being shown +here. + +Errors + +Since it is possible for custom Stringer/error interfaces to panic, spew +detects them and handles them internally by printing the panic information +inline with the output. Since spew is intended to provide deep pretty printing +capabilities on structures, it intentionally does not return any errors. +*/ +package spew diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go new file mode 100644 index 00000000..f78d89fc --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/dump.go @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "os" + "reflect" + "regexp" + "strconv" + "strings" +) + +var ( + // uint8Type is a reflect.Type representing a uint8. It is used to + // convert cgo types to uint8 slices for hexdumping. + uint8Type = reflect.TypeOf(uint8(0)) + + // cCharRE is a regular expression that matches a cgo char. + // It is used to detect character arrays to hexdump them. + cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`) + + // cUnsignedCharRE is a regular expression that matches a cgo unsigned + // char. It is used to detect unsigned character arrays to hexdump + // them. + cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`) + + // cUint8tCharRE is a regular expression that matches a cgo uint8_t. + // It is used to detect uint8_t arrays to hexdump them. + cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`) +) + +// dumpState contains information about the state of a dump operation. +type dumpState struct { + w io.Writer + depth int + pointers map[uintptr]int + ignoreNextType bool + ignoreNextIndent bool + cs *ConfigState +} + +// indent performs indentation according to the depth level and cs.Indent +// option. +func (d *dumpState) indent() { + if d.ignoreNextIndent { + d.ignoreNextIndent = false + return + } + d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) +} + +// unpackValue returns values inside of non-nil interfaces when possible. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface && !v.IsNil() { + v = v.Elem() + } + return v +} + +// dumpPtr handles formatting of pointers by indirecting them as necessary. +func (d *dumpState) dumpPtr(v reflect.Value) { + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range d.pointers { + if depth >= d.depth { + delete(d.pointers, k) + } + } + + // Keep list of all dereferenced pointers to show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by dereferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := d.pointers[addr]; ok && pd < d.depth { + cycleFound = true + indirects-- + break + } + d.pointers[addr] = d.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type information. + d.w.Write(openParenBytes) + d.w.Write(bytes.Repeat(asteriskBytes, indirects)) + d.w.Write([]byte(ve.Type().String())) + d.w.Write(closeParenBytes) + + // Display pointer information. + if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { + d.w.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + d.w.Write(pointerChainBytes) + } + printHexPtr(d.w, addr) + } + d.w.Write(closeParenBytes) + } + + // Display dereferenced value. + d.w.Write(openParenBytes) + switch { + case nilFound: + d.w.Write(nilAngleBytes) + + case cycleFound: + d.w.Write(circularBytes) + + default: + d.ignoreNextType = true + d.dump(ve) + } + d.w.Write(closeParenBytes) +} + +// dumpSlice handles formatting of arrays and slices. Byte (uint8 under +// reflection) arrays and slices are dumped in hexdump -C fashion. +func (d *dumpState) dumpSlice(v reflect.Value) { + // Determine whether this type should be hex dumped or not. Also, + // for types which should be hexdumped, try to use the underlying data + // first, then fall back to trying to convert them to a uint8 slice. + var buf []uint8 + doConvert := false + doHexDump := false + numEntries := v.Len() + if numEntries > 0 { + vt := v.Index(0).Type() + vts := vt.String() + switch { + // C types that need to be converted. + case cCharRE.MatchString(vts): + fallthrough + case cUnsignedCharRE.MatchString(vts): + fallthrough + case cUint8tCharRE.MatchString(vts): + doConvert = true + + // Try to use existing uint8 slices and fall back to converting + // and copying if that fails. + case vt.Kind() == reflect.Uint8: + // We need an addressable interface to convert the type + // to a byte slice. However, the reflect package won't + // give us an interface on certain things like + // unexported struct fields in order to enforce + // visibility rules. We use unsafe, when available, to + // bypass these restrictions since this package does not + // mutate the values. + vs := v + if !vs.CanInterface() || !vs.CanAddr() { + vs = unsafeReflectValue(vs) + } + if !UnsafeDisabled { + vs = vs.Slice(0, numEntries) + + // Use the existing uint8 slice if it can be + // type asserted. + iface := vs.Interface() + if slice, ok := iface.([]uint8); ok { + buf = slice + doHexDump = true + break + } + } + + // The underlying data needs to be converted if it can't + // be type asserted to a uint8 slice. + doConvert = true + } + + // Copy and convert the underlying type if needed. + if doConvert && vt.ConvertibleTo(uint8Type) { + // Convert and copy each element into a uint8 byte + // slice. + buf = make([]uint8, numEntries) + for i := 0; i < numEntries; i++ { + vv := v.Index(i) + buf[i] = uint8(vv.Convert(uint8Type).Uint()) + } + doHexDump = true + } + } + + // Hexdump the entire slice as needed. + if doHexDump { + indent := strings.Repeat(d.cs.Indent, d.depth) + str := indent + hex.Dump(buf) + str = strings.Replace(str, "\n", "\n"+indent, -1) + str = strings.TrimRight(str, d.cs.Indent) + d.w.Write([]byte(str)) + return + } + + // Recursively call dump for each item. + for i := 0; i < numEntries; i++ { + d.dump(d.unpackValue(v.Index(i))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } +} + +// dump is the main workhorse for dumping a value. It uses the passed reflect +// value to figure out what kind of object we are dealing with and formats it +// appropriately. It is a recursive function, however circular data structures +// are detected and handled properly. +func (d *dumpState) dump(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + d.w.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + d.indent() + d.dumpPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !d.ignoreNextType { + d.indent() + d.w.Write(openParenBytes) + d.w.Write([]byte(v.Type().String())) + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + d.ignoreNextType = false + + // Display length and capacity if the built-in len and cap functions + // work with the value's kind and the len/cap itself is non-zero. + valueLen, valueCap := 0, 0 + switch v.Kind() { + case reflect.Array, reflect.Slice, reflect.Chan: + valueLen, valueCap = v.Len(), v.Cap() + case reflect.Map, reflect.String: + valueLen = v.Len() + } + if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { + d.w.Write(openParenBytes) + if valueLen != 0 { + d.w.Write(lenEqualsBytes) + printInt(d.w, int64(valueLen), 10) + } + if !d.cs.DisableCapacities && valueCap != 0 { + if valueLen != 0 { + d.w.Write(spaceBytes) + } + d.w.Write(capEqualsBytes) + printInt(d.w, int64(valueCap), 10) + } + d.w.Write(closeParenBytes) + d.w.Write(spaceBytes) + } + + // Call Stringer/error interfaces if they exist and the handle methods flag + // is enabled + if !d.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(d.cs, d.w, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(d.w, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(d.w, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(d.w, v.Uint(), 10) + + case reflect.Float32: + printFloat(d.w, v.Float(), 32) + + case reflect.Float64: + printFloat(d.w, v.Float(), 64) + + case reflect.Complex64: + printComplex(d.w, v.Complex(), 32) + + case reflect.Complex128: + printComplex(d.w, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + d.dumpSlice(v) + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.String: + d.w.Write([]byte(strconv.Quote(v.String()))) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + d.w.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + d.w.Write(nilAngleBytes) + break + } + + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + numEntries := v.Len() + keys := v.MapKeys() + if d.cs.SortKeys { + sortValues(keys, d.cs) + } + for i, key := range keys { + d.dump(d.unpackValue(key)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.MapIndex(key))) + if i < (numEntries - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Struct: + d.w.Write(openBraceNewlineBytes) + d.depth++ + if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { + d.indent() + d.w.Write(maxNewlineBytes) + } else { + vt := v.Type() + numFields := v.NumField() + for i := 0; i < numFields; i++ { + d.indent() + vtf := vt.Field(i) + d.w.Write([]byte(vtf.Name)) + d.w.Write(colonSpaceBytes) + d.ignoreNextIndent = true + d.dump(d.unpackValue(v.Field(i))) + if i < (numFields - 1) { + d.w.Write(commaNewlineBytes) + } else { + d.w.Write(newlineBytes) + } + } + } + d.depth-- + d.indent() + d.w.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(d.w, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(d.w, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it in case any new + // types are added. + default: + if v.CanInterface() { + fmt.Fprintf(d.w, "%v", v.Interface()) + } else { + fmt.Fprintf(d.w, "%v", v.String()) + } + } +} + +// fdump is a helper function to consolidate the logic from the various public +// methods which take varying writers and config states. +func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { + for _, arg := range a { + if arg == nil { + w.Write(interfaceBytes) + w.Write(spaceBytes) + w.Write(nilAngleBytes) + w.Write(newlineBytes) + continue + } + + d := dumpState{w: w, cs: cs} + d.pointers = make(map[uintptr]int) + d.dump(reflect.ValueOf(arg)) + d.w.Write(newlineBytes) + } +} + +// Fdump formats and displays the passed arguments to io.Writer w. It formats +// exactly the same as Dump. +func Fdump(w io.Writer, a ...interface{}) { + fdump(&Config, w, a...) +} + +// Sdump returns a string with the passed arguments formatted exactly the same +// as Dump. +func Sdump(a ...interface{}) string { + var buf bytes.Buffer + fdump(&Config, &buf, a...) + return buf.String() +} + +/* +Dump displays the passed parameters to standard out with newlines, customizable +indentation, and additional debug information such as complete types and all +pointer addresses used to indirect to the final value. It provides the +following features over the built-in printing facilities provided by the fmt +package: + + * Pointers are dereferenced and followed + * Circular data structures are detected and handled properly + * Custom Stringer/error interfaces are optionally invoked, including + on unexported types + * Custom types which only implement the Stringer/error interfaces via + a pointer receiver are optionally invoked when passing non-pointer + variables + * Byte arrays and slices are dumped like the hexdump -C command which + includes offsets, byte values in hex, and ASCII output + +The configuration options are controlled by an exported package global, +spew.Config. See ConfigState for options documentation. + +See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to +get the formatted result as a string. +*/ +func Dump(a ...interface{}) { + fdump(&Config, os.Stdout, a...) +} diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go new file mode 100644 index 00000000..b04edb7d --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/format.go @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "strings" +) + +// supportedFlags is a list of all the character flags supported by fmt package. +const supportedFlags = "0-+# " + +// formatState implements the fmt.Formatter interface and contains information +// about the state of a formatting operation. The NewFormatter function can +// be used to get a new Formatter which can be used directly as arguments +// in standard fmt package printing calls. +type formatState struct { + value interface{} + fs fmt.State + depth int + pointers map[uintptr]int + ignoreNextType bool + cs *ConfigState +} + +// buildDefaultFormat recreates the original format string without precision +// and width information to pass in to fmt.Sprintf in the case of an +// unrecognized type. Unless new types are added to the language, this +// function won't ever be called. +func (f *formatState) buildDefaultFormat() (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + buf.WriteRune('v') + + format = buf.String() + return format +} + +// constructOrigFormat recreates the original format string including precision +// and width information to pass along to the standard fmt package. This allows +// automatic deferral of all format strings this package doesn't support. +func (f *formatState) constructOrigFormat(verb rune) (format string) { + buf := bytes.NewBuffer(percentBytes) + + for _, flag := range supportedFlags { + if f.fs.Flag(int(flag)) { + buf.WriteRune(flag) + } + } + + if width, ok := f.fs.Width(); ok { + buf.WriteString(strconv.Itoa(width)) + } + + if precision, ok := f.fs.Precision(); ok { + buf.Write(precisionBytes) + buf.WriteString(strconv.Itoa(precision)) + } + + buf.WriteRune(verb) + + format = buf.String() + return format +} + +// unpackValue returns values inside of non-nil interfaces when possible and +// ensures that types for values which have been unpacked from an interface +// are displayed when the show types flag is also set. +// This is useful for data types like structs, arrays, slices, and maps which +// can contain varying types packed inside an interface. +func (f *formatState) unpackValue(v reflect.Value) reflect.Value { + if v.Kind() == reflect.Interface { + f.ignoreNextType = false + if !v.IsNil() { + v = v.Elem() + } + } + return v +} + +// formatPtr handles formatting of pointers by indirecting them as necessary. +func (f *formatState) formatPtr(v reflect.Value) { + // Display nil if top level pointer is nil. + showTypes := f.fs.Flag('#') + if v.IsNil() && (!showTypes || f.ignoreNextType) { + f.fs.Write(nilAngleBytes) + return + } + + // Remove pointers at or below the current depth from map used to detect + // circular refs. + for k, depth := range f.pointers { + if depth >= f.depth { + delete(f.pointers, k) + } + } + + // Keep list of all dereferenced pointers to possibly show later. + pointerChain := make([]uintptr, 0) + + // Figure out how many levels of indirection there are by derferencing + // pointers and unpacking interfaces down the chain while detecting circular + // references. + nilFound := false + cycleFound := false + indirects := 0 + ve := v + for ve.Kind() == reflect.Ptr { + if ve.IsNil() { + nilFound = true + break + } + indirects++ + addr := ve.Pointer() + pointerChain = append(pointerChain, addr) + if pd, ok := f.pointers[addr]; ok && pd < f.depth { + cycleFound = true + indirects-- + break + } + f.pointers[addr] = f.depth + + ve = ve.Elem() + if ve.Kind() == reflect.Interface { + if ve.IsNil() { + nilFound = true + break + } + ve = ve.Elem() + } + } + + // Display type or indirection level depending on flags. + if showTypes && !f.ignoreNextType { + f.fs.Write(openParenBytes) + f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) + f.fs.Write([]byte(ve.Type().String())) + f.fs.Write(closeParenBytes) + } else { + if nilFound || cycleFound { + indirects += strings.Count(ve.Type().String(), "*") + } + f.fs.Write(openAngleBytes) + f.fs.Write([]byte(strings.Repeat("*", indirects))) + f.fs.Write(closeAngleBytes) + } + + // Display pointer information depending on flags. + if f.fs.Flag('+') && (len(pointerChain) > 0) { + f.fs.Write(openParenBytes) + for i, addr := range pointerChain { + if i > 0 { + f.fs.Write(pointerChainBytes) + } + printHexPtr(f.fs, addr) + } + f.fs.Write(closeParenBytes) + } + + // Display dereferenced value. + switch { + case nilFound: + f.fs.Write(nilAngleBytes) + + case cycleFound: + f.fs.Write(circularShortBytes) + + default: + f.ignoreNextType = true + f.format(ve) + } +} + +// format is the main workhorse for providing the Formatter interface. It +// uses the passed reflect value to figure out what kind of object we are +// dealing with and formats it appropriately. It is a recursive function, +// however circular data structures are detected and handled properly. +func (f *formatState) format(v reflect.Value) { + // Handle invalid reflect values immediately. + kind := v.Kind() + if kind == reflect.Invalid { + f.fs.Write(invalidAngleBytes) + return + } + + // Handle pointers specially. + if kind == reflect.Ptr { + f.formatPtr(v) + return + } + + // Print type information unless already handled elsewhere. + if !f.ignoreNextType && f.fs.Flag('#') { + f.fs.Write(openParenBytes) + f.fs.Write([]byte(v.Type().String())) + f.fs.Write(closeParenBytes) + } + f.ignoreNextType = false + + // Call Stringer/error interfaces if they exist and the handle methods + // flag is enabled. + if !f.cs.DisableMethods { + if (kind != reflect.Invalid) && (kind != reflect.Interface) { + if handled := handleMethods(f.cs, f.fs, v); handled { + return + } + } + } + + switch kind { + case reflect.Invalid: + // Do nothing. We should never get here since invalid has already + // been handled above. + + case reflect.Bool: + printBool(f.fs, v.Bool()) + + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + printInt(f.fs, v.Int(), 10) + + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + printUint(f.fs, v.Uint(), 10) + + case reflect.Float32: + printFloat(f.fs, v.Float(), 32) + + case reflect.Float64: + printFloat(f.fs, v.Float(), 64) + + case reflect.Complex64: + printComplex(f.fs, v.Complex(), 32) + + case reflect.Complex128: + printComplex(f.fs, v.Complex(), 64) + + case reflect.Slice: + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + fallthrough + + case reflect.Array: + f.fs.Write(openBracketBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + numEntries := v.Len() + for i := 0; i < numEntries; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(v.Index(i))) + } + } + f.depth-- + f.fs.Write(closeBracketBytes) + + case reflect.String: + f.fs.Write([]byte(v.String())) + + case reflect.Interface: + // The only time we should get here is for nil interfaces due to + // unpackValue calls. + if v.IsNil() { + f.fs.Write(nilAngleBytes) + } + + case reflect.Ptr: + // Do nothing. We should never get here since pointers have already + // been handled above. + + case reflect.Map: + // nil maps should be indicated as different than empty maps + if v.IsNil() { + f.fs.Write(nilAngleBytes) + break + } + + f.fs.Write(openMapBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + keys := v.MapKeys() + if f.cs.SortKeys { + sortValues(keys, f.cs) + } + for i, key := range keys { + if i > 0 { + f.fs.Write(spaceBytes) + } + f.ignoreNextType = true + f.format(f.unpackValue(key)) + f.fs.Write(colonBytes) + f.ignoreNextType = true + f.format(f.unpackValue(v.MapIndex(key))) + } + } + f.depth-- + f.fs.Write(closeMapBytes) + + case reflect.Struct: + numFields := v.NumField() + f.fs.Write(openBraceBytes) + f.depth++ + if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { + f.fs.Write(maxShortBytes) + } else { + vt := v.Type() + for i := 0; i < numFields; i++ { + if i > 0 { + f.fs.Write(spaceBytes) + } + vtf := vt.Field(i) + if f.fs.Flag('+') || f.fs.Flag('#') { + f.fs.Write([]byte(vtf.Name)) + f.fs.Write(colonBytes) + } + f.format(f.unpackValue(v.Field(i))) + } + } + f.depth-- + f.fs.Write(closeBraceBytes) + + case reflect.Uintptr: + printHexPtr(f.fs, uintptr(v.Uint())) + + case reflect.UnsafePointer, reflect.Chan, reflect.Func: + printHexPtr(f.fs, v.Pointer()) + + // There were not any other types at the time this code was written, but + // fall back to letting the default fmt package handle it if any get added. + default: + format := f.buildDefaultFormat() + if v.CanInterface() { + fmt.Fprintf(f.fs, format, v.Interface()) + } else { + fmt.Fprintf(f.fs, format, v.String()) + } + } +} + +// Format satisfies the fmt.Formatter interface. See NewFormatter for usage +// details. +func (f *formatState) Format(fs fmt.State, verb rune) { + f.fs = fs + + // Use standard formatting for verbs that are not v. + if verb != 'v' { + format := f.constructOrigFormat(verb) + fmt.Fprintf(fs, format, f.value) + return + } + + if f.value == nil { + if fs.Flag('#') { + fs.Write(interfaceBytes) + } + fs.Write(nilAngleBytes) + return + } + + f.format(reflect.ValueOf(f.value)) +} + +// newFormatter is a helper function to consolidate the logic from the various +// public methods which take varying config states. +func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { + fs := &formatState{value: v, cs: cs} + fs.pointers = make(map[uintptr]int) + return fs +} + +/* +NewFormatter returns a custom formatter that satisfies the fmt.Formatter +interface. As a result, it integrates cleanly with standard fmt package +printing functions. The formatter is useful for inline printing of smaller data +types similar to the standard %v format specifier. + +The custom formatter only responds to the %v (most compact), %+v (adds pointer +addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb +combinations. Any other verbs such as %x and %q will be sent to the the +standard fmt package for formatting. In addition, the custom formatter ignores +the width and precision arguments (however they will still work on the format +specifiers not handled by the custom formatter). + +Typically this function shouldn't be called directly. It is much easier to make +use of the custom formatter by calling one of the convenience functions such as +Printf, Println, or Fprintf. +*/ +func NewFormatter(v interface{}) fmt.Formatter { + return newFormatter(&Config, v) +} diff --git a/vendor/github.com/davecgh/go-spew/spew/spew.go b/vendor/github.com/davecgh/go-spew/spew/spew.go new file mode 100644 index 00000000..32c0e338 --- /dev/null +++ b/vendor/github.com/davecgh/go-spew/spew/spew.go @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2013-2016 Dave Collins + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package spew + +import ( + "fmt" + "io" +) + +// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the formatted string as a value that satisfies error. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Errorf(format string, a ...interface{}) (err error) { + return fmt.Errorf(format, convertArgs(a)...) +} + +// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprint(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprint(w, convertArgs(a)...) +} + +// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + return fmt.Fprintf(w, format, convertArgs(a)...) +} + +// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it +// passed with a default Formatter interface returned by NewFormatter. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) +func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { + return fmt.Fprintln(w, convertArgs(a)...) +} + +// Print is a wrapper for fmt.Print that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) +func Print(a ...interface{}) (n int, err error) { + return fmt.Print(convertArgs(a)...) +} + +// Printf is a wrapper for fmt.Printf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Printf(format string, a ...interface{}) (n int, err error) { + return fmt.Printf(format, convertArgs(a)...) +} + +// Println is a wrapper for fmt.Println that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the number of bytes written and any write error encountered. See +// NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) +func Println(a ...interface{}) (n int, err error) { + return fmt.Println(convertArgs(a)...) +} + +// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprint(a ...interface{}) string { + return fmt.Sprint(convertArgs(a)...) +} + +// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were +// passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintf(format string, a ...interface{}) string { + return fmt.Sprintf(format, convertArgs(a)...) +} + +// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it +// were passed with a default Formatter interface returned by NewFormatter. It +// returns the resulting string. See NewFormatter for formatting details. +// +// This function is shorthand for the following syntax: +// +// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) +func Sprintln(a ...interface{}) string { + return fmt.Sprintln(convertArgs(a)...) +} + +// convertArgs accepts a slice of arguments and returns a slice of the same +// length with each argument converted to a default spew Formatter interface. +func convertArgs(args []interface{}) (formatters []interface{}) { + formatters = make([]interface{}, len(args)) + for index, arg := range args { + formatters[index] = NewFormatter(arg) + } + return formatters +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/LICENSE b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/LICENSE new file mode 100644 index 00000000..d2d1dd93 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/LICENSE @@ -0,0 +1,17 @@ +ISC License + +Copyright (c) 2013-2017 The btcsuite developers +Copyright (c) 2015-2020 The Decred developers +Copyright (c) 2017 The Lightning Network Developers + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/README.md b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/README.md new file mode 100644 index 00000000..94c28c00 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/README.md @@ -0,0 +1,73 @@ +secp256k1 +========= + +[![Build Status](https://github.com/decred/dcrd/workflows/Build%20and%20Test/badge.svg)](https://github.com/decred/dcrd/actions) +[![ISC License](https://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) +[![Doc](https://img.shields.io/badge/doc-reference-blue.svg)](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v3) + +Package secp256k1 implements optimized secp256k1 elliptic curve operations. + +This package provides an optimized pure Go implementation of elliptic curve +cryptography operations over the secp256k1 curve as well as data structures and +functions for working with public and private secp256k1 keys. See +https://www.secg.org/sec2-v2.pdf for details on the standard. + +In addition, sub packages are provided to produce, verify, parse, and serialize +ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme +specific to Decred) signatures. See the README.md files in the relevant sub +packages for more details about those aspects. + +An overview of the features provided by this package are as follows: + +- Private key generation, serialization, and parsing +- Public key generation, serialization and parsing per ANSI X9.62-1998 + - Parses uncompressed, compressed, and hybrid public keys + - Serializes uncompressed and compressed public keys +- Specialized types for performing optimized and constant time field operations + - `FieldVal` type for working modulo the secp256k1 field prime + - `ModNScalar` type for working modulo the secp256k1 group order +- Elliptic curve operations in Jacobian projective coordinates + - Point addition + - Point doubling + - Scalar multiplication with an arbitrary point + - Scalar multiplication with the base point (group generator) +- Point decompression from a given x coordinate +- Nonce generation via RFC6979 with support for extra data and version + information that can be used to prevent nonce reuse between signing algorithms + +It also provides an implementation of the Go standard library `crypto/elliptic` +`Curve` interface via the `S256` function so that it may be used with other +packages in the standard library such as `crypto/tls`, `crypto/x509`, and +`crypto/ecdsa`. However, in the case of ECDSA, it is highly recommended to use +the `ecdsa` sub package of this package instead since it is optimized +specifically for secp256k1 and is significantly faster as a result. + +Although this package was primarily written for dcrd, it has intentionally been +designed so it can be used as a standalone package for any projects needing to +use optimized secp256k1 elliptic curve cryptography. + +Finally, a comprehensive suite of tests is provided to provide a high level of +quality assurance. + +## secp256k1 use in Decred + +At the time of this writing, the primary public key cryptography in widespread +use on the Decred network used to secure coins is based on elliptic curves +defined by the secp256k1 domain parameters. + +## Installation and Updating + +```bash +$ go get -u github.com/decred/dcrd/dcrec/secp256k1/v3 +``` + +## Examples + +* [Encryption](https://pkg.go.dev/github.com/decred/dcrd/dcrec/secp256k1/v3#example-package-EncryptDecryptMessage) + Demonstrates encrypting and decrypting a message using a shared key derived + through ECDHE. + +## License + +Package secp256k1 is licensed under the [copyfree](http://copyfree.org) ISC +License. diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/compressedbytepoints.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/compressedbytepoints.go new file mode 100644 index 00000000..985d3454 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/compressedbytepoints.go @@ -0,0 +1,11 @@ +// Copyright (c) 2015 The btcsuite developers +// Copyright (c) 2015-2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// Auto-generated file (see genprecomps.go) +// DO NOT EDIT + +var compressedBytePoints = "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" diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/curve.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/curve.go new file mode 100644 index 00000000..fa2686f1 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/curve.go @@ -0,0 +1,880 @@ +// Copyright (c) 2015-2020 The Decred developers +// Copyright 2013-2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "encoding/hex" + "math/big" +) + +// References: +// [SECG]: Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) + +// All group operations are performed using Jacobian coordinates. For a given +// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1) +// where x = x1/z1^2 and y = y1/z1^3. + +// hexToFieldVal converts the passed hex string into a FieldVal and will panic +// if there is an error. This is only provided for the hard-coded constants so +// errors in the source code can be detected. It will only (and must only) be +// called with hard-coded values. +func hexToFieldVal(s string) *FieldVal { + b, err := hex.DecodeString(s) + if err != nil { + panic("invalid hex in source file: " + s) + } + var f FieldVal + if overflow := f.SetByteSlice(b); overflow { + panic("hex in source file overflows mod P: " + s) + } + return &f +} + +var ( + // Next 6 constants are from Hal Finney's bitcointalk.org post: + // https://bitcointalk.org/index.php?topic=3238.msg45565#msg45565 + // May he rest in peace. + // + // They have also been independently derived from the code in the + // EndomorphismVectors function in genstatics.go. + endomorphismLambda = fromHex("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72") + endomorphismBeta = hexToFieldVal("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee") + endomorphismA1 = fromHex("3086d221a7d46bcde86c90e49284eb15") + endomorphismB1 = fromHex("-e4437ed6010e88286f547fa90abfe4c3") + endomorphismA2 = fromHex("114ca50f7a8e2f3f657c1108d9d44cfd8") + endomorphismB2 = fromHex("3086d221a7d46bcde86c90e49284eb15") + + // Alternatively, the following parameters are valid as well, however, they + // seem to be about 8% slower in practice. + // + // endomorphismLambda = fromHex("AC9C52B33FA3CF1F5AD9E3FD77ED9BA4A880B9FC8EC739C2E0CFC810B51283CE") + // endomorphismBeta = hexToFieldVal("851695D49A83F8EF919BB86153CBCB16630FB68AED0A766A3EC693D68E6AFA40") + // endomorphismA1 = fromHex("E4437ED6010E88286F547FA90ABFE4C3") + // endomorphismB1 = fromHex("-3086D221A7D46BCDE86C90E49284EB15") + // endomorphismA2 = fromHex("3086D221A7D46BCDE86C90E49284EB15") + // endomorphismB2 = fromHex("114CA50F7A8E2F3F657C1108D9D44CFD8") +) + +// JacobianPoint is an element of the group formed by the secp256k1 curve in +// Jacobian projective coordinates and thus represents a point on the curve. +type JacobianPoint struct { + // The X coordinate in Jacobian projective coordinates. The affine point is + // X/z^2. + X FieldVal + + // The Y coordinate in Jacobian projective coordinates. The affine point is + // Y/z^3. + Y FieldVal + + // The Z coordinate in Jacobian projective coordinates. + Z FieldVal +} + +// MakeJacobianPoint returns a Jacobian point with the provided X, Y, and Z +// coordinates. +func MakeJacobianPoint(x, y, z *FieldVal) JacobianPoint { + var p JacobianPoint + p.X.Set(x) + p.Y.Set(y) + p.Z.Set(z) + return p +} + +// Set sets the Jacobian point to the provided point. +func (p *JacobianPoint) Set(other *JacobianPoint) { + p.X.Set(&other.X) + p.Y.Set(&other.Y) + p.Z.Set(&other.Z) +} + +// ToAffine reduces the Z value of the existing point to 1 effectively +// making it an affine coordinate in constant time. The point will be +// normalized. +func (p *JacobianPoint) ToAffine() { + // Inversions are expensive and both point addition and point doubling + // are faster when working with points that have a z value of one. So, + // if the point needs to be converted to affine, go ahead and normalize + // the point itself at the same time as the calculation is the same. + var zInv, tempZ FieldVal + zInv.Set(&p.Z).Inverse() // zInv = Z^-1 + tempZ.SquareVal(&zInv) // tempZ = Z^-2 + p.X.Mul(&tempZ) // X = X/Z^2 (mag: 1) + p.Y.Mul(tempZ.Mul(&zInv)) // Y = Y/Z^3 (mag: 1) + p.Z.SetInt(1) // Z = 1 (mag: 1) + + // Normalize the x and y values. + p.X.Normalize() + p.Y.Normalize() +} + +// addZ1AndZ2EqualsOne adds two Jacobian points that are already known to have +// z values of 1 and stores the result in the provided result param. That is to +// say result = p1 + p2. It performs faster addition than the generic add +// routine since less arithmetic is needed due to the ability to avoid the z +// value multiplications. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addZ1AndZ2EqualsOne(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl + // + // In particular it performs the calculations using the following: + // H = X2-X1, HH = H^2, I = 4*HH, J = H*I, r = 2*(Y2-Y1), V = X1*I + // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = 2*H + // + // This results in a cost of 4 field multiplications, 2 field squarings, + // 6 field additions, and 5 integer multiplications. + x1, y1 := &p1.X, &p1.Y + x2, y2 := &p2.X, &p2.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity per the group law for elliptic curve cryptography. + if x1.Equals(x2) { + if y1.Equals(y2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var h, i, j, r, v FieldVal + var negJ, neg2V, negX3 FieldVal + h.Set(x1).Negate(1).Add(x2) // H = X2-X1 (mag: 3) + i.SquareVal(&h).MulInt(4) // I = 4*H^2 (mag: 4) + j.Mul2(&h, &i) // J = H*I (mag: 1) + r.Set(y1).Negate(1).Add(y2).MulInt(2) // r = 2*(Y2-Y1) (mag: 6) + v.Mul2(x1, &i) // V = X1*I (mag: 1) + negJ.Set(&j).Negate(1) // negJ = -J (mag: 2) + neg2V.Set(&v).MulInt(2).Negate(2) // neg2V = -(2*V) (mag: 3) + x3.Set(&r).Square().Add(&negJ).Add(&neg2V) // X3 = r^2-J-2*V (mag: 6) + negX3.Set(x3).Negate(6) // negX3 = -X3 (mag: 7) + j.Mul(y1).MulInt(2).Negate(2) // J = -(2*Y1*J) (mag: 3) + y3.Set(&v).Add(&negX3).Mul(&r).Add(&j) // Y3 = r*(V-X3)-2*Y1*J (mag: 4) + z3.Set(&h).MulInt(2) // Z3 = 2*H (mag: 6) + + // Normalize the resulting field values to a magnitude of 1 as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// addZ1EqualsZ2 adds two Jacobian points that are already known to have the +// same z value and stores the result in the provided result param. That is to +// say result = p1 + p2. It performs faster addition than the generic add +// routine since less arithmetic is needed due to the known equivalence. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addZ1EqualsZ2(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using a slightly modified version + // of the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl + // + // In particular it performs the calculations using the following: + // A = X2-X1, B = A^2, C=Y2-Y1, D = C^2, E = X1*B, F = X2*B + // X3 = D-E-F, Y3 = C*(E-X3)-Y1*(F-E), Z3 = Z1*A + // + // This results in a cost of 5 field multiplications, 2 field squarings, + // 9 field additions, and 0 integer multiplications. + x1, y1, z1 := &p1.X, &p1.Y, &p1.Z + x2, y2 := &p2.X, &p2.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity per the group law for elliptic curve cryptography. + if x1.Equals(x2) { + if y1.Equals(y2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var a, b, c, d, e, f FieldVal + var negX1, negY1, negE, negX3 FieldVal + negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2) + negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2) + a.Set(&negX1).Add(x2) // A = X2-X1 (mag: 3) + b.SquareVal(&a) // B = A^2 (mag: 1) + c.Set(&negY1).Add(y2) // C = Y2-Y1 (mag: 3) + d.SquareVal(&c) // D = C^2 (mag: 1) + e.Mul2(x1, &b) // E = X1*B (mag: 1) + negE.Set(&e).Negate(1) // negE = -E (mag: 2) + f.Mul2(x2, &b) // F = X2*B (mag: 1) + x3.Add2(&e, &f).Negate(3).Add(&d) // X3 = D-E-F (mag: 5) + negX3.Set(x3).Negate(5).Normalize() // negX3 = -X3 (mag: 1) + y3.Set(y1).Mul(f.Add(&negE)).Negate(3) // Y3 = -(Y1*(F-E)) (mag: 4) + y3.Add(e.Add(&negX3).Mul(&c)) // Y3 = C*(E-X3)+Y3 (mag: 5) + z3.Mul2(z1, &a) // Z3 = Z1*A (mag: 1) + + // Normalize the resulting field values to a magnitude of 1 as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// addZ2EqualsOne adds two Jacobian points when the second point is already +// known to have a z value of 1 (and the z value for the first point is not 1) +// and stores the result in the provided result param. That is to say result = +// p1 + p2. It performs faster addition than the generic add routine since +// less arithmetic is needed due to the ability to avoid multiplications by the +// second point's z value. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addZ2EqualsOne(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + // + // In particular it performs the calculations using the following: + // Z1Z1 = Z1^2, U2 = X2*Z1Z1, S2 = Y2*Z1*Z1Z1, H = U2-X1, HH = H^2, + // I = 4*HH, J = H*I, r = 2*(S2-Y1), V = X1*I + // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*Y1*J, Z3 = (Z1+H)^2-Z1Z1-HH + // + // This results in a cost of 7 field multiplications, 4 field squarings, + // 9 field additions, and 4 integer multiplications. + x1, y1, z1 := &p1.X, &p1.Y, &p1.Z + x2, y2 := &p2.X, &p2.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity per the group law for elliptic curve cryptography. Since + // any number of Jacobian coordinates can represent the same affine + // point, the x and y values need to be converted to like terms. Due to + // the assumption made for this function that the second point has a z + // value of 1 (z2=1), the first point is already "converted". + var z1z1, u2, s2 FieldVal + z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1) + u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1) + s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1) + if x1.Equals(&u2) { + if y1.Equals(&s2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var h, hh, i, j, r, rr, v FieldVal + var negX1, negY1, negX3 FieldVal + negX1.Set(x1).Negate(1) // negX1 = -X1 (mag: 2) + h.Add2(&u2, &negX1) // H = U2-X1 (mag: 3) + hh.SquareVal(&h) // HH = H^2 (mag: 1) + i.Set(&hh).MulInt(4) // I = 4 * HH (mag: 4) + j.Mul2(&h, &i) // J = H*I (mag: 1) + negY1.Set(y1).Negate(1) // negY1 = -Y1 (mag: 2) + r.Set(&s2).Add(&negY1).MulInt(2) // r = 2*(S2-Y1) (mag: 6) + rr.SquareVal(&r) // rr = r^2 (mag: 1) + v.Mul2(x1, &i) // V = X1*I (mag: 1) + x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4) + x3.Add(&rr) // X3 = r^2+X3 (mag: 5) + negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6) + y3.Set(y1).Mul(&j).MulInt(2).Negate(2) // Y3 = -(2*Y1*J) (mag: 3) + y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4) + z3.Add2(z1, &h).Square() // Z3 = (Z1+H)^2 (mag: 1) + z3.Add(z1z1.Add(&hh).Negate(2)) // Z3 = Z3-(Z1Z1+HH) (mag: 4) + + // Normalize the resulting field values to a magnitude of 1 as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// addGeneric adds two Jacobian points without any assumptions about the z +// values of the two points and stores the result in the provided result param. +// That is to say result = p1 + p2. It is the slowest of the add routines due +// to requiring the most arithmetic. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func addGeneric(p1, p2, result *JacobianPoint) { + // To compute the point addition efficiently, this implementation splits + // the equation into intermediate elements which are used to minimize + // the number of field multiplications using the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl + // + // In particular it performs the calculations using the following: + // Z1Z1 = Z1^2, Z2Z2 = Z2^2, U1 = X1*Z2Z2, U2 = X2*Z1Z1, S1 = Y1*Z2*Z2Z2 + // S2 = Y2*Z1*Z1Z1, H = U2-U1, I = (2*H)^2, J = H*I, r = 2*(S2-S1) + // V = U1*I + // X3 = r^2-J-2*V, Y3 = r*(V-X3)-2*S1*J, Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H + // + // This results in a cost of 11 field multiplications, 5 field squarings, + // 9 field additions, and 4 integer multiplications. + x1, y1, z1 := &p1.X, &p1.Y, &p1.Z + x2, y2, z2 := &p2.X, &p2.Y, &p2.Z + x3, y3, z3 := &result.X, &result.Y, &result.Z + + // When the x coordinates are the same for two points on the curve, the + // y coordinates either must be the same, in which case it is point + // doubling, or they are opposite and the result is the point at + // infinity. Since any number of Jacobian coordinates can represent the + // same affine point, the x and y values need to be converted to like + // terms. + var z1z1, z2z2, u1, u2, s1, s2 FieldVal + z1z1.SquareVal(z1) // Z1Z1 = Z1^2 (mag: 1) + z2z2.SquareVal(z2) // Z2Z2 = Z2^2 (mag: 1) + u1.Set(x1).Mul(&z2z2).Normalize() // U1 = X1*Z2Z2 (mag: 1) + u2.Set(x2).Mul(&z1z1).Normalize() // U2 = X2*Z1Z1 (mag: 1) + s1.Set(y1).Mul(&z2z2).Mul(z2).Normalize() // S1 = Y1*Z2*Z2Z2 (mag: 1) + s2.Set(y2).Mul(&z1z1).Mul(z1).Normalize() // S2 = Y2*Z1*Z1Z1 (mag: 1) + if u1.Equals(&u2) { + if s1.Equals(&s2) { + // Since x1 == x2 and y1 == y2, point doubling must be + // done, otherwise the addition would end up dividing + // by zero. + DoubleNonConst(p1, result) + return + } + + // Since x1 == x2 and y1 == -y2, the sum is the point at + // infinity per the group law. + x3.SetInt(0) + y3.SetInt(0) + z3.SetInt(0) + return + } + + // Calculate X3, Y3, and Z3 according to the intermediate elements + // breakdown above. + var h, i, j, r, rr, v FieldVal + var negU1, negS1, negX3 FieldVal + negU1.Set(&u1).Negate(1) // negU1 = -U1 (mag: 2) + h.Add2(&u2, &negU1) // H = U2-U1 (mag: 3) + i.Set(&h).MulInt(2).Square() // I = (2*H)^2 (mag: 2) + j.Mul2(&h, &i) // J = H*I (mag: 1) + negS1.Set(&s1).Negate(1) // negS1 = -S1 (mag: 2) + r.Set(&s2).Add(&negS1).MulInt(2) // r = 2*(S2-S1) (mag: 6) + rr.SquareVal(&r) // rr = r^2 (mag: 1) + v.Mul2(&u1, &i) // V = U1*I (mag: 1) + x3.Set(&v).MulInt(2).Add(&j).Negate(3) // X3 = -(J+2*V) (mag: 4) + x3.Add(&rr) // X3 = r^2+X3 (mag: 5) + negX3.Set(x3).Negate(5) // negX3 = -X3 (mag: 6) + y3.Mul2(&s1, &j).MulInt(2).Negate(2) // Y3 = -(2*S1*J) (mag: 3) + y3.Add(v.Add(&negX3).Mul(&r)) // Y3 = r*(V-X3)+Y3 (mag: 4) + z3.Add2(z1, z2).Square() // Z3 = (Z1+Z2)^2 (mag: 1) + z3.Add(z1z1.Add(&z2z2).Negate(2)) // Z3 = Z3-(Z1Z1+Z2Z2) (mag: 4) + z3.Mul(&h) // Z3 = Z3*H (mag: 1) + + // Normalize the resulting field values to a magnitude of 1 as needed. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// AddNonConst adds the passed Jacobian points together and stores the result in +// the provided result param in *non-constant* time. +// +// NOTE: The points must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func AddNonConst(p1, p2, result *JacobianPoint) { + // A point at infinity is the identity according to the group law for + // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P. + if (p1.X.IsZero() && p1.Y.IsZero()) || p1.Z.IsZero() { + result.Set(p2) + return + } + if (p2.X.IsZero() && p2.Y.IsZero()) || p2.Z.IsZero() { + result.Set(p1) + return + } + + // Faster point addition can be achieved when certain assumptions are + // met. For example, when both points have the same z value, arithmetic + // on the z values can be avoided. This section thus checks for these + // conditions and calls an appropriate add function which is accelerated + // by using those assumptions. + isZ1One := p1.Z.IsOne() + isZ2One := p2.Z.IsOne() + switch { + case isZ1One && isZ2One: + addZ1AndZ2EqualsOne(p1, p2, result) + return + case p1.Z.Equals(&p2.Z): + addZ1EqualsZ2(p1, p2, result) + return + case isZ2One: + addZ2EqualsOne(p1, p2, result) + return + } + + // None of the above assumptions are true, so fall back to generic + // point addition. + addGeneric(p1, p2, result) +} + +// doubleZ1EqualsOne performs point doubling on the passed Jacobian point when +// the point is already known to have a z value of 1 and stores the result in +// the provided result param. That is to say result = 2*p. It performs faster +// point doubling than the generic routine since less arithmetic is needed due +// to the ability to avoid multiplication by the z value. +// +// NOTE: The resulting point will be normalized. +func doubleZ1EqualsOne(p, result *JacobianPoint) { + // This function uses the assumptions that z1 is 1, thus the point + // doubling formulas reduce to: + // + // X3 = (3*X1^2)^2 - 8*X1*Y1^2 + // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4 + // Z3 = 2*Y1 + // + // To compute the above efficiently, this implementation splits the + // equation into intermediate elements which are used to minimize the + // number of field multiplications in favor of field squarings which + // are roughly 35% faster than field multiplications with the current + // implementation at the time this was written. + // + // This uses a slightly modified version of the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl + // + // In particular it performs the calculations using the following: + // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C) + // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C + // Z3 = 2*Y1 + // + // This results in a cost of 1 field multiplication, 5 field squarings, + // 6 field additions, and 5 integer multiplications. + x1, y1 := &p.X, &p.Y + x3, y3, z3 := &result.X, &result.Y, &result.Z + var a, b, c, d, e, f FieldVal + z3.Set(y1).MulInt(2) // Z3 = 2*Y1 (mag: 2) + a.SquareVal(x1) // A = X1^2 (mag: 1) + b.SquareVal(y1) // B = Y1^2 (mag: 1) + c.SquareVal(&b) // C = B^2 (mag: 1) + b.Add(x1).Square() // B = (X1+B)^2 (mag: 1) + d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3) + d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8) + e.Set(&a).MulInt(3) // E = 3*A (mag: 3) + f.SquareVal(&e) // F = E^2 (mag: 1) + x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17) + x3.Add(&f) // X3 = F+X3 (mag: 18) + f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1) + y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9) + y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10) + + // Normalize the field values back to a magnitude of 1. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// doubleGeneric performs point doubling on the passed Jacobian point without +// any assumptions about the z value and stores the result in the provided +// result param. That is to say result = 2*p. It is the slowest of the point +// doubling routines due to requiring the most arithmetic. +// +// NOTE: The resulting point will be normalized. +func doubleGeneric(p, result *JacobianPoint) { + // Point doubling formula for Jacobian coordinates for the secp256k1 + // curve: + // + // X3 = (3*X1^2)^2 - 8*X1*Y1^2 + // Y3 = (3*X1^2)*(4*X1*Y1^2 - X3) - 8*Y1^4 + // Z3 = 2*Y1*Z1 + // + // To compute the above efficiently, this implementation splits the + // equation into intermediate elements which are used to minimize the + // number of field multiplications in favor of field squarings which + // are roughly 35% faster than field multiplications with the current + // implementation at the time this was written. + // + // This uses a slightly modified version of the method shown at: + // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + // + // In particular it performs the calculations using the following: + // A = X1^2, B = Y1^2, C = B^2, D = 2*((X1+B)^2-A-C) + // E = 3*A, F = E^2, X3 = F-2*D, Y3 = E*(D-X3)-8*C + // Z3 = 2*Y1*Z1 + // + // This results in a cost of 1 field multiplication, 5 field squarings, + // 6 field additions, and 5 integer multiplications. + x1, y1, z1 := &p.X, &p.Y, &p.Z + x3, y3, z3 := &result.X, &result.Y, &result.Z + var a, b, c, d, e, f FieldVal + z3.Mul2(y1, z1).MulInt(2) // Z3 = 2*Y1*Z1 (mag: 2) + a.SquareVal(x1) // A = X1^2 (mag: 1) + b.SquareVal(y1) // B = Y1^2 (mag: 1) + c.SquareVal(&b) // C = B^2 (mag: 1) + b.Add(x1).Square() // B = (X1+B)^2 (mag: 1) + d.Set(&a).Add(&c).Negate(2) // D = -(A+C) (mag: 3) + d.Add(&b).MulInt(2) // D = 2*(B+D)(mag: 8) + e.Set(&a).MulInt(3) // E = 3*A (mag: 3) + f.SquareVal(&e) // F = E^2 (mag: 1) + x3.Set(&d).MulInt(2).Negate(16) // X3 = -(2*D) (mag: 17) + x3.Add(&f) // X3 = F+X3 (mag: 18) + f.Set(x3).Negate(18).Add(&d).Normalize() // F = D-X3 (mag: 1) + y3.Set(&c).MulInt(8).Negate(8) // Y3 = -(8*C) (mag: 9) + y3.Add(f.Mul(&e)) // Y3 = E*F+Y3 (mag: 10) + + // Normalize the field values back to a magnitude of 1. + x3.Normalize() + y3.Normalize() + z3.Normalize() +} + +// DoubleNonConst doubles the passed Jacobian point and stores the result in the +// provided result parameter in *non-constant* time. +// +// NOTE: The point must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func DoubleNonConst(p, result *JacobianPoint) { + // Doubling a point at infinity is still infinity. + if p.Y.IsZero() || p.Z.IsZero() { + result.X.SetInt(0) + result.Y.SetInt(0) + result.Z.SetInt(0) + return + } + + // Slightly faster point doubling can be achieved when the z value is 1 + // by avoiding the multiplication on the z value. This section calls + // a point doubling function which is accelerated by using that + // assumption when possible. + if p.Z.IsOne() { + doubleZ1EqualsOne(p, result) + return + } + + // Fall back to generic point doubling which works with arbitrary z + // values. + doubleGeneric(p, result) +} + +// splitK returns a balanced length-two representation of k and their signs. +// This is algorithm 3.74 from [GECC]. +// +// One thing of note about this algorithm is that no matter what c1 and c2 are, +// the final equation of k = k1 + k2 * lambda (mod n) will hold. This is +// provable mathematically due to how a1/b1/a2/b2 are computed. +// +// c1 and c2 are chosen to minimize the max(k1,k2). +func splitK(k []byte) ([]byte, []byte, int, int) { + // All math here is done with big.Int, which is slow. + // At some point, it might be useful to write something similar to + // FieldVal but for N instead of P as the prime field if this ends up + // being a bottleneck. + bigIntK := new(big.Int) + c1, c2 := new(big.Int), new(big.Int) + tmp1, tmp2 := new(big.Int), new(big.Int) + k1, k2 := new(big.Int), new(big.Int) + + bigIntK.SetBytes(k) + // c1 = round(b2 * k / n) from step 4. + // Rounding isn't really necessary and costs too much, hence skipped + c1.Mul(endomorphismB2, bigIntK) + c1.Div(c1, curveParams.N) + // c2 = round(b1 * k / n) from step 4 (sign reversed to optimize one step) + // Rounding isn't really necessary and costs too much, hence skipped + c2.Mul(endomorphismB1, bigIntK) + c2.Div(c2, curveParams.N) + // k1 = k - c1 * a1 - c2 * a2 from step 5 (note c2's sign is reversed) + tmp1.Mul(c1, endomorphismA1) + tmp2.Mul(c2, endomorphismA2) + k1.Sub(bigIntK, tmp1) + k1.Add(k1, tmp2) + // k2 = - c1 * b1 - c2 * b2 from step 5 (note c2's sign is reversed) + tmp1.Mul(c1, endomorphismB1) + tmp2.Mul(c2, endomorphismB2) + k2.Sub(tmp2, tmp1) + + // Note Bytes() throws out the sign of k1 and k2. This matters + // since k1 and/or k2 can be negative. Hence, we pass that + // back separately. + return k1.Bytes(), k2.Bytes(), k1.Sign(), k2.Sign() +} + +// ScalarMultNonConst multiplies k*P where k is a big endian integer modulo the +// curve order and P is a point in Jacobian projective coordinates and stores +// the result in the provided Jacobian point. +// +// NOTE: The point must be normalized for this function to return the correct +// result. The resulting point will be normalized. +func ScalarMultNonConst(k *ModNScalar, point, result *JacobianPoint) { + // Decompose K into k1 and k2 in order to halve the number of EC ops. + // See Algorithm 3.74 in [GECC]. + kBytes := k.Bytes() + k1, k2, signK1, signK2 := splitK(kBytes[:]) + zeroArray32(&kBytes) + + // The main equation here to remember is: + // k * P = k1 * P + k2 * ϕ(P) + // + // P1 below is P in the equation, P2 below is ϕ(P) in the equation + p1, p1Neg := new(JacobianPoint), new(JacobianPoint) + p1.Set(point) + p1Neg.Set(p1) + p1Neg.Y.Negate(1).Normalize() + + // NOTE: ϕ(x,y) = (βx,y). The Jacobian z coordinates are the same, so this + // math goes through. + p2, p2Neg := new(JacobianPoint), new(JacobianPoint) + p2.Set(p1) + p2.X.Mul(endomorphismBeta).Normalize() + p2Neg.Set(p2) + p2Neg.Y.Negate(1).Normalize() + + // Flip the positive and negative values of the points as needed + // depending on the signs of k1 and k2. As mentioned in the equation + // above, each of k1 and k2 are multiplied by the respective point. + // Since -k * P is the same thing as k * -P, and the group law for + // elliptic curves states that P(x, y) = -P(x, -y), it's faster and + // simplifies the code to just make the point negative. + if signK1 == -1 { + p1, p1Neg = p1Neg, p1 + } + if signK2 == -1 { + p2, p2Neg = p2Neg, p2 + } + + // NAF versions of k1 and k2 should have a lot more zeros. + // + // The Pos version of the bytes contain the +1s and the Neg versions + // contain the -1s. + k1PosNAF, k1NegNAF := naf(k1) + k2PosNAF, k2NegNAF := naf(k2) + k1Len := len(k1PosNAF) + k2Len := len(k2PosNAF) + + m := k1Len + if m < k2Len { + m = k2Len + } + + // Point Q = ∞ (point at infinity). + var q JacobianPoint + + // Add left-to-right using the NAF optimization. See algorithm 3.77 + // from [GECC]. This should be faster overall since there will be a lot + // more instances of 0, hence reducing the number of Jacobian additions + // at the cost of 1 possible extra doubling. + var k1BytePos, k1ByteNeg, k2BytePos, k2ByteNeg byte + for i := 0; i < m; i++ { + // Since we're going left-to-right, pad the front with 0s. + if i < m-k1Len { + k1BytePos = 0 + k1ByteNeg = 0 + } else { + k1BytePos = k1PosNAF[i-(m-k1Len)] + k1ByteNeg = k1NegNAF[i-(m-k1Len)] + } + if i < m-k2Len { + k2BytePos = 0 + k2ByteNeg = 0 + } else { + k2BytePos = k2PosNAF[i-(m-k2Len)] + k2ByteNeg = k2NegNAF[i-(m-k2Len)] + } + + for j := 7; j >= 0; j-- { + // Q = 2 * Q + DoubleNonConst(&q, &q) + + if k1BytePos&0x80 == 0x80 { + AddNonConst(&q, p1, &q) + } else if k1ByteNeg&0x80 == 0x80 { + AddNonConst(&q, p1Neg, &q) + } + + if k2BytePos&0x80 == 0x80 { + AddNonConst(&q, p2, &q) + } else if k2ByteNeg&0x80 == 0x80 { + AddNonConst(&q, p2Neg, &q) + } + k1BytePos <<= 1 + k1ByteNeg <<= 1 + k2BytePos <<= 1 + k2ByteNeg <<= 1 + } + } + + result.Set(&q) +} + +// ScalarBaseMultNonConst multiplies k*G where G is the base point of the group +// and k is a big endian integer. The result is stored in Jacobian coordinates +// (x1, y1, z1). +// +// NOTE: The resulting point will be normalized. +func ScalarBaseMultNonConst(k *ModNScalar, result *JacobianPoint) { + bytePoints := S256().bytePoints + + // Point Q = ∞ (point at infinity). + var q JacobianPoint + + // curve.bytePoints has all 256 byte points for each 8-bit window. The + // strategy is to add up the byte points. This is best understood by + // expressing k in base-256 which it already sort of is. Each "digit" in + // the 8-bit window can be looked up using bytePoints and added together. + var pt JacobianPoint + for i, byteVal := range k.Bytes() { + p := bytePoints[i][byteVal] + pt.X.Set(&p[0]) + pt.Y.Set(&p[1]) + pt.Z.Set(&p[2]) + AddNonConst(&q, &pt, &q) + } + + result.Set(&q) +} + +// naf takes a positive integer k and returns the Non-Adjacent Form (NAF) as two +// byte slices. The first is where 1s will be. The second is where -1s will +// be. NAF is convenient in that on average, only 1/3rd of its values are +// non-zero. This is algorithm 3.30 from [GECC]. +// +// Essentially, this makes it possible to minimize the number of operations +// since the resulting ints returned will be at least 50% 0s. +func naf(k []byte) ([]byte, []byte) { + // The essence of this algorithm is that whenever we have consecutive 1s + // in the binary, we want to put a -1 in the lowest bit and get a bunch + // of 0s up to the highest bit of consecutive 1s. This is due to this + // identity: + // 2^n + 2^(n-1) + 2^(n-2) + ... + 2^(n-k) = 2^(n+1) - 2^(n-k) + // + // The algorithm thus may need to go 1 more bit than the length of the + // bits we actually have, hence bits being 1 bit longer than was + // necessary. Since we need to know whether adding will cause a carry, + // we go from right-to-left in this addition. + var carry, curIsOne, nextIsOne bool + // these default to zero + retPos := make([]byte, len(k)+1) + retNeg := make([]byte, len(k)+1) + for i := len(k) - 1; i >= 0; i-- { + curByte := k[i] + for j := uint(0); j < 8; j++ { + curIsOne = curByte&1 == 1 + if j == 7 { + if i == 0 { + nextIsOne = false + } else { + nextIsOne = k[i-1]&1 == 1 + } + } else { + nextIsOne = curByte&2 == 2 + } + if carry { + if curIsOne { + // This bit is 1, so continue to carry + // and don't need to do anything. + } else { + // We've hit a 0 after some number of + // 1s. + if nextIsOne { + // Start carrying again since + // a new sequence of 1s is + // starting. + retNeg[i+1] += 1 << j + } else { + // Stop carrying since 1s have + // stopped. + carry = false + retPos[i+1] += 1 << j + } + } + } else if curIsOne { + if nextIsOne { + // If this is the start of at least 2 + // consecutive 1s, set the current one + // to -1 and start carrying. + retNeg[i+1] += 1 << j + carry = true + } else { + // This is a singleton, not consecutive + // 1s. + retPos[i+1] += 1 << j + } + } + curByte >>= 1 + } + } + if carry { + retPos[0] = 1 + return retPos, retNeg + } + return retPos[1:], retNeg[1:] +} + +// isOnCurve returns whether or not the affine point (x,y) is on the curve. +func isOnCurve(fx, fy *FieldVal) bool { + // Elliptic curve equation for secp256k1 is: y^2 = x^3 + 7 + y2 := new(FieldVal).SquareVal(fy).Normalize() + result := new(FieldVal).SquareVal(fx).Mul(fx).AddInt(7).Normalize() + return y2.Equals(result) +} + +// DecompressY attempts to calculate the Y coordinate for the given X coordinate +// such that the result pair is a point on the secp256k1 curve. It adjusts Y +// based on the desired oddness and returns whether or not it was successful +// since not all X coordinates are valid. +// +// The magnitude of the provided X coordinate field val must be a max of 8 for a +// correct result. The resulting Y field val will have a max magnitude of 2. +func DecompressY(x *FieldVal, odd bool, resultY *FieldVal) bool { + // The curve equation for secp256k1 is: y^2 = x^3 + 7. Thus + // y = +-sqrt(x^3 + 7). + // + // The x coordinate must be invalid if there is no square root for the + // calculated rhs because it means the X coordinate is not for a point on + // the curve. + x3PlusB := new(FieldVal).SquareVal(x).Mul(x).AddInt(7) + if hasSqrt := resultY.SquareRootVal(x3PlusB); !hasSqrt { + return false + } + if resultY.Normalize().IsOdd() != odd { + resultY.Negate(1) + } + return true +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/doc.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/doc.go new file mode 100644 index 00000000..91a670e5 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/doc.go @@ -0,0 +1,58 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2019 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +/* +Package secp256k1 implements optimized secp256k1 elliptic curve operations. + +This package provides an optimized pure Go implementation of elliptic curve +cryptography operations over the secp256k1 curve as well as data structures and +functions for working with public and private secp256k1 keys. See +https://www.secg.org/sec2-v2.pdf for details on the standard. + +In addition, sub packages are provided to produce, verify, parse, and serialize +ECDSA signatures and EC-Schnorr-DCRv0 (a custom Schnorr-based signature scheme +specific to Decred) signatures. See the README.md files in the relevant sub +packages for more details about those aspects. + +An overview of the features provided by this package are as follows: + + - Private key generation, serialization, and parsing + - Public key generation, serialization and parsing per ANSI X9.62-1998 + - Parses uncompressed, compressed, and hybrid public keys + - Serializes uncompressed and compressed public keys + - Specialized types for performing optimized and constant time field operations + - FieldVal type for working modulo the secp256k1 field prime + - ModNScalar type for working modulo the secp256k1 group order + - Elliptic curve operations in Jacobian projective coordinates + - Point addition + - Point doubling + - Scalar multiplication with an arbitrary point + - Scalar multiplication with the base point (group generator) + - Point decompression from a given x coordinate + - Nonce generation via RFC6979 with support for extra data and version + information that can be used to prevent nonce reuse between signing + algorithms + +It also provides an implementation of the Go standard library crypto/elliptic +Curve interface via the S256 function so that it may be used with other packages +in the standard library such as crypto/tls, crypto/x509, and crypto/ecdsa. +However, in the case of ECDSA, it is highly recommended to use the ecdsa sub +package of this package instead since it is optimized specifically for secp256k1 +and is significantly faster as a result. + +Although this package was primarily written for dcrd, it has intentionally been +designed so it can be used as a standalone package for any projects needing to +use optimized secp256k1 elliptic curve cryptography. + +Finally, a comprehensive suite of tests is provided to provide a high level of +quality assurance. + +Use of secp256k1 in Decred + +At the time of this writing, the primary public key cryptography in widespread +use on the Decred network used to secure coins is based on elliptic curves +defined by the secp256k1 domain parameters. +*/ +package secp256k1 diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/ecdh.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/ecdh.go new file mode 100644 index 00000000..ebbdfc54 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/ecdh.go @@ -0,0 +1,21 @@ +// Copyright (c) 2015 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// GenerateSharedSecret generates a shared secret based on a private key and a +// public key using Diffie-Hellman key exchange (ECDH) (RFC 5903). +// RFC5903 Section 9 states we should only return x. +// +// It is recommended to securily hash the result before using as a cryptographic +// key. +func GenerateSharedSecret(privkey *PrivateKey, pubkey *PublicKey) []byte { + var point, result JacobianPoint + pubkey.AsJacobian(&point) + ScalarMultNonConst(&privkey.Key, &point, &result) + result.ToAffine() + xBytes := result.X.Bytes() + return xBytes[:] +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/ellipticadaptor.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/ellipticadaptor.go new file mode 100644 index 00000000..dc532178 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/ellipticadaptor.go @@ -0,0 +1,276 @@ +// Copyright 2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// References: +// [SECG]: Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "math/big" + "sync" +) + +// CurveParams contains the parameters for the secp256k1 curve. +type CurveParams struct { + // P is the prime used in the secp256k1 field. + P *big.Int + + // N is the order of the secp256k1 curve group generated by the base point. + N *big.Int + + // Gx and Gy are the x and y coordinate of the base point, respectively. + Gx, Gy *big.Int + + // BitSize is the size of the underlying secp256k1 field in bits. + BitSize int + + // H is the cofactor of the secp256k1 curve. + H int + + // ByteSize is simply the bit size / 8 and is provided for convenience + // since it is calculated repeatedly. + ByteSize int +} + +// Curve parameters taken from [SECG] section 2.4.1. +var curveParams = CurveParams{ + P: fromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"), + N: fromHex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"), + Gx: fromHex("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"), + Gy: fromHex("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"), + BitSize: 256, + H: 1, + ByteSize: 256 / 8, +} + +// Params returns the secp256k1 curve parameters for convenience. +func Params() *CurveParams { + return &curveParams +} + +// KoblitzCurve provides an implementation for secp256k1 that fits the ECC Curve +// interface from crypto/elliptic. +type KoblitzCurve struct { + *elliptic.CurveParams + + // bytePoints + bytePoints *[32][256][3]FieldVal +} + +// bigAffineToJacobian takes an affine point (x, y) as big integers and converts +// it to Jacobian point with Z=1. +func bigAffineToJacobian(x, y *big.Int, result *JacobianPoint) { + result.X.SetByteSlice(x.Bytes()) + result.Y.SetByteSlice(y.Bytes()) + result.Z.SetInt(1) +} + +// jacobianToBigAffine takes a Jacobian point (x, y, z) as field values and +// converts it to an affine point as big integers. +func jacobianToBigAffine(point *JacobianPoint) (*big.Int, *big.Int) { + point.ToAffine() + + // Convert the field values for the now affine point to big.Ints. + x3, y3 := new(big.Int), new(big.Int) + x3.SetBytes(point.X.Bytes()[:]) + y3.SetBytes(point.Y.Bytes()[:]) + return x3, y3 +} + +// Params returns the parameters for the curve. +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) Params() *elliptic.CurveParams { + return curve.CurveParams +} + +// IsOnCurve returns whether or not the affine point (x,y) is on the curve. +// +// This is part of the elliptic.Curve interface implementation. This function +// differs from the crypto/elliptic algorithm since a = 0 not -3. +func (curve *KoblitzCurve) IsOnCurve(x, y *big.Int) bool { + // Convert big ints to a Jacobian point for faster arithmetic. + var point JacobianPoint + bigAffineToJacobian(x, y, &point) + return isOnCurve(&point.X, &point.Y) +} + +// Add returns the sum of (x1,y1) and (x2,y2). +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { + // A point at infinity is the identity according to the group law for + // elliptic curve cryptography. Thus, ∞ + P = P and P + ∞ = P. + if x1.Sign() == 0 && y1.Sign() == 0 { + return x2, y2 + } + if x2.Sign() == 0 && y2.Sign() == 0 { + return x1, y1 + } + + // Convert the affine coordinates from big integers to Jacobian points, + // do the point addition in Jacobian projective space, and convert the + // Jacobian point back to affine big.Ints. + var p1, p2, result JacobianPoint + bigAffineToJacobian(x1, y1, &p1) + bigAffineToJacobian(x2, y2, &p2) + AddNonConst(&p1, &p2, &result) + return jacobianToBigAffine(&result) +} + +// Double returns 2*(x1,y1). +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { + if y1.Sign() == 0 { + return new(big.Int), new(big.Int) + } + + // Convert the affine coordinates from big integers to Jacobian points, + // do the point doubling in Jacobian projective space, and convert the + // Jacobian point back to affine big.Ints. + var point, result JacobianPoint + bigAffineToJacobian(x1, y1, &point) + DoubleNonConst(&point, &result) + return jacobianToBigAffine(&result) +} + +// moduloReduce reduces k from more than 32 bytes to 32 bytes and under. This +// is done by doing a simple modulo curve.N. We can do this since G^N = 1 and +// thus any other valid point on the elliptic curve has the same order. +func moduloReduce(k []byte) []byte { + // Since the order of G is curve.N, we can use a much smaller number by + // doing modulo curve.N + if len(k) > curveParams.ByteSize { + tmpK := new(big.Int).SetBytes(k) + tmpK.Mod(tmpK, curveParams.N) + return tmpK.Bytes() + } + + return k +} + +// ScalarMult returns k*(Bx, By) where k is a big endian integer. +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { + // Convert the affine coordinates from big integers to Jacobian points, + // do the multiplication in Jacobian projective space, and convert the + // Jacobian point back to affine big.Ints. + var kModN ModNScalar + kModN.SetByteSlice(moduloReduce(k)) + var point, result JacobianPoint + bigAffineToJacobian(Bx, By, &point) + ScalarMultNonConst(&kModN, &point, &result) + return jacobianToBigAffine(&result) +} + +// ScalarBaseMult returns k*G where G is the base point of the group and k is a +// big endian integer. +// +// This is part of the elliptic.Curve interface implementation. +func (curve *KoblitzCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { + // Perform the multiplication and convert the Jacobian point back to affine + // big.Ints. + var kModN ModNScalar + kModN.SetByteSlice(moduloReduce(k)) + var result JacobianPoint + ScalarBaseMultNonConst(&kModN, &result) + return jacobianToBigAffine(&result) +} + +// X returns the x coordinate of the public key. +func (p *PublicKey) X() *big.Int { + return new(big.Int).SetBytes(p.x.Bytes()[:]) +} + +// Y returns the y coordinate of the public key. +func (p *PublicKey) Y() *big.Int { + return new(big.Int).SetBytes(p.y.Bytes()[:]) +} + +// ToECDSA returns the public key as a *ecdsa.PublicKey. +func (p *PublicKey) ToECDSA() *ecdsa.PublicKey { + return &ecdsa.PublicKey{ + Curve: S256(), + X: p.X(), + Y: p.Y(), + } +} + +// ToECDSA returns the private key as a *ecdsa.PrivateKey. +func (p *PrivateKey) ToECDSA() *ecdsa.PrivateKey { + var privKeyBytes [PrivKeyBytesLen]byte + p.Key.PutBytes(&privKeyBytes) + var result JacobianPoint + ScalarBaseMultNonConst(&p.Key, &result) + x, y := jacobianToBigAffine(&result) + newPrivKey := &ecdsa.PrivateKey{ + PublicKey: ecdsa.PublicKey{ + Curve: S256(), + X: x, + Y: y, + }, + D: new(big.Int).SetBytes(privKeyBytes[:]), + } + zeroArray32(&privKeyBytes) + return newPrivKey +} + +// fromHex converts the passed hex string into a big integer pointer and will +// panic is there is an error. This is only provided for the hard-coded +// constants so errors in the source code can bet detected. It will only (and +// must only) be called for initialization purposes. +func fromHex(s string) *big.Int { + r, ok := new(big.Int).SetString(s, 16) + if !ok { + panic("invalid hex in source file: " + s) + } + return r +} + +var ( + // initonce is used to initialize the global secp256k1 koblitz curve instance + // dynamically upon first access. + initonce sync.Once + + // secp256k1 is a global instance of the KoblitzCurve implementation which + // in turn embeds and implements elliptic.CurveParams. + secp256k1 KoblitzCurve +) + +// initS256 initializes the global secp256k1 instance that gets returned by the +// S256 function which provides access to the fields and methods provided by +// elliptic.CurveParms. +func initS256() { + // Curve parameters taken from [SECG] section 2.4.1. + secp256k1.CurveParams = &elliptic.CurveParams{ + P: curveParams.P, + N: curveParams.N, + B: fromHex("0000000000000000000000000000000000000000000000000000000000000007"), + Gx: curveParams.Gx, + Gy: curveParams.Gy, + BitSize: curveParams.BitSize, + Name: "secp256k1", + } + + // Deserialize and set the pre-computed table used to accelerate scalar + // base multiplication. This is hard-coded data, so any errors are + // panics because it means something is wrong in the source code. + if err := loadBytePoints(); err != nil { + panic(err) + } +} + +// S256 returns a Curve which implements secp256k1. +func S256() *KoblitzCurve { + initonce.Do(initS256) + return &secp256k1 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/error.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/error.go new file mode 100644 index 00000000..30f4f124 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/error.go @@ -0,0 +1,126 @@ +// Copyright (c) 2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "fmt" +) + +// ErrorCode identifies a kind of pubkey-related error. It has full support for +// errors.Is and errors.As, so the caller can directly check against an error +// code when determining the reason for an error. +type ErrorCode int + +// These constants are used to identify a specific RuleError. +const ( + // ErrPubKeyInvalidLen indicates that the length of a serialized public + // key is not one of the allowed lengths. + ErrPubKeyInvalidLen ErrorCode = iota + + // ErrPubKeyInvalidFormat indicates an attempt was made to parse a public + // key that does not specify one of the supported formats. + ErrPubKeyInvalidFormat + + // ErrPubKeyXTooBig indicates that the x coordinate for a public key + // is greater than or equal to the prime of the field underlying the group. + ErrPubKeyXTooBig + + // ErrPubKeyYTooBig indicates that the y coordinate for a public key is + // greater than or equal to the prime of the field underlying the group. + ErrPubKeyYTooBig + + // ErrPubKeyNotOnCurve indicates that a public key is not a point on the + // secp256k1 curve. + ErrPubKeyNotOnCurve + + // ErrPubKeyMismatchedOddness indicates that a hybrid public key specified + // an oddness of the y coordinate that does not match the actual oddness of + // the provided y coordinate. + ErrPubKeyMismatchedOddness + + // numErrorCodes is the maximum error code number used in tests. This entry + // MUST be the last entry in the enum. + numErrorCodes +) + +// Map of ErrorCode values back to their constant names for pretty printing. +var errorCodeStrings = map[ErrorCode]string{ + ErrPubKeyInvalidLen: "ErrPubKeyInvalidLen", + ErrPubKeyXTooBig: "ErrPubKeyXTooBig", + ErrPubKeyYTooBig: "ErrPubKeyYTooBig", + ErrPubKeyNotOnCurve: "ErrPubKeyNotOnCurve", + ErrPubKeyMismatchedOddness: "ErrPubKeyMismatchedOddness", + ErrPubKeyInvalidFormat: "ErrPubKeyInvalidFormat", +} + +// String returns the ErrorCode as a human-readable name. +func (e ErrorCode) String() string { + if s := errorCodeStrings[e]; s != "" { + return s + } + return fmt.Sprintf("Unknown ErrorCode (%d)", int(e)) +} + +// Error implements the error interface. +func (e ErrorCode) Error() string { + return e.String() +} + +// Is implements the interface to work with the standard library's errors.Is. +// +// It returns true in the following cases: +// - The target is a Error and the error codes match +// - The target is a ErrorCode and the error codes match +func (e ErrorCode) Is(target error) bool { + switch target := target.(type) { + case Error: + return e == target.ErrorCode + + case ErrorCode: + return e == target + } + + return false +} + +// Error identifies a pubkey-related error. It has full support for errors.Is +// and errors.As, so the caller can ascertain the specific reason for the error +// by checking the underlying error code. +type Error struct { + ErrorCode ErrorCode // Describes the kind of error + Description string // Human readable description of the issue +} + +// Error satisfies the error interface and prints human-readable errors. +func (e Error) Error() string { + return e.Description +} + +// Is implements the interface to work with the standard library's errors.Is. +// +// It returns true in the following cases: +// - The target is a Error and the error codes match +// - The target is a ErrorCode and it the error codes match +func (e Error) Is(target error) bool { + switch target := target.(type) { + case Error: + return e.ErrorCode == target.ErrorCode + + case ErrorCode: + return target == e.ErrorCode + } + + return false +} + +// Unwrap returns the underlying wrapped error code. +func (e Error) Unwrap() error { + return e.ErrorCode +} + +// makeError creates a Error given a set of arguments. +func makeError(c ErrorCode, desc string) Error { + return Error{ErrorCode: c, Description: desc} +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/field.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/field.go new file mode 100644 index 00000000..1b7809cc --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/field.go @@ -0,0 +1,1680 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2020 The Decred developers +// Copyright (c) 2013-2020 Dave Collins +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// References: +// [HAC]: Handbook of Applied Cryptography Menezes, van Oorschot, Vanstone. +// http://cacr.uwaterloo.ca/hac/ + +// All elliptic curve operations for secp256k1 are done in a finite field +// characterized by a 256-bit prime. Given this precision is larger than the +// biggest available native type, obviously some form of bignum math is needed. +// This package implements specialized fixed-precision field arithmetic rather +// than relying on an arbitrary-precision arithmetic package such as math/big +// for dealing with the field math since the size is known. As a result, rather +// large performance gains are achieved by taking advantage of many +// optimizations not available to arbitrary-precision arithmetic and generic +// modular arithmetic algorithms. +// +// There are various ways to internally represent each finite field element. +// For example, the most obvious representation would be to use an array of 4 +// uint64s (64 bits * 4 = 256 bits). However, that representation suffers from +// a couple of issues. First, there is no native Go type large enough to handle +// the intermediate results while adding or multiplying two 64-bit numbers, and +// second there is no space left for overflows when performing the intermediate +// arithmetic between each array element which would lead to expensive carry +// propagation. +// +// Given the above, this implementation represents the field elements as +// 10 uint32s with each word (array entry) treated as base 2^26. This was +// chosen for the following reasons: +// 1) Most systems at the current time are 64-bit (or at least have 64-bit +// registers available for specialized purposes such as MMX) so the +// intermediate results can typically be done using a native register (and +// using uint64s to avoid the need for additional half-word arithmetic) +// 2) In order to allow addition of the internal words without having to +// propagate the carry, the max normalized value for each register must +// be less than the number of bits available in the register +// 3) Since we're dealing with 32-bit values, 64-bits of overflow is a +// reasonable choice for #2 +// 4) Given the need for 256-bits of precision and the properties stated in #1, +// #2, and #3, the representation which best accommodates this is 10 uint32s +// with base 2^26 (26 bits * 10 = 260 bits, so the final word only needs 22 +// bits) which leaves the desired 64 bits (32 * 10 = 320, 320 - 256 = 64) for +// overflow +// +// Since it is so important that the field arithmetic is extremely fast for high +// performance crypto, this type does not perform any validation where it +// ordinarily would. See the documentation for FieldVal for more details. + +import ( + "encoding/hex" +) + +// Constants used to make the code more readable. +const ( + twoBitsMask = 0x3 + fourBitsMask = 0xf + sixBitsMask = 0x3f + eightBitsMask = 0xff +) + +// Constants related to the field representation. +const ( + // fieldWords is the number of words used to internally represent the + // 256-bit value. + fieldWords = 10 + + // fieldBase is the exponent used to form the numeric base of each word. + // 2^(fieldBase*i) where i is the word position. + fieldBase = 26 + + // fieldBaseMask is the mask for the bits in each word needed to + // represent the numeric base of each word (except the most significant + // word). + fieldBaseMask = (1 << fieldBase) - 1 + + // fieldMSBBits is the number of bits in the most significant word used + // to represent the value. + fieldMSBBits = 256 - (fieldBase * (fieldWords - 1)) + + // fieldMSBMask is the mask for the bits in the most significant word + // needed to represent the value. + fieldMSBMask = (1 << fieldMSBBits) - 1 + + // These fields provide convenient access to each of the words of the + // secp256k1 prime in the internal field representation to improve code + // readability. + fieldPrimeWordZero = 0x03fffc2f + fieldPrimeWordOne = 0x03ffffbf + fieldPrimeWordTwo = 0x03ffffff + fieldPrimeWordThree = 0x03ffffff + fieldPrimeWordFour = 0x03ffffff + fieldPrimeWordFive = 0x03ffffff + fieldPrimeWordSix = 0x03ffffff + fieldPrimeWordSeven = 0x03ffffff + fieldPrimeWordEight = 0x03ffffff + fieldPrimeWordNine = 0x003fffff +) + +// FieldVal implements optimized fixed-precision arithmetic over the +// secp256k1 finite field. This means all arithmetic is performed modulo +// 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f. +// +// WARNING: Since it is so important for the field arithmetic to be extremely +// fast for high performance crypto, this type does not perform any validation +// of documented preconditions where it ordinarily would. As a result, it is +// IMPERATIVE for callers to understand some key concepts that are described +// below and ensure the methods are called with the necessary preconditions that +// each method is documented with. For example, some methods only give the +// correct result if the field value is normalized and others require the field +// values involved to have a maximum magnitude and THERE ARE NO EXPLICIT CHECKS +// TO ENSURE THOSE PRECONDITIONS ARE SATISFIED. This does, unfortunately, make +// the type more difficult to use correctly and while I typically prefer to +// ensure all state and input is valid for most code, this is a bit of an +// exception because those extra checks really add up in what ends up being +// critical hot paths. +// +// The first key concept when working with this type is normalization. In order +// to avoid the need to propagate a ton of carries, the internal representation +// provides additional overflow bits for each word of the overall 256-bit value. +// This means that there are multiple internal representations for the same +// value and, as a result, any methods that rely on comparison of the value, +// such as equality and oddness determination, require the caller to provide a +// normalized value. +// +// The second key concept when working with this type is magnitude. As +// previously mentioned, the internal representation provides additional +// overflow bits which means that the more math operations that are performed on +// the field value between normalizations, the more those overflow bits +// accumulate. The magnitude is effectively that maximum possible number of +// those overflow bits that could possibly be required as a result of a given +// operation. Since there are only a limited number of overflow bits available, +// this implies that the max possible magnitude MUST be tracked by the caller +// and the caller MUST normalize the field value if a given operation would +// cause the magnitude of the result to exceed the max allowed value. +// +// IMPORTANT: The max allowed magnitude of a field value is 64. +type FieldVal struct { + // Each 256-bit value is represented as 10 32-bit integers in base 2^26. + // This provides 6 bits of overflow in each word (10 bits in the most + // significant word) for a total of 64 bits of overflow (9*6 + 10 = 64). It + // only implements the arithmetic needed for elliptic curve operations. + // + // The following depicts the internal representation: + // ----------------------------------------------------------------- + // | n[9] | n[8] | ... | n[0] | + // | 32 bits available | 32 bits available | ... | 32 bits available | + // | 22 bits for value | 26 bits for value | ... | 26 bits for value | + // | 10 bits overflow | 6 bits overflow | ... | 6 bits overflow | + // | Mult: 2^(26*9) | Mult: 2^(26*8) | ... | Mult: 2^(26*0) | + // ----------------------------------------------------------------- + // + // For example, consider the number 2^49 + 1. It would be represented as: + // n[0] = 1 + // n[1] = 2^23 + // n[2..9] = 0 + // + // The full 256-bit value is then calculated by looping i from 9..0 and + // doing sum(n[i] * 2^(26i)) like so: + // n[9] * 2^(26*9) = 0 * 2^234 = 0 + // n[8] * 2^(26*8) = 0 * 2^208 = 0 + // ... + // n[1] * 2^(26*1) = 2^23 * 2^26 = 2^49 + // n[0] * 2^(26*0) = 1 * 2^0 = 1 + // Sum: 0 + 0 + ... + 2^49 + 1 = 2^49 + 1 + n [10]uint32 +} + +// String returns the field value as a normalized human-readable hex string. +// +// Preconditions: None +// Output Normalized: Field is not modified -- same as input value +// Output Max Magnitude: Field is not modified -- same as input value +func (f FieldVal) String() string { + // f is a copy, so it's safe to normalize it without mutating the original. + f.Normalize() + return hex.EncodeToString(f.Bytes()[:]) +} + +// Zero sets the field value to zero in constant time. A newly created field +// value is already set to zero. This function can be useful to clear an +// existing field value for reuse. +// +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 +func (f *FieldVal) Zero() { + f.n[0] = 0 + f.n[1] = 0 + f.n[2] = 0 + f.n[3] = 0 + f.n[4] = 0 + f.n[5] = 0 + f.n[6] = 0 + f.n[7] = 0 + f.n[8] = 0 + f.n[9] = 0 +} + +// Set sets the field value equal to the passed value in constant time. The +// normalization and magnitude of the two fields will be identical. +// +// The field value is returned to support chaining. This enables syntax like: +// f := new(FieldVal).Set(f2).Add(1) so that f = f2 + 1 where f2 is not +// modified. +// +// Preconditions: None +// Output Normalized: Same as input value +// Output Max Magnitude: Same as input value +func (f *FieldVal) Set(val *FieldVal) *FieldVal { + *f = *val + return f +} + +// SetInt sets the field value to the passed integer in constant time. This is +// a convenience function since it is fairly common to perform some arithmetic +// with small native integers. +// +// The field value is returned to support chaining. This enables syntax such +// as f := new(FieldVal).SetInt(2).Mul(f2) so that f = 2 * f2. +// +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 +func (f *FieldVal) SetInt(ui uint16) *FieldVal { + f.Zero() + f.n[0] = uint32(ui) + return f +} + +// SetBytes packs the passed 32-byte big-endian value into the internal field +// value representation in constant time. SetBytes interprets the provided +// array as a 256-bit big-endian unsigned integer, packs it into the internal +// field value representation, and returns either 1 if it is greater than or +// equal to the field prime (aka it overflowed) or 0 otherwise in constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. +// +// Preconditions: None +// Output Normalized: Yes if no overflow, no otherwise +// Output Max Magnitude: 1 +func (f *FieldVal) SetBytes(b *[32]byte) uint32 { + // Pack the 256 total bits across the 10 uint32 words with a max of + // 26-bits per word. This could be done with a couple of for loops, + // but this unrolled version is significantly faster. Benchmarks show + // this is about 34 times faster than the variant which uses loops. + f.n[0] = uint32(b[31]) | uint32(b[30])<<8 | uint32(b[29])<<16 | + (uint32(b[28])&twoBitsMask)<<24 + f.n[1] = uint32(b[28])>>2 | uint32(b[27])<<6 | uint32(b[26])<<14 | + (uint32(b[25])&fourBitsMask)<<22 + f.n[2] = uint32(b[25])>>4 | uint32(b[24])<<4 | uint32(b[23])<<12 | + (uint32(b[22])&sixBitsMask)<<20 + f.n[3] = uint32(b[22])>>6 | uint32(b[21])<<2 | uint32(b[20])<<10 | + uint32(b[19])<<18 + f.n[4] = uint32(b[18]) | uint32(b[17])<<8 | uint32(b[16])<<16 | + (uint32(b[15])&twoBitsMask)<<24 + f.n[5] = uint32(b[15])>>2 | uint32(b[14])<<6 | uint32(b[13])<<14 | + (uint32(b[12])&fourBitsMask)<<22 + f.n[6] = uint32(b[12])>>4 | uint32(b[11])<<4 | uint32(b[10])<<12 | + (uint32(b[9])&sixBitsMask)<<20 + f.n[7] = uint32(b[9])>>6 | uint32(b[8])<<2 | uint32(b[7])<<10 | + uint32(b[6])<<18 + f.n[8] = uint32(b[5]) | uint32(b[4])<<8 | uint32(b[3])<<16 | + (uint32(b[2])&twoBitsMask)<<24 + f.n[9] = uint32(b[2])>>2 | uint32(b[1])<<6 | uint32(b[0])<<14 + + // The intuition here is that the field value is greater than the prime if + // one of the higher individual words is greater than corresponding word of + // the prime and all higher words in the field value are equal to their + // corresponding word of the prime. Since this type is modulo the prime, + // being equal is also an overflow back to 0. + // + // Note that because the input is 32 bytes and it was just packed into the + // field representation, the only words that can possibly be greater are + // zero and one, because ceil(log_2(2^256 - 1 - P)) = 33 bits max and the + // internal field representation encodes 26 bits with each word. + // + // Thus, there is no need to test if the upper words of the field value + // exceeds them, hence, only equality is checked for them. + highWordsEq := constantTimeEq(f.n[9], fieldPrimeWordNine) + highWordsEq &= constantTimeEq(f.n[8], fieldPrimeWordEight) + highWordsEq &= constantTimeEq(f.n[7], fieldPrimeWordSeven) + highWordsEq &= constantTimeEq(f.n[6], fieldPrimeWordSix) + highWordsEq &= constantTimeEq(f.n[5], fieldPrimeWordFive) + highWordsEq &= constantTimeEq(f.n[4], fieldPrimeWordFour) + highWordsEq &= constantTimeEq(f.n[3], fieldPrimeWordThree) + highWordsEq &= constantTimeEq(f.n[2], fieldPrimeWordTwo) + overflow := highWordsEq & constantTimeGreater(f.n[1], fieldPrimeWordOne) + highWordsEq &= constantTimeEq(f.n[1], fieldPrimeWordOne) + overflow |= highWordsEq & constantTimeGreaterOrEq(f.n[0], fieldPrimeWordZero) + + return overflow +} + +// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned +// integer (meaning it is truncated to the first 32 bytes), packs it into the +// internal field value representation, and returns whether or not the resulting +// truncated 256-bit integer is greater than or equal to the field prime (aka it +// overflowed) in constant time. +// +// Note that since passing a slice with more than 32 bytes is truncated, it is +// possible that the truncated value is less than the field prime and hence it +// will not be reported as having overflowed in that case. It is up to the +// caller to decide whether it needs to provide numbers of the appropriate size +// or it if is acceptable to use this function with the described truncation and +// overflow behavior. +// +// Preconditions: None +// Output Normalized: Yes if no overflow, no otherwise +// Output Max Magnitude: 1 +func (f *FieldVal) SetByteSlice(b []byte) bool { + var b32 [32]byte + b = b[:constantTimeMin(uint32(len(b)), 32)] + copy(b32[:], b32[:32-len(b)]) + copy(b32[32-len(b):], b) + result := f.SetBytes(&b32) + zeroArray32(&b32) + return result != 0 +} + +// Normalize normalizes the internal field words into the desired range and +// performs fast modular reduction over the secp256k1 prime by making use of the +// special form of the prime in constant time. +// +// Preconditions: None +// Output Normalized: Yes +// Output Max Magnitude: 1 +func (f *FieldVal) Normalize() *FieldVal { + // The field representation leaves 6 bits of overflow in each word so + // intermediate calculations can be performed without needing to + // propagate the carry to each higher word during the calculations. In + // order to normalize, we need to "compact" the full 256-bit value to + // the right while propagating any carries through to the high order + // word. + // + // Since this field is doing arithmetic modulo the secp256k1 prime, we + // also need to perform modular reduction over the prime. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, highly efficient + // reduction can be achieved. + // + // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits + // this criteria. + // + // 4294968273 in field representation (base 2^26) is: + // n[0] = 977 + // n[1] = 64 + // That is to say (2^26 * 64) + 977 = 4294968273 + // + // The algorithm presented in the referenced section typically repeats + // until the quotient is zero. However, due to our field representation + // we already know to within one reduction how many times we would need + // to repeat as it's the uppermost bits of the high order word. Thus we + // can simply multiply the magnitude by the field representation of the + // prime and do a single iteration. After this step there might be an + // additional carry to bit 256 (bit 22 of the high order word). + t9 := f.n[9] + m := t9 >> fieldMSBBits + t9 = t9 & fieldMSBMask + t0 := f.n[0] + m*977 + t1 := (t0 >> fieldBase) + f.n[1] + (m << 6) + t0 = t0 & fieldBaseMask + t2 := (t1 >> fieldBase) + f.n[2] + t1 = t1 & fieldBaseMask + t3 := (t2 >> fieldBase) + f.n[3] + t2 = t2 & fieldBaseMask + t4 := (t3 >> fieldBase) + f.n[4] + t3 = t3 & fieldBaseMask + t5 := (t4 >> fieldBase) + f.n[5] + t4 = t4 & fieldBaseMask + t6 := (t5 >> fieldBase) + f.n[6] + t5 = t5 & fieldBaseMask + t7 := (t6 >> fieldBase) + f.n[7] + t6 = t6 & fieldBaseMask + t8 := (t7 >> fieldBase) + f.n[8] + t7 = t7 & fieldBaseMask + t9 = (t8 >> fieldBase) + t9 + t8 = t8 & fieldBaseMask + + // At this point, the magnitude is guaranteed to be one, however, the + // value could still be greater than the prime if there was either a + // carry through to bit 256 (bit 22 of the higher order word) or the + // value is greater than or equal to the field characteristic. The + // following determines if either or these conditions are true and does + // the final reduction in constant time. + // + // Also note that 'm' will be zero when neither of the aforementioned + // conditions are true and the value will not be changed when 'm' is zero. + m = constantTimeEq(t9, fieldMSBMask) + m &= constantTimeEq(t8&t7&t6&t5&t4&t3&t2, fieldBaseMask) + m &= constantTimeGreater(t1+64+((t0+977)>>fieldBase), fieldBaseMask) + m |= t9 >> fieldMSBBits + t0 = t0 + m*977 + t1 = (t0 >> fieldBase) + t1 + (m << 6) + t0 = t0 & fieldBaseMask + t2 = (t1 >> fieldBase) + t2 + t1 = t1 & fieldBaseMask + t3 = (t2 >> fieldBase) + t3 + t2 = t2 & fieldBaseMask + t4 = (t3 >> fieldBase) + t4 + t3 = t3 & fieldBaseMask + t5 = (t4 >> fieldBase) + t5 + t4 = t4 & fieldBaseMask + t6 = (t5 >> fieldBase) + t6 + t5 = t5 & fieldBaseMask + t7 = (t6 >> fieldBase) + t7 + t6 = t6 & fieldBaseMask + t8 = (t7 >> fieldBase) + t8 + t7 = t7 & fieldBaseMask + t9 = (t8 >> fieldBase) + t9 + t8 = t8 & fieldBaseMask + t9 = t9 & fieldMSBMask // Remove potential multiple of 2^256. + + // Finally, set the normalized and reduced words. + f.n[0] = t0 + f.n[1] = t1 + f.n[2] = t2 + f.n[3] = t3 + f.n[4] = t4 + f.n[5] = t5 + f.n[6] = t6 + f.n[7] = t7 + f.n[8] = t8 + f.n[9] = t9 + return f +} + +// PutBytesUnchecked unpacks the field value to a 32-byte big-endian value +// directly into the passed byte slice in constant time. The target slice must +// must have at least 32 bytes available or it will panic. +// +// There is a similar function, PutBytes, which unpacks the field value into a +// 32-byte array directly. This version is provided since it can be useful +// to write directly into part of a larger buffer without needing a separate +// allocation. +// +// Preconditions: +// - The field value MUST be normalized +// - The target slice MUST have at least 32 bytes available +func (f *FieldVal) PutBytesUnchecked(b []byte) { + // Unpack the 256 total bits from the 10 uint32 words with a max of + // 26-bits per word. This could be done with a couple of for loops, + // but this unrolled version is a bit faster. Benchmarks show this is + // about 10 times faster than the variant which uses loops. + b[31] = byte(f.n[0] & eightBitsMask) + b[30] = byte((f.n[0] >> 8) & eightBitsMask) + b[29] = byte((f.n[0] >> 16) & eightBitsMask) + b[28] = byte((f.n[0]>>24)&twoBitsMask | (f.n[1]&sixBitsMask)<<2) + b[27] = byte((f.n[1] >> 6) & eightBitsMask) + b[26] = byte((f.n[1] >> 14) & eightBitsMask) + b[25] = byte((f.n[1]>>22)&fourBitsMask | (f.n[2]&fourBitsMask)<<4) + b[24] = byte((f.n[2] >> 4) & eightBitsMask) + b[23] = byte((f.n[2] >> 12) & eightBitsMask) + b[22] = byte((f.n[2]>>20)&sixBitsMask | (f.n[3]&twoBitsMask)<<6) + b[21] = byte((f.n[3] >> 2) & eightBitsMask) + b[20] = byte((f.n[3] >> 10) & eightBitsMask) + b[19] = byte((f.n[3] >> 18) & eightBitsMask) + b[18] = byte(f.n[4] & eightBitsMask) + b[17] = byte((f.n[4] >> 8) & eightBitsMask) + b[16] = byte((f.n[4] >> 16) & eightBitsMask) + b[15] = byte((f.n[4]>>24)&twoBitsMask | (f.n[5]&sixBitsMask)<<2) + b[14] = byte((f.n[5] >> 6) & eightBitsMask) + b[13] = byte((f.n[5] >> 14) & eightBitsMask) + b[12] = byte((f.n[5]>>22)&fourBitsMask | (f.n[6]&fourBitsMask)<<4) + b[11] = byte((f.n[6] >> 4) & eightBitsMask) + b[10] = byte((f.n[6] >> 12) & eightBitsMask) + b[9] = byte((f.n[6]>>20)&sixBitsMask | (f.n[7]&twoBitsMask)<<6) + b[8] = byte((f.n[7] >> 2) & eightBitsMask) + b[7] = byte((f.n[7] >> 10) & eightBitsMask) + b[6] = byte((f.n[7] >> 18) & eightBitsMask) + b[5] = byte(f.n[8] & eightBitsMask) + b[4] = byte((f.n[8] >> 8) & eightBitsMask) + b[3] = byte((f.n[8] >> 16) & eightBitsMask) + b[2] = byte((f.n[8]>>24)&twoBitsMask | (f.n[9]&sixBitsMask)<<2) + b[1] = byte((f.n[9] >> 6) & eightBitsMask) + b[0] = byte((f.n[9] >> 14) & eightBitsMask) +} + +// PutBytes unpacks the field value to a 32-byte big-endian value using the +// passed byte array in constant time. +// +// There is a similar function, PutBytesUnchecked, which unpacks the field value +// into a slice that must have at least 32 bytes available. This version is +// provided since it can be useful to write directly into an array that is type +// checked. +// +// Alternatively, there is also Bytes, which unpacks the field value into a new +// array and returns that which can sometimes be more ergonomic in applications +// that aren't concerned about an additional copy. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) PutBytes(b *[32]byte) { + f.PutBytesUnchecked(b[:]) +} + +// Bytes unpacks the field value to a 32-byte big-endian value in constant time. +// +// See PutBytes and PutBytesUnchecked for variants that allow an array or slice +// to be passed which can be useful to cut down on the number of allocations by +// allowing the caller to reuse a buffer or write directly into part of a larger +// buffer. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) Bytes() *[32]byte { + b := new([32]byte) + f.PutBytesUnchecked(b[:]) + return b +} + +// IsZeroBit returns 1 when the field value is equal to zero or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsZero for the version that returns +// a bool. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsZeroBit() uint32 { + // The value can only be zero if no bits are set in any of the words. + // This is a constant time implementation. + bits := f.n[0] | f.n[1] | f.n[2] | f.n[3] | f.n[4] | + f.n[5] | f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return constantTimeEq(bits, 0) +} + +// IsZero returns whether or not the field value is equal to zero in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsZero() bool { + // The value can only be zero if no bits are set in any of the words. + // This is a constant time implementation. + bits := f.n[0] | f.n[1] | f.n[2] | f.n[3] | f.n[4] | + f.n[5] | f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return bits == 0 +} + +// IsOneBit returns 1 when the field value is equal to one or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsOne for the version that returns a +// bool. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOneBit() uint32 { + // The value can only be one if the single lowest significant bit is set in + // the the first word and no other bits are set in any of the other words. + // This is a constant time implementation. + bits := (f.n[0] ^ 1) | f.n[1] | f.n[2] | f.n[3] | f.n[4] | f.n[5] | + f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return constantTimeEq(bits, 0) +} + +// IsOne returns whether or not the field value is equal to one in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOne() bool { + // The value can only be one if the single lowest significant bit is set in + // the the first word and no other bits are set in any of the other words. + // This is a constant time implementation. + bits := (f.n[0] ^ 1) | f.n[1] | f.n[2] | f.n[3] | f.n[4] | f.n[5] | + f.n[6] | f.n[7] | f.n[8] | f.n[9] + + return bits == 0 +} + +// IsOddBit returns 1 when the field value is an odd number or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. See IsOdd for the version that returns a +// bool. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOddBit() uint32 { + // Only odd numbers have the bottom bit set. + return f.n[0] & 1 +} + +// IsOdd returns whether or not the field value is an odd number in constant +// time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsOdd() bool { + // Only odd numbers have the bottom bit set. + return f.n[0]&1 == 1 +} + +// Equals returns whether or not the two field values are the same in constant +// time. +// +// Preconditions: +// - Both field values being compared MUST be normalized +func (f *FieldVal) Equals(val *FieldVal) bool { + // Xor only sets bits when they are different, so the two field values + // can only be the same if no bits are set after xoring each word. + // This is a constant time implementation. + bits := (f.n[0] ^ val.n[0]) | (f.n[1] ^ val.n[1]) | (f.n[2] ^ val.n[2]) | + (f.n[3] ^ val.n[3]) | (f.n[4] ^ val.n[4]) | (f.n[5] ^ val.n[5]) | + (f.n[6] ^ val.n[6]) | (f.n[7] ^ val.n[7]) | (f.n[8] ^ val.n[8]) | + (f.n[9] ^ val.n[9]) + + return bits == 0 +} + +// NegateVal negates the passed value and stores the result in f in constant +// time. The caller must provide the magnitude of the passed value for a +// correct result. +// +// The field value is returned to support chaining. This enables syntax like: +// f.NegateVal(f2).AddInt(1) so that f = -f2 + 1. +// +// Preconditions: +// - The max magnitude MUST be 63 +// Output Normalized: No +// Output Max Magnitude: Input magnitude + 1 +func (f *FieldVal) NegateVal(val *FieldVal, magnitude uint32) *FieldVal { + // Negation in the field is just the prime minus the value. However, + // in order to allow negation against a field value without having to + // normalize/reduce it first, multiply by the magnitude (that is how + // "far" away it is from the normalized value) to adjust. Also, since + // negating a value pushes it one more order of magnitude away from the + // normalized range, add 1 to compensate. + // + // For some intuition here, imagine you're performing mod 12 arithmetic + // (picture a clock) and you are negating the number 7. So you start at + // 12 (which is of course 0 under mod 12) and count backwards (left on + // the clock) 7 times to arrive at 5. Notice this is just 12-7 = 5. + // Now, assume you're starting with 19, which is a number that is + // already larger than the modulus and congruent to 7 (mod 12). When a + // value is already in the desired range, its magnitude is 1. Since 19 + // is an additional "step", its magnitude (mod 12) is 2. Since any + // multiple of the modulus is congruent to zero (mod m), the answer can + // be shortcut by simply multiplying the magnitude by the modulus and + // subtracting. Keeping with the example, this would be (2*12)-19 = 5. + f.n[0] = (magnitude+1)*fieldPrimeWordZero - val.n[0] + f.n[1] = (magnitude+1)*fieldPrimeWordOne - val.n[1] + f.n[2] = (magnitude+1)*fieldBaseMask - val.n[2] + f.n[3] = (magnitude+1)*fieldBaseMask - val.n[3] + f.n[4] = (magnitude+1)*fieldBaseMask - val.n[4] + f.n[5] = (magnitude+1)*fieldBaseMask - val.n[5] + f.n[6] = (magnitude+1)*fieldBaseMask - val.n[6] + f.n[7] = (magnitude+1)*fieldBaseMask - val.n[7] + f.n[8] = (magnitude+1)*fieldBaseMask - val.n[8] + f.n[9] = (magnitude+1)*fieldMSBMask - val.n[9] + + return f +} + +// Negate negates the field value in constant time. The existing field value is +// modified. The caller must provide the magnitude of the field value for a +// correct result. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Negate().AddInt(1) so that f = -f + 1. +// +// Preconditions: +// - The max magnitude MUST be 63 +// Output Normalized: No +// Output Max Magnitude: Input magnitude + 1 +func (f *FieldVal) Negate(magnitude uint32) *FieldVal { + return f.NegateVal(f, magnitude) +} + +// AddInt adds the passed integer to the existing field value and stores the +// result in f in constant time. This is a convenience function since it is +// fairly common to perform some arithmetic with small native integers. +// +// The field value is returned to support chaining. This enables syntax like: +// f.AddInt(1).Add(f2) so that f = f + 1 + f2. +// +// Preconditions: +// - The field value MUST have a max magnitude of 63 +// Output Normalized: No +// Output Max Magnitude: Existing field magnitude + 1 +func (f *FieldVal) AddInt(ui uint16) *FieldVal { + // Since the field representation intentionally provides overflow bits, + // it's ok to use carryless addition as the carry bit is safely part of + // the word and will be normalized out. + f.n[0] += uint32(ui) + + return f +} + +// Add adds the passed value to the existing field value and stores the result +// in f in constant time. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Add(f2).AddInt(1) so that f = f + f2 + 1. +// +// Preconditions: +// - The sum of the magnitudes of the two field values MUST be a max of 64 +// Output Normalized: No +// Output Max Magnitude: Sum of the magnitude of the two individual field values +func (f *FieldVal) Add(val *FieldVal) *FieldVal { + // Since the field representation intentionally provides overflow bits, + // it's ok to use carryless addition as the carry bit is safely part of + // each word and will be normalized out. This could obviously be done + // in a loop, but the unrolled version is faster. + f.n[0] += val.n[0] + f.n[1] += val.n[1] + f.n[2] += val.n[2] + f.n[3] += val.n[3] + f.n[4] += val.n[4] + f.n[5] += val.n[5] + f.n[6] += val.n[6] + f.n[7] += val.n[7] + f.n[8] += val.n[8] + f.n[9] += val.n[9] + + return f +} + +// Add2 adds the passed two field values together and stores the result in f in +// constant time. +// +// The field value is returned to support chaining. This enables syntax like: +// f3.Add2(f, f2).AddInt(1) so that f3 = f + f2 + 1. +// +// Preconditions: +// - The sum of the magnitudes of the two field values MUST be a max of 64 +// Output Normalized: No +// Output Max Magnitude: Sum of the magnitude of the two field values +func (f *FieldVal) Add2(val *FieldVal, val2 *FieldVal) *FieldVal { + // Since the field representation intentionally provides overflow bits, + // it's ok to use carryless addition as the carry bit is safely part of + // each word and will be normalized out. This could obviously be done + // in a loop, but the unrolled version is faster. + f.n[0] = val.n[0] + val2.n[0] + f.n[1] = val.n[1] + val2.n[1] + f.n[2] = val.n[2] + val2.n[2] + f.n[3] = val.n[3] + val2.n[3] + f.n[4] = val.n[4] + val2.n[4] + f.n[5] = val.n[5] + val2.n[5] + f.n[6] = val.n[6] + val2.n[6] + f.n[7] = val.n[7] + val2.n[7] + f.n[8] = val.n[8] + val2.n[8] + f.n[9] = val.n[9] + val2.n[9] + + return f +} + +// MulInt multiplies the field value by the passed int and stores the result in +// f in constant time. Note that this function can overflow if multiplying the +// value by any of the individual words exceeds a max uint32. Therefore it is +// important that the caller ensures no overflows will occur before using this +// function. +// +// The field value is returned to support chaining. This enables syntax like: +// f.MulInt(2).Add(f2) so that f = 2 * f + f2. +// +// Preconditions: +// - The field value magnitude multiplied by given val MUST be a max of 64 +// Output Normalized: No +// Output Max Magnitude: Existing field magnitude times the provided integer val +func (f *FieldVal) MulInt(val uint8) *FieldVal { + // Since each word of the field representation can hold up to + // 32 - fieldBase extra bits which will be normalized out, it's safe + // to multiply each word without using a larger type or carry + // propagation so long as the values won't overflow a uint32. This + // could obviously be done in a loop, but the unrolled version is + // faster. + ui := uint32(val) + f.n[0] *= ui + f.n[1] *= ui + f.n[2] *= ui + f.n[3] *= ui + f.n[4] *= ui + f.n[5] *= ui + f.n[6] *= ui + f.n[7] *= ui + f.n[8] *= ui + f.n[9] *= ui + + return f +} + +// Mul multiplies the passed value to the existing field value and stores the +// result in f in constant time. Note that this function can overflow if +// multiplying any of the individual words exceeds a max uint32. In practice, +// this means the magnitude of either value involved in the multiplication must +// be a max of 8. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Mul(f2).AddInt(1) so that f = (f * f2) + 1. +// +// Preconditions: +// - Both field values MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Mul(val *FieldVal) *FieldVal { + return f.Mul2(f, val) +} + +// Mul2 multiplies the passed two field values together and stores the result +// result in f in constant time. Note that this function can overflow if +// multiplying any of the individual words exceeds a max uint32. In practice, +// this means the magnitude of either value involved in the multiplication must +// be a max of 8. +// +// The field value is returned to support chaining. This enables syntax like: +// f3.Mul2(f, f2).AddInt(1) so that f3 = (f * f2) + 1. +// +// Preconditions: +// - Both input field values MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Mul2(val *FieldVal, val2 *FieldVal) *FieldVal { + // This could be done with a couple of for loops and an array to store + // the intermediate terms, but this unrolled version is significantly + // faster. + + // Terms for 2^(fieldBase*0). + m := uint64(val.n[0]) * uint64(val2.n[0]) + t0 := m & fieldBaseMask + + // Terms for 2^(fieldBase*1). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[1]) + + uint64(val.n[1])*uint64(val2.n[0]) + t1 := m & fieldBaseMask + + // Terms for 2^(fieldBase*2). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[2]) + + uint64(val.n[1])*uint64(val2.n[1]) + + uint64(val.n[2])*uint64(val2.n[0]) + t2 := m & fieldBaseMask + + // Terms for 2^(fieldBase*3). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[3]) + + uint64(val.n[1])*uint64(val2.n[2]) + + uint64(val.n[2])*uint64(val2.n[1]) + + uint64(val.n[3])*uint64(val2.n[0]) + t3 := m & fieldBaseMask + + // Terms for 2^(fieldBase*4). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[4]) + + uint64(val.n[1])*uint64(val2.n[3]) + + uint64(val.n[2])*uint64(val2.n[2]) + + uint64(val.n[3])*uint64(val2.n[1]) + + uint64(val.n[4])*uint64(val2.n[0]) + t4 := m & fieldBaseMask + + // Terms for 2^(fieldBase*5). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[5]) + + uint64(val.n[1])*uint64(val2.n[4]) + + uint64(val.n[2])*uint64(val2.n[3]) + + uint64(val.n[3])*uint64(val2.n[2]) + + uint64(val.n[4])*uint64(val2.n[1]) + + uint64(val.n[5])*uint64(val2.n[0]) + t5 := m & fieldBaseMask + + // Terms for 2^(fieldBase*6). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[6]) + + uint64(val.n[1])*uint64(val2.n[5]) + + uint64(val.n[2])*uint64(val2.n[4]) + + uint64(val.n[3])*uint64(val2.n[3]) + + uint64(val.n[4])*uint64(val2.n[2]) + + uint64(val.n[5])*uint64(val2.n[1]) + + uint64(val.n[6])*uint64(val2.n[0]) + t6 := m & fieldBaseMask + + // Terms for 2^(fieldBase*7). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[7]) + + uint64(val.n[1])*uint64(val2.n[6]) + + uint64(val.n[2])*uint64(val2.n[5]) + + uint64(val.n[3])*uint64(val2.n[4]) + + uint64(val.n[4])*uint64(val2.n[3]) + + uint64(val.n[5])*uint64(val2.n[2]) + + uint64(val.n[6])*uint64(val2.n[1]) + + uint64(val.n[7])*uint64(val2.n[0]) + t7 := m & fieldBaseMask + + // Terms for 2^(fieldBase*8). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[8]) + + uint64(val.n[1])*uint64(val2.n[7]) + + uint64(val.n[2])*uint64(val2.n[6]) + + uint64(val.n[3])*uint64(val2.n[5]) + + uint64(val.n[4])*uint64(val2.n[4]) + + uint64(val.n[5])*uint64(val2.n[3]) + + uint64(val.n[6])*uint64(val2.n[2]) + + uint64(val.n[7])*uint64(val2.n[1]) + + uint64(val.n[8])*uint64(val2.n[0]) + t8 := m & fieldBaseMask + + // Terms for 2^(fieldBase*9). + m = (m >> fieldBase) + + uint64(val.n[0])*uint64(val2.n[9]) + + uint64(val.n[1])*uint64(val2.n[8]) + + uint64(val.n[2])*uint64(val2.n[7]) + + uint64(val.n[3])*uint64(val2.n[6]) + + uint64(val.n[4])*uint64(val2.n[5]) + + uint64(val.n[5])*uint64(val2.n[4]) + + uint64(val.n[6])*uint64(val2.n[3]) + + uint64(val.n[7])*uint64(val2.n[2]) + + uint64(val.n[8])*uint64(val2.n[1]) + + uint64(val.n[9])*uint64(val2.n[0]) + t9 := m & fieldBaseMask + + // Terms for 2^(fieldBase*10). + m = (m >> fieldBase) + + uint64(val.n[1])*uint64(val2.n[9]) + + uint64(val.n[2])*uint64(val2.n[8]) + + uint64(val.n[3])*uint64(val2.n[7]) + + uint64(val.n[4])*uint64(val2.n[6]) + + uint64(val.n[5])*uint64(val2.n[5]) + + uint64(val.n[6])*uint64(val2.n[4]) + + uint64(val.n[7])*uint64(val2.n[3]) + + uint64(val.n[8])*uint64(val2.n[2]) + + uint64(val.n[9])*uint64(val2.n[1]) + t10 := m & fieldBaseMask + + // Terms for 2^(fieldBase*11). + m = (m >> fieldBase) + + uint64(val.n[2])*uint64(val2.n[9]) + + uint64(val.n[3])*uint64(val2.n[8]) + + uint64(val.n[4])*uint64(val2.n[7]) + + uint64(val.n[5])*uint64(val2.n[6]) + + uint64(val.n[6])*uint64(val2.n[5]) + + uint64(val.n[7])*uint64(val2.n[4]) + + uint64(val.n[8])*uint64(val2.n[3]) + + uint64(val.n[9])*uint64(val2.n[2]) + t11 := m & fieldBaseMask + + // Terms for 2^(fieldBase*12). + m = (m >> fieldBase) + + uint64(val.n[3])*uint64(val2.n[9]) + + uint64(val.n[4])*uint64(val2.n[8]) + + uint64(val.n[5])*uint64(val2.n[7]) + + uint64(val.n[6])*uint64(val2.n[6]) + + uint64(val.n[7])*uint64(val2.n[5]) + + uint64(val.n[8])*uint64(val2.n[4]) + + uint64(val.n[9])*uint64(val2.n[3]) + t12 := m & fieldBaseMask + + // Terms for 2^(fieldBase*13). + m = (m >> fieldBase) + + uint64(val.n[4])*uint64(val2.n[9]) + + uint64(val.n[5])*uint64(val2.n[8]) + + uint64(val.n[6])*uint64(val2.n[7]) + + uint64(val.n[7])*uint64(val2.n[6]) + + uint64(val.n[8])*uint64(val2.n[5]) + + uint64(val.n[9])*uint64(val2.n[4]) + t13 := m & fieldBaseMask + + // Terms for 2^(fieldBase*14). + m = (m >> fieldBase) + + uint64(val.n[5])*uint64(val2.n[9]) + + uint64(val.n[6])*uint64(val2.n[8]) + + uint64(val.n[7])*uint64(val2.n[7]) + + uint64(val.n[8])*uint64(val2.n[6]) + + uint64(val.n[9])*uint64(val2.n[5]) + t14 := m & fieldBaseMask + + // Terms for 2^(fieldBase*15). + m = (m >> fieldBase) + + uint64(val.n[6])*uint64(val2.n[9]) + + uint64(val.n[7])*uint64(val2.n[8]) + + uint64(val.n[8])*uint64(val2.n[7]) + + uint64(val.n[9])*uint64(val2.n[6]) + t15 := m & fieldBaseMask + + // Terms for 2^(fieldBase*16). + m = (m >> fieldBase) + + uint64(val.n[7])*uint64(val2.n[9]) + + uint64(val.n[8])*uint64(val2.n[8]) + + uint64(val.n[9])*uint64(val2.n[7]) + t16 := m & fieldBaseMask + + // Terms for 2^(fieldBase*17). + m = (m >> fieldBase) + + uint64(val.n[8])*uint64(val2.n[9]) + + uint64(val.n[9])*uint64(val2.n[8]) + t17 := m & fieldBaseMask + + // Terms for 2^(fieldBase*18). + m = (m >> fieldBase) + uint64(val.n[9])*uint64(val2.n[9]) + t18 := m & fieldBaseMask + + // What's left is for 2^(fieldBase*19). + t19 := m >> fieldBase + + // At this point, all of the terms are grouped into their respective + // base. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, highly efficient + // reduction can be achieved per the provided algorithm. + // + // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits + // this criteria. + // + // 4294968273 in field representation (base 2^26) is: + // n[0] = 977 + // n[1] = 64 + // That is to say (2^26 * 64) + 977 = 4294968273 + // + // Since each word is in base 26, the upper terms (t10 and up) start + // at 260 bits (versus the final desired range of 256 bits), so the + // field representation of 'c' from above needs to be adjusted for the + // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 = + // 68719492368. Thus, the adjusted field representation of 'c' is: + // n[0] = 977 * 16 = 15632 + // n[1] = 64 * 16 = 1024 + // That is to say (2^26 * 1024) + 15632 = 68719492368 + // + // To reduce the final term, t19, the entire 'c' value is needed instead + // of only n[0] because there are no more terms left to handle n[1]. + // This means there might be some magnitude left in the upper bits that + // is handled below. + m = t0 + t10*15632 + t0 = m & fieldBaseMask + m = (m >> fieldBase) + t1 + t10*1024 + t11*15632 + t1 = m & fieldBaseMask + m = (m >> fieldBase) + t2 + t11*1024 + t12*15632 + t2 = m & fieldBaseMask + m = (m >> fieldBase) + t3 + t12*1024 + t13*15632 + t3 = m & fieldBaseMask + m = (m >> fieldBase) + t4 + t13*1024 + t14*15632 + t4 = m & fieldBaseMask + m = (m >> fieldBase) + t5 + t14*1024 + t15*15632 + t5 = m & fieldBaseMask + m = (m >> fieldBase) + t6 + t15*1024 + t16*15632 + t6 = m & fieldBaseMask + m = (m >> fieldBase) + t7 + t16*1024 + t17*15632 + t7 = m & fieldBaseMask + m = (m >> fieldBase) + t8 + t17*1024 + t18*15632 + t8 = m & fieldBaseMask + m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368 + t9 = m & fieldMSBMask + m = m >> fieldMSBBits + + // At this point, if the magnitude is greater than 0, the overall value + // is greater than the max possible 256-bit value. In particular, it is + // "how many times larger" than the max value it is. + // + // The algorithm presented in [HAC] section 14.3.4 repeats until the + // quotient is zero. However, due to the above, we already know at + // least how many times we would need to repeat as it's the value + // currently in m. Thus we can simply multiply the magnitude by the + // field representation of the prime and do a single iteration. Notice + // that nothing will be changed when the magnitude is zero, so we could + // skip this in that case, however always running regardless allows it + // to run in constant time. The final result will be in the range + // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a + // magnitude of 1, but it is denormalized. + d := t0 + m*977 + f.n[0] = uint32(d & fieldBaseMask) + d = (d >> fieldBase) + t1 + m*64 + f.n[1] = uint32(d & fieldBaseMask) + f.n[2] = uint32((d >> fieldBase) + t2) + f.n[3] = uint32(t3) + f.n[4] = uint32(t4) + f.n[5] = uint32(t5) + f.n[6] = uint32(t6) + f.n[7] = uint32(t7) + f.n[8] = uint32(t8) + f.n[9] = uint32(t9) + + return f +} + +// SquareRootVal either calculates the square root of the passed value when it +// exists or the square root of the negation of the value when it does not exist +// and stores the result in f in constant time. The return flag is true when +// the calculated square root is for the passed value itself and false when it +// is for its negation. +// +// Note that this function can overflow if multiplying any of the individual +// words exceeds a max uint32. In practice, this means the magnitude of the +// field must be a max of 8 to prevent overflow. The magnitude of the result +// will be 1. +// +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) SquareRootVal(val *FieldVal) bool { + // This uses the Tonelli-Shanks method for calculating the square root of + // the value when it exists. The key principles of the method follow. + // + // Fermat's little theorem states that for a nonzero number 'a' and prime + // 'p', a^(p-1) ≡ 1 (mod p). + // + // Further, Euler's criterion states that an integer 'a' has a square root + // (aka is a quadratic residue) modulo a prime if a^((p-1)/2) ≡ 1 (mod p) + // and, conversely, when it does NOT have a square root (aka 'a' is a + // non-residue) a^((p-1)/2) ≡ -1 (mod p). + // + // This can be seen by considering that Fermat's little theorem can be + // written as (a^((p-1)/2) - 1)(a^((p-1)/2) + 1) ≡ 0 (mod p). Therefore, + // one of the two factors must be 0. Then, when a ≡ x^2 (aka 'a' is a + // quadratic residue), (x^2)^((p-1)/2) ≡ x^(p-1) ≡ 1 (mod p) which implies + // the first factor must be zero. Finally, per Lagrange's theorem, the + // non-residues are the only remaining possible solutions and thus must make + // the second factor zero to satisfy Fermat's little theorem implying that + // a^((p-1)/2) ≡ -1 (mod p) for that case. + // + // The Tonelli-Shanks method uses these facts along with factoring out + // powers of two to solve a congruence that results in either the solution + // when the square root exists or the square root of the negation of the + // value when it does not. In the case of primes that are ≡ 3 (mod 4), the + // possible solutions are r = ±a^((p+1)/4) (mod p). Therefore, either r^2 ≡ + // a (mod p) is true in which case ±r are the two solutions, or r^2 ≡ -a + // (mod p) in which case 'a' is a non-residue and there are no solutions. + // + // The secp256k1 prime is ≡ 3 (mod 4), so this result applies. + // + // In other words, calculate a^((p+1)/4) and then square it and check it + // against the original value to determine if it is actually the square + // root. + // + // In order to efficiently compute a^((p+1)/4), (p+1)/4 needs to be split + // into a sequence of squares and multiplications that minimizes the number + // of multiplications needed (since they are more costly than squarings). + // + // The secp256k1 prime + 1 / 4 is 2^254 - 2^30 - 244. In binary, that is: + // + // 00111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 11111111 11111111 11111111 11111111 + // 10111111 11111111 11111111 00001100 + // + // Notice that can be broken up into three windows of consecutive 1s (in + // order of least to most signifcant) as: + // + // 6-bit window with two bits set (bits 4, 5, 6, 7 unset) + // 23-bit window with 22 bits set (bit 30 unset) + // 223-bit window with all 223 bits set + // + // Thus, the groups of 1 bits in each window forms the set: + // S = {2, 22, 223}. + // + // The strategy is to calculate a^(2^n - 1) for each grouping via an + // addition chain with a sliding window. + // + // The addition chain used is (credits to Peter Dettman): + // (0,0),(1,0),(2,2),(3,2),(4,1),(5,5),(6,6),(7,7),(8,8),(9,7),(10,2) + // => 2^1 2^[2] 2^3 2^6 2^9 2^11 2^[22] 2^44 2^88 2^176 2^220 2^[223] + // + // This has a cost of 254 field squarings and 13 field multiplications. + var a, a2, a3, a6, a9, a11, a22, a44, a88, a176, a220, a223 FieldVal + a.Set(val) + a2.SquareVal(&a).Mul(&a) // a2 = a^(2^2 - 1) + a3.SquareVal(&a2).Mul(&a) // a3 = a^(2^3 - 1) + a6.SquareVal(&a3).Square().Square() // a6 = a^(2^6 - 2^3) + a6.Mul(&a3) // a6 = a^(2^6 - 1) + a9.SquareVal(&a6).Square().Square() // a9 = a^(2^9 - 2^3) + a9.Mul(&a3) // a9 = a^(2^9 - 1) + a11.SquareVal(&a9).Square() // a11 = a^(2^11 - 2^2) + a11.Mul(&a2) // a11 = a^(2^11 - 1) + a22.SquareVal(&a11).Square().Square().Square().Square() // a22 = a^(2^16 - 2^5) + a22.Square().Square().Square().Square().Square() // a22 = a^(2^21 - 2^10) + a22.Square() // a22 = a^(2^22 - 2^11) + a22.Mul(&a11) // a22 = a^(2^22 - 1) + a44.SquareVal(&a22).Square().Square().Square().Square() // a44 = a^(2^27 - 2^5) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^32 - 2^10) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^37 - 2^15) + a44.Square().Square().Square().Square().Square() // a44 = a^(2^42 - 2^20) + a44.Square().Square() // a44 = a^(2^44 - 2^22) + a44.Mul(&a22) // a44 = a^(2^44 - 1) + a88.SquareVal(&a44).Square().Square().Square().Square() // a88 = a^(2^49 - 2^5) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^54 - 2^10) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^59 - 2^15) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^64 - 2^20) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^69 - 2^25) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^74 - 2^30) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^79 - 2^35) + a88.Square().Square().Square().Square().Square() // a88 = a^(2^84 - 2^40) + a88.Square().Square().Square().Square() // a88 = a^(2^88 - 2^44) + a88.Mul(&a44) // a88 = a^(2^88 - 1) + a176.SquareVal(&a88).Square().Square().Square().Square() // a176 = a^(2^93 - 2^5) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^98 - 2^10) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^103 - 2^15) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^108 - 2^20) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^113 - 2^25) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^118 - 2^30) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^123 - 2^35) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^128 - 2^40) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^133 - 2^45) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^138 - 2^50) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^143 - 2^55) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^148 - 2^60) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^153 - 2^65) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^158 - 2^70) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^163 - 2^75) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^168 - 2^80) + a176.Square().Square().Square().Square().Square() // a176 = a^(2^173 - 2^85) + a176.Square().Square().Square() // a176 = a^(2^176 - 2^88) + a176.Mul(&a88) // a176 = a^(2^176 - 1) + a220.SquareVal(&a176).Square().Square().Square().Square() // a220 = a^(2^181 - 2^5) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^186 - 2^10) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^191 - 2^15) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^196 - 2^20) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^201 - 2^25) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^206 - 2^30) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^211 - 2^35) + a220.Square().Square().Square().Square().Square() // a220 = a^(2^216 - 2^40) + a220.Square().Square().Square().Square() // a220 = a^(2^220 - 2^44) + a220.Mul(&a44) // a220 = a^(2^220 - 1) + a223.SquareVal(&a220).Square().Square() // a223 = a^(2^223 - 2^3) + a223.Mul(&a3) // a223 = a^(2^223 - 1) + + f.SquareVal(&a223).Square().Square().Square().Square() // f = a^(2^228 - 2^5) + f.Square().Square().Square().Square().Square() // f = a^(2^233 - 2^10) + f.Square().Square().Square().Square().Square() // f = a^(2^238 - 2^15) + f.Square().Square().Square().Square().Square() // f = a^(2^243 - 2^20) + f.Square().Square().Square() // f = a^(2^246 - 2^23) + f.Mul(&a22) // f = a^(2^246 - 2^22 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^251 - 2^27 - 2^5) + f.Square() // f = a^(2^252 - 2^28 - 2^6) + f.Mul(&a2) // f = a^(2^252 - 2^28 - 2^6 - 2^1 - 1) + f.Square().Square() // f = a^(2^254 - 2^30 - 2^8 - 2^3 - 2^2) + // // = a^(2^254 - 2^30 - 244) + // // = a^((p+1)/4) + + // Ensure the calculated result is actually the square root by squaring it + // and checking against the original value. + var sqr FieldVal + return sqr.SquareVal(f).Normalize().Equals(val.Normalize()) +} + +// Square squares the field value in constant time. The existing field value is +// modified. Note that this function can overflow if multiplying any of the +// individual words exceeds a max uint32. In practice, this means the magnitude +// of the field must be a max of 8 to prevent overflow. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Square().Mul(f2) so that f = f^2 * f2. +// +// Preconditions: +// - The field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Square() *FieldVal { + return f.SquareVal(f) +} + +// SquareVal squares the passed value and stores the result in f in constant +// time. Note that this function can overflow if multiplying any of the +// individual words exceeds a max uint32. In practice, this means the magnitude +// of the field being squared must be a max of 8 to prevent overflow. +// +// The field value is returned to support chaining. This enables syntax like: +// f3.SquareVal(f).Mul(f) so that f3 = f^2 * f = f^3. +// +// Preconditions: +// - The input field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) SquareVal(val *FieldVal) *FieldVal { + // This could be done with a couple of for loops and an array to store + // the intermediate terms, but this unrolled version is significantly + // faster. + + // Terms for 2^(fieldBase*0). + m := uint64(val.n[0]) * uint64(val.n[0]) + t0 := m & fieldBaseMask + + // Terms for 2^(fieldBase*1). + m = (m >> fieldBase) + 2*uint64(val.n[0])*uint64(val.n[1]) + t1 := m & fieldBaseMask + + // Terms for 2^(fieldBase*2). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[2]) + + uint64(val.n[1])*uint64(val.n[1]) + t2 := m & fieldBaseMask + + // Terms for 2^(fieldBase*3). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[3]) + + 2*uint64(val.n[1])*uint64(val.n[2]) + t3 := m & fieldBaseMask + + // Terms for 2^(fieldBase*4). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[4]) + + 2*uint64(val.n[1])*uint64(val.n[3]) + + uint64(val.n[2])*uint64(val.n[2]) + t4 := m & fieldBaseMask + + // Terms for 2^(fieldBase*5). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[5]) + + 2*uint64(val.n[1])*uint64(val.n[4]) + + 2*uint64(val.n[2])*uint64(val.n[3]) + t5 := m & fieldBaseMask + + // Terms for 2^(fieldBase*6). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[6]) + + 2*uint64(val.n[1])*uint64(val.n[5]) + + 2*uint64(val.n[2])*uint64(val.n[4]) + + uint64(val.n[3])*uint64(val.n[3]) + t6 := m & fieldBaseMask + + // Terms for 2^(fieldBase*7). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[7]) + + 2*uint64(val.n[1])*uint64(val.n[6]) + + 2*uint64(val.n[2])*uint64(val.n[5]) + + 2*uint64(val.n[3])*uint64(val.n[4]) + t7 := m & fieldBaseMask + + // Terms for 2^(fieldBase*8). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[8]) + + 2*uint64(val.n[1])*uint64(val.n[7]) + + 2*uint64(val.n[2])*uint64(val.n[6]) + + 2*uint64(val.n[3])*uint64(val.n[5]) + + uint64(val.n[4])*uint64(val.n[4]) + t8 := m & fieldBaseMask + + // Terms for 2^(fieldBase*9). + m = (m >> fieldBase) + + 2*uint64(val.n[0])*uint64(val.n[9]) + + 2*uint64(val.n[1])*uint64(val.n[8]) + + 2*uint64(val.n[2])*uint64(val.n[7]) + + 2*uint64(val.n[3])*uint64(val.n[6]) + + 2*uint64(val.n[4])*uint64(val.n[5]) + t9 := m & fieldBaseMask + + // Terms for 2^(fieldBase*10). + m = (m >> fieldBase) + + 2*uint64(val.n[1])*uint64(val.n[9]) + + 2*uint64(val.n[2])*uint64(val.n[8]) + + 2*uint64(val.n[3])*uint64(val.n[7]) + + 2*uint64(val.n[4])*uint64(val.n[6]) + + uint64(val.n[5])*uint64(val.n[5]) + t10 := m & fieldBaseMask + + // Terms for 2^(fieldBase*11). + m = (m >> fieldBase) + + 2*uint64(val.n[2])*uint64(val.n[9]) + + 2*uint64(val.n[3])*uint64(val.n[8]) + + 2*uint64(val.n[4])*uint64(val.n[7]) + + 2*uint64(val.n[5])*uint64(val.n[6]) + t11 := m & fieldBaseMask + + // Terms for 2^(fieldBase*12). + m = (m >> fieldBase) + + 2*uint64(val.n[3])*uint64(val.n[9]) + + 2*uint64(val.n[4])*uint64(val.n[8]) + + 2*uint64(val.n[5])*uint64(val.n[7]) + + uint64(val.n[6])*uint64(val.n[6]) + t12 := m & fieldBaseMask + + // Terms for 2^(fieldBase*13). + m = (m >> fieldBase) + + 2*uint64(val.n[4])*uint64(val.n[9]) + + 2*uint64(val.n[5])*uint64(val.n[8]) + + 2*uint64(val.n[6])*uint64(val.n[7]) + t13 := m & fieldBaseMask + + // Terms for 2^(fieldBase*14). + m = (m >> fieldBase) + + 2*uint64(val.n[5])*uint64(val.n[9]) + + 2*uint64(val.n[6])*uint64(val.n[8]) + + uint64(val.n[7])*uint64(val.n[7]) + t14 := m & fieldBaseMask + + // Terms for 2^(fieldBase*15). + m = (m >> fieldBase) + + 2*uint64(val.n[6])*uint64(val.n[9]) + + 2*uint64(val.n[7])*uint64(val.n[8]) + t15 := m & fieldBaseMask + + // Terms for 2^(fieldBase*16). + m = (m >> fieldBase) + + 2*uint64(val.n[7])*uint64(val.n[9]) + + uint64(val.n[8])*uint64(val.n[8]) + t16 := m & fieldBaseMask + + // Terms for 2^(fieldBase*17). + m = (m >> fieldBase) + 2*uint64(val.n[8])*uint64(val.n[9]) + t17 := m & fieldBaseMask + + // Terms for 2^(fieldBase*18). + m = (m >> fieldBase) + uint64(val.n[9])*uint64(val.n[9]) + t18 := m & fieldBaseMask + + // What's left is for 2^(fieldBase*19). + t19 := m >> fieldBase + + // At this point, all of the terms are grouped into their respective + // base. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, highly efficient + // reduction can be achieved per the provided algorithm. + // + // The secp256k1 prime is equivalent to 2^256 - 4294968273, so it fits + // this criteria. + // + // 4294968273 in field representation (base 2^26) is: + // n[0] = 977 + // n[1] = 64 + // That is to say (2^26 * 64) + 977 = 4294968273 + // + // Since each word is in base 26, the upper terms (t10 and up) start + // at 260 bits (versus the final desired range of 256 bits), so the + // field representation of 'c' from above needs to be adjusted for the + // extra 4 bits by multiplying it by 2^4 = 16. 4294968273 * 16 = + // 68719492368. Thus, the adjusted field representation of 'c' is: + // n[0] = 977 * 16 = 15632 + // n[1] = 64 * 16 = 1024 + // That is to say (2^26 * 1024) + 15632 = 68719492368 + // + // To reduce the final term, t19, the entire 'c' value is needed instead + // of only n[0] because there are no more terms left to handle n[1]. + // This means there might be some magnitude left in the upper bits that + // is handled below. + m = t0 + t10*15632 + t0 = m & fieldBaseMask + m = (m >> fieldBase) + t1 + t10*1024 + t11*15632 + t1 = m & fieldBaseMask + m = (m >> fieldBase) + t2 + t11*1024 + t12*15632 + t2 = m & fieldBaseMask + m = (m >> fieldBase) + t3 + t12*1024 + t13*15632 + t3 = m & fieldBaseMask + m = (m >> fieldBase) + t4 + t13*1024 + t14*15632 + t4 = m & fieldBaseMask + m = (m >> fieldBase) + t5 + t14*1024 + t15*15632 + t5 = m & fieldBaseMask + m = (m >> fieldBase) + t6 + t15*1024 + t16*15632 + t6 = m & fieldBaseMask + m = (m >> fieldBase) + t7 + t16*1024 + t17*15632 + t7 = m & fieldBaseMask + m = (m >> fieldBase) + t8 + t17*1024 + t18*15632 + t8 = m & fieldBaseMask + m = (m >> fieldBase) + t9 + t18*1024 + t19*68719492368 + t9 = m & fieldMSBMask + m = m >> fieldMSBBits + + // At this point, if the magnitude is greater than 0, the overall value + // is greater than the max possible 256-bit value. In particular, it is + // "how many times larger" than the max value it is. + // + // The algorithm presented in [HAC] section 14.3.4 repeats until the + // quotient is zero. However, due to the above, we already know at + // least how many times we would need to repeat as it's the value + // currently in m. Thus we can simply multiply the magnitude by the + // field representation of the prime and do a single iteration. Notice + // that nothing will be changed when the magnitude is zero, so we could + // skip this in that case, however always running regardless allows it + // to run in constant time. The final result will be in the range + // 0 <= result <= prime + (2^64 - c), so it is guaranteed to have a + // magnitude of 1, but it is denormalized. + n := t0 + m*977 + f.n[0] = uint32(n & fieldBaseMask) + n = (n >> fieldBase) + t1 + m*64 + f.n[1] = uint32(n & fieldBaseMask) + f.n[2] = uint32((n >> fieldBase) + t2) + f.n[3] = uint32(t3) + f.n[4] = uint32(t4) + f.n[5] = uint32(t5) + f.n[6] = uint32(t6) + f.n[7] = uint32(t7) + f.n[8] = uint32(t8) + f.n[9] = uint32(t9) + + return f +} + +// Inverse finds the modular multiplicative inverse of the field value in +// constant time. The existing field value is modified. +// +// The field value is returned to support chaining. This enables syntax like: +// f.Inverse().Mul(f2) so that f = f^-1 * f2. +// +// Preconditions: +// - The field value MUST have a max magnitude of 8 +// Output Normalized: No +// Output Max Magnitude: 1 +func (f *FieldVal) Inverse() *FieldVal { + // Fermat's little theorem states that for a nonzero number a and prime + // prime p, a^(p-1) = 1 (mod p). Since the multiplicative inverse is + // a*b = 1 (mod p), it follows that b = a*a^(p-2) = a^(p-1) = 1 (mod p). + // Thus, a^(p-2) is the multiplicative inverse. + // + // In order to efficiently compute a^(p-2), p-2 needs to be split into + // a sequence of squares and multiplications that minimizes the number + // of multiplications needed (since they are more costly than + // squarings). Intermediate results are saved and reused as well. + // + // The secp256k1 prime - 2 is 2^256 - 4294968275. + // + // This has a cost of 258 field squarings and 33 field multiplications. + var a2, a3, a4, a10, a11, a21, a42, a45, a63, a1019, a1023 FieldVal + a2.SquareVal(f) + a3.Mul2(&a2, f) + a4.SquareVal(&a2) + a10.SquareVal(&a4).Mul(&a2) + a11.Mul2(&a10, f) + a21.Mul2(&a10, &a11) + a42.SquareVal(&a21) + a45.Mul2(&a42, &a3) + a63.Mul2(&a42, &a21) + a1019.SquareVal(&a63).Square().Square().Square().Mul(&a11) + a1023.Mul2(&a1019, &a4) + f.Set(&a63) // f = a^(2^6 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^11 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^16 - 1024) + f.Mul(&a1023) // f = a^(2^16 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^21 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^26 - 1024) + f.Mul(&a1023) // f = a^(2^26 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^31 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^36 - 1024) + f.Mul(&a1023) // f = a^(2^36 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^41 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^46 - 1024) + f.Mul(&a1023) // f = a^(2^46 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^51 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^56 - 1024) + f.Mul(&a1023) // f = a^(2^56 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^61 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^66 - 1024) + f.Mul(&a1023) // f = a^(2^66 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^71 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^76 - 1024) + f.Mul(&a1023) // f = a^(2^76 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^81 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^86 - 1024) + f.Mul(&a1023) // f = a^(2^86 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^91 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^96 - 1024) + f.Mul(&a1023) // f = a^(2^96 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^101 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^106 - 1024) + f.Mul(&a1023) // f = a^(2^106 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^111 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^116 - 1024) + f.Mul(&a1023) // f = a^(2^116 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^121 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^126 - 1024) + f.Mul(&a1023) // f = a^(2^126 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^131 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^136 - 1024) + f.Mul(&a1023) // f = a^(2^136 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^141 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^146 - 1024) + f.Mul(&a1023) // f = a^(2^146 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^151 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^156 - 1024) + f.Mul(&a1023) // f = a^(2^156 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^161 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^166 - 1024) + f.Mul(&a1023) // f = a^(2^166 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^171 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^176 - 1024) + f.Mul(&a1023) // f = a^(2^176 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^181 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^186 - 1024) + f.Mul(&a1023) // f = a^(2^186 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^191 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^196 - 1024) + f.Mul(&a1023) // f = a^(2^196 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^201 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^206 - 1024) + f.Mul(&a1023) // f = a^(2^206 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^211 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^216 - 1024) + f.Mul(&a1023) // f = a^(2^216 - 1) + f.Square().Square().Square().Square().Square() // f = a^(2^221 - 32) + f.Square().Square().Square().Square().Square() // f = a^(2^226 - 1024) + f.Mul(&a1019) // f = a^(2^226 - 5) + f.Square().Square().Square().Square().Square() // f = a^(2^231 - 160) + f.Square().Square().Square().Square().Square() // f = a^(2^236 - 5120) + f.Mul(&a1023) // f = a^(2^236 - 4097) + f.Square().Square().Square().Square().Square() // f = a^(2^241 - 131104) + f.Square().Square().Square().Square().Square() // f = a^(2^246 - 4195328) + f.Mul(&a1023) // f = a^(2^246 - 4194305) + f.Square().Square().Square().Square().Square() // f = a^(2^251 - 134217760) + f.Square().Square().Square().Square().Square() // f = a^(2^256 - 4294968320) + return f.Mul(&a45) // f = a^(2^256 - 4294968275) = a^(p-2) +} + +// IsGtOrEqPrimeMinusOrder returns whether or not the field value exceeds the +// group order divided by 2 in constant time. +// +// Preconditions: +// - The field value MUST be normalized +func (f *FieldVal) IsGtOrEqPrimeMinusOrder() bool { + // The secp256k1 prime is equivalent to 2^256 - 4294968273 and the group + // order is 2^256 - 432420386565659656852420866394968145599. Thus, + // the prime minus the group order is: + // 432420386565659656852420866390673177326 + // + // In hex that is: + // 0x00000000 00000000 00000000 00000001 45512319 50b75fc4 402da172 2fc9baee + // + // Converting that to field representation (base 2^26) is: + // + // n[0] = 0x03c9baee + // n[1] = 0x03685c8b + // n[2] = 0x01fc4402 + // n[3] = 0x006542dd + // n[4] = 0x01455123 + // + // This can be verified with the following test code: + // pMinusN := new(big.Int).Sub(curveParams.P, curveParams.N) + // var fv FieldVal + // fv.SetByteSlice(pMinusN.Bytes()) + // t.Logf("%x", fv.n) + // + // Outputs: [3c9baee 3685c8b 1fc4402 6542dd 1455123 0 0 0 0 0] + const ( + pMinusNWordZero = 0x03c9baee + pMinusNWordOne = 0x03685c8b + pMinusNWordTwo = 0x01fc4402 + pMinusNWordThree = 0x006542dd + pMinusNWordFour = 0x01455123 + pMinusNWordFive = 0x00000000 + pMinusNWordSix = 0x00000000 + pMinusNWordSeven = 0x00000000 + pMinusNWordEight = 0x00000000 + pMinusNWordNine = 0x00000000 + ) + + // The intuition here is that the value is greater than field prime minus + // the group order if one of the higher individual words is greater than the + // corresponding word and all higher words in the value are equal. + result := constantTimeGreater(f.n[9], pMinusNWordNine) + highWordsEqual := constantTimeEq(f.n[9], pMinusNWordNine) + result |= highWordsEqual & constantTimeGreater(f.n[8], pMinusNWordEight) + highWordsEqual &= constantTimeEq(f.n[8], pMinusNWordEight) + result |= highWordsEqual & constantTimeGreater(f.n[7], pMinusNWordSeven) + highWordsEqual &= constantTimeEq(f.n[7], pMinusNWordSeven) + result |= highWordsEqual & constantTimeGreater(f.n[6], pMinusNWordSix) + highWordsEqual &= constantTimeEq(f.n[6], pMinusNWordSix) + result |= highWordsEqual & constantTimeGreater(f.n[5], pMinusNWordFive) + highWordsEqual &= constantTimeEq(f.n[5], pMinusNWordFive) + result |= highWordsEqual & constantTimeGreater(f.n[4], pMinusNWordFour) + highWordsEqual &= constantTimeEq(f.n[4], pMinusNWordFour) + result |= highWordsEqual & constantTimeGreater(f.n[3], pMinusNWordThree) + highWordsEqual &= constantTimeEq(f.n[3], pMinusNWordThree) + result |= highWordsEqual & constantTimeGreater(f.n[2], pMinusNWordTwo) + highWordsEqual &= constantTimeEq(f.n[2], pMinusNWordTwo) + result |= highWordsEqual & constantTimeGreater(f.n[1], pMinusNWordOne) + highWordsEqual &= constantTimeEq(f.n[1], pMinusNWordOne) + result |= highWordsEqual & constantTimeGreaterOrEq(f.n[0], pMinusNWordZero) + + return result != 0 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/genstatics.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/genstatics.go new file mode 100644 index 00000000..888b5167 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/genstatics.go @@ -0,0 +1,203 @@ +// Copyright (c) 2014-2015 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +// This file is ignored during the regular build due to the following build tag. +// This build tag is set during go generate. +// +build gensecp256k1 + +package secp256k1 + +// References: +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) + +import ( + "encoding/binary" + "math/big" +) + +// compressedBytePoints are dummy points used so the code which generates the +// real values can compile. +var compressedBytePoints = "" + +// getDoublingPoints returns all the possible G^(2^i) for i in +// 0..n-1 where n is the curve's bit size (256 in the case of secp256k1) +// the coordinates are recorded as Jacobian coordinates. +func (curve *KoblitzCurve) getDoublingPoints() []JacobianPoint { + doublingPoints := make([]JacobianPoint, curve.BitSize) + + // Initialize point to the Jacobian coordinates for the base point. + var point JacobianPoint + bigAffineToJacobian(curve.Gx, curve.Gy, &point) + for i := 0; i < curve.BitSize; i++ { + doublingPoints[i] = point + // P = 2*P + DoubleNonConst(&point, &point) + } + return doublingPoints +} + +// SerializedBytePoints returns a serialized byte slice which contains all of +// the possible points per 8-bit window. This is used to when generating +// secp256k1.go. +func (curve *KoblitzCurve) SerializedBytePoints() []byte { + doublingPoints := curve.getDoublingPoints() + + // Segregate the bits into byte-sized windows + serialized := make([]byte, curve.byteSize*256*3*10*4) + offset := 0 + for byteNum := 0; byteNum < curve.byteSize; byteNum++ { + // Grab the 8 bits that make up this byte from doublingPoints. + startingBit := 8 * (curve.byteSize - byteNum - 1) + computingPoints := doublingPoints[startingBit : startingBit+8] + + // Compute all points in this window and serialize them. + for i := 0; i < 256; i++ { + var point JacobianPoint + for j := 0; j < 8; j++ { + if i>>uint(j)&1 == 1 { + AddNonConst(&point, &computingPoints[j], &point) + } + } + for i := 0; i < 10; i++ { + binary.LittleEndian.PutUint32(serialized[offset:], point.X.n[i]) + offset += 4 + } + for i := 0; i < 10; i++ { + binary.LittleEndian.PutUint32(serialized[offset:], point.Y.n[i]) + offset += 4 + } + for i := 0; i < 10; i++ { + binary.LittleEndian.PutUint32(serialized[offset:], point.Z.n[i]) + offset += 4 + } + } + } + + return serialized +} + +// sqrt returns the square root of the provided big integer using Newton's +// method. It's only compiled and used during generation of pre-computed +// values, so speed is not a huge concern. +func sqrt(n *big.Int) *big.Int { + // Initial guess = 2^(log_2(n)/2) + guess := big.NewInt(2) + guess.Exp(guess, big.NewInt(int64(n.BitLen()/2)), nil) + + // Now refine using Newton's method. + big2 := big.NewInt(2) + prevGuess := big.NewInt(0) + for { + prevGuess.Set(guess) + guess.Add(guess, new(big.Int).Div(n, guess)) + guess.Div(guess, big2) + if guess.Cmp(prevGuess) == 0 { + break + } + } + return guess +} + +// EndomorphismVectors runs the first 3 steps of algorithm 3.74 from [GECC] to +// generate the linearly independent vectors needed to generate a balanced +// length-two representation of a multiplier such that k = k1 + k2λ (mod N) and +// returns them. Since the values will always be the same given the fact that N +// and λ are fixed, the final results can be accelerated by storing the +// precomputed values. +func EndomorphismVectors() (a1, b1, a2, b2 *big.Int) { + bigMinus1 := big.NewInt(-1) + + // This section uses an extended Euclidean algorithm to generate a + // sequence of equations: + // s[i] * N + t[i] * λ = r[i] + + nSqrt := sqrt(curveParams.N) + u, v := new(big.Int).Set(curveParams.N), new(big.Int).Set(endomorphismLambda) + x1, y1 := big.NewInt(1), big.NewInt(0) + x2, y2 := big.NewInt(0), big.NewInt(1) + q, r := new(big.Int), new(big.Int) + qu, qx1, qy1 := new(big.Int), new(big.Int), new(big.Int) + s, t := new(big.Int), new(big.Int) + ri, ti := new(big.Int), new(big.Int) + a1, b1, a2, b2 = new(big.Int), new(big.Int), new(big.Int), new(big.Int) + found, oneMore := false, false + for u.Sign() != 0 { + // q = v/u + q.Div(v, u) + + // r = v - q*u + qu.Mul(q, u) + r.Sub(v, qu) + + // s = x2 - q*x1 + qx1.Mul(q, x1) + s.Sub(x2, qx1) + + // t = y2 - q*y1 + qy1.Mul(q, y1) + t.Sub(y2, qy1) + + // v = u, u = r, x2 = x1, x1 = s, y2 = y1, y1 = t + v.Set(u) + u.Set(r) + x2.Set(x1) + x1.Set(s) + y2.Set(y1) + y1.Set(t) + + // As soon as the remainder is less than the sqrt of n, the + // values of a1 and b1 are known. + if !found && r.Cmp(nSqrt) < 0 { + // When this condition executes ri and ti represent the + // r[i] and t[i] values such that i is the greatest + // index for which r >= sqrt(n). Meanwhile, the current + // r and t values are r[i+1] and t[i+1], respectively. + + // a1 = r[i+1], b1 = -t[i+1] + a1.Set(r) + b1.Mul(t, bigMinus1) + found = true + oneMore = true + + // Skip to the next iteration so ri and ti are not + // modified. + continue + + } else if oneMore { + // When this condition executes ri and ti still + // represent the r[i] and t[i] values while the current + // r and t are r[i+2] and t[i+2], respectively. + + // sum1 = r[i]^2 + t[i]^2 + rSquared := new(big.Int).Mul(ri, ri) + tSquared := new(big.Int).Mul(ti, ti) + sum1 := new(big.Int).Add(rSquared, tSquared) + + // sum2 = r[i+2]^2 + t[i+2]^2 + r2Squared := new(big.Int).Mul(r, r) + t2Squared := new(big.Int).Mul(t, t) + sum2 := new(big.Int).Add(r2Squared, t2Squared) + + // if (r[i]^2 + t[i]^2) <= (r[i+2]^2 + t[i+2]^2) + if sum1.Cmp(sum2) <= 0 { + // a2 = r[i], b2 = -t[i] + a2.Set(ri) + b2.Mul(ti, bigMinus1) + } else { + // a2 = r[i+2], b2 = -t[i+2] + a2.Set(r) + b2.Mul(t, bigMinus1) + } + + // All done. + break + } + + ri.Set(r) + ti.Set(t) + } + + return a1, b1, a2, b2 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/go.mod b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/go.mod new file mode 100644 index 00000000..3c7ba1fc --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/go.mod @@ -0,0 +1,8 @@ +module github.com/decred/dcrd/dcrec/secp256k1/v3 + +go 1.13 + +require ( + github.com/decred/dcrd/chaincfg/chainhash v1.0.2 + github.com/decred/dcrd/crypto/blake256 v1.0.0 +) diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/go.sum b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/go.sum new file mode 100644 index 00000000..b41490e3 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/go.sum @@ -0,0 +1,4 @@ +github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU= +github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/loadprecomputed.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/loadprecomputed.go new file mode 100644 index 00000000..af0e0ac7 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/loadprecomputed.go @@ -0,0 +1,68 @@ +// Copyright 2015 The btcsuite developers +// Copyright (c) 2015-2016 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "compress/zlib" + "encoding/base64" + "encoding/binary" + "io/ioutil" + "strings" +) + +//go:generate go run -tags gensecp256k1 genprecomps.go + +// loadBytePoints decompresses and deserializes the pre-computed byte points +// used to accelerate scalar base multiplication for the secp256k1 curve. This +// approach is used since it allows the compile to use significantly less ram +// and be performed much faster than it is with hard-coding the final in-memory +// data structure. At the same time, it is quite fast to generate the in-memory +// data structure at init time with this approach versus computing the table. +func loadBytePoints() error { + // There will be no byte points to load when generating them. + bp := compressedBytePoints + if len(bp) == 0 { + return nil + } + + // Decompress the pre-computed table used to accelerate scalar base + // multiplication. + decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp)) + r, err := zlib.NewReader(decoder) + if err != nil { + return err + } + serialized, err := ioutil.ReadAll(r) + if err != nil { + return err + } + + // Deserialize the precomputed byte points and set the curve to them. + offset := 0 + var bytePoints [32][256][3]FieldVal + for byteNum := 0; byteNum < 32; byteNum++ { + // All points in this window. + for i := 0; i < 256; i++ { + px := &bytePoints[byteNum][i][0] + py := &bytePoints[byteNum][i][1] + pz := &bytePoints[byteNum][i][2] + for i := 0; i < 10; i++ { + px.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) + offset += 4 + } + for i := 0; i < 10; i++ { + py.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) + offset += 4 + } + for i := 0; i < 10; i++ { + pz.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) + offset += 4 + } + } + } + secp256k1.bytePoints = &bytePoints + return nil +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/modnscalar.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/modnscalar.go new file mode 100644 index 00000000..218cade2 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/modnscalar.go @@ -0,0 +1,1090 @@ +// Copyright (c) 2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "encoding/hex" + "math/big" +) + +// References: +// [SECG]: Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [HAC]: Handbook of Applied Cryptography Menezes, van Oorschot, Vanstone. +// http://cacr.uwaterloo.ca/hac/ + +// Many elliptic curve operations require working with scalars in a finite field +// characterized by the order of the group underlying the secp256k1 curve. +// Given this precision is larger than the biggest available native type, +// obviously some form of bignum math is needed. This code implements +// specialized fixed-precision field arithmetic rather than relying on an +// arbitrary-precision arithmetic package such as math/big for dealing with the +// math modulo the group order since the size is known. As a result, rather +// large performance gains are achieved by taking advantage of many +// optimizations not available to arbitrary-precision arithmetic and generic +// modular arithmetic algorithms. +// +// There are various ways to internally represent each element. For example, +// the most obvious representation would be to use an array of 4 uint64s (64 +// bits * 4 = 256 bits). However, that representation suffers from the fact +// that there is no native Go type large enough to handle the intermediate +// results while adding or multiplying two 64-bit numbers. +// +// Given the above, this implementation represents the field elements as 8 +// uint32s with each word (array entry) treated as base 2^32. This was chosen +// because most systems at the current time are 64-bit (or at least have 64-bit +// registers available for specialized purposes such as MMX) so the intermediate +// results can typically be done using a native register (and using uint64s to +// avoid the need for additional half-word arithmetic) + +const ( + // These fields provide convenient access to each of the words of the + // secp256k1 curve group order N to improve code readability. + // + // The group order of the curve per [SECG] is: + // 0xffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141 + orderWordZero uint32 = 0xd0364141 + orderWordOne uint32 = 0xbfd25e8c + orderWordTwo uint32 = 0xaf48a03b + orderWordThree uint32 = 0xbaaedce6 + orderWordFour uint32 = 0xfffffffe + orderWordFive uint32 = 0xffffffff + orderWordSix uint32 = 0xffffffff + orderWordSeven uint32 = 0xffffffff + + // These fields provide convenient access to each of the words of the two's + // complement of the secp256k1 curve group order N to improve code + // readability. + // + // The two's complement of the group order is: + // 0x00000000 00000000 00000000 00000001 45512319 50b75fc4 402da173 2fc9bebf + orderComplementWordZero uint32 = (^orderWordZero) + 1 + orderComplementWordOne uint32 = ^orderWordOne + orderComplementWordTwo uint32 = ^orderWordTwo + orderComplementWordThree uint32 = ^orderWordThree + //orderComplementWordFour uint32 = ^orderWordFour // unused + //orderComplementWordFive uint32 = ^orderWordFive // unused + //orderComplementWordSix uint32 = ^orderWordSix // unused + //orderComplementWordSeven uint32 = ^orderWordSeven // unused + + // These fields provide convenient access to each of the words of the + // secp256k1 curve group order N / 2 to improve code readability and avoid + // the need to recalculate them. + // + // The half order of the secp256k1 curve group is: + // 0x7fffffff ffffffff ffffffff ffffffff 5d576e73 57a4501d dfe92f46 681b20a0 + halfOrderWordZero uint32 = 0x681b20a0 + halfOrderWordOne uint32 = 0xdfe92f46 + halfOrderWordTwo uint32 = 0x57a4501d + halfOrderWordThree uint32 = 0x5d576e73 + halfOrderWordFour uint32 = 0xffffffff + halfOrderWordFive uint32 = 0xffffffff + halfOrderWordSix uint32 = 0xffffffff + halfOrderWordSeven uint32 = 0x7fffffff + + // uint32Mask is simply a mask with all bits set for a uint32 and is used to + // improve the readability of the code. + uint32Mask = 0xffffffff +) + +var ( + // zero32 is an array of 32 bytes used for the purposes of zeroing and is + // defined here to avoid extra allocations. + zero32 = [32]byte{} +) + +// ModNScalar implements optimized 256-bit constant-time fixed-precision +// arithmetic over the secp256k1 group order. This means all arithmetic is +// performed modulo: +// +// 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 +// +// It only implements the arithmetic needed for elliptic curve operations, +// however, the operations that are not implemented can typically be worked +// around if absolutely needed. For example, subtraction can be performed by +// adding the negation. +// +// Should it be absolutely necessary, conversion to the standard library +// math/big.Int can be accomplished by using the Bytes method, slicing the +// resulting fixed-size array, and feeding it to big.Int.SetBytes. However, +// that should typically be avoided when possible as conversion to big.Ints +// requires allocations, is not constant time, and is slower when working modulo +// the group order. +type ModNScalar struct { + // The scalar is represented as 8 32-bit integers in base 2^32. + // + // The following depicts the internal representation: + // --------------------------------------------------------- + // | n[7] | n[6] | ... | n[0] | + // | 32 bits | 32 bits | ... | 32 bits | + // | Mult: 2^(32*7) | Mult: 2^(32*6) | ... | Mult: 2^(32*0) | + // --------------------------------------------------------- + // + // For example, consider the number 2^87 + 2^42 + 1. It would be + // represented as: + // n[0] = 1 + // n[1] = 2^10 + // n[2] = 2^23 + // n[3..7] = 0 + // + // The full 256-bit value is then calculated by looping i from 7..0 and + // doing sum(n[i] * 2^(32i)) like so: + // n[7] * 2^(32*7) = 0 * 2^224 = 0 + // n[6] * 2^(32*6) = 0 * 2^192 = 0 + // ... + // n[2] * 2^(32*2) = 2^23 * 2^64 = 2^87 + // n[1] * 2^(32*1) = 2^10 * 2^32 = 2^42 + // n[0] * 2^(32*0) = 1 * 2^0 = 1 + // Sum: 0 + 0 + ... + 2^87 + 2^42 + 1 = 2^87 + 2^42 + 1 + n [8]uint32 +} + +// String returns the scalar as a human-readable hex string. +// +// This is NOT constant time. +func (s ModNScalar) String() string { + b := s.Bytes() + return hex.EncodeToString(b[:]) +} + +// Set sets the scalar equal to a copy of the passed one in constant time. +// +// The scalar is returned to support chaining. This enables syntax like: +// s := new(ModNScalar).Set(s2).Add(1) so that s = s2 + 1 where s2 is not +// modified. +func (s *ModNScalar) Set(val *ModNScalar) *ModNScalar { + *s = *val + return s +} + +// Zero sets the scalar to zero in constant time. A newly created scalar is +// already set to zero. This function can be useful to clear an existing scalar +// for reuse. +func (s *ModNScalar) Zero() { + s.n[0] = 0 + s.n[1] = 0 + s.n[2] = 0 + s.n[3] = 0 + s.n[4] = 0 + s.n[5] = 0 + s.n[6] = 0 + s.n[7] = 0 +} + +// IsZero returns whether or not the scalar is equal to zero in constant time. +func (s *ModNScalar) IsZero() bool { + // The scalar can only be zero if no bits are set in any of the words. + bits := s.n[0] | s.n[1] | s.n[2] | s.n[3] | s.n[4] | s.n[5] | s.n[6] | s.n[7] + return bits == 0 +} + +// SetInt sets the scalar to the passed integer in constant time. This is a +// convenience function since it is fairly common to perform some arithmetic +// with small native integers. +// +// The scalar is returned to support chaining. This enables syntax like: +// s := new(ModNScalar).SetInt(2).Mul(s2) so that s = 2 * s2. +func (s *ModNScalar) SetInt(ui uint32) *ModNScalar { + s.Zero() + s.n[0] = ui + return s +} + +// constantTimeEq returns 1 if a == b or 0 otherwise in constant time. +func constantTimeEq(a, b uint32) uint32 { + return uint32((uint64(a^b) - 1) >> 63) +} + +// constantTimeNotEq returns 1 if a != b or 0 otherwise in constant time. +func constantTimeNotEq(a, b uint32) uint32 { + return ^uint32((uint64(a^b)-1)>>63) & 1 +} + +// constantTimeLess returns 1 if a < b or 0 otherwise in constant time. +func constantTimeLess(a, b uint32) uint32 { + return uint32((uint64(a) - uint64(b)) >> 63) +} + +// constantTimeLessOrEq returns 1 if a <= b or 0 otherwise in constant time. +func constantTimeLessOrEq(a, b uint32) uint32 { + return uint32((uint64(a) - uint64(b) - 1) >> 63) +} + +// constantTimeGreater returns 1 if a > b or 0 otherwise in constant time. +func constantTimeGreater(a, b uint32) uint32 { + return constantTimeLess(b, a) +} + +// constantTimeGreaterOrEq returns 1 if a >= b or 0 otherwise in constant time. +func constantTimeGreaterOrEq(a, b uint32) uint32 { + return constantTimeLessOrEq(b, a) +} + +// constantTimeMin returns min(a,b) in constant time. +func constantTimeMin(a, b uint32) uint32 { + return b ^ ((a ^ b) & -constantTimeLess(a, b)) +} + +// overflows determines if the current scalar is greater than or equal to the +// group order in constant time and returns 1 if it is or 0 otherwise. +func (s *ModNScalar) overflows() uint32 { + // The intuition here is that the scalar is greater than the group order if + // one of the higher individual words is greater than corresponding word of + // the group order and all higher words in the scalar are equal to their + // corresponding word of the group order. Since this type is modulo the + // group order, being equal is also an overflow back to 0. + // + // Note that the words 5, 6, and 7 are all the max uint32 value, so there is + // no need to test if those individual words of the scalar exceeds them, + // hence, only equality is checked for them. + highWordsEqual := constantTimeEq(s.n[7], orderWordSeven) + highWordsEqual &= constantTimeEq(s.n[6], orderWordSix) + highWordsEqual &= constantTimeEq(s.n[5], orderWordFive) + overflow := highWordsEqual & constantTimeGreater(s.n[4], orderWordFour) + highWordsEqual &= constantTimeEq(s.n[4], orderWordFour) + overflow |= highWordsEqual & constantTimeGreater(s.n[3], orderWordThree) + highWordsEqual &= constantTimeEq(s.n[3], orderWordThree) + overflow |= highWordsEqual & constantTimeGreater(s.n[2], orderWordTwo) + highWordsEqual &= constantTimeEq(s.n[2], orderWordTwo) + overflow |= highWordsEqual & constantTimeGreater(s.n[1], orderWordOne) + highWordsEqual &= constantTimeEq(s.n[1], orderWordOne) + overflow |= highWordsEqual & constantTimeGreaterOrEq(s.n[0], orderWordZero) + + return overflow +} + +// reduce256 reduces the current scalar modulo the group order in accordance +// with the overflows parameter in constant time. The overflows parameter +// specifies whether or not the scalar is known to be greater than the group +// order and MUST either be 1 in the case it is or 0 in the case it is not for a +// correct result. +func (s *ModNScalar) reduce256(overflows uint32) { + // Notice that since s < 2^256 < 2N (where N is the group order), the max + // possible number of reductions required is one. Therefore, in the case a + // reduction is needed, it can be performed with a single subtraction of N. + // Also, recall that subtraction is equivalent to addition by the two's + // complement while ignoring the carry. + // + // When s >= N, the overflows parameter will be 1. Conversely, it will be 0 + // when s < N. Thus multiplying by the overflows parameter will either + // result in 0 or the multiplicand itself. + // + // Combining the above along with the fact that s + 0 = s, the following is + // a constant time implementation that works by either adding 0 or the two's + // complement of N as needed. + // + // The final result will be in the range 0 <= s < N as expected. + overflows64 := uint64(overflows) + c := uint64(s.n[0]) + overflows64*uint64(orderComplementWordZero) + s.n[0] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[1]) + overflows64*uint64(orderComplementWordOne) + s.n[1] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[2]) + overflows64*uint64(orderComplementWordTwo) + s.n[2] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[3]) + overflows64*uint64(orderComplementWordThree) + s.n[3] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[4]) + overflows64 // * 1 + s.n[4] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[5]) // + overflows64 * 0 + s.n[5] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[6]) // + overflows64 * 0 + s.n[6] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(s.n[7]) // + overflows64 * 0 + s.n[7] = uint32(c & uint32Mask) +} + +// SetBytes interprets the provided array as a 256-bit big-endian unsigned +// integer, reduces it modulo the group order, sets the scalar to the result, +// and returns either 1 if it was reduced (aka it overflowed) or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. +func (s *ModNScalar) SetBytes(b *[32]byte) uint32 { + // Pack the 256 total bits across the 8 uint32 words. This could be done + // with a for loop, but benchmarks show this unrolled version is about 2 + // times faster than the variant that uses a loop. + s.n[0] = uint32(b[31]) | uint32(b[30])<<8 | uint32(b[29])<<16 | uint32(b[28])<<24 + s.n[1] = uint32(b[27]) | uint32(b[26])<<8 | uint32(b[25])<<16 | uint32(b[24])<<24 + s.n[2] = uint32(b[23]) | uint32(b[22])<<8 | uint32(b[21])<<16 | uint32(b[20])<<24 + s.n[3] = uint32(b[19]) | uint32(b[18])<<8 | uint32(b[17])<<16 | uint32(b[16])<<24 + s.n[4] = uint32(b[15]) | uint32(b[14])<<8 | uint32(b[13])<<16 | uint32(b[12])<<24 + s.n[5] = uint32(b[11]) | uint32(b[10])<<8 | uint32(b[9])<<16 | uint32(b[8])<<24 + s.n[6] = uint32(b[7]) | uint32(b[6])<<8 | uint32(b[5])<<16 | uint32(b[4])<<24 + s.n[7] = uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 + + // The value might be >= N, so reduce it as required and return whether or + // not it was reduced. + needsReduce := s.overflows() + s.reduce256(needsReduce) + return needsReduce +} + +// zeroArray32 zeroes the provided 32-byte buffer. +func zeroArray32(b *[32]byte) { + copy(b[:], zero32[:]) +} + +// SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned +// integer (meaning it is truncated to the first 32 bytes), reduces it modulo +// the group order, sets the scalar to the result, and returns whether or not +// the resulting truncated 256-bit integer overflowed in constant time. +// +// Note that since passing a slice with more than 32 bytes is truncated, it is +// possible that the truncated value is less than the order of the curve and +// hence it will not be reported as having overflowed in that case. It is up to +// the caller to decide whether it needs to provide numbers of the appropriate +// size or it is acceptable to use this function with the described truncation +// and overflow behavior. +func (s *ModNScalar) SetByteSlice(b []byte) bool { + var b32 [32]byte + b = b[:constantTimeMin(uint32(len(b)), 32)] + copy(b32[:], b32[:32-len(b)]) + copy(b32[32-len(b):], b) + result := s.SetBytes(&b32) + zeroArray32(&b32) + return result != 0 +} + +// PutBytesUnchecked unpacks the scalar to a 32-byte big-endian value directly +// into the passed byte slice in constant time. The target slice must must have +// at least 32 bytes available or it will panic. +// +// There is a similar function, PutBytes, which unpacks the scalar into a +// 32-byte array directly. This version is provided since it can be useful to +// write directly into part of a larger buffer without needing a separate +// allocation. +// +// Preconditions: +// - The target slice MUST have at least 32 bytes available +func (s *ModNScalar) PutBytesUnchecked(b []byte) { + // Unpack the 256 total bits from the 8 uint32 words. This could be done + // with a for loop, but benchmarks show this unrolled version is about 2 + // times faster than the variant which uses a loop. + b[31] = byte(s.n[0]) + b[30] = byte(s.n[0] >> 8) + b[29] = byte(s.n[0] >> 16) + b[28] = byte(s.n[0] >> 24) + b[27] = byte(s.n[1]) + b[26] = byte(s.n[1] >> 8) + b[25] = byte(s.n[1] >> 16) + b[24] = byte(s.n[1] >> 24) + b[23] = byte(s.n[2]) + b[22] = byte(s.n[2] >> 8) + b[21] = byte(s.n[2] >> 16) + b[20] = byte(s.n[2] >> 24) + b[19] = byte(s.n[3]) + b[18] = byte(s.n[3] >> 8) + b[17] = byte(s.n[3] >> 16) + b[16] = byte(s.n[3] >> 24) + b[15] = byte(s.n[4]) + b[14] = byte(s.n[4] >> 8) + b[13] = byte(s.n[4] >> 16) + b[12] = byte(s.n[4] >> 24) + b[11] = byte(s.n[5]) + b[10] = byte(s.n[5] >> 8) + b[9] = byte(s.n[5] >> 16) + b[8] = byte(s.n[5] >> 24) + b[7] = byte(s.n[6]) + b[6] = byte(s.n[6] >> 8) + b[5] = byte(s.n[6] >> 16) + b[4] = byte(s.n[6] >> 24) + b[3] = byte(s.n[7]) + b[2] = byte(s.n[7] >> 8) + b[1] = byte(s.n[7] >> 16) + b[0] = byte(s.n[7] >> 24) +} + +// PutBytes unpacks the scalar to a 32-byte big-endian value using the passed +// byte array in constant time. +// +// There is a similar function, PutBytesUnchecked, which unpacks the scalar into +// a slice that must have at least 32 bytes available. This version is provided +// since it can be useful to write directly into an array that is type checked. +// +// Alternatively, there is also Bytes, which unpacks the scalar into a new array +// and returns that which can sometimes be more ergonomic in applications that +// aren't concerned about an additional copy. +func (s *ModNScalar) PutBytes(b *[32]byte) { + s.PutBytesUnchecked(b[:]) +} + +// Bytes unpacks the scalar to a 32-byte big-endian value in constant time. +// +// See PutBytes and PutBytesUnchecked for variants that allow an array or slice +// to be passed which can be useful to cut down on the number of allocations +// by allowing the caller to reuse a buffer or write directly into part of a +// larger buffer. +func (s *ModNScalar) Bytes() [32]byte { + var b [32]byte + s.PutBytesUnchecked(b[:]) + return b +} + +// IsOdd returns whether or not the scalar is an odd number in constant time. +func (s *ModNScalar) IsOdd() bool { + // Only odd numbers have the bottom bit set. + return s.n[0]&1 == 1 +} + +// Equals returns whether or not the two scalars are the same in constant time. +func (s *ModNScalar) Equals(val *ModNScalar) bool { + // Xor only sets bits when they are different, so the two scalars can only + // be the same if no bits are set after xoring each word. + bits := (s.n[0] ^ val.n[0]) | (s.n[1] ^ val.n[1]) | (s.n[2] ^ val.n[2]) | + (s.n[3] ^ val.n[3]) | (s.n[4] ^ val.n[4]) | (s.n[5] ^ val.n[5]) | + (s.n[6] ^ val.n[6]) | (s.n[7] ^ val.n[7]) + + return bits == 0 +} + +// Add2 adds the passed two scalars together modulo the group order in constant +// time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.Add2(s, s2).AddInt(1) so that s3 = s + s2 + 1. +func (s *ModNScalar) Add2(val1, val2 *ModNScalar) *ModNScalar { + c := uint64(val1.n[0]) + uint64(val2.n[0]) + s.n[0] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[1]) + uint64(val2.n[1]) + s.n[1] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[2]) + uint64(val2.n[2]) + s.n[2] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[3]) + uint64(val2.n[3]) + s.n[3] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[4]) + uint64(val2.n[4]) + s.n[4] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[5]) + uint64(val2.n[5]) + s.n[5] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[6]) + uint64(val2.n[6]) + s.n[6] = uint32(c & uint32Mask) + c = (c >> 32) + uint64(val1.n[7]) + uint64(val2.n[7]) + s.n[7] = uint32(c & uint32Mask) + + // The result is now 256 bits, but it might still be >= N, so use the + // existing normal reduce method for 256-bit values. + s.reduce256(uint32(c>>32) + s.overflows()) + return s +} + +// Add adds the passed scalar to the existing one modulo the group order in +// constant time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Add(s2).AddInt(1) so that s = s + s2 + 1. +func (s *ModNScalar) Add(val *ModNScalar) *ModNScalar { + return s.Add2(s, val) +} + +// accumulator96 provides a 96-bit accumulator for use in the intermediate +// calculations requiring more than 64-bits. +type accumulator96 struct { + n [3]uint32 +} + +// Add adds the passed unsigned 64-bit value to the accumulator. +func (a *accumulator96) Add(v uint64) { + low := uint32(v & uint32Mask) + hi := uint32(v >> 32) + a.n[0] += low + a.n[1] += constantTimeLess(a.n[0], low) // Carry if overflow in n[0]. + a.n[1] += hi + a.n[2] += constantTimeLess(a.n[1], hi) // Carry if overflow in n[1]. +} + +// Rsh32 right shifts the accumulator by 32 bits. +func (a *accumulator96) Rsh32() { + a.n[0] = a.n[1] + a.n[1] = a.n[2] + a.n[2] = 0 +} + +// reduce385 reduces the 385-bit intermediate result in the passed terms modulo +// the group order in constant time and stores the result in s. +func (s *ModNScalar) reduce385(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12 uint64) { + // At this point, the intermediate result in the passed terms has been + // reduced to fit within 385 bits, so reduce it again using the same method + // described in reduce512. As before, the intermediate result will end up + // being reduced by another 127 bits to 258 bits, thus 9 32-bit terms are + // needed for this iteration. The reduced terms are assigned back to t0 + // through t8. + // + // Note that several of the intermediate calculations require adding 64-bit + // products together which would overflow a uint64, so a 96-bit accumulator + // is used instead until the value is reduced enough to use native uint64s. + + // Terms for 2^(32*0). + var acc accumulator96 + acc.n[0] = uint32(t0) // == acc.Add(t0) because acc is guaranteed to be 0. + acc.Add(t8 * uint64(orderComplementWordZero)) + t0 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*1). + acc.Add(t1) + acc.Add(t8 * uint64(orderComplementWordOne)) + acc.Add(t9 * uint64(orderComplementWordZero)) + t1 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*2). + acc.Add(t2) + acc.Add(t8 * uint64(orderComplementWordTwo)) + acc.Add(t9 * uint64(orderComplementWordOne)) + acc.Add(t10 * uint64(orderComplementWordZero)) + t2 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*3). + acc.Add(t3) + acc.Add(t8 * uint64(orderComplementWordThree)) + acc.Add(t9 * uint64(orderComplementWordTwo)) + acc.Add(t10 * uint64(orderComplementWordOne)) + acc.Add(t11 * uint64(orderComplementWordZero)) + t3 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*4). + acc.Add(t4) + acc.Add(t8) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t9 * uint64(orderComplementWordThree)) + acc.Add(t10 * uint64(orderComplementWordTwo)) + acc.Add(t11 * uint64(orderComplementWordOne)) + acc.Add(t12 * uint64(orderComplementWordZero)) + t4 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*5). + acc.Add(t5) + // acc.Add(t8 * uint64(orderComplementWordFive)) // 0 + acc.Add(t9) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t10 * uint64(orderComplementWordThree)) + acc.Add(t11 * uint64(orderComplementWordTwo)) + acc.Add(t12 * uint64(orderComplementWordOne)) + t5 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*6). + acc.Add(t6) + // acc.Add(t8 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t9 * uint64(orderComplementWordFive)) // 0 + acc.Add(t10) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t11 * uint64(orderComplementWordThree)) + acc.Add(t12 * uint64(orderComplementWordTwo)) + t6 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*7). + acc.Add(t7) + // acc.Add(t8 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t9 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t10 * uint64(orderComplementWordFive)) // 0 + acc.Add(t11) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t12 * uint64(orderComplementWordThree)) + t7 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*8). + // acc.Add(t9 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t10 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t11 * uint64(orderComplementWordFive)) // 0 + acc.Add(t12) // * uint64(orderComplementWordFour) // * 1 + t8 = uint64(acc.n[0]) + // acc.Rsh32() // No need since not used after this. Guaranteed to be 0. + + // NOTE: All of the remaining multiplications for this iteration result in 0 + // as they all involve multiplying by combinations of the the fifth, sixth, + // and seventh words of the two's complement of N, which are 0, so skip + // them. + + // At this point, the result is reduced to fit within 258 bits, so reduce it + // again using a slightly modified version of the same method. The maximum + // value in t8 is 2 at this point and therefore multiplying it by each word + // of the two's complement of N and adding it to a 32-bit term will result + // in a maximum requirement of 33 bits, so it is safe to use native uint64s + // here for the intermediate term carry propagation. + // + // Also, since the maximum value in t8 is 2, this ends up reducing by + // another 2 bits to 256 bits. + c := t0 + t8*uint64(orderComplementWordZero) + s.n[0] = uint32(c & uint32Mask) + c = (c >> 32) + t1 + t8*uint64(orderComplementWordOne) + s.n[1] = uint32(c & uint32Mask) + c = (c >> 32) + t2 + t8*uint64(orderComplementWordTwo) + s.n[2] = uint32(c & uint32Mask) + c = (c >> 32) + t3 + t8*uint64(orderComplementWordThree) + s.n[3] = uint32(c & uint32Mask) + c = (c >> 32) + t4 + t8 // * uint64(orderComplementWordFour) == * 1 + s.n[4] = uint32(c & uint32Mask) + c = (c >> 32) + t5 // + t8*uint64(orderComplementWordFive) == 0 + s.n[5] = uint32(c & uint32Mask) + c = (c >> 32) + t6 // + t8*uint64(orderComplementWordSix) == 0 + s.n[6] = uint32(c & uint32Mask) + c = (c >> 32) + t7 // + t8*uint64(orderComplementWordSeven) == 0 + s.n[7] = uint32(c & uint32Mask) + + // The result is now 256 bits, but it might still be >= N, so use the + // existing normal reduce method for 256-bit values. + s.reduce256(uint32(c>>32) + s.overflows()) +} + +// reduce512 reduces the 512-bit intermediate result in the passed terms modulo +// the group order down to 385 bits in constant time and stores the result in s. +func (s *ModNScalar) reduce512(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15 uint64) { + // At this point, the intermediate result in the passed terms is grouped + // into the respective bases. + // + // Per [HAC] section 14.3.4: Reduction method of moduli of special form, + // when the modulus is of the special form m = b^t - c, where log_2(c) < t, + // highly efficient reduction can be achieved per the provided algorithm. + // + // The secp256k1 group order fits this criteria since it is: + // 2^256 - 432420386565659656852420866394968145599 + // + // Technically the max possible value here is (N-1)^2 since the two scalars + // being multiplied are always mod N. Nevertheless, it is safer to consider + // it to be (2^256-1)^2 = 2^512 - 2^256 + 1 since it is the product of two + // 256-bit values. + // + // The algorithm is to reduce the result modulo the prime by subtracting + // multiples of the group order N. However, in order simplify carry + // propagation, this adds with the two's complement of N to achieve the same + // result. + // + // Since the two's complement of N has 127 leading zero bits, this will end + // up reducing the intermediate result from 512 bits to 385 bits, resulting + // in 13 32-bit terms. The reduced terms are assigned back to t0 through + // t12. + // + // Note that several of the intermediate calculations require adding 64-bit + // products together which would overflow a uint64, so a 96-bit accumulator + // is used instead. + + // Terms for 2^(32*0). + var acc accumulator96 + acc.n[0] = uint32(t0) // == acc.Add(t0) because acc is guaranteed to be 0. + acc.Add(t8 * uint64(orderComplementWordZero)) + t0 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*1). + acc.Add(t1) + acc.Add(t8 * uint64(orderComplementWordOne)) + acc.Add(t9 * uint64(orderComplementWordZero)) + t1 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*2). + acc.Add(t2) + acc.Add(t8 * uint64(orderComplementWordTwo)) + acc.Add(t9 * uint64(orderComplementWordOne)) + acc.Add(t10 * uint64(orderComplementWordZero)) + t2 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*3). + acc.Add(t3) + acc.Add(t8 * uint64(orderComplementWordThree)) + acc.Add(t9 * uint64(orderComplementWordTwo)) + acc.Add(t10 * uint64(orderComplementWordOne)) + acc.Add(t11 * uint64(orderComplementWordZero)) + t3 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*4). + acc.Add(t4) + acc.Add(t8) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t9 * uint64(orderComplementWordThree)) + acc.Add(t10 * uint64(orderComplementWordTwo)) + acc.Add(t11 * uint64(orderComplementWordOne)) + acc.Add(t12 * uint64(orderComplementWordZero)) + t4 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*5). + acc.Add(t5) + // acc.Add(t8 * uint64(orderComplementWordFive)) // 0 + acc.Add(t9) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t10 * uint64(orderComplementWordThree)) + acc.Add(t11 * uint64(orderComplementWordTwo)) + acc.Add(t12 * uint64(orderComplementWordOne)) + acc.Add(t13 * uint64(orderComplementWordZero)) + t5 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*6). + acc.Add(t6) + // acc.Add(t8 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t9 * uint64(orderComplementWordFive)) // 0 + acc.Add(t10) // * uint64(orderComplementWordFour)) // * 1 + acc.Add(t11 * uint64(orderComplementWordThree)) + acc.Add(t12 * uint64(orderComplementWordTwo)) + acc.Add(t13 * uint64(orderComplementWordOne)) + acc.Add(t14 * uint64(orderComplementWordZero)) + t6 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*7). + acc.Add(t7) + // acc.Add(t8 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t9 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t10 * uint64(orderComplementWordFive)) // 0 + acc.Add(t11) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t12 * uint64(orderComplementWordThree)) + acc.Add(t13 * uint64(orderComplementWordTwo)) + acc.Add(t14 * uint64(orderComplementWordOne)) + acc.Add(t15 * uint64(orderComplementWordZero)) + t7 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*8). + // acc.Add(t9 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t10 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t11 * uint64(orderComplementWordFive)) // 0 + acc.Add(t12) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t13 * uint64(orderComplementWordThree)) + acc.Add(t14 * uint64(orderComplementWordTwo)) + acc.Add(t15 * uint64(orderComplementWordOne)) + t8 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*9). + // acc.Add(t10 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t11 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t12 * uint64(orderComplementWordFive)) // 0 + acc.Add(t13) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t14 * uint64(orderComplementWordThree)) + acc.Add(t15 * uint64(orderComplementWordTwo)) + t9 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*10). + // acc.Add(t11 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t12 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t13 * uint64(orderComplementWordFive)) // 0 + acc.Add(t14) // * uint64(orderComplementWordFour) // * 1 + acc.Add(t15 * uint64(orderComplementWordThree)) + t10 = uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*11). + // acc.Add(t12 * uint64(orderComplementWordSeven)) // 0 + // acc.Add(t13 * uint64(orderComplementWordSix)) // 0 + // acc.Add(t14 * uint64(orderComplementWordFive)) // 0 + acc.Add(t15) // * uint64(orderComplementWordFour) // * 1 + t11 = uint64(acc.n[0]) + acc.Rsh32() + + // NOTE: All of the remaining multiplications for this iteration result in 0 + // as they all involve multiplying by combinations of the the fifth, sixth, + // and seventh words of the two's complement of N, which are 0, so skip + // them. + + // Terms for 2^(32*12). + t12 = uint64(acc.n[0]) + // acc.Rsh32() // No need since not used after this. Guaranteed to be 0. + + // At this point, the result is reduced to fit within 385 bits, so reduce it + // again using the same method accordingly. + s.reduce385(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) +} + +// Mul2 multiplies the passed two scalars together modulo the group order in +// constant time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.Mul2(s, s2).AddInt(1) so that s3 = (s * s2) + 1. +func (s *ModNScalar) Mul2(val, val2 *ModNScalar) *ModNScalar { + // This could be done with for loops and an array to store the intermediate + // terms, but this unrolled version is significantly faster. + + // The overall strategy employed here is: + // 1) Calculate the 512-bit product of the two scalars using the standard + // pencil-and-paper method. + // 2) Reduce the result modulo the prime by effectively subtracting + // multiples of the group order N (actually performed by adding multiples + // of the two's complement of N to avoid implementing subtraction). + // 3) Repeat step 2 noting that each iteration reduces the required number + // of bits by 127 because the two's complement of N has 127 leading zero + // bits. + // 4) Once reduced to 256 bits, call the existing reduce method to perform + // a final reduction as needed. + // + // Note that several of the intermediate calculations require adding 64-bit + // products together which would overflow a uint64, so a 96-bit accumulator + // is used instead. + + // Terms for 2^(32*0). + var acc accumulator96 + acc.Add(uint64(val.n[0]) * uint64(val2.n[0])) + t0 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*1). + acc.Add(uint64(val.n[0]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[0])) + t1 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*2). + acc.Add(uint64(val.n[0]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[0])) + t2 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*3). + acc.Add(uint64(val.n[0]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[0])) + t3 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*4). + acc.Add(uint64(val.n[0]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[0])) + t4 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*5). + acc.Add(uint64(val.n[0]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[0])) + t5 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*6). + acc.Add(uint64(val.n[0]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[0])) + t6 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*7). + acc.Add(uint64(val.n[0]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[1]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[1])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[0])) + t7 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*8). + acc.Add(uint64(val.n[1]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[2]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[2])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[1])) + t8 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*9). + acc.Add(uint64(val.n[2]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[3]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[3])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[2])) + t9 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*10). + acc.Add(uint64(val.n[3]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[4]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[4])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[3])) + t10 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*11). + acc.Add(uint64(val.n[4]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[5]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[5])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[4])) + t11 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*12). + acc.Add(uint64(val.n[5]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[6]) * uint64(val2.n[6])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[5])) + t12 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*13). + acc.Add(uint64(val.n[6]) * uint64(val2.n[7])) + acc.Add(uint64(val.n[7]) * uint64(val2.n[6])) + t13 := uint64(acc.n[0]) + acc.Rsh32() + + // Terms for 2^(32*14). + acc.Add(uint64(val.n[7]) * uint64(val2.n[7])) + t14 := uint64(acc.n[0]) + acc.Rsh32() + + // What's left is for 2^(32*15). + t15 := uint64(acc.n[0]) + // acc.Rsh32() // No need since not used after this. Guaranteed to be 0. + + // At this point, all of the terms are grouped into their respective base + // and occupy up to 512 bits. Reduce the result accordingly. + s.reduce512(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, + t15) + return s +} + +// Mul multiplies the passed scalar with the existing one modulo the group order +// in constant time and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Mul(s2).AddInt(1) so that s = (s * s2) + 1. +func (s *ModNScalar) Mul(val *ModNScalar) *ModNScalar { + return s.Mul2(s, val) +} + +// SquareVal squares the passed scalar modulo the group order in constant time +// and stores the result in s. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.SquareVal(s).Mul(s) so that s3 = s^2 * s = s^3. +func (s *ModNScalar) SquareVal(val *ModNScalar) *ModNScalar { + // This could technically be optimized slightly to take advantage of the + // fact that many of the intermediate calculations in squaring are just + // doubling, however, benchmarking has shown that due to the need to use a + // 96-bit accumulator, any savings are essentially offset by that and + // consequently there is no real difference in performance over just + // multiplying the value by itself to justify the extra code for now. This + // can be revisited in the future if it becomes a bottleneck in practice. + + return s.Mul2(val, val) +} + +// Square squares the scalar modulo the group order in constant time. The +// existing scalar is modified. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Square().Mul(s2) so that s = s^2 * s2. +func (s *ModNScalar) Square() *ModNScalar { + return s.SquareVal(s) +} + +// NegateVal negates the passed scalar modulo the group order and stores the +// result in s in constant time. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.NegateVal(s2).AddInt(1) so that s = -s2 + 1. +func (s *ModNScalar) NegateVal(val *ModNScalar) *ModNScalar { + // Since the scalar is already in the range 0 <= val < N, where N is the + // group order, negation modulo the group order is just the group order + // minus the value. This implies that the result will always be in the + // desired range with the sole exception of 0 because N - 0 = N itself. + // + // Therefore, in order to avoid the need to reduce the result for every + // other case in order to achieve constant time, this creates a mask that is + // all 0s in the case of the scalar being negated is 0 and all 1s otherwise + // and bitwise ands that mask with each word. + // + // Finally, to simplify the carry propagation, this adds the two's + // complement of the scalar to N in order to achieve the same result. + bits := val.n[0] | val.n[1] | val.n[2] | val.n[3] | val.n[4] | val.n[5] | + val.n[6] | val.n[7] + mask := uint64(uint32Mask * constantTimeNotEq(bits, 0)) + c := uint64(orderWordZero) + (uint64(^val.n[0]) + 1) + s.n[0] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordOne) + uint64(^val.n[1]) + s.n[1] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordTwo) + uint64(^val.n[2]) + s.n[2] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordThree) + uint64(^val.n[3]) + s.n[3] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordFour) + uint64(^val.n[4]) + s.n[4] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordFive) + uint64(^val.n[5]) + s.n[5] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordSix) + uint64(^val.n[6]) + s.n[6] = uint32(c & mask) + c = (c >> 32) + uint64(orderWordSeven) + uint64(^val.n[7]) + s.n[7] = uint32(c & mask) + return s +} + +// Negate negates the scalar modulo the group order in constant time. The +// existing scalar is modified. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Negate().AddInt(1) so that s = -s + 1. +func (s *ModNScalar) Negate() *ModNScalar { + return s.NegateVal(s) +} + +// InverseValNonConst finds the modular multiplicative inverse of the passed +// scalar and stores result in s in *non-constant* time. +// +// The scalar is returned to support chaining. This enables syntax like: +// s3.InverseVal(s1).Mul(s2) so that s3 = s1^-1 * s2. +func (s *ModNScalar) InverseValNonConst(val *ModNScalar) *ModNScalar { + // This is making use of big integers for now. Ideally it will be replaced + // with an implementation that does not depend on big integers. + valBytes := val.Bytes() + bigVal := new(big.Int).SetBytes(valBytes[:]) + bigVal.ModInverse(bigVal, curveParams.N) + s.SetByteSlice(bigVal.Bytes()) + return s +} + +// InverseNonConst finds the modular multiplicative inverse of the scalar in +// *non-constant* time. The existing scalar is modified. +// +// The scalar is returned to support chaining. This enables syntax like: +// s.Inverse().Mul(s2) so that s = s^-1 * s2. +func (s *ModNScalar) InverseNonConst() *ModNScalar { + return s.InverseValNonConst(s) +} + +// IsOverHalfOrder returns whether or not the scalar exceeds the group order +// divided by 2 in constant time. +func (s *ModNScalar) IsOverHalfOrder() bool { + // The intuition here is that the scalar is greater than half of the group + // order if one of the higher individual words is greater than the + // corresponding word of the half group order and all higher words in the + // scalar are equal to their corresponding word of the half group order. + // + // Note that the words 4, 5, and 6 are all the max uint32 value, so there is + // no need to test if those individual words of the scalar exceeds them, + // hence, only equality is checked for them. + result := constantTimeGreater(s.n[7], halfOrderWordSeven) + highWordsEqual := constantTimeEq(s.n[7], halfOrderWordSeven) + highWordsEqual &= constantTimeEq(s.n[6], halfOrderWordSix) + highWordsEqual &= constantTimeEq(s.n[5], halfOrderWordFive) + highWordsEqual &= constantTimeEq(s.n[4], halfOrderWordFour) + result |= highWordsEqual & constantTimeGreater(s.n[3], halfOrderWordThree) + highWordsEqual &= constantTimeEq(s.n[3], halfOrderWordThree) + result |= highWordsEqual & constantTimeGreater(s.n[2], halfOrderWordTwo) + highWordsEqual &= constantTimeEq(s.n[2], halfOrderWordTwo) + result |= highWordsEqual & constantTimeGreater(s.n[1], halfOrderWordOne) + highWordsEqual &= constantTimeEq(s.n[1], halfOrderWordOne) + result |= highWordsEqual & constantTimeGreater(s.n[0], halfOrderWordZero) + + return result != 0 +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/nonce.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/nonce.go new file mode 100644 index 00000000..81b205d9 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/nonce.go @@ -0,0 +1,263 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "bytes" + "crypto/sha256" + "hash" +) + +// References: +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) +// +// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules: +// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules +// (CER) and Distinguished Encoding Rules (DER) +// +// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0) +// https://www.secg.org/sec1-v2.pdf + +var ( + // singleZero is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + singleZero = []byte{0x00} + + // zeroInitializer is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + zeroInitializer = bytes.Repeat([]byte{0x00}, sha256.BlockSize) + + // singleOne is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + singleOne = []byte{0x01} + + // oneInitializer is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + oneInitializer = bytes.Repeat([]byte{0x01}, sha256.Size) +) + +// hmacsha256 implements a resettable version of HMAC-SHA256. +type hmacsha256 struct { + inner, outer hash.Hash + ipad, opad [sha256.BlockSize]byte +} + +// Write adds data to the running hash. +func (h *hmacsha256) Write(p []byte) { + h.inner.Write(p) +} + +// initKey initializes the HMAC-SHA256 instance to the provided key. +func (h *hmacsha256) initKey(key []byte) { + // Hash the key if it is too large. + if len(key) > sha256.BlockSize { + h.outer.Write(key) + key = h.outer.Sum(nil) + } + copy(h.ipad[:], key) + copy(h.opad[:], key) + for i := range h.ipad { + h.ipad[i] ^= 0x36 + } + for i := range h.opad { + h.opad[i] ^= 0x5c + } + h.inner.Write(h.ipad[:]) +} + +// ResetKey resets the HMAC-SHA256 to its initial state and then initializes it +// with the provided key. It is equivalent to creating a new instance with the +// provided key without allocating more memory. +func (h *hmacsha256) ResetKey(key []byte) { + h.inner.Reset() + h.outer.Reset() + copy(h.ipad[:], zeroInitializer) + copy(h.opad[:], zeroInitializer) + h.initKey(key) +} + +// Resets the HMAC-SHA256 to its initial state using the current key. +func (h *hmacsha256) Reset() { + h.inner.Reset() + h.inner.Write(h.ipad[:]) +} + +// Sum returns the hash of the written data. +func (h *hmacsha256) Sum() []byte { + h.outer.Reset() + h.outer.Write(h.opad[:]) + h.outer.Write(h.inner.Sum(nil)) + return h.outer.Sum(nil) +} + +// newHMACSHA256 returns a new HMAC-SHA256 hasher using the provided key. +func newHMACSHA256(key []byte) *hmacsha256 { + h := new(hmacsha256) + h.inner = sha256.New() + h.outer = sha256.New() + h.initKey(key) + return h +} + +// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using +// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input +// and returns a 32-byte nonce to be used for deterministic signing. The extra +// and version arguments are optional, but allow additional data to be added to +// the input of the HMAC. When provided, the extra data must be 32-bytes and +// version must be 16 bytes or they will be ignored. +// +// Finally, the extraIterations parameter provides a method to produce a stream +// of deterministic nonces to ensure the signing code is able to produce a nonce +// that results in a valid signature in the extremely unlikely event the +// original nonce produced results in an invalid signature (e.g. R == 0). +// Signing code should start with 0 and increment it if necessary. +func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte, extraIterations uint32) *ModNScalar { + // Input to HMAC is the 32-byte private key and the 32-byte hash. In + // addition, it may include the optional 32-byte extra data and 16-byte + // version. Create a fixed-size array to avoid extra allocs and slice it + // properly. + const ( + privKeyLen = 32 + hashLen = 32 + extraLen = 32 + versionLen = 16 + ) + var keyBuf [privKeyLen + hashLen + extraLen + versionLen]byte + + // Truncate rightmost bytes of private key and hash if they are too long and + // leave left padding of zeros when they're too short. + if len(privKey) > privKeyLen { + privKey = privKey[:privKeyLen] + } + if len(hash) > hashLen { + hash = hash[:hashLen] + } + offset := privKeyLen - len(privKey) // Zero left padding if needed. + offset += copy(keyBuf[offset:], privKey) + offset += hashLen - len(hash) // Zero left padding if needed. + offset += copy(keyBuf[offset:], hash) + if len(extra) == extraLen { + offset += copy(keyBuf[offset:], extra) + if len(version) == versionLen { + offset += copy(keyBuf[offset:], version) + } + } else if len(version) == versionLen { + // When the version was specified, but not the extra data, leave the + // extra data portion all zero. + offset += privKeyLen + offset += copy(keyBuf[offset:], version) + } + key := keyBuf[:offset] + + // Step B. + // + // V = 0x01 0x01 0x01 ... 0x01 such that the length of V, in bits, is + // equal to 8*ceil(hashLen/8). + // + // Note that since the hash length is a multiple of 8 for the chosen hash + // function in this optimized implementation, the result is just the hash + // length, so avoid the extra calculations. Also, since it isn't modified, + // start with a global value. + v := oneInitializer + + // Step C (Go zeroes all allocated memory). + // + // K = 0x00 0x00 0x00 ... 0x00 such that the length of K, in bits, is + // equal to 8*ceil(hashLen/8). + // + // As above, since the hash length is a multiple of 8 for the chosen hash + // function in this optimized implementation, the result is just the hash + // length, so avoid the extra calculations. + k := zeroInitializer[:hashLen] + + // Step D. + // + // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1)) + // + // Note that key is the "int2octets(x) || bits2octets(h1)" portion along + // with potential additional data as described by section 3.6 of the RFC. + hasher := newHMACSHA256(k) + hasher.Write(oneInitializer) + hasher.Write(singleZero[:]) + hasher.Write(key) + k = hasher.Sum() + + // Step E. + // + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + + // Step F. + // + // K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1)) + // + // Note that key is the "int2octets(x) || bits2octets(h1)" portion along + // with potential additional data as described by section 3.6 of the RFC. + hasher.Reset() + hasher.Write(v) + hasher.Write(singleOne[:]) + hasher.Write(key[:]) + k = hasher.Sum() + + // Step G. + // + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + + // Step H. + // + // Repeat until the value is nonzero and less than the curve order. + var generated uint32 + for { + // Step H1 and H2. + // + // Set T to the empty sequence. The length of T (in bits) is denoted + // tlen; thus, at that point, tlen = 0. + // + // While tlen < qlen, do the following: + // V = HMAC_K(V) + // T = T || V + // + // Note that because the hash function output is the same length as the + // private key in this optimized implementation, there is no need to + // loop or create an intermediate T. + hasher.Reset() + hasher.Write(v) + v = hasher.Sum() + + // Step H3. + // + // k = bits2int(T) + // If k is within the range [1,q-1], return it. + // + // Otherwise, compute: + // K = HMAC_K(V || 0x00) + // V = HMAC_K(V) + var secret ModNScalar + overflow := secret.SetByteSlice(v) + if !overflow && !secret.IsZero() { + generated++ + if generated > extraIterations { + return &secret + } + } + + // K = HMAC_K(V || 0x00) + hasher.Reset() + hasher.Write(v) + hasher.Write(singleZero[:]) + k = hasher.Sum() + + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + } +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/privkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/privkey.go new file mode 100644 index 00000000..70e5d405 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/privkey.go @@ -0,0 +1,78 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "crypto/ecdsa" + "crypto/rand" +) + +// PrivateKey provides facilities for working with secp256k1 private keys within +// this package and includes functionality such as serializing and parsing them +// as well as computing their associated public key. +type PrivateKey struct { + Key ModNScalar +} + +// NewPrivateKey instantiates a new private key from a scalar encoded as a +// big integer. +func NewPrivateKey(key *ModNScalar) *PrivateKey { + return &PrivateKey{Key: *key} +} + +// PrivKeyFromBytes returns a private based on the provided byte slice which is +// interpreted as an unsigned 256-bit big-endian integer in the range [0, N-1], +// where N is the order of the curve. +// +// Note that this means passing a slice with more than 32 bytes is truncated and +// that truncated value is reduced modulo N. It is up to the caller to either +// provide a value in the appropriate range or choose to accept the described +// behavior. +// +// Typically callers should simply make use of GeneratePrivateKey when creating +// private keys which properly handles generation of appropriate values. +func PrivKeyFromBytes(privKeyBytes []byte) *PrivateKey { + var privKey PrivateKey + privKey.Key.SetByteSlice(privKeyBytes) + return &privKey +} + +// GeneratePrivateKey returns a private key that is suitable for use with +// secp256k1. +func GeneratePrivateKey() (*PrivateKey, error) { + key, err := ecdsa.GenerateKey(S256(), rand.Reader) + if err != nil { + return nil, err + } + return PrivKeyFromBytes(key.D.Bytes()), nil +} + +// PubKey computes and returns the public key corresponding to this private key. +// PubKey returns the PublicKey corresponding to this private key. +func (p *PrivateKey) PubKey() *PublicKey { + var result JacobianPoint + ScalarBaseMultNonConst(&p.Key, &result) + result.ToAffine() + return NewPublicKey(&result.X, &result.Y) +} + +// Zero manually clears the memory associated with the private key. This can be +// used to explicitly clear key material from memory for enhanced security +// against memory scraping. +func (p *PrivateKey) Zero() { + p.Key.Zero() +} + +// PrivKeyBytesLen defines the length in bytes of a serialized private key. +const PrivKeyBytesLen = 32 + +// Serialize returns the private key as a 256-bit big-endian binary-encoded +// number, padded to a length of 32 bytes. +func (p PrivateKey) Serialize() []byte { + var privKeyBytes [PrivKeyBytesLen]byte + p.Key.PutBytes(&privKeyBytes) + return privKeyBytes[:] +} diff --git a/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/pubkey.go b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/pubkey.go new file mode 100644 index 00000000..e301c8a3 --- /dev/null +++ b/vendor/github.com/decred/dcrd/dcrec/secp256k1/v3/pubkey.go @@ -0,0 +1,232 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +// References: +// [SEC1] Elliptic Curve Cryptography +// https://www.secg.org/sec1-v2.pdf +// +// [SEC2] Recommended Elliptic Curve Domain Parameters +// https://www.secg.org/sec2-v2.pdf +// +// [ANSI X9.62-1998] Public Key Cryptography For The Financial Services +// Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA) + +import ( + "fmt" +) + +const ( + // PubKeyBytesLenCompressed is the number of bytes of a serialized + // compressed public key. + PubKeyBytesLenCompressed = 33 + + // PubKeyBytesLenCompressed is the number of bytes of a serialized + // uncompressed public key. + PubKeyBytesLenUncompressed = 65 + + // PubKeyFormatCompressedEven is the identifier prefix byte for a public key + // whose Y coordinate is even when serialized in the compressed format per + // section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4). + PubKeyFormatCompressedEven byte = 0x02 + + // PubKeyFormatCompressedOdd is the identifier prefix byte for a public key + // whose Y coordinate is odd when serialized in the compressed format per + // section 2.3.4 of [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.4). + PubKeyFormatCompressedOdd byte = 0x03 + + // PubKeyFormatUncompressed is the identifier prefix byte for a public key + // when serialized according in the uncompressed format per section 2.3.3 of + // [SEC1](https://secg.org/sec1-v2.pdf#subsubsection.2.3.3). + PubKeyFormatUncompressed byte = 0x04 + + // PubKeyFormatHybridEven is the identifier prefix byte for a public key + // whose Y coordinate is even when serialized according to the hybrid format + // per section 4.3.6 of [ANSI X9.62-1998]. + // + // NOTE: This format makes little sense in practice an therefore this + // package will not produce public keys serialized in this format. However, + // it will parse them since they exist in the wild. + PubKeyFormatHybridEven byte = 0x06 + + // PubKeyIDHybridEven is the identifier prefix byte for a public key whose Y + // coordingate is odd when serialized according to the hybrid format per + // section 4.3.6 of [ANSI X9.62-1998]. + // + // NOTE: This format makes little sense in practice an therefore this + // package will not produce public keys serialized in this format. However, + // it will parse them since they exist in the wild. + PubKeyFormatHybridOdd byte = 0x07 +) + +// PublicKey provides facilities for efficiently working with secp256k1 public +// keys within this package and includes functions to serialize in both +// uncompressed and compressed SEC (Standards for Efficient Cryptography) +// formats. +type PublicKey struct { + x FieldVal + y FieldVal +} + +// NewPublicKey instantiates a new public key with the given x and y +// coordinates. +// +// It should be noted that, unlike ParsePubKey, since this accepts arbitrary x +// and y coordinates, it allows creation of public keys that are not valid +// points on the secp256k1 curve. The IsOnCurve method of the returned instance +// can be used to determine validity. +func NewPublicKey(x, y *FieldVal) *PublicKey { + var pubKey PublicKey + pubKey.x.Set(x) + pubKey.y.Set(y) + return &pubKey +} + +// ParsePubKey parses a secp256k1 public key encoded according to the format +// specified by ANSI X9.62-1998, which means it is also compatible with the +// SEC (Standards for Efficient Cryptography) specification which is a subset of +// the former. In other words, it supports the uncompressed, compressed, and +// hybrid formats as follows: +// +// Compressed: +// <32-byte X coordinate> +// Uncompressed: +// <32-byte X coordinate><32-byte Y coordinate> +// Hybrid: +// <32-byte X coordinate><32-byte Y coordinate> +// +// NOTE: The hybrid format makes little sense in practice an therefore this +// package will not produce public keys serialized in this format. However, +// this function will properly parse them since they exist in the wild. +func ParsePubKey(serialized []byte) (key *PublicKey, err error) { + var x, y FieldVal + switch len(serialized) { + case PubKeyBytesLenUncompressed: + // Reject unsupported public key formats for the given length. + format := serialized[0] + switch format { + case PubKeyFormatUncompressed: + case PubKeyFormatHybridEven, PubKeyFormatHybridOdd: + default: + str := fmt.Sprintf("invalid public key: unsupported format: %x", + format) + return nil, makeError(ErrPubKeyInvalidFormat, str) + } + + // Parse the x and y coordinates while ensuring that they are in the + // allowed range. + if overflow := x.SetByteSlice(serialized[1:33]); overflow { + str := "invalid public key: x >= field prime" + return nil, makeError(ErrPubKeyXTooBig, str) + } + if overflow := y.SetByteSlice(serialized[33:]); overflow { + str := "invalid public key: y >= field prime" + return nil, makeError(ErrPubKeyYTooBig, str) + } + + // Ensure the oddness of the y coordinate matches the specified format + // for hybrid public keys. + if format == PubKeyFormatHybridEven || format == PubKeyFormatHybridOdd { + wantOddY := format == PubKeyFormatHybridOdd + if y.IsOdd() != wantOddY { + str := fmt.Sprintf("invalid public key: y oddness does not "+ + "match specified value of %v", wantOddY) + return nil, makeError(ErrPubKeyMismatchedOddness, str) + } + } + + // Reject public keys that are not on the secp256k1 curve. + if !isOnCurve(&x, &y) { + str := fmt.Sprintf("invalid public key: [%v,%v] not on secp256k1 "+ + "curve", x, y) + return nil, makeError(ErrPubKeyNotOnCurve, str) + } + + case PubKeyBytesLenCompressed: + // Reject unsupported public key formats for the given length. + format := serialized[0] + switch format { + case PubKeyFormatCompressedEven, PubKeyFormatCompressedOdd: + default: + str := fmt.Sprintf("invalid public key: unsupported format: %x", + format) + return nil, makeError(ErrPubKeyInvalidFormat, str) + } + + // Parse the x coordinate while ensuring that it is in the allowed + // range. + if overflow := x.SetByteSlice(serialized[1:33]); overflow { + str := "invalid public key: x >= field prime" + return nil, makeError(ErrPubKeyXTooBig, str) + } + + // Attempt to calculate the y coordinate for the given x coordinate such + // that the result pair is a point on the secp256k1 curve and the + // solution with desired oddness is chosen. + wantOddY := format == PubKeyFormatCompressedOdd + if !DecompressY(&x, wantOddY, &y) { + str := fmt.Sprintf("invalid public key: x coordinate %v is not on "+ + "the secp256k1 curve", x) + return nil, makeError(ErrPubKeyNotOnCurve, str) + } + y.Normalize() + + default: + str := fmt.Sprintf("malformed public key: invalid length: %d", + len(serialized)) + return nil, makeError(ErrPubKeyInvalidLen, str) + } + + return NewPublicKey(&x, &y), nil +} + +// SerializeUncompressed serializes a public key in the 65-byte uncompressed +// format. +func (p PublicKey) SerializeUncompressed() []byte { + // 0x04 || 32-byte x coordinate || 32-byte y coordinate + var b [PubKeyBytesLenUncompressed]byte + b[0] = PubKeyFormatUncompressed + p.x.PutBytesUnchecked(b[1:33]) + p.y.PutBytesUnchecked(b[33:65]) + return b[:] +} + +// SerializeCompressed serializes a public key in the 33-byte compressed format. +func (p PublicKey) SerializeCompressed() []byte { + // Choose the format byte depending on the oddness of the Y coordinate. + format := PubKeyFormatCompressedEven + if p.y.IsOdd() { + format = PubKeyFormatCompressedOdd + } + + // 0x02 or 0x03 || 32-byte x coordinate + var b [PubKeyBytesLenCompressed]byte + b[0] = format + p.x.PutBytesUnchecked(b[1:33]) + return b[:] +} + +// IsEqual compares this PublicKey instance to the one passed, returning true if +// both PublicKeys are equivalent. A PublicKey is equivalent to another, if they +// both have the same X and Y coordinate. +func (p *PublicKey) IsEqual(otherPubKey *PublicKey) bool { + return p.x.Equals(&otherPubKey.x) && p.y.Equals(&otherPubKey.y) +} + +// AsJacobian converts the public key into a Jacobian point with Z=1 and stores +// the result in the provided result param. This allows the public key to be +// treated a Jacobian point in the secp256k1 group in calculations. +func (p *PublicKey) AsJacobian(result *JacobianPoint) { + result.X.Set(&p.x) + result.Y.Set(&p.y) + result.Z.SetInt(1) +} + +// IsOnCurve returns whether or not the public key represents a point on the +// secp256k1 curve. +func (p *PublicKey) IsOnCurve() bool { + return isOnCurve(&p.x, &p.y) +} diff --git a/vendor/github.com/duosecurity/duo_universal_golang/LICENSE b/vendor/github.com/duosecurity/duo_universal_golang/LICENSE new file mode 100644 index 00000000..0c8839de --- /dev/null +++ b/vendor/github.com/duosecurity/duo_universal_golang/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2020, Duo Security, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/duosecurity/duo_universal_golang/duouniversal/client.go b/vendor/github.com/duosecurity/duo_universal_golang/duouniversal/client.go new file mode 100644 index 00000000..d28048f6 --- /dev/null +++ b/vendor/github.com/duosecurity/duo_universal_golang/duouniversal/client.go @@ -0,0 +1,705 @@ +package duouniversal + +import ( + "context" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "math/big" + "net" + "net/http" + "net/url" + "runtime" + "strings" + "time" +) + +const defaultStateLength = 36 +const minimumStateLength = 22 +const maximumStateLength = 1024 +const defaultJtiLength = 36 +const clientIdLength = 20 +const clientSecretLength = 40 +const expirationTime = 300 +const allowedSkew = time.Duration(60) * time.Second +const healthCheckEndpoint = "https://%s/oauth/v1/health_check" +const oauthV1AuthorizeEndpoint = "https://%s/oauth/v1/authorize" +const apiHostURIFormat = "https://%s" +const tokenEndpoint = "https://%s/oauth/v1/token" +const clientAssertionType = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" + +// StateCharacters is the set of possible characters used in the random state +const stateCharacters = "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + "1234567890" +const clientIdError = "The Duo client id is invalid." +const clientSecretError = "The Duo client secret is invalid." +const usernameError = "The username is invalid." +const parameterError = "Did not recieve expected parameters." +const duoCodeError = "Missing authorization code" +const httpUseError = "This client does not allow use of http, please use https" +const duoVersion = "1.0.3" + +var stateLengthError = fmt.Sprintf("State must be at least %d characters long and no longer than %d characters", minimumStateLength, maximumStateLength) +var generateStateLengthError = fmt.Sprintf("Length needs to be at least %d", minimumStateLength) + +type FlagStatus int32 + +const ( + Disabled FlagStatus = iota + Enabled + Unknown = 99 +) + +func (f FlagStatus) MarshalJSON() ([]byte, error) { + switch f { + case Unknown: + return json.Marshal("unknown") + case Enabled: + return json.Marshal(true) + case Disabled: + return json.Marshal(false) + default: + return nil, errors.New("Error marshaling value") + } +} + +func (f *FlagStatus) UnmarshalJSON(data []byte) error { + var i bool + if err := json.Unmarshal(data, &i); err != nil { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + if s == "unknown" { + *f = Unknown + return nil + } else { + return errors.New("Error unmarshaling value") + } + } + if i == true { + *f = FlagStatus(Enabled) + } else { + *f = FlagStatus(Disabled) + } + return nil +} + +type HealthCheckTime struct { + Time int `json:"time"` +} + +type HealthCheckResponse struct { + Stat string `json:"stat"` + Message string `json:"message"` + MessageDetail string `json:"message_detail"` + Response HealthCheckTime `json:"response"` + Code int `json:"code"` +} + +type BodyToken struct { + IdToken string `json:"id_token"` + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` + TokenType string `json:"token_type"` +} + +type AuthResultInfo struct { + Result string `json:"result"` + Status string `json:"status"` + StatusMsg string `json:"status_msg"` +} + +type LocationInfo struct { + City string `json:"city"` + Country string `json:"country"` + State string `json:"state"` +} + +type AccessDeviceInfo struct { + Browser string `json:"browser"` + BrowserVersion string `json:"browser_version"` + FlashVersion string `json:"flash_version"` + Hostname string `json:"host_name"` + Ip string `json:"ip"` + IsEncryptionEnabled FlagStatus `json:"is_encryption_enabled"` + IsFirewallEnabled FlagStatus `json:"is_firewall_enabled"` + IsPasswordSet FlagStatus `json:"is_password_set"` + JavaVersion string `json:"java_version"` + Location LocationInfo `json:"location"` + Os string `json:"os"` + OsVersion string `json:"os_version"` +} + +type AuthDeviceInfo struct { + Ip string `json:"ip"` + Location LocationInfo `json:"location"` + Name string `json:"name"` +} + +type ApplicationInfo struct { + Key string `json:"key"` + Name string `json:"name"` +} + +type UserInfo struct { + Groups []string `json:"groups"` + Key string `json:"key"` + Name string `json:"name"` +} + +type AuthContextInfo struct { + AccessDevice AccessDeviceInfo `json:"access_device"` + Alias string `json:"alias"` + Application ApplicationInfo `json:"application"` + AuthDevice AuthDeviceInfo `json:"auth_device"` + Email string `json:"email"` + EventType string `json:"event_type"` + Factor string `json:"factor"` + Isotimestamp string `json:"isotimestamp"` + OodSoftware string `json:"ood_software"` + Reason string `json:"reason"` + Result string `json:"result"` + Timestamp int `json:"timestamp"` + Txid string `json:"txid"` + User UserInfo `json:"user"` +} + +type TokenResponse struct { + PreferredUsername string `json:"preferred_username"` + AuthTime int `json:"auth_time"` + Nonce string `json:"nonce"` + AuthResult AuthResultInfo `json:"auth_result"` + AuthContext AuthContextInfo `json:"auth_context"` + Audience string `json:"aud"` + ExpiresAt int64 `json:"exp"` + Id string `json:"jti"` + IssuedAt int64 `json:"iat"` + Issuer string `json:"iss"` + Subject string `json:"sub"` +} + +type Client struct { + clientId string + clientSecret string + apiHost string + redirectUri string + useDuoCodeAttribute bool + duoHttpClient httpClient +} + +type httpClient interface { + Do(req *http.Request) (*http.Response, error) +} + +// Blocks HTTP requests +func refuseHttpConnection(ctx context.Context, network, address string) (net.Conn, error) { + return nil, fmt.Errorf(httpUseError) +} + +// Creates a http.Transport that pins certs to Duo and refuses HTTP connections +func newStrictTLSTransport() *http.Transport { + certPool := x509.NewCertPool() + certPool.AppendCertsFromPEM([]byte(duoPinnedCert)) + + tlsDialer := &tls.Dialer{ + Config: &tls.Config{ + RootCAs: certPool, + }, + } + return &http.Transport{ + DialContext: refuseHttpConnection, + DialTLSContext: tlsDialer.DialContext, + } +} + +func NewClient(clientId, clientSecret, apiHost, redirectUri string) (*Client, error) { + return NewClientDuoCodeAttribute(clientId, clientSecret, apiHost, redirectUri, true) +} + +// Creates a new Client with the ability to turn off use_duo_code_attribute +func NewClientDuoCodeAttribute(clientId, clientSecret, apiHost, redirectUri string, useDuoCodeAttribute bool) (*Client, error) { + if len(clientId) != clientIdLength { + return nil, fmt.Errorf(clientIdError) + } else if len(clientSecret) != clientSecretLength { + return nil, fmt.Errorf(clientSecretError) + } + + return &Client{ + clientId: clientId, + clientSecret: clientSecret, + apiHost: apiHost, + redirectUri: redirectUri, + useDuoCodeAttribute: useDuoCodeAttribute, + duoHttpClient: &http.Client{ + Transport: newStrictTLSTransport(), + }, + }, nil +} + +// Return a cryptographically-secure string of random characters +// with the default length +func (client *Client) GenerateState() (string, error) { + return client.GenerateStateWithLength(defaultStateLength) +} + +// Return a cryptographically-secure string of random characters +// suitable for use in state values. +// length is the number of characters in the randomly generated string +func (client *Client) GenerateStateWithLength(length int) (string, error) { + if length < minimumStateLength { + return "", fmt.Errorf(generateStateLengthError) + } + + result := make([]byte, length) + possibleCharacters := int64(len(stateCharacters)) + for i := range result { + n, err := rand.Int(rand.Reader, big.NewInt(possibleCharacters)) + if err != nil { + return "", err + } + result[i] = stateCharacters[n.Int64()] + } + return string(result), nil +} + +// Creates a JWT token used for the "client_assertion" parameter in the health check +// and "requset" parameter in the token endpoint +func (client *Client) createJwtArgs(aud string) (string, error) { + jti, err := client.GenerateStateWithLength(defaultJtiLength) + if err != nil { + return "", err + } + + claims := MapClaims{ + "iss": client.clientId, + "sub": client.clientId, + "aud": aud, + "exp": time.Now().Add(time.Second * time.Duration(expirationTime)).Unix(), + "jti": jti, + } + + token, err := client.createSignedToken(claims) + if err != nil { + return "", err + } + + return token, nil +} + +// Makes HTTP request to Duo +func (client *Client) _makeHttpRequest(e, userAgent string, p url.Values) ([]byte, error) { + r, err := http.NewRequest(http.MethodPost, e, strings.NewReader(p.Encode())) + if err != nil { + return nil, err + } + + r.Header.Add("Content-Type", "application/x-www-form-urlencoded") + if userAgent != "" { + r.Header.Set("User-Agent", userAgent) + } + resp, err := client.duoHttpClient.Do(r) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return nil, fmt.Errorf("%s", resp.Status) + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return body, nil +} + +// Checks whether or not Duo is available. +func (client *Client) HealthCheck() (*HealthCheckResponse, error) { + postParams := url.Values{} + healthCheckResponse := &HealthCheckResponse{} + healthCheckUrl := fmt.Sprintf(healthCheckEndpoint, client.apiHost) + + token, err := client.createJwtArgs(healthCheckUrl) + if err != nil { + return nil, err + } + + postParams.Add("client_assertion", token) + postParams.Add("client_id", client.clientId) + body, err := client._makeHttpRequest(healthCheckUrl, "", postParams) + if err != nil { + return nil, err + } + + err = json.Unmarshal(body, healthCheckResponse) + if err != nil { + return nil, err + } + if healthCheckResponse.Stat != "OK" { + return nil, fmt.Errorf("%s: %s", healthCheckResponse.Message, healthCheckResponse.MessageDetail) + } + + return healthCheckResponse, nil +} + +func (client *Client) CreateAuthURL(username string, state string) (string, error) { + + err := validateClientCreateAuthURLInputs(username, state) + if err != nil { + return "", err + } + + authorizeEndpoint := fmt.Sprintf(oauthV1AuthorizeEndpoint, client.apiHost) + + claims := MapClaims{ + "scope": "openid", + "redirect_uri": client.redirectUri, + "client_id": client.clientId, + "iss": client.clientId, + "aud": fmt.Sprintf(apiHostURIFormat, client.apiHost), + "exp": time.Now().Add(time.Second * time.Duration(expirationTime)).Unix(), + "state": state, + "response_type": "code", + "duo_uname": username, + "use_duo_code_attribute": client.useDuoCodeAttribute, + } + + requestJWTSigned, err := client.createSignedToken(claims) + if err != nil { + return "", err + } + + params := url.Values{} + params.Add("response_type", "code") + params.Add("client_id", client.clientId) + params.Add("request", requestJWTSigned) + + base, err := url.Parse(authorizeEndpoint) + if err != nil { + return "", err + } + base.RawQuery = params.Encode() + authorizationURI := base.String() + + return authorizationURI, nil +} + +func (client *Client) createSignedToken(claims MapClaims) (string, error) { + return jwtCreateSignedToken(claims, client.clientSecret) +} + +func validateClientCreateAuthURLInputs(username string, state string) error { + stateLength := len(state) + if stateLength < minimumStateLength || stateLength > maximumStateLength { + return fmt.Errorf(stateLengthError) + } + + if username == "" { + return fmt.Errorf(usernameError) + } + + return nil +} + +func (client *Client) ExchangeAuthorizationCodeFor2faResult(duoCode string, username string) (*TokenResponse, error) { + return client.ExchangeAuthorizationCodeFor2faResultWithNonce(duoCode, username, "") +} + +// Exchange the duo_code for a token with Duo to determine if the auth was successful. +func (client *Client) ExchangeAuthorizationCodeFor2faResultWithNonce(duoCode string, username string, nonce string) (*TokenResponse, error) { + if duoCode == "" { + return nil, fmt.Errorf(duoCodeError) + } + tokenUrl := fmt.Sprintf(tokenEndpoint, client.apiHost) + postParams := url.Values{} + bodyToken := &BodyToken{} + jwtToken, err := client.createJwtArgs(tokenUrl) + if err != nil { + return nil, err + } + + postParams.Add("redirect_uri", client.redirectUri) + postParams.Add("grant_type", "authorization_code") + postParams.Add("code", duoCode) + postParams.Add("client_id", client.clientId) + postParams.Add("client_assertion_type", clientAssertionType) + postParams.Add("client_assertion", jwtToken) + + duoUserAgent := fmt.Sprintf("duo_universal_golang/%s Golang/%s %s/%s", duoVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH) + + body, err := client._makeHttpRequest(tokenUrl, duoUserAgent, postParams) + if err != nil { + return nil, err + } + + err = json.Unmarshal(body, bodyToken) + if err != nil { + return nil, err + } + if bodyToken.AccessToken == "" || bodyToken.IdToken == "" || + bodyToken.ExpiresIn == 0 || bodyToken.TokenType == "" { + return nil, fmt.Errorf(parameterError) + } + + claimsToVerify := MapClaims{ + "aud": client.clientId, + "iss": fmt.Sprintf(tokenEndpoint, client.apiHost), + "preferred_username": username, + "nonce": nonce, + } + + jwtResponse, err := jwtParseAndValidate(bodyToken.IdToken, client.clientSecret, claimsToVerify) + + if err != nil { + return nil, err + } + + return jwtResponse, nil +} + +const duoPinnedCert string = ` +subject= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Assured ID Root CA +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +subject= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +subject= /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +subject= /C=US/O=SecureTrust Corporation/CN=SecureTrust CA +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +subject= /C=US/O=SecureTrust Corporation/CN=Secure Global CA +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +subject=C = US, O = Amazon, CN = Amazon Root CA 1 +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +subject=C = US, O = Amazon, CN = Amazon Root CA 2 +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- + +subject=C = US, O = Amazon, CN = Amazon Root CA 3 +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +subject=C = US, O = Amazon, CN = Amazon Root CA 4 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +subject=C = BM, O = QuoVadis Limited, CN = QuoVadis Root CA 2 +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE-----` diff --git a/vendor/github.com/duosecurity/duo_universal_golang/duouniversal/duo_jwt.go b/vendor/github.com/duosecurity/duo_universal_golang/duouniversal/duo_jwt.go new file mode 100644 index 00000000..c29550be --- /dev/null +++ b/vendor/github.com/duosecurity/duo_universal_golang/duouniversal/duo_jwt.go @@ -0,0 +1,100 @@ +package duouniversal + +import ( + "encoding/json" + "fmt" + + "github.com/lestrrat-go/jwx/jwa" + "github.com/lestrrat-go/jwx/jwt" +) + +// This file encapsulates all calls to the JWT library. +// To swap to a different library, only this file should need to be changed. + +type MapClaims map[string]interface{} + +const duoSignatureAlgorithm = "HS512" +const audLengthError = "didn't receive exactly 1 aud" + +func jwtCreateSignedToken(claims MapClaims, secret string) (string, error) { + return jwtCreateSignedTokenWithSignature(claims, secret, duoSignatureAlgorithm) +} + +func jwtCreateSignedTokenWithSignature(claims MapClaims, secret string, signature string) (string, error) { + req := jwt.New() + + for key, value := range claims { + req.Set(key, value) + } + + requestJWTSignedBytes, err := jwt.Sign(req, jwa.SignatureAlgorithm(signature), []byte(secret)) + if err != nil { + return "", err + } + + return string(requestJWTSignedBytes), nil +} + +func jwtParseAndValidate(inToken string, secret string, claims MapClaims) (*TokenResponse, error) { + ltoken, err := jwt.ParseString(inToken, jwt.WithVerify(duoSignatureAlgorithm, []byte(secret))) + if err != nil { + return nil, err + } + + validateOptions := []jwt.ValidateOption{} + + validateOptions = append(validateOptions, jwt.WithAcceptableSkew(allowedSkew)) + if str, ok := (claims["aud"]).(string); ok { + validateOptions = append(validateOptions, jwt.WithAudience(str)) + } + if str, ok := (claims["iss"]).(string); ok { + validateOptions = append(validateOptions, jwt.WithIssuer(str)) + } + if str, ok := (claims["preferred_username"]).(string); ok { + validateOptions = append(validateOptions, jwt.WithClaimValue("preferred_username", str)) + } + if str, ok := (claims["nonce"]).(string); ok && str != "" { + validateOptions = append(validateOptions, jwt.WithClaimValue("nonce", str)) + } + + err = jwt.Validate(ltoken, validateOptions...) + if err != nil { + return nil, err + } + // JWX token assumes `aud` is an array of strings. Our token assumes aud is a string. + // Remove 'aud' from a copy of the token to avoid unmarshalling errors + aud := ltoken.Audience() + ltoken.Remove("aud") + + // Convert from the JWX token format to our own token object by taking advantage of json marshalling/unmarshalling + j, err := json.Marshal(ltoken) + if err != nil { + return nil, err + } + token := &TokenResponse{} + err = json.Unmarshal(j, &token) + if err != nil { + return nil, err + } + + // Manually copy back over the aud field + if len(aud) == 1 { + token.Audience = aud[0] + } else { + return nil, fmt.Errorf(audLengthError) + } + + return token, nil +} + +// Parse specific field values out of a token. Useful for testing. +func jwtParseFields(inToken string, secret string, fields []string) MapClaims { + parsedClaims := MapClaims{} + + token, _ := jwt.ParseString(inToken, jwt.WithVerify(duoSignatureAlgorithm, []byte(secret))) + for _, element := range fields { + f, _ := token.Get(element) + parsedClaims[element] = f + } + return parsedClaims +} diff --git a/vendor/github.com/goccy/go-json/.codecov.yml b/vendor/github.com/goccy/go-json/.codecov.yml new file mode 100644 index 00000000..e9813457 --- /dev/null +++ b/vendor/github.com/goccy/go-json/.codecov.yml @@ -0,0 +1,32 @@ +codecov: + require_ci_to_pass: yes + +coverage: + precision: 2 + round: down + range: "70...100" + + status: + project: + default: + target: 70% + threshold: 2% + patch: off + changes: no + +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: no + macro: no + +comment: + layout: "header,diff" + behavior: default + require_changes: no + +ignore: + - internal/encoder/vm_color + - internal/encoder/vm_color_indent diff --git a/vendor/github.com/goccy/go-json/.gitignore b/vendor/github.com/goccy/go-json/.gitignore new file mode 100644 index 00000000..37828382 --- /dev/null +++ b/vendor/github.com/goccy/go-json/.gitignore @@ -0,0 +1,2 @@ +cover.html +cover.out diff --git a/vendor/github.com/goccy/go-json/.golangci.yml b/vendor/github.com/goccy/go-json/.golangci.yml new file mode 100644 index 00000000..44ae40f6 --- /dev/null +++ b/vendor/github.com/goccy/go-json/.golangci.yml @@ -0,0 +1,75 @@ +run: + skip-files: + - encode_optype.go + - ".*_test\\.go$" + +linters-settings: + govet: + enable-all: true + disable: + - shadow + +linters: + enable-all: true + disable: + - dogsled + - dupl + - exhaustive + - exhaustivestruct + - errorlint + - forbidigo + - funlen + - gci + - gochecknoglobals + - gochecknoinits + - gocognit + - gocritic + - gocyclo + - godot + - godox + - goerr113 + - gofumpt + - gomnd + - gosec + - ifshort + - lll + - makezero + - nakedret + - nestif + - nlreturn + - paralleltest + - testpackage + - thelper + - wrapcheck + - interfacer + - lll + - nakedret + - nestif + - nlreturn + - testpackage + - wsl + +issues: + exclude-rules: + # not needed + - path: /*.go + text: "ST1003: should not use underscores in package names" + linters: + - stylecheck + - path: /*.go + text: "don't use an underscore in package name" + linters: + - golint + - path: rtype.go + linters: + - golint + - stylecheck + - path: error.go + linters: + - staticcheck + + # Maximum issues count per one linter. Set to 0 to disable. Default is 50. + max-issues-per-linter: 0 + + # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. + max-same-issues: 0 diff --git a/vendor/github.com/goccy/go-json/CHANGELOG.md b/vendor/github.com/goccy/go-json/CHANGELOG.md new file mode 100644 index 00000000..fd6aa9d6 --- /dev/null +++ b/vendor/github.com/goccy/go-json/CHANGELOG.md @@ -0,0 +1,236 @@ +# v0.7.4 - 2021/07/06 + +* Fix encoding of indirect layout structure ( #264 ) + +# v0.7.3 - 2021/06/29 + +* Fix encoding of pointer type in empty interface ( #262 ) + +# v0.7.2 - 2021/06/26 + +### Fix decoder + +* Add decoder for func type to fix decoding of nil function value ( #257 ) +* Fix stream decoding of []byte type ( #258 ) + +### Performance + +* Improve decoding performance of map[string]interface{} type ( use `mapassign_faststr` ) ( #256 ) +* Improve encoding performance of empty interface type ( remove recursive calling of `vm.Run` ) ( #259 ) + +### Benchmark + +* Add bytedance/sonic as benchmark target ( #254 ) + +# v0.7.1 - 2021/06/18 + +### Fix decoder + +* Fix error when unmarshal empty array ( #253 ) + +# v0.7.0 - 2021/06/12 + +### Support context for MarshalJSON and UnmarshalJSON ( #248 ) + +* json.MarshalContext(context.Context, interface{}, ...json.EncodeOption) ([]byte, error) +* json.NewEncoder(io.Writer).EncodeContext(context.Context, interface{}, ...json.EncodeOption) error +* json.UnmarshalContext(context.Context, []byte, interface{}, ...json.DecodeOption) error +* json.NewDecoder(io.Reader).DecodeContext(context.Context, interface{}) error + +```go +type MarshalerContext interface { + MarshalJSON(context.Context) ([]byte, error) +} + +type UnmarshalerContext interface { + UnmarshalJSON(context.Context, []byte) error +} +``` + +### Add DecodeFieldPriorityFirstWin option ( #242 ) + +In the default behavior, go-json, like encoding/json, will reflect the result of the last evaluation when a field with the same name exists. I've added new options to allow you to change this behavior. `json.DecodeFieldPriorityFirstWin` option reflects the result of the first evaluation if a field with the same name exists. This behavior has a performance advantage as it allows the subsequent strings to be skipped if all fields have been evaluated. + +### Fix encoder + +* Fix indent number contains recursive type ( #249 ) +* Fix encoding of using empty interface as map key ( #244 ) + +### Fix decoder + +* Fix decoding fields containing escaped characters ( #237 ) + +### Refactor + +* Move some tests to subdirectory ( #243 ) +* Refactor package layout for decoder ( #238 ) + +# v0.6.1 - 2021/06/02 + +### Fix encoder + +* Fix value of totalLength for encoding ( #236 ) + +# v0.6.0 - 2021/06/01 + +### Support Colorize option for encoding (#233) + +```go +b, err := json.MarshalWithOption(v, json.Colorize(json.DefaultColorScheme)) +if err != nil { + ... +} +fmt.Println(string(b)) // print colored json +``` + +### Refactor + +* Fix opcode layout - Adjust memory layout of the opcode to 128 bytes in a 64-bit environment ( #230 ) +* Refactor encode option ( #231 ) +* Refactor escape string ( #232 ) + +# v0.5.1 - 2021/5/20 + +### Optimization + +* Add type addrShift to enable bigger encoder/decoder cache ( #213 ) + +### Fix decoder + +* Keep original reference of slice element ( #229 ) + +### Refactor + +* Refactor Debug mode for encoding ( #226 ) +* Generate VM sources for encoding ( #227 ) +* Refactor validator for null/true/false for decoding ( #221 ) + +# v0.5.0 - 2021/5/9 + +### Supports using omitempty and string tags at the same time ( #216 ) + +### Fix decoder + +* Fix stream decoder for unicode char ( #215 ) +* Fix decoding of slice element ( #219 ) +* Fix calculating of buffer length for stream decoder ( #220 ) + +### Refactor + +* replace skipWhiteSpace goto by loop ( #212 ) + +# v0.4.14 - 2021/5/4 + +### Benchmark + +* Add valyala/fastjson to benchmark ( #193 ) +* Add benchmark task for CI ( #211 ) + +### Fix decoder + +* Fix decoding of slice with unmarshal json type ( #198 ) +* Fix decoding of null value for interface type that does not implement Unmarshaler ( #205 ) +* Fix decoding of null value to []byte by json.Unmarshal ( #206 ) +* Fix decoding of backslash char at the end of string ( #207 ) +* Fix stream decoder for null/true/false value ( #208 ) +* Fix stream decoder for slow reader ( #211 ) + +### Performance + +* If cap of slice is enough, reuse slice data for compatibility with encoding/json ( #200 ) + +# v0.4.13 - 2021/4/20 + +### Fix json.Compact and json.Indent + +* Support validation the input buffer for json.Compact and json.Indent ( #189 ) +* Optimize json.Compact and json.Indent ( improve memory footprint ) ( #190 ) + +# v0.4.12 - 2021/4/15 + +### Fix encoder + +* Fix unnecessary indent for empty slice type ( #181 ) +* Fix encoding of omitempty feature for the slice or interface type ( #183 ) +* Fix encoding custom types zero values with omitempty when marshaller exists ( #187 ) + +### Fix decoder + +* Fix decoder for invalid top level value ( #184 ) +* Fix decoder for invalid number value ( #185 ) + +# v0.4.11 - 2021/4/3 + +* Improve decoder performance for interface type + +# v0.4.10 - 2021/4/2 + +### Fix encoder + +* Fixed a bug when encoding slice and map containing recursive structures +* Fixed a logic to determine if indirect reference + +# v0.4.9 - 2021/3/29 + +### Add debug mode + +If you use `json.MarshalWithOption(v, json.Debug())` and `panic` occurred in `go-json`, produces debug information to console. + +### Support a new feature to compatible with encoding/json + +- invalid UTF-8 is coerced to valid UTF-8 ( without performance down ) + +### Fix encoder + +- Fixed handling of MarshalJSON of function type + +### Fix decoding of slice of pointer type + +If there is a pointer value, go-json will use it. (This behavior is necessary to achieve the ability to prioritize pre-filled values). However, since slices are reused internally, there was a bug that referred to the previous pointer value. Therefore, it is not necessary to refer to the pointer value in advance for the slice element, so we explicitly initialize slice element by `nil`. + +# v0.4.8 - 2021/3/21 + +### Reduce memory usage at compile time + +* go-json have used about 2GB of memory at compile time, but now it can compile with about less than 550MB. + +### Fix any encoder's bug + +* Add many test cases for encoder +* Fix composite type ( slice/array/map ) +* Fix pointer types +* Fix encoding of MarshalJSON or MarshalText or json.Number type + +### Refactor encoder + +* Change package layout for reducing memory usage at compile +* Remove anonymous and only operation +* Remove root property from encodeCompileContext and opcode + +### Fix CI + +* Add Go 1.16 +* Remove Go 1.13 +* Fix `make cover` task + +### Number/Delim/Token/RawMessage use the types defined in encoding/json by type alias + +# v0.4.7 - 2021/02/22 + +### Fix decoder + +* Fix decoding of deep recursive structure +* Fix decoding of embedded unexported pointer field +* Fix invalid test case +* Fix decoding of invalid value +* Fix decoding of prefilled value +* Fix not being able to return UnmarshalTypeError when it should be returned +* Fix decoding of null value +* Fix decoding of type of null string +* Use pre allocated pointer if exists it at decoding + +### Reduce memory usage at compile + +* Integrate int/int8/int16/int32/int64 and uint/uint8/uint16/uint32/uint64 operation to reduce memory usage at compile + +### Remove unnecessary optype diff --git a/vendor/github.com/goccy/go-json/LICENSE b/vendor/github.com/goccy/go-json/LICENSE new file mode 100644 index 00000000..6449c8bf --- /dev/null +++ b/vendor/github.com/goccy/go-json/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Masaaki Goshima + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/goccy/go-json/Makefile b/vendor/github.com/goccy/go-json/Makefile new file mode 100644 index 00000000..363563ab --- /dev/null +++ b/vendor/github.com/goccy/go-json/Makefile @@ -0,0 +1,39 @@ +PKG := github.com/goccy/go-json + +BIN_DIR := $(CURDIR)/bin +PKGS := $(shell go list ./... | grep -v internal/cmd|grep -v test) +COVER_PKGS := $(foreach pkg,$(PKGS),$(subst $(PKG),.,$(pkg))) + +COMMA := , +EMPTY := +SPACE := $(EMPTY) $(EMPTY) +COVERPKG_OPT := $(subst $(SPACE),$(COMMA),$(COVER_PKGS)) + +$(BIN_DIR): + @mkdir -p $(BIN_DIR) + +.PHONY: cover +cover: + go test -coverpkg=$(COVERPKG_OPT) -coverprofile=cover.out ./... + +.PHONY: cover-html +cover-html: cover + go tool cover -html=cover.out + +.PHONY: lint +lint: golangci-lint + golangci-lint run + +golangci-lint: | $(BIN_DIR) + @{ \ + set -e; \ + GOLANGCI_LINT_TMP_DIR=$$(mktemp -d); \ + cd $$GOLANGCI_LINT_TMP_DIR; \ + go mod init tmp; \ + GOBIN=$(BIN_DIR) go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.36.0; \ + rm -rf $$GOLANGCI_LINT_TMP_DIR; \ + } + +.PHONY: generate +generate: + go generate ./internal/... diff --git a/vendor/github.com/goccy/go-json/README.md b/vendor/github.com/goccy/go-json/README.md new file mode 100644 index 00000000..418854e5 --- /dev/null +++ b/vendor/github.com/goccy/go-json/README.md @@ -0,0 +1,529 @@ +# go-json + +![Go](https://github.com/goccy/go-json/workflows/Go/badge.svg) +[![GoDoc](https://godoc.org/github.com/goccy/go-json?status.svg)](https://pkg.go.dev/github.com/goccy/go-json?tab=doc) +[![codecov](https://codecov.io/gh/goccy/go-json/branch/master/graph/badge.svg)](https://codecov.io/gh/goccy/go-json) + +Fast JSON encoder/decoder compatible with encoding/json for Go + + + +# Roadmap + +``` +* version ( expected release date ) + +* v0.7.0 + | + | while maintaining compatibility with encoding/json, we will add convenient APIs + | + v +* v1.0.0 +``` + +We are accepting requests for features that will be implemented between v0.7.0 and v.1.0.0. +If you have the API you need, please submit your issue [here](https://github.com/goccy/go-json/issues). +For example, I'm thinking of supporting `context.Context` of `json.Marshaler` and decoding using JSON Path. + +# Features + +- Drop-in replacement of `encoding/json` +- Fast ( See [Benchmark section](https://github.com/goccy/go-json#benchmarks) ) +- Flexible customization with options +- Coloring the encoded string +- Can propagate context.Context to `MarshalJSON` or `UnmarshalJSON` + +# Installation + +``` +go get github.com/goccy/go-json +``` + +# How to use + +Replace import statement from `encoding/json` to `github.com/goccy/go-json` + +``` +-import "encoding/json" ++import "github.com/goccy/go-json" +``` + +# JSON library comparison + +| name | encoder | decoder | compatible with `encoding/json` | +| :----: | :------: | :-----: | :-----------------------------: | +| encoding/json | yes | yes | N/A | +| [json-iterator/go](https://github.com/json-iterator/go) | yes | yes | partial | +| [easyjson](https://github.com/mailru/easyjson) | yes | yes | no | +| [gojay](https://github.com/francoispqt/gojay) | yes | yes | no | +| [segmentio/encoding/json](https://github.com/segmentio/encoding/tree/master/json) | yes | yes | partial | +| [jettison](https://github.com/wI2L/jettison) | yes | no | no | +| [simdjson-go](https://github.com/minio/simdjson-go) | no | yes | no | +| goccy/go-json | yes | yes | yes | + +- `json-iterator/go` isn't compatible with `encoding/json` in many ways (e.g. https://github.com/json-iterator/go/issues/229 ), but it hasn't been supported for a long time. +- `segmentio/encoding/json` is well supported for encoders, but some are not supported for decoder APIs such as `Token` ( streaming decode ) + +## Other libraries + +- [jingo](https://github.com/bet365/jingo) + +I tried the benchmark but it didn't work. +Also, it seems to panic when it receives an unexpected value because there is no error handling... + +- [ffjson](https://github.com/pquerna/ffjson) + +Benchmarking gave very slow results. +It seems that it is assumed that the user will use the buffer pool properly. +Also, development seems to have already stopped + +# Benchmarks + +``` +$ cd benchmarks +$ go test -bench . +``` + +## Encode + + + + +## Decode + + + + + + +# Fuzzing + +[go-json-fuzz](https://github.com/goccy/go-json-fuzz) is the repository for fuzzing tests. +If you run the test in this repository and find a bug, please commit to corpus to go-json-fuzz and report the issue to [go-json](https://github.com/goccy/go-json/issues). + +# How it works + +`go-json` is very fast in both encoding and decoding compared to other libraries. +It's easier to implement by using automatic code generation for performance or by using a dedicated interface, but `go-json` dares to stick to compatibility with `encoding/json` and is the simple interface. Despite this, we are developing with the aim of being the fastest library. + +Here, we explain the various speed-up techniques implemented by `go-json`. + +## Basic technique + +The techniques listed here are the ones used by most of the libraries listed above. + +### Buffer reuse + +Since the only value required for the result of `json.Marshal(interface{}) ([]byte, error)` is `[]byte`, the only value that must be allocated during encoding is the return value `[]byte` . + +Also, as the number of allocations increases, the performance will be affected, so the number of allocations should be kept as low as possible when creating `[]byte`. + +Therefore, there is a technique to reduce the number of times a new buffer must be allocated by reusing the buffer used for the previous encoding by using `sync.Pool`. + +Finally, you allocate a buffer that is as long as the resulting buffer and copy the contents into it, you only need to allocate the buffer once in theory. + +```go +type buffer struct { + data []byte +} + +var bufPool = sync.Pool{ + New: func() interface{} { + return &buffer{data: make([]byte, 0, 1024)} + }, +} + +buf := bufPool.Get().(*buffer) +data := encode(buf.data) // reuse buf.data + +newBuf := make([]byte, len(data)) +copy(newBuf, buf) + +buf.data = data +bufPool.Put(buf) +``` + +### Elimination of reflection + +As you know, the reflection operation is very slow. + +Therefore, using the fact that the address position where the type information is stored is fixed for each binary ( we call this `typeptr` ), +we can use the address in the type information to call a pre-built optimized process. + +For example, you can get the address to the type information from `interface{}` as follows and you can use that information to call a process that does not have reflection. + +To process without reflection, pass a pointer (`unsafe.Pointer`) to the value is stored. + +```go + +type emptyInterface struct { + typ unsafe.Pointer + ptr unsafe.Pointer +} + +var typeToEncoder = map[uintptr]func(unsafe.Pointer)([]byte, error){} + +func Marshal(v interface{}) ([]byte, error) { + iface := (*emptyInterface)(unsafe.Pointer(&v) + typeptr := uintptr(iface.typ) + if enc, exists := typeToEncoder[typeptr]; exists { + return enc(iface.ptr) + } + ... +} +``` + +※ In reality, `typeToEncoder` can be referenced by multiple goroutines, so exclusive control is required. + +## Unique speed-up technique + +## Encoder + +### Do not escape arguments of `Marshal` + +`json.Marshal` and `json.Unmarshal` receive `interface{}` value and they perform type determination dynamically to process. +In normal case, you need to use the `reflect` library to determine the type dynamically, but since `reflect.Type` is defined as `interface`, when you call the method of `reflect.Type`, The reflect's argument is escaped. + +Therefore, the arguments for `Marshal` and `Unmarshal` are always escape to the heap. +However, `go-json` can use the feature of `reflect.Type` while avoiding escaping. + +`reflect.Type` is defined as `interface`, but in reality `reflect.Type` is implemented only by the structure `rtype` defined in the `reflect` package. +For this reason, to date `reflect.Type` is the same as `*reflect.rtype`. + +Therefore, by directly handling `*reflect.rtype`, which is an implementation of `reflect.Type`, it is possible to avoid escaping because it changes from `interface` to using `struct`. + +The technique for working with `*reflect.rtype` directly from `go-json` is implemented at [rtype.go](https://github.com/goccy/go-json/blob/master/internal/runtime/rtype.go) + +Also, the same technique is cut out as a library ( https://github.com/goccy/go-reflect ) + +Initially this feature was the default behavior of `go-json`. +But after careful testing, I found that I passed a large value to `json.Marshal()` and if the argument could not be assigned to the stack, it could not be properly escaped to the heap (a bug in the Go compiler). + +Therefore, this feature will be provided as an **optional** until this issue is resolved. + +To use it, add `NoEscape` like `MarshalNoEscape()` + +### Encoding using opcode sequence + +I explained that you can use `typeptr` to call a pre-built process from type information. + +In other libraries, this dedicated process is processed by making it an function calling like anonymous function, but function calls are inherently slow processes and should be avoided as much as possible. + +Therefore, `go-json` adopted the Instruction-based execution processing system, which is also used to implement virtual machines for programming language. + +If it is the first type to encode, create the opcode ( instruction ) sequence required for encoding. +From the second time onward, use `typeptr` to get the cached pre-built opcode sequence and encode it based on it. An example of the opcode sequence is shown below. + +```go +json.Marshal(struct{ + X int `json:"x"` + Y string `json:"y"` +}{X: 1, Y: "hello"}) +``` + +When encoding a structure like the one above, create a sequence of opcodes like this: + +``` +- opStructFieldHead ( `{` ) +- opStructFieldInt ( `"x": 1,` ) +- opStructFieldString ( `"y": "hello"` ) +- opStructEnd ( `}` ) +- opEnd +``` + +※ When processing each operation, write the letters on the right. + +In addition, each opcode is managed by the following structure ( +Pseudo code ). + +```go +type opType int +const ( + opStructFieldHead opType = iota + opStructFieldInt + opStructFieldStirng + opStructEnd + opEnd +) +type opcode struct { + op opType + key []byte + next *opcode +} +``` + +The process of encoding using the opcode sequence is roughly implemented as follows. + +```go +func encode(code *opcode, b []byte, p unsafe.Pointer) ([]byte, error) { + for { + switch code.op { + case opStructFieldHead: + b = append(b, '{') + code = code.next + case opStructFieldInt: + b = append(b, code.key...) + b = appendInt((*int)(unsafe.Pointer(uintptr(p)+code.offset))) + code = code.next + case opStructFieldString: + b = append(b, code.key...) + b = appendString((*string)(unsafe.Pointer(uintptr(p)+code.offset))) + code = code.next + case opStructEnd: + b = append(b, '}') + code = code.next + case opEnd: + goto END + } + } +END: + return b, nil +} +``` + +In this way, the huge `switch-case` is used to encode by manipulating the linked list opcodes to avoid unnecessary function calls. + +### Opcode sequence optimization + +One of the advantages of encoding using the opcode sequence is the ease of optimization. +The opcode sequence mentioned above is actually converted into the following optimized operations and used. + +``` +- opStructFieldHeadInt ( `{"x": 1,` ) +- opStructEndString ( `"y": "hello"}` ) +- opEnd +``` + +It has been reduced from 5 opcodes to 3 opcodes ! +Reducing the number of opcodees means reducing the number of branches with `switch-case`. +In other words, the closer the number of operations is to 1, the faster the processing can be performed. + +In `go-json`, optimization to reduce the number of opcodes itself like the above and it speeds up by preparing opcodes with optimized paths. + +### Change recursive call from CALL to JMP + +Recursive processing is required during encoding if the type is defined recursively as follows: + +```go +type T struct { + X int + U *U +} + +type U struct { + T *T +} + +b, err := json.Marshal(&T{ + X: 1, + U: &U{ + T: &T{ + X: 2, + }, + }, +}) +fmt.Println(string(b)) // {"X":1,"U":{"T":{"X":2,"U":null}}} +``` + +In `go-json`, recursive processing is processed by the operation type of ` opStructFieldRecursive`. + +In this operation, after acquiring the opcode sequence used for recursive processing, the function is **not** called recursively as it is, but the necessary values ​​are saved by itself and implemented by moving to the next operation. + +The technique of implementing recursive processing with the `JMP` operation while avoiding the `CALL` operation is a famous technique for implementing a high-speed virtual machine. + +For more details, please refer to [the article](https://engineering.mercari.com/blog/entry/1599563768-081104c850) ( but Japanese only ). + +### Dispatch by typeptr from map to slice + +When retrieving the data cached from the type information by `typeptr`, we usually use map. +Map requires exclusive control, so use `sync.Map` for a naive implementation. + +However, this is slow, so it's a good idea to use the `atomic` package for exclusive control as implemented by `segmentio/encoding/json` ( https://github.com/segmentio/encoding/blob/master/json/codec.go#L41-L55 ). + +This implementation slows down the set instead of speeding up the get, but it works well because of the nature of the library, it encodes much more for the same type. + +However, as a result of profiling, I noticed that `runtime.mapaccess2` accounts for a significant percentage of the execution time. So I thought if I could change the lookup from map to slice. + +There is an API named `typelinks` defined in the `runtime` package that the `reflect` package uses internally. +This allows you to get all the type information defined in the binary at runtime. + +The fact that all type information can be acquired means that by constructing slices in advance with the acquired total number of type information, it is possible to look up with the value of `typeptr` without worrying about out-of-range access. + +However, if there is too much type information, it will use a lot of memory, so by default we will only use this optimization if the slice size fits within **2Mib** . + +If this approach is not available, it will fall back to the `atomic` based process described above. + +If you want to know more, please refer to the implementation [here](https://github.com/goccy/go-json/blob/master/internal/runtime/type.go#L36-L100) + +## Decoder + +### Dispatch by typeptr from map to slice + +Like the encoder, the decoder also uses typeptr to call the dedicated process. + +### Faster termination character inspection using NUL character + +In order to decode, you have to traverse the input buffer character by position. +At that time, if you check whether the buffer has reached the end, it will be very slow. + +`buf` : `[]byte` type variable. holds the string passed to the decoder +`cursor` : `int64` type variable. holds the current read position + +```go +buflen := len(buf) +for ; cursor < buflen; cursor++ { // compare cursor and buflen at all times, it is so slow. + switch buf[cursor] { + case ' ', '\n', '\r', '\t': + } +} +``` + +Therefore, by adding the `NUL` (`\000`) character to the end of the read buffer as shown below, it is possible to check the termination character at the same time as other characters. + +```go +for { + switch buf[cursor] { + case ' ', '\n', '\r', '\t': + case '\000': + return nil + } + cursor++ +} +``` + +### Use Boundary Check Elimination + +Due to the `NUL` character optimization, the Go compiler does a boundary check every time, even though `buf[cursor]` does not cause out-of-range access. + +Therefore, `go-json` eliminates boundary check by fetching characters for hotspot by pointer operation. For example, the following code. + +```go +func char(ptr unsafe.Pointer, offset int64) byte { + return *(*byte)(unsafe.Pointer(uintptr(ptr) + uintptr(offset))) +} + +p := (*sliceHeader)(&unsafe.Pointer(buf)).data +for { + switch char(p, cursor) { + case ' ', '\n', '\r', '\t': + case '\000': + return nil + } + cursor++ +} +``` + +### Checking the existence of fields of struct using Bitmaps + +I found by the profiling result, in the struct decode, lookup process for field was taking a long time. + +For example, consider decoding a string like `{"a":1,"b":2,"c":3}` into the following structure: + +```go +type T struct { + A int `json:"a"` + B int `json:"b"` + C int `json:"c"` +} +``` + +At this time, it was found that it takes a lot of time to acquire the decoding process corresponding to the field from the field name as shown below during the decoding process. + +```go +fieldName := decodeKey(buf, cursor) // "a" or "b" or "c" +decoder, exists := fieldToDecoderMap[fieldName] // so slow +if exists { + decoder(buf, cursor) +} else { + skipValue(buf, cursor) +} +``` + +To improve this process, `json-iterator/go` is optimized so that it can be branched by switch-case when the number of fields in the structure is 10 or less (switch-case is faster than map). However, there is a risk of hash collision because the value hashed by the FNV algorithm is used for conditional branching. Also, `gojay` processes this part at high speed by letting the library user yourself write `switch-case`. + + +`go-json` considers and implements a new approach that is different from these. I call this **bitmap field optimization**. + +The range of values ​​per character can be represented by `[256]byte`. Also, if the number of fields in the structure is 8 or less, `int8` type can represent the state of each field. +In other words, it has the following structure. + +- Base ( 8bit ): `00000000` +- Key "a": `00000001` ( assign key "a" to the first bit ) +- Key "b": `00000010` ( assign key "b" to the second bit ) +- Key "c": `00000100` ( assign key "c" to the third bit ) + +Bitmap structure is the following + +``` + | key index(0) | +------------------------ + 0 | 00000000 | + 1 | 00000000 | +~~ | | +97 (a) | 00000001 | +98 (b) | 00000010 | +99 (c) | 00000100 | +~~ | | +255 | 00000000 | +``` + +You can think of this as a Bitmap with a height of `256` and a width of the maximum string length in the field name. +In other words, it can be represented by the following type . + +```go +[maxFieldKeyLength][256]int8 +``` + +When decoding a field character, check whether the corresponding character exists by referring to the pre-built bitmap like the following. + +```go +var curBit int8 = math.MaxInt8 // 11111111 + +c := char(buf, cursor) +bit := bitmap[keyIdx][c] +curBit &= bit +if curBit == 0 { + // not found field +} +``` + +If `curBit` is not `0` until the end of the field string, then the string is +You may have hit one of the fields. +But the possibility is that if the decoded string is shorter than the field string, you will get a false hit. + +- input: `{"a":1}` +```go +type T struct { + X int `json:"abc"` +} +``` +※ Since `a` is shorter than `abc`, it can decode to the end of the field character without `curBit` being 0. + +Rest assured. In this case, it doesn't matter because you can tell if you hit by comparing the string length of `a` with the string length of `abc`. + +Finally, calculate the position of the bit where `1` is set and get the corresponding value, and you're done. + +Using this technique, field lookups are possible with only bitwise operations and access to slices. + +`go-json` uses a similar technique for fields with 9 or more and 16 or less fields. At this time, Bitmap is constructed as `[maxKeyLen][256]int16` type. + +Currently, this optimization is not performed when the maximum length of the field name is long (specifically, 64 bytes or more) in addition to the limitation of the number of fields from the viewpoint of saving memory usage. + +### Others + +I have done a lot of other optimizations. I will find time to write about them. If you have any questions about what's written here or other optimizations, please visit the `#go-json` channel on `gophers.slack.com` . + +## Reference + +Regarding the story of go-json, there are the following articles in Japanese only. + +- https://speakerdeck.com/goccy/zui-su-falsejsonraiburariwoqiu-mete +- https://engineering.mercari.com/blog/entry/1599563768-081104c850/ + +# Looking for Sponsors + +I'm looking for sponsors this library. This library is being developed as a personal project in my spare time. If you want a quick response or problem resolution when using this library in your project, please register as a [sponsor](https://github.com/sponsors/goccy). I will cooperate as much as possible. Of course, this library is developed as an MIT license, so you can use it freely for free. + +# License + +MIT diff --git a/vendor/github.com/goccy/go-json/color.go b/vendor/github.com/goccy/go-json/color.go new file mode 100644 index 00000000..e80b22b4 --- /dev/null +++ b/vendor/github.com/goccy/go-json/color.go @@ -0,0 +1,68 @@ +package json + +import ( + "fmt" + + "github.com/goccy/go-json/internal/encoder" +) + +type ( + ColorFormat = encoder.ColorFormat + ColorScheme = encoder.ColorScheme +) + +const escape = "\x1b" + +type colorAttr int + +//nolint:deadcode,varcheck +const ( + fgBlackColor colorAttr = iota + 30 + fgRedColor + fgGreenColor + fgYellowColor + fgBlueColor + fgMagentaColor + fgCyanColor + fgWhiteColor +) + +//nolint:deadcode,varcheck +const ( + fgHiBlackColor colorAttr = iota + 90 + fgHiRedColor + fgHiGreenColor + fgHiYellowColor + fgHiBlueColor + fgHiMagentaColor + fgHiCyanColor + fgHiWhiteColor +) + +func createColorFormat(attr colorAttr) ColorFormat { + return ColorFormat{ + Header: wrapColor(attr), + Footer: resetColor(), + } +} + +func wrapColor(attr colorAttr) string { + return fmt.Sprintf("%s[%dm", escape, attr) +} + +func resetColor() string { + return wrapColor(colorAttr(0)) +} + +var ( + DefaultColorScheme = &ColorScheme{ + Int: createColorFormat(fgHiMagentaColor), + Uint: createColorFormat(fgHiMagentaColor), + Float: createColorFormat(fgHiMagentaColor), + Bool: createColorFormat(fgHiYellowColor), + String: createColorFormat(fgHiGreenColor), + Binary: createColorFormat(fgHiRedColor), + ObjectKey: createColorFormat(fgHiCyanColor), + Null: createColorFormat(fgBlueColor), + } +) diff --git a/vendor/github.com/goccy/go-json/decode.go b/vendor/github.com/goccy/go-json/decode.go new file mode 100644 index 00000000..d99749d0 --- /dev/null +++ b/vendor/github.com/goccy/go-json/decode.go @@ -0,0 +1,232 @@ +package json + +import ( + "context" + "fmt" + "io" + "reflect" + "unsafe" + + "github.com/goccy/go-json/internal/decoder" + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type Decoder struct { + s *decoder.Stream +} + +const ( + nul = '\000' +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func unmarshal(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { + src := make([]byte, len(data)+1) // append nul byte to the end + copy(src, data) + + header := (*emptyInterface)(unsafe.Pointer(&v)) + + if err := validateType(header.typ, uintptr(header.ptr)); err != nil { + return err + } + dec, err := decoder.CompileToGetDecoder(header.typ) + if err != nil { + return err + } + ctx := decoder.TakeRuntimeContext() + ctx.Buf = src + ctx.Option.Flags = 0 + for _, optFunc := range optFuncs { + optFunc(ctx.Option) + } + cursor, err := dec.Decode(ctx, 0, 0, header.ptr) + if err != nil { + decoder.ReleaseRuntimeContext(ctx) + return err + } + decoder.ReleaseRuntimeContext(ctx) + return validateEndBuf(src, cursor) +} + +func unmarshalContext(ctx context.Context, data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { + src := make([]byte, len(data)+1) // append nul byte to the end + copy(src, data) + + header := (*emptyInterface)(unsafe.Pointer(&v)) + + if err := validateType(header.typ, uintptr(header.ptr)); err != nil { + return err + } + dec, err := decoder.CompileToGetDecoder(header.typ) + if err != nil { + return err + } + rctx := decoder.TakeRuntimeContext() + rctx.Buf = src + rctx.Option.Flags = 0 + rctx.Option.Flags |= decoder.ContextOption + rctx.Option.Context = ctx + for _, optFunc := range optFuncs { + optFunc(rctx.Option) + } + cursor, err := dec.Decode(rctx, 0, 0, header.ptr) + if err != nil { + decoder.ReleaseRuntimeContext(rctx) + return err + } + decoder.ReleaseRuntimeContext(rctx) + return validateEndBuf(src, cursor) +} + +func unmarshalNoEscape(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { + src := make([]byte, len(data)+1) // append nul byte to the end + copy(src, data) + + header := (*emptyInterface)(unsafe.Pointer(&v)) + + if err := validateType(header.typ, uintptr(header.ptr)); err != nil { + return err + } + dec, err := decoder.CompileToGetDecoder(header.typ) + if err != nil { + return err + } + + ctx := decoder.TakeRuntimeContext() + ctx.Buf = src + ctx.Option.Flags = 0 + for _, optFunc := range optFuncs { + optFunc(ctx.Option) + } + cursor, err := dec.Decode(ctx, 0, 0, noescape(header.ptr)) + if err != nil { + decoder.ReleaseRuntimeContext(ctx) + return err + } + decoder.ReleaseRuntimeContext(ctx) + return validateEndBuf(src, cursor) +} + +func validateEndBuf(src []byte, cursor int64) error { + for { + switch src[cursor] { + case ' ', '\t', '\n', '\r': + cursor++ + continue + case nul: + return nil + } + return errors.ErrSyntax( + fmt.Sprintf("invalid character '%c' after top-level value", src[cursor]), + cursor+1, + ) + } +} + +//nolint:staticcheck +//go:nosplit +func noescape(p unsafe.Pointer) unsafe.Pointer { + x := uintptr(p) + return unsafe.Pointer(x ^ 0) +} + +func validateType(typ *runtime.Type, p uintptr) error { + if typ == nil || typ.Kind() != reflect.Ptr || p == 0 { + return &InvalidUnmarshalError{Type: runtime.RType2Type(typ)} + } + return nil +} + +// NewDecoder returns a new decoder that reads from r. +// +// The decoder introduces its own buffering and may +// read data from r beyond the JSON values requested. +func NewDecoder(r io.Reader) *Decoder { + s := decoder.NewStream(r) + return &Decoder{ + s: s, + } +} + +// Buffered returns a reader of the data remaining in the Decoder's +// buffer. The reader is valid until the next call to Decode. +func (d *Decoder) Buffered() io.Reader { + return d.s.Buffered() +} + +// Decode reads the next JSON-encoded value from its +// input and stores it in the value pointed to by v. +// +// See the documentation for Unmarshal for details about +// the conversion of JSON into a Go value. +func (d *Decoder) Decode(v interface{}) error { + return d.DecodeWithOption(v) +} + +// DecodeContext reads the next JSON-encoded value from its +// input and stores it in the value pointed to by v with context.Context. +func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error { + d.s.Option.Flags |= decoder.ContextOption + d.s.Option.Context = ctx + return d.DecodeWithOption(v) +} + +func (d *Decoder) DecodeWithOption(v interface{}, optFuncs ...DecodeOptionFunc) error { + header := (*emptyInterface)(unsafe.Pointer(&v)) + typ := header.typ + ptr := uintptr(header.ptr) + typeptr := uintptr(unsafe.Pointer(typ)) + // noescape trick for header.typ ( reflect.*rtype ) + copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr)) + + if err := validateType(copiedType, ptr); err != nil { + return err + } + + dec, err := decoder.CompileToGetDecoder(typ) + if err != nil { + return err + } + if err := d.s.PrepareForDecode(); err != nil { + return err + } + s := d.s + for _, optFunc := range optFuncs { + optFunc(s.Option) + } + if err := dec.DecodeStream(s, 0, header.ptr); err != nil { + return err + } + s.Reset() + return nil +} + +func (d *Decoder) More() bool { + return d.s.More() +} + +func (d *Decoder) Token() (Token, error) { + return d.s.Token() +} + +// DisallowUnknownFields causes the Decoder to return an error when the destination +// is a struct and the input contains object keys which do not match any +// non-ignored, exported fields in the destination. +func (d *Decoder) DisallowUnknownFields() { + d.s.DisallowUnknownFields = true +} + +func (d *Decoder) InputOffset() int64 { + return d.s.TotalOffset() +} + +// UseNumber causes the Decoder to unmarshal a number into an interface{} as a +// Number instead of as a float64. +func (d *Decoder) UseNumber() { + d.s.UseNumber = true +} diff --git a/vendor/github.com/goccy/go-json/docker-compose.yml b/vendor/github.com/goccy/go-json/docker-compose.yml new file mode 100644 index 00000000..e5106662 --- /dev/null +++ b/vendor/github.com/goccy/go-json/docker-compose.yml @@ -0,0 +1,13 @@ +version: '2' +services: + go-json: + image: golang:1.16 + volumes: + - '.:/go/src/go-json' + deploy: + resources: + limits: + memory: 620M + working_dir: /go/src/go-json + command: | + sh -c "go test -c . && ls go-json.test" diff --git a/vendor/github.com/goccy/go-json/encode.go b/vendor/github.com/goccy/go-json/encode.go new file mode 100644 index 00000000..7f198bdc --- /dev/null +++ b/vendor/github.com/goccy/go-json/encode.go @@ -0,0 +1,323 @@ +package json + +import ( + "context" + "io" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/encoder/vm" + "github.com/goccy/go-json/internal/encoder/vm_color" + "github.com/goccy/go-json/internal/encoder/vm_color_indent" + "github.com/goccy/go-json/internal/encoder/vm_indent" +) + +// An Encoder writes JSON values to an output stream. +type Encoder struct { + w io.Writer + enabledIndent bool + enabledHTMLEscape bool + prefix string + indentStr string +} + +// NewEncoder returns a new encoder that writes to w. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{w: w, enabledHTMLEscape: true} +} + +// Encode writes the JSON encoding of v to the stream, followed by a newline character. +// +// See the documentation for Marshal for details about the conversion of Go values to JSON. +func (e *Encoder) Encode(v interface{}) error { + return e.EncodeWithOption(v) +} + +// EncodeWithOption call Encode with EncodeOption. +func (e *Encoder) EncodeWithOption(v interface{}, optFuncs ...EncodeOptionFunc) error { + ctx := encoder.TakeRuntimeContext() + ctx.Option.Flag = 0 + + err := e.encodeWithOption(ctx, v, optFuncs...) + + encoder.ReleaseRuntimeContext(ctx) + return err +} + +// EncodeContext call Encode with context.Context and EncodeOption. +func (e *Encoder) EncodeContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) error { + rctx := encoder.TakeRuntimeContext() + rctx.Option.Flag = 0 + rctx.Option.Flag |= encoder.ContextOption + rctx.Option.Context = ctx + + err := e.encodeWithOption(rctx, v, optFuncs...) + + encoder.ReleaseRuntimeContext(rctx) + return err +} + +func (e *Encoder) encodeWithOption(ctx *encoder.RuntimeContext, v interface{}, optFuncs ...EncodeOptionFunc) error { + if e.enabledHTMLEscape { + ctx.Option.Flag |= encoder.HTMLEscapeOption + } + for _, optFunc := range optFuncs { + optFunc(ctx.Option) + } + var ( + buf []byte + err error + ) + if e.enabledIndent { + buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr) + } else { + buf, err = encode(ctx, v) + } + if err != nil { + return err + } + if e.enabledIndent { + buf = buf[:len(buf)-2] + } else { + buf = buf[:len(buf)-1] + } + buf = append(buf, '\n') + if _, err := e.w.Write(buf); err != nil { + return err + } + return nil +} + +// SetEscapeHTML specifies whether problematic HTML characters should be escaped inside JSON quoted strings. +// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e to avoid certain safety problems that can arise when embedding JSON in HTML. +// +// In non-HTML settings where the escaping interferes with the readability of the output, SetEscapeHTML(false) disables this behavior. +func (e *Encoder) SetEscapeHTML(on bool) { + e.enabledHTMLEscape = on +} + +// SetIndent instructs the encoder to format each subsequent encoded value as if indented by the package-level function Indent(dst, src, prefix, indent). +// Calling SetIndent("", "") disables indentation. +func (e *Encoder) SetIndent(prefix, indent string) { + if prefix == "" && indent == "" { + e.enabledIndent = false + return + } + e.prefix = prefix + e.indentStr = indent + e.enabledIndent = true +} + +func marshalContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) { + rctx := encoder.TakeRuntimeContext() + rctx.Option.Flag = 0 + rctx.Option.Flag = encoder.HTMLEscapeOption | encoder.ContextOption + rctx.Option.Context = ctx + for _, optFunc := range optFuncs { + optFunc(rctx.Option) + } + + buf, err := encode(rctx, v) + if err != nil { + encoder.ReleaseRuntimeContext(rctx) + return nil, err + } + + // this line exists to escape call of `runtime.makeslicecopy` . + // if use `make([]byte, len(buf)-1)` and `copy(copied, buf)`, + // dst buffer size and src buffer size are differrent. + // in this case, compiler uses `runtime.makeslicecopy`, but it is slow. + buf = buf[:len(buf)-1] + copied := make([]byte, len(buf)) + copy(copied, buf) + + encoder.ReleaseRuntimeContext(rctx) + return copied, nil +} + +func marshal(v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) { + ctx := encoder.TakeRuntimeContext() + + ctx.Option.Flag = 0 + ctx.Option.Flag |= encoder.HTMLEscapeOption + for _, optFunc := range optFuncs { + optFunc(ctx.Option) + } + + buf, err := encode(ctx, v) + if err != nil { + encoder.ReleaseRuntimeContext(ctx) + return nil, err + } + + // this line exists to escape call of `runtime.makeslicecopy` . + // if use `make([]byte, len(buf)-1)` and `copy(copied, buf)`, + // dst buffer size and src buffer size are differrent. + // in this case, compiler uses `runtime.makeslicecopy`, but it is slow. + buf = buf[:len(buf)-1] + copied := make([]byte, len(buf)) + copy(copied, buf) + + encoder.ReleaseRuntimeContext(ctx) + return copied, nil +} + +func marshalNoEscape(v interface{}) ([]byte, error) { + ctx := encoder.TakeRuntimeContext() + + ctx.Option.Flag = 0 + ctx.Option.Flag |= encoder.HTMLEscapeOption + + buf, err := encodeNoEscape(ctx, v) + if err != nil { + encoder.ReleaseRuntimeContext(ctx) + return nil, err + } + + // this line exists to escape call of `runtime.makeslicecopy` . + // if use `make([]byte, len(buf)-1)` and `copy(copied, buf)`, + // dst buffer size and src buffer size are differrent. + // in this case, compiler uses `runtime.makeslicecopy`, but it is slow. + buf = buf[:len(buf)-1] + copied := make([]byte, len(buf)) + copy(copied, buf) + + encoder.ReleaseRuntimeContext(ctx) + return copied, nil +} + +func marshalIndent(v interface{}, prefix, indent string, optFuncs ...EncodeOptionFunc) ([]byte, error) { + ctx := encoder.TakeRuntimeContext() + + ctx.Option.Flag = 0 + ctx.Option.Flag |= (encoder.HTMLEscapeOption | encoder.IndentOption) + for _, optFunc := range optFuncs { + optFunc(ctx.Option) + } + + buf, err := encodeIndent(ctx, v, prefix, indent) + if err != nil { + encoder.ReleaseRuntimeContext(ctx) + return nil, err + } + + buf = buf[:len(buf)-2] + copied := make([]byte, len(buf)) + copy(copied, buf) + + encoder.ReleaseRuntimeContext(ctx) + return copied, nil +} + +func encode(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) { + b := ctx.Buf[:0] + if v == nil { + b = encoder.AppendNull(ctx, b) + b = encoder.AppendComma(ctx, b) + return b, nil + } + header := (*emptyInterface)(unsafe.Pointer(&v)) + typ := header.typ + + typeptr := uintptr(unsafe.Pointer(typ)) + codeSet, err := encoder.CompileToGetCodeSet(typeptr) + if err != nil { + return nil, err + } + + p := uintptr(header.ptr) + ctx.Init(p, codeSet.CodeLength) + ctx.KeepRefs = append(ctx.KeepRefs, header.ptr) + + buf, err := encodeRunCode(ctx, b, codeSet) + if err != nil { + return nil, err + } + ctx.Buf = buf + return buf, nil +} + +func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}) ([]byte, error) { + b := ctx.Buf[:0] + if v == nil { + b = encoder.AppendNull(ctx, b) + b = encoder.AppendComma(ctx, b) + return b, nil + } + header := (*emptyInterface)(unsafe.Pointer(&v)) + typ := header.typ + + typeptr := uintptr(unsafe.Pointer(typ)) + codeSet, err := encoder.CompileToGetCodeSet(typeptr) + if err != nil { + return nil, err + } + + p := uintptr(header.ptr) + ctx.Init(p, codeSet.CodeLength) + buf, err := encodeRunCode(ctx, b, codeSet) + if err != nil { + return nil, err + } + + ctx.Buf = buf + return buf, nil +} + +func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent string) ([]byte, error) { + b := ctx.Buf[:0] + if v == nil { + b = encoder.AppendNull(ctx, b) + b = encoder.AppendCommaIndent(ctx, b) + return b, nil + } + header := (*emptyInterface)(unsafe.Pointer(&v)) + typ := header.typ + + typeptr := uintptr(unsafe.Pointer(typ)) + codeSet, err := encoder.CompileToGetCodeSet(typeptr) + if err != nil { + return nil, err + } + + p := uintptr(header.ptr) + ctx.Init(p, codeSet.CodeLength) + buf, err := encodeRunIndentCode(ctx, b, codeSet, prefix, indent) + + ctx.KeepRefs = append(ctx.KeepRefs, header.ptr) + + if err != nil { + return nil, err + } + + ctx.Buf = buf + return buf, nil +} + +func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { + if (ctx.Option.Flag & encoder.DebugOption) != 0 { + if (ctx.Option.Flag & encoder.ColorizeOption) != 0 { + return vm_color.DebugRun(ctx, b, codeSet) + } + return vm.DebugRun(ctx, b, codeSet) + } + if (ctx.Option.Flag & encoder.ColorizeOption) != 0 { + return vm_color.Run(ctx, b, codeSet) + } + return vm.Run(ctx, b, codeSet) +} + +func encodeRunIndentCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, prefix, indent string) ([]byte, error) { + ctx.Prefix = []byte(prefix) + ctx.IndentStr = []byte(indent) + if (ctx.Option.Flag & encoder.DebugOption) != 0 { + if (ctx.Option.Flag & encoder.ColorizeOption) != 0 { + return vm_color_indent.DebugRun(ctx, b, codeSet) + } + return vm_indent.DebugRun(ctx, b, codeSet) + } + if (ctx.Option.Flag & encoder.ColorizeOption) != 0 { + return vm_color_indent.Run(ctx, b, codeSet) + } + return vm_indent.Run(ctx, b, codeSet) +} diff --git a/vendor/github.com/goccy/go-json/error.go b/vendor/github.com/goccy/go-json/error.go new file mode 100644 index 00000000..94c1339a --- /dev/null +++ b/vendor/github.com/goccy/go-json/error.go @@ -0,0 +1,39 @@ +package json + +import ( + "github.com/goccy/go-json/internal/errors" +) + +// Before Go 1.2, an InvalidUTF8Error was returned by Marshal when +// attempting to encode a string value with invalid UTF-8 sequences. +// As of Go 1.2, Marshal instead coerces the string to valid UTF-8 by +// replacing invalid bytes with the Unicode replacement rune U+FFFD. +// +// Deprecated: No longer used; kept for compatibility. +type InvalidUTF8Error = errors.InvalidUTF8Error + +// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. +// (The argument to Unmarshal must be a non-nil pointer.) +type InvalidUnmarshalError = errors.InvalidUnmarshalError + +// A MarshalerError represents an error from calling a MarshalJSON or MarshalText method. +type MarshalerError = errors.MarshalerError + +// A SyntaxError is a description of a JSON syntax error. +type SyntaxError = errors.SyntaxError + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// +// Deprecated: No longer used; kept for compatibility. +type UnmarshalFieldError = errors.UnmarshalFieldError + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError = errors.UnmarshalTypeError + +// An UnsupportedTypeError is returned by Marshal when attempting +// to encode an unsupported value type. +type UnsupportedTypeError = errors.UnsupportedTypeError + +type UnsupportedValueError = errors.UnsupportedValueError diff --git a/vendor/github.com/goccy/go-json/go.mod b/vendor/github.com/goccy/go-json/go.mod new file mode 100644 index 00000000..58a14881 --- /dev/null +++ b/vendor/github.com/goccy/go-json/go.mod @@ -0,0 +1,3 @@ +module github.com/goccy/go-json + +go 1.12 diff --git a/vendor/github.com/goccy/go-json/go.sum b/vendor/github.com/goccy/go-json/go.sum new file mode 100644 index 00000000..e69de29b diff --git a/vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go b/vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go new file mode 100644 index 00000000..030cb7a9 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go @@ -0,0 +1,37 @@ +package decoder + +import ( + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +type anonymousFieldDecoder struct { + structType *runtime.Type + offset uintptr + dec Decoder +} + +func newAnonymousFieldDecoder(structType *runtime.Type, offset uintptr, dec Decoder) *anonymousFieldDecoder { + return &anonymousFieldDecoder{ + structType: structType, + offset: offset, + dec: dec, + } +} + +func (d *anonymousFieldDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + if *(*unsafe.Pointer)(p) == nil { + *(*unsafe.Pointer)(p) = unsafe_New(d.structType) + } + p = *(*unsafe.Pointer)(p) + return d.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+d.offset)) +} + +func (d *anonymousFieldDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + if *(*unsafe.Pointer)(p) == nil { + *(*unsafe.Pointer)(p) = unsafe_New(d.structType) + } + p = *(*unsafe.Pointer)(p) + return d.dec.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+d.offset)) +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/array.go b/vendor/github.com/goccy/go-json/internal/decoder/array.go new file mode 100644 index 00000000..21f1fd58 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/array.go @@ -0,0 +1,169 @@ +package decoder + +import ( + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type arrayDecoder struct { + elemType *runtime.Type + size uintptr + valueDecoder Decoder + alen int + structName string + fieldName string + zeroValue unsafe.Pointer +} + +func newArrayDecoder(dec Decoder, elemType *runtime.Type, alen int, structName, fieldName string) *arrayDecoder { + zeroValue := *(*unsafe.Pointer)(unsafe_New(elemType)) + return &arrayDecoder{ + valueDecoder: dec, + elemType: elemType, + size: elemType.Size(), + alen: alen, + structName: structName, + fieldName: fieldName, + zeroValue: zeroValue, + } +} + +func (d *arrayDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + depth++ + if depth > maxDecodeNestingDepth { + return errors.ErrExceededMaxDepth(s.char(), s.cursor) + } + + for { + switch s.char() { + case ' ', '\n', '\t', '\r': + case 'n': + if err := nullBytes(s); err != nil { + return err + } + return nil + case '[': + idx := 0 + s.cursor++ + if s.skipWhiteSpace() == ']' { + for idx < d.alen { + *(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue + idx++ + } + s.cursor++ + return nil + } + for { + if idx < d.alen { + if err := d.valueDecoder.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)); err != nil { + return err + } + } else { + if err := s.skipValue(depth); err != nil { + return err + } + } + idx++ + switch s.skipWhiteSpace() { + case ']': + for idx < d.alen { + *(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue + idx++ + } + s.cursor++ + return nil + case ',': + s.cursor++ + continue + case nul: + if s.read() { + s.cursor++ + continue + } + goto ERROR + default: + goto ERROR + } + } + case nul: + if s.read() { + continue + } + goto ERROR + default: + goto ERROR + } + s.cursor++ + } +ERROR: + return errors.ErrUnexpectedEndOfJSON("array", s.totalOffset()) +} + +func (d *arrayDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + depth++ + if depth > maxDecodeNestingDepth { + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + + for { + switch buf[cursor] { + case ' ', '\n', '\t', '\r': + cursor++ + continue + case 'n': + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + return cursor, nil + case '[': + idx := 0 + cursor++ + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == ']' { + for idx < d.alen { + *(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue + idx++ + } + cursor++ + return cursor, nil + } + for { + if idx < d.alen { + c, err := d.valueDecoder.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+uintptr(idx)*d.size)) + if err != nil { + return 0, err + } + cursor = c + } else { + c, err := skipValue(buf, cursor, depth) + if err != nil { + return 0, err + } + cursor = c + } + idx++ + cursor = skipWhiteSpace(buf, cursor) + switch buf[cursor] { + case ']': + for idx < d.alen { + *(*unsafe.Pointer)(unsafe.Pointer(uintptr(p) + uintptr(idx)*d.size)) = d.zeroValue + idx++ + } + cursor++ + return cursor, nil + case ',': + cursor++ + continue + default: + return 0, errors.ErrInvalidCharacter(buf[cursor], "array", cursor) + } + } + default: + return 0, errors.ErrUnexpectedEndOfJSON("array", cursor) + } + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/bool.go b/vendor/github.com/goccy/go-json/internal/decoder/bool.go new file mode 100644 index 00000000..455042a5 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/bool.go @@ -0,0 +1,78 @@ +package decoder + +import ( + "unsafe" + + "github.com/goccy/go-json/internal/errors" +) + +type boolDecoder struct { + structName string + fieldName string +} + +func newBoolDecoder(structName, fieldName string) *boolDecoder { + return &boolDecoder{structName: structName, fieldName: fieldName} +} + +func (d *boolDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + c := s.skipWhiteSpace() + for { + switch c { + case 't': + if err := trueBytes(s); err != nil { + return err + } + **(**bool)(unsafe.Pointer(&p)) = true + return nil + case 'f': + if err := falseBytes(s); err != nil { + return err + } + **(**bool)(unsafe.Pointer(&p)) = false + return nil + case 'n': + if err := nullBytes(s); err != nil { + return err + } + return nil + case nul: + if s.read() { + c = s.char() + continue + } + goto ERROR + } + break + } +ERROR: + return errors.ErrUnexpectedEndOfJSON("bool", s.totalOffset()) +} + +func (d *boolDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + cursor = skipWhiteSpace(buf, cursor) + switch buf[cursor] { + case 't': + if err := validateTrue(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + **(**bool)(unsafe.Pointer(&p)) = true + return cursor, nil + case 'f': + if err := validateFalse(buf, cursor); err != nil { + return 0, err + } + cursor += 5 + **(**bool)(unsafe.Pointer(&p)) = false + return cursor, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + return cursor, nil + } + return 0, errors.ErrUnexpectedEndOfJSON("bool", cursor) +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/bytes.go b/vendor/github.com/goccy/go-json/internal/decoder/bytes.go new file mode 100644 index 00000000..0c4681a1 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/bytes.go @@ -0,0 +1,177 @@ +package decoder + +import ( + "encoding/base64" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type bytesDecoder struct { + typ *runtime.Type + sliceDecoder Decoder + structName string + fieldName string +} + +func byteUnmarshalerSliceDecoder(typ *runtime.Type, structName string, fieldName string) Decoder { + var unmarshalDecoder Decoder + switch { + case runtime.PtrTo(typ).Implements(unmarshalJSONType): + unmarshalDecoder = newUnmarshalJSONDecoder(runtime.PtrTo(typ), structName, fieldName) + case runtime.PtrTo(typ).Implements(unmarshalTextType): + unmarshalDecoder = newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName) + } + if unmarshalDecoder == nil { + return nil + } + return newSliceDecoder(unmarshalDecoder, typ, 1, structName, fieldName) +} + +func newBytesDecoder(typ *runtime.Type, structName string, fieldName string) *bytesDecoder { + return &bytesDecoder{ + typ: typ, + sliceDecoder: byteUnmarshalerSliceDecoder(typ, structName, fieldName), + structName: structName, + fieldName: fieldName, + } +} + +func (d *bytesDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + bytes, err := d.decodeStreamBinary(s, depth, p) + if err != nil { + return err + } + if bytes == nil { + s.reset() + return nil + } + decodedLen := base64.StdEncoding.DecodedLen(len(bytes)) + buf := make([]byte, decodedLen) + n, err := base64.StdEncoding.Decode(buf, bytes) + if err != nil { + return err + } + *(*[]byte)(p) = buf[:n] + s.reset() + return nil +} + +func (d *bytesDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + bytes, c, err := d.decodeBinary(ctx, cursor, depth, p) + if err != nil { + return 0, err + } + if bytes == nil { + return c, nil + } + cursor = c + decodedLen := base64.StdEncoding.DecodedLen(len(bytes)) + b := make([]byte, decodedLen) + n, err := base64.StdEncoding.Decode(b, bytes) + if err != nil { + return 0, err + } + *(*[]byte)(p) = b[:n] + return cursor, nil +} + +func binaryBytes(s *Stream) ([]byte, error) { + s.cursor++ + start := s.cursor + for { + switch s.char() { + case '"': + literal := s.buf[start:s.cursor] + s.cursor++ + return literal, nil + case nul: + if s.read() { + continue + } + goto ERROR + } + s.cursor++ + } +ERROR: + return nil, errors.ErrUnexpectedEndOfJSON("[]byte", s.totalOffset()) +} + +func (d *bytesDecoder) decodeStreamBinary(s *Stream, depth int64, p unsafe.Pointer) ([]byte, error) { + for { + switch s.char() { + case ' ', '\n', '\t', '\r': + s.cursor++ + continue + case '"': + return binaryBytes(s) + case 'n': + if err := nullBytes(s); err != nil { + return nil, err + } + return nil, nil + case '[': + if d.sliceDecoder == nil { + return nil, &errors.UnmarshalTypeError{ + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + } + if err := d.sliceDecoder.DecodeStream(s, depth, p); err != nil { + return nil, err + } + return nil, nil + case nul: + if s.read() { + continue + } + } + break + } + return nil, errors.ErrNotAtBeginningOfValue(s.totalOffset()) +} + +func (d *bytesDecoder) decodeBinary(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) ([]byte, int64, error) { + buf := ctx.Buf + for { + switch buf[cursor] { + case ' ', '\n', '\t', '\r': + cursor++ + case '"': + cursor++ + start := cursor + for { + switch buf[cursor] { + case '"': + literal := buf[start:cursor] + cursor++ + return literal, cursor, nil + case nul: + return nil, 0, errors.ErrUnexpectedEndOfJSON("[]byte", cursor) + } + cursor++ + } + case '[': + if d.sliceDecoder == nil { + return nil, 0, &errors.UnmarshalTypeError{ + Type: runtime.RType2Type(d.typ), + Offset: cursor, + } + } + c, err := d.sliceDecoder.Decode(ctx, cursor, depth, p) + if err != nil { + return nil, 0, err + } + return nil, c, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return nil, cursor, nil + default: + return nil, 0, errors.ErrNotAtBeginningOfValue(cursor) + } + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/compile.go b/vendor/github.com/goccy/go-json/internal/decoder/compile.go new file mode 100644 index 00000000..08dd044e --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/compile.go @@ -0,0 +1,510 @@ +package decoder + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" + "sync/atomic" + "unicode" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +var ( + jsonNumberType = reflect.TypeOf(json.Number("")) + typeAddr *runtime.TypeAddr + cachedDecoderMap unsafe.Pointer // map[uintptr]decoder + cachedDecoder []Decoder +) + +func init() { + typeAddr = runtime.AnalyzeTypeAddr() + if typeAddr == nil { + typeAddr = &runtime.TypeAddr{} + } + cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift) +} + +func loadDecoderMap() map[uintptr]Decoder { + p := atomic.LoadPointer(&cachedDecoderMap) + return *(*map[uintptr]Decoder)(unsafe.Pointer(&p)) +} + +func storeDecoder(typ uintptr, dec Decoder, m map[uintptr]Decoder) { + newDecoderMap := make(map[uintptr]Decoder, len(m)+1) + newDecoderMap[typ] = dec + + for k, v := range m { + newDecoderMap[k] = v + } + + atomic.StorePointer(&cachedDecoderMap, *(*unsafe.Pointer)(unsafe.Pointer(&newDecoderMap))) +} + +func compileToGetDecoderSlowPath(typeptr uintptr, typ *runtime.Type) (Decoder, error) { + decoderMap := loadDecoderMap() + if dec, exists := decoderMap[typeptr]; exists { + return dec, nil + } + + dec, err := compileHead(typ, map[uintptr]Decoder{}) + if err != nil { + return nil, err + } + storeDecoder(typeptr, dec, decoderMap) + return dec, nil +} + +func compileHead(typ *runtime.Type, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { + switch { + case implementsUnmarshalJSONType(runtime.PtrTo(typ)): + return newUnmarshalJSONDecoder(runtime.PtrTo(typ), "", ""), nil + case runtime.PtrTo(typ).Implements(unmarshalTextType): + return newUnmarshalTextDecoder(runtime.PtrTo(typ), "", ""), nil + } + return compile(typ.Elem(), "", "", structTypeToDecoder) +} + +func compile(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { + switch { + case implementsUnmarshalJSONType(runtime.PtrTo(typ)): + return newUnmarshalJSONDecoder(runtime.PtrTo(typ), structName, fieldName), nil + case runtime.PtrTo(typ).Implements(unmarshalTextType): + return newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName), nil + } + + switch typ.Kind() { + case reflect.Ptr: + return compilePtr(typ, structName, fieldName, structTypeToDecoder) + case reflect.Struct: + return compileStruct(typ, structName, fieldName, structTypeToDecoder) + case reflect.Slice: + elem := typ.Elem() + if elem.Kind() == reflect.Uint8 { + return compileBytes(elem, structName, fieldName) + } + return compileSlice(typ, structName, fieldName, structTypeToDecoder) + case reflect.Array: + return compileArray(typ, structName, fieldName, structTypeToDecoder) + case reflect.Map: + return compileMap(typ, structName, fieldName, structTypeToDecoder) + case reflect.Interface: + return compileInterface(typ, structName, fieldName) + case reflect.Uintptr: + return compileUint(typ, structName, fieldName) + case reflect.Int: + return compileInt(typ, structName, fieldName) + case reflect.Int8: + return compileInt8(typ, structName, fieldName) + case reflect.Int16: + return compileInt16(typ, structName, fieldName) + case reflect.Int32: + return compileInt32(typ, structName, fieldName) + case reflect.Int64: + return compileInt64(typ, structName, fieldName) + case reflect.Uint: + return compileUint(typ, structName, fieldName) + case reflect.Uint8: + return compileUint8(typ, structName, fieldName) + case reflect.Uint16: + return compileUint16(typ, structName, fieldName) + case reflect.Uint32: + return compileUint32(typ, structName, fieldName) + case reflect.Uint64: + return compileUint64(typ, structName, fieldName) + case reflect.String: + return compileString(typ, structName, fieldName) + case reflect.Bool: + return compileBool(structName, fieldName) + case reflect.Float32: + return compileFloat32(structName, fieldName) + case reflect.Float64: + return compileFloat64(structName, fieldName) + case reflect.Func: + return compileFunc(typ, structName, fieldName) + } + return nil, &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(typ), + Offset: 0, + Struct: structName, + Field: fieldName, + } +} + +func isStringTagSupportedType(typ *runtime.Type) bool { + switch { + case implementsUnmarshalJSONType(runtime.PtrTo(typ)): + return false + case runtime.PtrTo(typ).Implements(unmarshalTextType): + return false + } + switch typ.Kind() { + case reflect.Map: + return false + case reflect.Slice: + return false + case reflect.Array: + return false + case reflect.Struct: + return false + case reflect.Interface: + return false + } + return true +} + +func compileMapKey(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { + if runtime.PtrTo(typ).Implements(unmarshalTextType) { + return newUnmarshalTextDecoder(runtime.PtrTo(typ), structName, fieldName), nil + } + dec, err := compile(typ, structName, fieldName, structTypeToDecoder) + if err != nil { + return nil, err + } + for { + switch t := dec.(type) { + case *stringDecoder, *interfaceDecoder: + return dec, nil + case *boolDecoder, *intDecoder, *uintDecoder, *numberDecoder: + return newWrappedStringDecoder(typ, dec, structName, fieldName), nil + case *ptrDecoder: + dec = t.dec + default: + goto ERROR + } + } +ERROR: + return nil, &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(typ), + Offset: 0, + Struct: structName, + Field: fieldName, + } +} + +func compilePtr(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { + dec, err := compile(typ.Elem(), structName, fieldName, structTypeToDecoder) + if err != nil { + return nil, err + } + return newPtrDecoder(dec, typ.Elem(), structName, fieldName), nil +} + +func compileInt(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { + *(*int)(p) = int(v) + }), nil +} + +func compileInt8(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { + *(*int8)(p) = int8(v) + }), nil +} + +func compileInt16(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { + *(*int16)(p) = int16(v) + }), nil +} + +func compileInt32(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { + *(*int32)(p) = int32(v) + }), nil +} + +func compileInt64(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newIntDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v int64) { + *(*int64)(p) = v + }), nil +} + +func compileUint(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { + *(*uint)(p) = uint(v) + }), nil +} + +func compileUint8(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { + *(*uint8)(p) = uint8(v) + }), nil +} + +func compileUint16(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { + *(*uint16)(p) = uint16(v) + }), nil +} + +func compileUint32(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { + *(*uint32)(p) = uint32(v) + }), nil +} + +func compileUint64(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newUintDecoder(typ, structName, fieldName, func(p unsafe.Pointer, v uint64) { + *(*uint64)(p) = v + }), nil +} + +func compileFloat32(structName, fieldName string) (Decoder, error) { + return newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { + *(*float32)(p) = float32(v) + }), nil +} + +func compileFloat64(structName, fieldName string) (Decoder, error) { + return newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { + *(*float64)(p) = v + }), nil +} + +func compileString(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + if typ == runtime.Type2RType(jsonNumberType) { + return newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) { + *(*json.Number)(p) = v + }), nil + } + return newStringDecoder(structName, fieldName), nil +} + +func compileBool(structName, fieldName string) (Decoder, error) { + return newBoolDecoder(structName, fieldName), nil +} + +func compileBytes(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newBytesDecoder(typ, structName, fieldName), nil +} + +func compileSlice(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { + elem := typ.Elem() + decoder, err := compile(elem, structName, fieldName, structTypeToDecoder) + if err != nil { + return nil, err + } + return newSliceDecoder(decoder, elem, elem.Size(), structName, fieldName), nil +} + +func compileArray(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { + elem := typ.Elem() + decoder, err := compile(elem, structName, fieldName, structTypeToDecoder) + if err != nil { + return nil, err + } + return newArrayDecoder(decoder, elem, typ.Len(), structName, fieldName), nil +} + +func compileMap(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { + keyDec, err := compileMapKey(typ.Key(), structName, fieldName, structTypeToDecoder) + if err != nil { + return nil, err + } + valueDec, err := compile(typ.Elem(), structName, fieldName, structTypeToDecoder) + if err != nil { + return nil, err + } + return newMapDecoder(typ, typ.Key(), keyDec, typ.Elem(), valueDec, structName, fieldName), nil +} + +func compileInterface(typ *runtime.Type, structName, fieldName string) (Decoder, error) { + return newInterfaceDecoder(typ, structName, fieldName), nil +} + +func compileFunc(typ *runtime.Type, strutName, fieldName string) (Decoder, error) { + return newFuncDecoder(typ, strutName, fieldName), nil +} + +func removeConflictFields(fieldMap map[string]*structFieldSet, conflictedMap map[string]struct{}, dec *structDecoder, field reflect.StructField) { + for k, v := range dec.fieldMap { + if _, exists := conflictedMap[k]; exists { + // already conflicted key + continue + } + set, exists := fieldMap[k] + if !exists { + fieldSet := &structFieldSet{ + dec: v.dec, + offset: field.Offset + v.offset, + isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), + } + fieldMap[k] = fieldSet + lower := strings.ToLower(k) + if _, exists := fieldMap[lower]; !exists { + fieldMap[lower] = fieldSet + } + continue + } + if set.isTaggedKey { + if v.isTaggedKey { + // conflict tag key + delete(fieldMap, k) + delete(fieldMap, strings.ToLower(k)) + conflictedMap[k] = struct{}{} + conflictedMap[strings.ToLower(k)] = struct{}{} + } + } else { + if v.isTaggedKey { + fieldSet := &structFieldSet{ + dec: v.dec, + offset: field.Offset + v.offset, + isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), + } + fieldMap[k] = fieldSet + lower := strings.ToLower(k) + if _, exists := fieldMap[lower]; !exists { + fieldMap[lower] = fieldSet + } + } else { + // conflict tag key + delete(fieldMap, k) + delete(fieldMap, strings.ToLower(k)) + conflictedMap[k] = struct{}{} + conflictedMap[strings.ToLower(k)] = struct{}{} + } + } + } +} + +func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { + fieldNum := typ.NumField() + conflictedMap := map[string]struct{}{} + fieldMap := map[string]*structFieldSet{} + typeptr := uintptr(unsafe.Pointer(typ)) + if dec, exists := structTypeToDecoder[typeptr]; exists { + return dec, nil + } + structDec := newStructDecoder(structName, fieldName, fieldMap) + structTypeToDecoder[typeptr] = structDec + structName = typ.Name() + for i := 0; i < fieldNum; i++ { + field := typ.Field(i) + if runtime.IsIgnoredStructField(field) { + continue + } + isUnexportedField := unicode.IsLower([]rune(field.Name)[0]) + tag := runtime.StructTagFromField(field) + dec, err := compile(runtime.Type2RType(field.Type), structName, field.Name, structTypeToDecoder) + if err != nil { + return nil, err + } + if field.Anonymous && !tag.IsTaggedKey { + if stDec, ok := dec.(*structDecoder); ok { + if runtime.Type2RType(field.Type) == typ { + // recursive definition + continue + } + removeConflictFields(fieldMap, conflictedMap, stDec, field) + } else if pdec, ok := dec.(*ptrDecoder); ok { + contentDec := pdec.contentDecoder() + if pdec.typ == typ { + // recursive definition + continue + } + var fieldSetErr error + if isUnexportedField { + fieldSetErr = fmt.Errorf( + "json: cannot set embedded pointer to unexported struct: %v", + field.Type.Elem(), + ) + } + if dec, ok := contentDec.(*structDecoder); ok { + for k, v := range dec.fieldMap { + if _, exists := conflictedMap[k]; exists { + // already conflicted key + continue + } + set, exists := fieldMap[k] + if !exists { + fieldSet := &structFieldSet{ + dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec), + offset: field.Offset, + isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), + err: fieldSetErr, + } + fieldMap[k] = fieldSet + lower := strings.ToLower(k) + if _, exists := fieldMap[lower]; !exists { + fieldMap[lower] = fieldSet + } + continue + } + if set.isTaggedKey { + if v.isTaggedKey { + // conflict tag key + delete(fieldMap, k) + delete(fieldMap, strings.ToLower(k)) + conflictedMap[k] = struct{}{} + conflictedMap[strings.ToLower(k)] = struct{}{} + } + } else { + if v.isTaggedKey { + fieldSet := &structFieldSet{ + dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec), + offset: field.Offset, + isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), + err: fieldSetErr, + } + fieldMap[k] = fieldSet + lower := strings.ToLower(k) + if _, exists := fieldMap[lower]; !exists { + fieldMap[lower] = fieldSet + } + } else { + // conflict tag key + delete(fieldMap, k) + delete(fieldMap, strings.ToLower(k)) + conflictedMap[k] = struct{}{} + conflictedMap[strings.ToLower(k)] = struct{}{} + } + } + } + } + } + } else { + if tag.IsString && isStringTagSupportedType(runtime.Type2RType(field.Type)) { + dec = newWrappedStringDecoder(runtime.Type2RType(field.Type), dec, structName, field.Name) + } + var key string + if tag.Key != "" { + key = tag.Key + } else { + key = field.Name + } + fieldSet := &structFieldSet{ + dec: dec, + offset: field.Offset, + isTaggedKey: tag.IsTaggedKey, + key: key, + keyLen: int64(len(key)), + } + fieldMap[key] = fieldSet + lower := strings.ToLower(key) + if _, exists := fieldMap[lower]; !exists { + fieldMap[lower] = fieldSet + } + } + } + delete(structTypeToDecoder, typeptr) + structDec.tryOptimize() + return structDec, nil +} + +func implementsUnmarshalJSONType(typ *runtime.Type) bool { + return typ.Implements(unmarshalJSONType) || typ.Implements(unmarshalJSONContextType) +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/compile_norace.go b/vendor/github.com/goccy/go-json/internal/decoder/compile_norace.go new file mode 100644 index 00000000..592f6373 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/compile_norace.go @@ -0,0 +1,28 @@ +// +build !race + +package decoder + +import ( + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) { + typeptr := uintptr(unsafe.Pointer(typ)) + if typeptr > typeAddr.MaxTypeAddr { + return compileToGetDecoderSlowPath(typeptr, typ) + } + + index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift + if dec := cachedDecoder[index]; dec != nil { + return dec, nil + } + + dec, err := compileHead(typ, map[uintptr]Decoder{}) + if err != nil { + return nil, err + } + cachedDecoder[index] = dec + return dec, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/compile_race.go b/vendor/github.com/goccy/go-json/internal/decoder/compile_race.go new file mode 100644 index 00000000..b691bc94 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/compile_race.go @@ -0,0 +1,36 @@ +// +build race + +package decoder + +import ( + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +var decMu sync.RWMutex + +func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) { + typeptr := uintptr(unsafe.Pointer(typ)) + if typeptr > typeAddr.MaxTypeAddr { + return compileToGetDecoderSlowPath(typeptr, typ) + } + + index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift + decMu.RLock() + if dec := cachedDecoder[index]; dec != nil { + decMu.RUnlock() + return dec, nil + } + decMu.RUnlock() + + dec, err := compileHead(typ, map[uintptr]Decoder{}) + if err != nil { + return nil, err + } + decMu.Lock() + cachedDecoder[index] = dec + decMu.Unlock() + return dec, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/context.go b/vendor/github.com/goccy/go-json/internal/decoder/context.go new file mode 100644 index 00000000..cb2ffdaf --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/context.go @@ -0,0 +1,254 @@ +package decoder + +import ( + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/errors" +) + +type RuntimeContext struct { + Buf []byte + Option *Option +} + +var ( + runtimeContextPool = sync.Pool{ + New: func() interface{} { + return &RuntimeContext{ + Option: &Option{}, + } + }, + } +) + +func TakeRuntimeContext() *RuntimeContext { + return runtimeContextPool.Get().(*RuntimeContext) +} + +func ReleaseRuntimeContext(ctx *RuntimeContext) { + runtimeContextPool.Put(ctx) +} + +var ( + isWhiteSpace = [256]bool{} +) + +func init() { + isWhiteSpace[' '] = true + isWhiteSpace['\n'] = true + isWhiteSpace['\t'] = true + isWhiteSpace['\r'] = true +} + +func char(ptr unsafe.Pointer, offset int64) byte { + return *(*byte)(unsafe.Pointer(uintptr(ptr) + uintptr(offset))) +} + +func skipWhiteSpace(buf []byte, cursor int64) int64 { + for isWhiteSpace[buf[cursor]] { + cursor++ + } + return cursor +} + +func skipObject(buf []byte, cursor, depth int64) (int64, error) { + braceCount := 1 + for { + switch buf[cursor] { + case '{': + braceCount++ + depth++ + if depth > maxDecodeNestingDepth { + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + case '}': + depth-- + braceCount-- + if braceCount == 0 { + return cursor + 1, nil + } + case '[': + depth++ + if depth > maxDecodeNestingDepth { + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + case ']': + depth-- + case '"': + for { + cursor++ + switch buf[cursor] { + case '\\': + cursor++ + if buf[cursor] == nul { + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + case '"': + goto SWITCH_OUT + case nul: + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + } + case nul: + return 0, errors.ErrUnexpectedEndOfJSON("object of object", cursor) + } + SWITCH_OUT: + cursor++ + } +} + +func skipArray(buf []byte, cursor, depth int64) (int64, error) { + bracketCount := 1 + for { + switch buf[cursor] { + case '[': + bracketCount++ + depth++ + if depth > maxDecodeNestingDepth { + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + case ']': + bracketCount-- + depth-- + if bracketCount == 0 { + return cursor + 1, nil + } + case '{': + depth++ + if depth > maxDecodeNestingDepth { + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + case '}': + depth-- + case '"': + for { + cursor++ + switch buf[cursor] { + case '\\': + cursor++ + if buf[cursor] == nul { + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + case '"': + goto SWITCH_OUT + case nul: + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + } + case nul: + return 0, errors.ErrUnexpectedEndOfJSON("array of object", cursor) + } + SWITCH_OUT: + cursor++ + } +} + +func skipValue(buf []byte, cursor, depth int64) (int64, error) { + for { + switch buf[cursor] { + case ' ', '\t', '\n', '\r': + cursor++ + continue + case '{': + return skipObject(buf, cursor+1, depth+1) + case '[': + return skipArray(buf, cursor+1, depth+1) + case '"': + for { + cursor++ + switch buf[cursor] { + case '\\': + cursor++ + if buf[cursor] == nul { + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + case '"': + return cursor + 1, nil + case nul: + return 0, errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + for { + cursor++ + if floatTable[buf[cursor]] { + continue + } + break + } + return cursor, nil + case 't': + if err := validateTrue(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + return cursor, nil + case 'f': + if err := validateFalse(buf, cursor); err != nil { + return 0, err + } + cursor += 5 + return cursor, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + return cursor, nil + default: + return cursor, errors.ErrUnexpectedEndOfJSON("null", cursor) + } + } +} + +func validateTrue(buf []byte, cursor int64) error { + if cursor+3 >= int64(len(buf)) { + return errors.ErrUnexpectedEndOfJSON("true", cursor) + } + if buf[cursor+1] != 'r' { + return errors.ErrInvalidCharacter(buf[cursor+1], "true", cursor) + } + if buf[cursor+2] != 'u' { + return errors.ErrInvalidCharacter(buf[cursor+2], "true", cursor) + } + if buf[cursor+3] != 'e' { + return errors.ErrInvalidCharacter(buf[cursor+3], "true", cursor) + } + return nil +} + +func validateFalse(buf []byte, cursor int64) error { + if cursor+4 >= int64(len(buf)) { + return errors.ErrUnexpectedEndOfJSON("false", cursor) + } + if buf[cursor+1] != 'a' { + return errors.ErrInvalidCharacter(buf[cursor+1], "false", cursor) + } + if buf[cursor+2] != 'l' { + return errors.ErrInvalidCharacter(buf[cursor+2], "false", cursor) + } + if buf[cursor+3] != 's' { + return errors.ErrInvalidCharacter(buf[cursor+3], "false", cursor) + } + if buf[cursor+4] != 'e' { + return errors.ErrInvalidCharacter(buf[cursor+4], "false", cursor) + } + return nil +} + +func validateNull(buf []byte, cursor int64) error { + if cursor+3 >= int64(len(buf)) { + return errors.ErrUnexpectedEndOfJSON("null", cursor) + } + if buf[cursor+1] != 'u' { + return errors.ErrInvalidCharacter(buf[cursor+1], "null", cursor) + } + if buf[cursor+2] != 'l' { + return errors.ErrInvalidCharacter(buf[cursor+2], "null", cursor) + } + if buf[cursor+3] != 'l' { + return errors.ErrInvalidCharacter(buf[cursor+3], "null", cursor) + } + return nil +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/float.go b/vendor/github.com/goccy/go-json/internal/decoder/float.go new file mode 100644 index 00000000..dfb7168d --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/float.go @@ -0,0 +1,158 @@ +package decoder + +import ( + "strconv" + "unsafe" + + "github.com/goccy/go-json/internal/errors" +) + +type floatDecoder struct { + op func(unsafe.Pointer, float64) + structName string + fieldName string +} + +func newFloatDecoder(structName, fieldName string, op func(unsafe.Pointer, float64)) *floatDecoder { + return &floatDecoder{op: op, structName: structName, fieldName: fieldName} +} + +var ( + floatTable = [256]bool{ + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + '.': true, + 'e': true, + 'E': true, + '+': true, + '-': true, + } + + validEndNumberChar = [256]bool{ + nul: true, + ' ': true, + '\t': true, + '\r': true, + '\n': true, + ',': true, + ':': true, + '}': true, + ']': true, + } +) + +func floatBytes(s *Stream) []byte { + start := s.cursor + for { + s.cursor++ + if floatTable[s.char()] { + continue + } else if s.char() == nul { + if s.read() { + s.cursor-- // for retry current character + continue + } + } + break + } + return s.buf[start:s.cursor] +} + +func (d *floatDecoder) decodeStreamByte(s *Stream) ([]byte, error) { + for { + switch s.char() { + case ' ', '\n', '\t', '\r': + s.cursor++ + continue + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return floatBytes(s), nil + case 'n': + if err := nullBytes(s); err != nil { + return nil, err + } + return nil, nil + case nul: + if s.read() { + continue + } + goto ERROR + default: + goto ERROR + } + } +ERROR: + return nil, errors.ErrUnexpectedEndOfJSON("float", s.totalOffset()) +} + +func (d *floatDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { + for { + switch buf[cursor] { + case ' ', '\n', '\t', '\r': + cursor++ + continue + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + start := cursor + cursor++ + for floatTable[buf[cursor]] { + cursor++ + } + num := buf[start:cursor] + return num, cursor, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return nil, cursor, nil + default: + return nil, 0, errors.ErrUnexpectedEndOfJSON("float", cursor) + } + } +} + +func (d *floatDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + bytes, err := d.decodeStreamByte(s) + if err != nil { + return err + } + if bytes == nil { + return nil + } + str := *(*string)(unsafe.Pointer(&bytes)) + f64, err := strconv.ParseFloat(str, 64) + if err != nil { + return errors.ErrSyntax(err.Error(), s.totalOffset()) + } + d.op(p, f64) + return nil +} + +func (d *floatDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + bytes, c, err := d.decodeByte(buf, cursor) + if err != nil { + return 0, err + } + if bytes == nil { + return c, nil + } + cursor = c + if !validEndNumberChar[buf[cursor]] { + return 0, errors.ErrUnexpectedEndOfJSON("float", cursor) + } + s := *(*string)(unsafe.Pointer(&bytes)) + f64, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0, errors.ErrSyntax(err.Error(), cursor) + } + d.op(p, f64) + return cursor, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/func.go b/vendor/github.com/goccy/go-json/internal/decoder/func.go new file mode 100644 index 00000000..75afe75c --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/func.go @@ -0,0 +1,141 @@ +package decoder + +import ( + "bytes" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type funcDecoder struct { + typ *runtime.Type + structName string + fieldName string +} + +func newFuncDecoder(typ *runtime.Type, structName, fieldName string) *funcDecoder { + fnDecoder := &funcDecoder{typ, structName, fieldName} + return fnDecoder +} + +func (d *funcDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + s.skipWhiteSpace() + start := s.cursor + if err := s.skipValue(depth); err != nil { + return err + } + src := s.buf[start:s.cursor] + if len(src) > 0 { + switch src[0] { + case '"': + return &errors.UnmarshalTypeError{ + Value: "string", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + case '[': + return &errors.UnmarshalTypeError{ + Value: "array", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + case '{': + return &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return &errors.UnmarshalTypeError{ + Value: "number", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + case 'n': + if err := nullBytes(s); err != nil { + return err + } + *(*unsafe.Pointer)(p) = nil + return nil + case 't': + if err := trueBytes(s); err == nil { + return &errors.UnmarshalTypeError{ + Value: "boolean", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + } + case 'f': + if err := falseBytes(s); err == nil { + return &errors.UnmarshalTypeError{ + Value: "boolean", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + } + } + } + return errors.ErrNotAtBeginningOfValue(start) +} + +func (d *funcDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + cursor = skipWhiteSpace(buf, cursor) + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return 0, err + } + src := buf[start:end] + if len(src) > 0 { + switch src[0] { + case '"': + return 0, &errors.UnmarshalTypeError{ + Value: "string", + Type: runtime.RType2Type(d.typ), + Offset: start, + } + case '[': + return 0, &errors.UnmarshalTypeError{ + Value: "array", + Type: runtime.RType2Type(d.typ), + Offset: start, + } + case '{': + return 0, &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(d.typ), + Offset: start, + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return 0, &errors.UnmarshalTypeError{ + Value: "number", + Type: runtime.RType2Type(d.typ), + Offset: start, + } + case 'n': + if bytes.Equal(src, nullbytes) { + *(*unsafe.Pointer)(p) = nil + return end, nil + } + case 't': + if err := validateTrue(buf, start); err == nil { + return 0, &errors.UnmarshalTypeError{ + Value: "boolean", + Type: runtime.RType2Type(d.typ), + Offset: start, + } + } + case 'f': + if err := validateFalse(buf, start); err == nil { + return 0, &errors.UnmarshalTypeError{ + Value: "boolean", + Type: runtime.RType2Type(d.typ), + Offset: start, + } + } + } + } + return 0, errors.ErrNotAtBeginningOfValue(start) +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/int.go b/vendor/github.com/goccy/go-json/internal/decoder/int.go new file mode 100644 index 00000000..7edfb041 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/int.go @@ -0,0 +1,242 @@ +package decoder + +import ( + "fmt" + "reflect" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type intDecoder struct { + typ *runtime.Type + kind reflect.Kind + op func(unsafe.Pointer, int64) + structName string + fieldName string +} + +func newIntDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, int64)) *intDecoder { + return &intDecoder{ + typ: typ, + kind: typ.Kind(), + op: op, + structName: structName, + fieldName: fieldName, + } +} + +func (d *intDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ + Value: fmt.Sprintf("number %s", string(buf)), + Type: runtime.RType2Type(d.typ), + Struct: d.structName, + Field: d.fieldName, + Offset: offset, + } +} + +var ( + pow10i64 = [...]int64{ + 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, + } + pow10i64Len = len(pow10i64) +) + +func (d *intDecoder) parseInt(b []byte) (int64, error) { + isNegative := false + if b[0] == '-' { + b = b[1:] + isNegative = true + } + maxDigit := len(b) + if maxDigit > pow10i64Len { + return 0, fmt.Errorf("invalid length of number") + } + sum := int64(0) + for i := 0; i < maxDigit; i++ { + c := int64(b[i]) - 48 + digitValue := pow10i64[maxDigit-i-1] + sum += c * digitValue + } + if isNegative { + return -1 * sum, nil + } + return sum, nil +} + +var ( + numTable = [256]bool{ + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + } +) + +var ( + numZeroBuf = []byte{'0'} +) + +func (d *intDecoder) decodeStreamByte(s *Stream) ([]byte, error) { + for { + switch s.char() { + case ' ', '\n', '\t', '\r': + s.cursor++ + continue + case '-': + start := s.cursor + for { + s.cursor++ + if numTable[s.char()] { + continue + } else if s.char() == nul { + if s.read() { + s.cursor-- // for retry current character + continue + } + } + break + } + num := s.buf[start:s.cursor] + if len(num) < 2 { + goto ERROR + } + return num, nil + case '0': + s.cursor++ + return numZeroBuf, nil + case '1', '2', '3', '4', '5', '6', '7', '8', '9': + start := s.cursor + for { + s.cursor++ + if numTable[s.char()] { + continue + } else if s.char() == nul { + if s.read() { + s.cursor-- // for retry current character + continue + } + } + break + } + num := s.buf[start:s.cursor] + return num, nil + case 'n': + if err := nullBytes(s); err != nil { + return nil, err + } + return nil, nil + case nul: + if s.read() { + continue + } + goto ERROR + default: + return nil, d.typeError([]byte{s.char()}, s.totalOffset()) + } + } +ERROR: + return nil, errors.ErrUnexpectedEndOfJSON("number(integer)", s.totalOffset()) +} + +func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { + b := (*sliceHeader)(unsafe.Pointer(&buf)).data + for { + switch char(b, cursor) { + case ' ', '\n', '\t', '\r': + cursor++ + continue + case '0': + cursor++ + return numZeroBuf, cursor, nil + case '-', '1', '2', '3', '4', '5', '6', '7', '8', '9': + start := cursor + cursor++ + for numTable[char(b, cursor)] { + cursor++ + } + num := buf[start:cursor] + return num, cursor, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return nil, cursor, nil + default: + return nil, 0, d.typeError([]byte{char(b, cursor)}, cursor) + } + } +} + +func (d *intDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + bytes, err := d.decodeStreamByte(s) + if err != nil { + return err + } + if bytes == nil { + return nil + } + i64, err := d.parseInt(bytes) + if err != nil { + return d.typeError(bytes, s.totalOffset()) + } + switch d.kind { + case reflect.Int8: + if i64 <= -1*(1<<7) || (1<<7) <= i64 { + return d.typeError(bytes, s.totalOffset()) + } + case reflect.Int16: + if i64 <= -1*(1<<15) || (1<<15) <= i64 { + return d.typeError(bytes, s.totalOffset()) + } + case reflect.Int32: + if i64 <= -1*(1<<31) || (1<<31) <= i64 { + return d.typeError(bytes, s.totalOffset()) + } + } + d.op(p, i64) + s.reset() + return nil +} + +func (d *intDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + bytes, c, err := d.decodeByte(ctx.Buf, cursor) + if err != nil { + return 0, err + } + if bytes == nil { + return c, nil + } + cursor = c + + i64, err := d.parseInt(bytes) + if err != nil { + return 0, d.typeError(bytes, cursor) + } + switch d.kind { + case reflect.Int8: + if i64 <= -1*(1<<7) || (1<<7) <= i64 { + return 0, d.typeError(bytes, cursor) + } + case reflect.Int16: + if i64 <= -1*(1<<15) || (1<<15) <= i64 { + return 0, d.typeError(bytes, cursor) + } + case reflect.Int32: + if i64 <= -1*(1<<31) || (1<<31) <= i64 { + return 0, d.typeError(bytes, cursor) + } + } + d.op(p, i64) + return cursor, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/interface.go b/vendor/github.com/goccy/go-json/internal/decoder/interface.go new file mode 100644 index 00000000..ea1b4aa5 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/interface.go @@ -0,0 +1,458 @@ +package decoder + +import ( + "bytes" + "encoding" + "encoding/json" + "reflect" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type interfaceDecoder struct { + typ *runtime.Type + structName string + fieldName string + sliceDecoder *sliceDecoder + mapDecoder *mapDecoder + floatDecoder *floatDecoder + numberDecoder *numberDecoder + stringDecoder *stringDecoder +} + +func newEmptyInterfaceDecoder(structName, fieldName string) *interfaceDecoder { + ifaceDecoder := &interfaceDecoder{ + typ: emptyInterfaceType, + structName: structName, + fieldName: fieldName, + floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { + *(*interface{})(p) = v + }), + numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) { + *(*interface{})(p) = v + }), + stringDecoder: newStringDecoder(structName, fieldName), + } + ifaceDecoder.sliceDecoder = newSliceDecoder( + ifaceDecoder, + emptyInterfaceType, + emptyInterfaceType.Size(), + structName, fieldName, + ) + ifaceDecoder.mapDecoder = newMapDecoder( + interfaceMapType, + stringType, + ifaceDecoder.stringDecoder, + interfaceMapType.Elem(), + ifaceDecoder, + structName, + fieldName, + ) + return ifaceDecoder +} + +func newInterfaceDecoder(typ *runtime.Type, structName, fieldName string) *interfaceDecoder { + emptyIfaceDecoder := newEmptyInterfaceDecoder(structName, fieldName) + stringDecoder := newStringDecoder(structName, fieldName) + return &interfaceDecoder{ + typ: typ, + structName: structName, + fieldName: fieldName, + sliceDecoder: newSliceDecoder( + emptyIfaceDecoder, + emptyInterfaceType, + emptyInterfaceType.Size(), + structName, fieldName, + ), + mapDecoder: newMapDecoder( + interfaceMapType, + stringType, + stringDecoder, + interfaceMapType.Elem(), + emptyIfaceDecoder, + structName, + fieldName, + ), + floatDecoder: newFloatDecoder(structName, fieldName, func(p unsafe.Pointer, v float64) { + *(*interface{})(p) = v + }), + numberDecoder: newNumberDecoder(structName, fieldName, func(p unsafe.Pointer, v json.Number) { + *(*interface{})(p) = v + }), + stringDecoder: stringDecoder, + } +} + +func (d *interfaceDecoder) numDecoder(s *Stream) Decoder { + if s.UseNumber { + return d.numberDecoder + } + return d.floatDecoder +} + +var ( + emptyInterfaceType = runtime.Type2RType(reflect.TypeOf((*interface{})(nil)).Elem()) + interfaceMapType = runtime.Type2RType( + reflect.TypeOf((*map[string]interface{})(nil)).Elem(), + ) + stringType = runtime.Type2RType( + reflect.TypeOf(""), + ) +) + +func decodeStreamUnmarshaler(s *Stream, depth int64, unmarshaler json.Unmarshaler) error { + start := s.cursor + if err := s.skipValue(depth); err != nil { + return err + } + src := s.buf[start:s.cursor] + dst := make([]byte, len(src)) + copy(dst, src) + + if err := unmarshaler.UnmarshalJSON(dst); err != nil { + return err + } + return nil +} + +func decodeStreamUnmarshalerContext(s *Stream, depth int64, unmarshaler unmarshalerContext) error { + start := s.cursor + if err := s.skipValue(depth); err != nil { + return err + } + src := s.buf[start:s.cursor] + dst := make([]byte, len(src)) + copy(dst, src) + + if err := unmarshaler.UnmarshalJSON(s.Option.Context, dst); err != nil { + return err + } + return nil +} + +func decodeUnmarshaler(buf []byte, cursor, depth int64, unmarshaler json.Unmarshaler) (int64, error) { + cursor = skipWhiteSpace(buf, cursor) + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return 0, err + } + src := buf[start:end] + dst := make([]byte, len(src)) + copy(dst, src) + + if err := unmarshaler.UnmarshalJSON(dst); err != nil { + return 0, err + } + return end, nil +} + +func decodeUnmarshalerContext(ctx *RuntimeContext, buf []byte, cursor, depth int64, unmarshaler unmarshalerContext) (int64, error) { + cursor = skipWhiteSpace(buf, cursor) + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return 0, err + } + src := buf[start:end] + dst := make([]byte, len(src)) + copy(dst, src) + + if err := unmarshaler.UnmarshalJSON(ctx.Option.Context, dst); err != nil { + return 0, err + } + return end, nil +} + +func decodeStreamTextUnmarshaler(s *Stream, depth int64, unmarshaler encoding.TextUnmarshaler, p unsafe.Pointer) error { + start := s.cursor + if err := s.skipValue(depth); err != nil { + return err + } + src := s.buf[start:s.cursor] + if bytes.Equal(src, nullbytes) { + *(*unsafe.Pointer)(p) = nil + return nil + } + + dst := make([]byte, len(src)) + copy(dst, src) + + if err := unmarshaler.UnmarshalText(dst); err != nil { + return err + } + return nil +} + +func decodeTextUnmarshaler(buf []byte, cursor, depth int64, unmarshaler encoding.TextUnmarshaler, p unsafe.Pointer) (int64, error) { + cursor = skipWhiteSpace(buf, cursor) + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return 0, err + } + src := buf[start:end] + if bytes.Equal(src, nullbytes) { + *(*unsafe.Pointer)(p) = nil + return end, nil + } + if s, ok := unquoteBytes(src); ok { + src = s + } + if err := unmarshaler.UnmarshalText(src); err != nil { + return 0, err + } + return end, nil +} + +func (d *interfaceDecoder) decodeStreamEmptyInterface(s *Stream, depth int64, p unsafe.Pointer) error { + c := s.skipWhiteSpace() + for { + switch c { + case '{': + var v map[string]interface{} + ptr := unsafe.Pointer(&v) + if err := d.mapDecoder.DecodeStream(s, depth, ptr); err != nil { + return err + } + *(*interface{})(p) = v + return nil + case '[': + var v []interface{} + ptr := unsafe.Pointer(&v) + if err := d.sliceDecoder.DecodeStream(s, depth, ptr); err != nil { + return err + } + *(*interface{})(p) = v + return nil + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return d.numDecoder(s).DecodeStream(s, depth, p) + case '"': + s.cursor++ + start := s.cursor + for { + switch s.char() { + case '\\': + if _, err := decodeEscapeString(s, nil); err != nil { + return err + } + case '"': + literal := s.buf[start:s.cursor] + s.cursor++ + *(*interface{})(p) = string(literal) + return nil + case nul: + if s.read() { + continue + } + return errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) + } + s.cursor++ + } + case 't': + if err := trueBytes(s); err != nil { + return err + } + **(**interface{})(unsafe.Pointer(&p)) = true + return nil + case 'f': + if err := falseBytes(s); err != nil { + return err + } + **(**interface{})(unsafe.Pointer(&p)) = false + return nil + case 'n': + if err := nullBytes(s); err != nil { + return err + } + *(*interface{})(p) = nil + return nil + case nul: + if s.read() { + c = s.char() + continue + } + } + break + } + return errors.ErrNotAtBeginningOfValue(s.totalOffset()) +} + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func (d *interfaceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: d.typ, + ptr: p, + })) + rv := reflect.ValueOf(runtimeInterfaceValue) + if rv.NumMethod() > 0 && rv.CanInterface() { + if u, ok := rv.Interface().(unmarshalerContext); ok { + return decodeStreamUnmarshalerContext(s, depth, u) + } + if u, ok := rv.Interface().(json.Unmarshaler); ok { + return decodeStreamUnmarshaler(s, depth, u) + } + if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok { + return decodeStreamTextUnmarshaler(s, depth, u, p) + } + if s.skipWhiteSpace() == 'n' { + if err := nullBytes(s); err != nil { + return err + } + *(*interface{})(p) = nil + return nil + } + return d.errUnmarshalType(rv.Type(), s.totalOffset()) + } + iface := rv.Interface() + ifaceHeader := (*emptyInterface)(unsafe.Pointer(&iface)) + typ := ifaceHeader.typ + if ifaceHeader.ptr == nil || d.typ == typ || typ == nil { + // concrete type is empty interface + return d.decodeStreamEmptyInterface(s, depth, p) + } + if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr { + return d.decodeStreamEmptyInterface(s, depth, p) + } + if s.skipWhiteSpace() == 'n' { + if err := nullBytes(s); err != nil { + return err + } + *(*interface{})(p) = nil + return nil + } + decoder, err := CompileToGetDecoder(typ) + if err != nil { + return err + } + return decoder.DecodeStream(s, depth, ifaceHeader.ptr) +} + +func (d *interfaceDecoder) errUnmarshalType(typ reflect.Type, offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ + Value: typ.String(), + Type: typ, + Offset: offset, + Struct: d.structName, + Field: d.fieldName, + } +} + +func (d *interfaceDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + runtimeInterfaceValue := *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: d.typ, + ptr: p, + })) + rv := reflect.ValueOf(runtimeInterfaceValue) + if rv.NumMethod() > 0 && rv.CanInterface() { + if u, ok := rv.Interface().(unmarshalerContext); ok { + return decodeUnmarshalerContext(ctx, buf, cursor, depth, u) + } + if u, ok := rv.Interface().(json.Unmarshaler); ok { + return decodeUnmarshaler(buf, cursor, depth, u) + } + if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok { + return decodeTextUnmarshaler(buf, cursor, depth, u, p) + } + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == 'n' { + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + **(**interface{})(unsafe.Pointer(&p)) = nil + return cursor, nil + } + return 0, d.errUnmarshalType(rv.Type(), cursor) + } + + iface := rv.Interface() + ifaceHeader := (*emptyInterface)(unsafe.Pointer(&iface)) + typ := ifaceHeader.typ + if ifaceHeader.ptr == nil || d.typ == typ || typ == nil { + // concrete type is empty interface + return d.decodeEmptyInterface(ctx, cursor, depth, p) + } + if typ.Kind() == reflect.Ptr && typ.Elem() == d.typ || typ.Kind() != reflect.Ptr { + return d.decodeEmptyInterface(ctx, cursor, depth, p) + } + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == 'n' { + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + **(**interface{})(unsafe.Pointer(&p)) = nil + return cursor, nil + } + decoder, err := CompileToGetDecoder(typ) + if err != nil { + return 0, err + } + return decoder.Decode(ctx, cursor, depth, ifaceHeader.ptr) +} + +func (d *interfaceDecoder) decodeEmptyInterface(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + cursor = skipWhiteSpace(buf, cursor) + switch buf[cursor] { + case '{': + var v map[string]interface{} + ptr := unsafe.Pointer(&v) + cursor, err := d.mapDecoder.Decode(ctx, cursor, depth, ptr) + if err != nil { + return 0, err + } + **(**interface{})(unsafe.Pointer(&p)) = v + return cursor, nil + case '[': + var v []interface{} + ptr := unsafe.Pointer(&v) + cursor, err := d.sliceDecoder.Decode(ctx, cursor, depth, ptr) + if err != nil { + return 0, err + } + **(**interface{})(unsafe.Pointer(&p)) = v + return cursor, nil + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return d.floatDecoder.Decode(ctx, cursor, depth, p) + case '"': + var v string + ptr := unsafe.Pointer(&v) + cursor, err := d.stringDecoder.Decode(ctx, cursor, depth, ptr) + if err != nil { + return 0, err + } + **(**interface{})(unsafe.Pointer(&p)) = v + return cursor, nil + case 't': + if err := validateTrue(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + **(**interface{})(unsafe.Pointer(&p)) = true + return cursor, nil + case 'f': + if err := validateFalse(buf, cursor); err != nil { + return 0, err + } + cursor += 5 + **(**interface{})(unsafe.Pointer(&p)) = false + return cursor, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + **(**interface{})(unsafe.Pointer(&p)) = nil + return cursor, nil + } + return cursor, errors.ErrNotAtBeginningOfValue(cursor) +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/map.go b/vendor/github.com/goccy/go-json/internal/decoder/map.go new file mode 100644 index 00000000..dd480e16 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/map.go @@ -0,0 +1,173 @@ +package decoder + +import ( + "reflect" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type mapDecoder struct { + mapType *runtime.Type + keyType *runtime.Type + valueType *runtime.Type + stringKeyType bool + keyDecoder Decoder + valueDecoder Decoder + structName string + fieldName string +} + +func newMapDecoder(mapType *runtime.Type, keyType *runtime.Type, keyDec Decoder, valueType *runtime.Type, valueDec Decoder, structName, fieldName string) *mapDecoder { + return &mapDecoder{ + mapType: mapType, + keyDecoder: keyDec, + keyType: keyType, + stringKeyType: keyType.Kind() == reflect.String, + valueType: valueType, + valueDecoder: valueDec, + structName: structName, + fieldName: fieldName, + } +} + +//go:linkname makemap reflect.makemap +func makemap(*runtime.Type, int) unsafe.Pointer + +//nolint:golint +//go:linkname mapassign_faststr runtime.mapassign_faststr +//go:noescape +func mapassign_faststr(t *runtime.Type, m unsafe.Pointer, s string) unsafe.Pointer + +//go:linkname mapassign reflect.mapassign +//go:noescape +func mapassign(t *runtime.Type, m unsafe.Pointer, k, v unsafe.Pointer) + +func (d *mapDecoder) mapassign(t *runtime.Type, m, k, v unsafe.Pointer) { + if d.stringKeyType { + mapV := mapassign_faststr(d.mapType, m, *(*string)(k)) + typedmemmove(d.valueType, mapV, v) + } else { + mapassign(t, m, k, v) + } +} + +func (d *mapDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + depth++ + if depth > maxDecodeNestingDepth { + return errors.ErrExceededMaxDepth(s.char(), s.cursor) + } + + switch s.skipWhiteSpace() { + case 'n': + if err := nullBytes(s); err != nil { + return err + } + **(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil + return nil + case '{': + default: + return errors.ErrExpected("{ character for map value", s.totalOffset()) + } + mapValue := *(*unsafe.Pointer)(p) + if mapValue == nil { + mapValue = makemap(d.mapType, 0) + } + if s.buf[s.cursor+1] == '}' { + *(*unsafe.Pointer)(p) = mapValue + s.cursor += 2 + return nil + } + for { + s.cursor++ + k := unsafe_New(d.keyType) + if err := d.keyDecoder.DecodeStream(s, depth, k); err != nil { + return err + } + s.skipWhiteSpace() + if !s.equalChar(':') { + return errors.ErrExpected("colon after object key", s.totalOffset()) + } + s.cursor++ + v := unsafe_New(d.valueType) + if err := d.valueDecoder.DecodeStream(s, depth, v); err != nil { + return err + } + d.mapassign(d.mapType, mapValue, k, v) + s.skipWhiteSpace() + if s.equalChar('}') { + **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue + s.cursor++ + return nil + } + if !s.equalChar(',') { + return errors.ErrExpected("comma after object value", s.totalOffset()) + } + } +} + +func (d *mapDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + depth++ + if depth > maxDecodeNestingDepth { + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + + cursor = skipWhiteSpace(buf, cursor) + buflen := int64(len(buf)) + if buflen < 2 { + return 0, errors.ErrExpected("{} for map", cursor) + } + switch buf[cursor] { + case 'n': + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + **(**unsafe.Pointer)(unsafe.Pointer(&p)) = nil + return cursor, nil + case '{': + default: + return 0, errors.ErrExpected("{ character for map value", cursor) + } + cursor++ + cursor = skipWhiteSpace(buf, cursor) + mapValue := *(*unsafe.Pointer)(p) + if mapValue == nil { + mapValue = makemap(d.mapType, 0) + } + if buf[cursor] == '}' { + **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue + cursor++ + return cursor, nil + } + for { + k := unsafe_New(d.keyType) + keyCursor, err := d.keyDecoder.Decode(ctx, cursor, depth, k) + if err != nil { + return 0, err + } + cursor = skipWhiteSpace(buf, keyCursor) + if buf[cursor] != ':' { + return 0, errors.ErrExpected("colon after object key", cursor) + } + cursor++ + v := unsafe_New(d.valueType) + valueCursor, err := d.valueDecoder.Decode(ctx, cursor, depth, v) + if err != nil { + return 0, err + } + d.mapassign(d.mapType, mapValue, k, v) + cursor = skipWhiteSpace(buf, valueCursor) + if buf[cursor] == '}' { + **(**unsafe.Pointer)(unsafe.Pointer(&p)) = mapValue + cursor++ + return cursor, nil + } + if buf[cursor] != ',' { + return 0, errors.ErrExpected("comma after object value", cursor) + } + cursor++ + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/number.go b/vendor/github.com/goccy/go-json/internal/decoder/number.go new file mode 100644 index 00000000..c50d62b9 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/number.go @@ -0,0 +1,108 @@ +package decoder + +import ( + "encoding/json" + "strconv" + "unsafe" + + "github.com/goccy/go-json/internal/errors" +) + +type numberDecoder struct { + stringDecoder *stringDecoder + op func(unsafe.Pointer, json.Number) + structName string + fieldName string +} + +func newNumberDecoder(structName, fieldName string, op func(unsafe.Pointer, json.Number)) *numberDecoder { + return &numberDecoder{ + stringDecoder: newStringDecoder(structName, fieldName), + op: op, + structName: structName, + fieldName: fieldName, + } +} + +func (d *numberDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + bytes, err := d.decodeStreamByte(s) + if err != nil { + return err + } + if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil { + return errors.ErrSyntax(err.Error(), s.totalOffset()) + } + d.op(p, json.Number(string(bytes))) + s.reset() + return nil +} + +func (d *numberDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + bytes, c, err := d.decodeByte(ctx.Buf, cursor) + if err != nil { + return 0, err + } + if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&bytes)), 64); err != nil { + return 0, errors.ErrSyntax(err.Error(), c) + } + cursor = c + s := *(*string)(unsafe.Pointer(&bytes)) + d.op(p, json.Number(s)) + return cursor, nil +} + +func (d *numberDecoder) decodeStreamByte(s *Stream) ([]byte, error) { + for { + switch s.char() { + case ' ', '\n', '\t', '\r': + s.cursor++ + continue + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return floatBytes(s), nil + case 'n': + if err := nullBytes(s); err != nil { + return nil, err + } + return nil, nil + case '"': + return d.stringDecoder.decodeStreamByte(s) + case nul: + if s.read() { + continue + } + goto ERROR + default: + goto ERROR + } + } +ERROR: + return nil, errors.ErrUnexpectedEndOfJSON("json.Number", s.totalOffset()) +} + +func (d *numberDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { + for { + switch buf[cursor] { + case ' ', '\n', '\t', '\r': + cursor++ + continue + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + start := cursor + cursor++ + for floatTable[buf[cursor]] { + cursor++ + } + num := buf[start:cursor] + return num, cursor, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return nil, cursor, nil + case '"': + return d.stringDecoder.decodeByte(buf, cursor) + default: + return nil, 0, errors.ErrUnexpectedEndOfJSON("json.Number", cursor) + } + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/option.go b/vendor/github.com/goccy/go-json/internal/decoder/option.go new file mode 100644 index 00000000..e41f876b --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/option.go @@ -0,0 +1,15 @@ +package decoder + +import "context" + +type OptionFlags uint8 + +const ( + FirstWinOption OptionFlags = 1 << iota + ContextOption +) + +type Option struct { + Flags OptionFlags + Context context.Context +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/ptr.go b/vendor/github.com/goccy/go-json/internal/decoder/ptr.go new file mode 100644 index 00000000..2c83b9c4 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/ptr.go @@ -0,0 +1,87 @@ +package decoder + +import ( + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +type ptrDecoder struct { + dec Decoder + typ *runtime.Type + structName string + fieldName string +} + +func newPtrDecoder(dec Decoder, typ *runtime.Type, structName, fieldName string) *ptrDecoder { + return &ptrDecoder{ + dec: dec, + typ: typ, + structName: structName, + fieldName: fieldName, + } +} + +func (d *ptrDecoder) contentDecoder() Decoder { + dec, ok := d.dec.(*ptrDecoder) + if !ok { + return d.dec + } + return dec.contentDecoder() +} + +//nolint:golint +//go:linkname unsafe_New reflect.unsafe_New +func unsafe_New(*runtime.Type) unsafe.Pointer + +func (d *ptrDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + if s.skipWhiteSpace() == nul { + s.read() + } + if s.char() == 'n' { + if err := nullBytes(s); err != nil { + return err + } + *(*unsafe.Pointer)(p) = nil + return nil + } + var newptr unsafe.Pointer + if *(*unsafe.Pointer)(p) == nil { + newptr = unsafe_New(d.typ) + *(*unsafe.Pointer)(p) = newptr + } else { + newptr = *(*unsafe.Pointer)(p) + } + if err := d.dec.DecodeStream(s, depth, newptr); err != nil { + return err + } + return nil +} + +func (d *ptrDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == 'n' { + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + if p != nil { + *(*unsafe.Pointer)(p) = nil + } + cursor += 4 + return cursor, nil + } + var newptr unsafe.Pointer + if *(*unsafe.Pointer)(p) == nil { + newptr = unsafe_New(d.typ) + *(*unsafe.Pointer)(p) = newptr + } else { + newptr = *(*unsafe.Pointer)(p) + } + c, err := d.dec.Decode(ctx, cursor, depth, newptr) + if err != nil { + return 0, err + } + cursor = c + return cursor, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/slice.go b/vendor/github.com/goccy/go-json/internal/decoder/slice.go new file mode 100644 index 00000000..853a555e --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/slice.go @@ -0,0 +1,294 @@ +package decoder + +import ( + "reflect" + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type sliceDecoder struct { + elemType *runtime.Type + isElemPointerType bool + valueDecoder Decoder + size uintptr + arrayPool sync.Pool + structName string + fieldName string +} + +// If use reflect.SliceHeader, data type is uintptr. +// In this case, Go compiler cannot trace reference created by newArray(). +// So, define using unsafe.Pointer as data type +type sliceHeader struct { + data unsafe.Pointer + len int + cap int +} + +const ( + defaultSliceCapacity = 2 +) + +func newSliceDecoder(dec Decoder, elemType *runtime.Type, size uintptr, structName, fieldName string) *sliceDecoder { + return &sliceDecoder{ + valueDecoder: dec, + elemType: elemType, + isElemPointerType: elemType.Kind() == reflect.Ptr || elemType.Kind() == reflect.Map, + size: size, + arrayPool: sync.Pool{ + New: func() interface{} { + return &sliceHeader{ + data: newArray(elemType, defaultSliceCapacity), + len: 0, + cap: defaultSliceCapacity, + } + }, + }, + structName: structName, + fieldName: fieldName, + } +} + +func (d *sliceDecoder) newSlice(src *sliceHeader) *sliceHeader { + slice := d.arrayPool.Get().(*sliceHeader) + if src.len > 0 { + // copy original elem + if slice.cap < src.cap { + data := newArray(d.elemType, src.cap) + slice = &sliceHeader{data: data, len: src.len, cap: src.cap} + } else { + slice.len = src.len + } + copySlice(d.elemType, *slice, *src) + } else { + slice.len = 0 + } + return slice +} + +func (d *sliceDecoder) releaseSlice(p *sliceHeader) { + d.arrayPool.Put(p) +} + +//go:linkname copySlice reflect.typedslicecopy +func copySlice(elemType *runtime.Type, dst, src sliceHeader) int + +//go:linkname newArray reflect.unsafe_NewArray +func newArray(*runtime.Type, int) unsafe.Pointer + +//go:linkname typedmemmove reflect.typedmemmove +func typedmemmove(t *runtime.Type, dst, src unsafe.Pointer) + +func (d *sliceDecoder) errNumber(offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ + Value: "number", + Type: reflect.SliceOf(runtime.RType2Type(d.elemType)), + Struct: d.structName, + Field: d.fieldName, + Offset: offset, + } +} + +func (d *sliceDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + depth++ + if depth > maxDecodeNestingDepth { + return errors.ErrExceededMaxDepth(s.char(), s.cursor) + } + + for { + switch s.char() { + case ' ', '\n', '\t', '\r': + s.cursor++ + continue + case 'n': + if err := nullBytes(s); err != nil { + return err + } + *(*unsafe.Pointer)(p) = nil + return nil + case '[': + s.cursor++ + if s.skipWhiteSpace() == ']' { + dst := (*sliceHeader)(p) + if dst.data == nil { + dst.data = newArray(d.elemType, 0) + } else { + dst.len = 0 + } + s.cursor++ + return nil + } + idx := 0 + slice := d.newSlice((*sliceHeader)(p)) + srcLen := slice.len + capacity := slice.cap + data := slice.data + for { + if capacity <= idx { + src := sliceHeader{data: data, len: idx, cap: capacity} + capacity *= 2 + data = newArray(d.elemType, capacity) + dst := sliceHeader{data: data, len: idx, cap: capacity} + copySlice(d.elemType, dst, src) + } + ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) + + // if srcLen is greater than idx, keep the original reference + if srcLen <= idx { + if d.isElemPointerType { + **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer + } else { + // assign new element to the slice + typedmemmove(d.elemType, ep, unsafe_New(d.elemType)) + } + } + + if err := d.valueDecoder.DecodeStream(s, depth, ep); err != nil { + return err + } + s.skipWhiteSpace() + RETRY: + switch s.char() { + case ']': + slice.cap = capacity + slice.len = idx + 1 + slice.data = data + dst := (*sliceHeader)(p) + dst.len = idx + 1 + if dst.len > dst.cap { + dst.data = newArray(d.elemType, dst.len) + dst.cap = dst.len + } + copySlice(d.elemType, *dst, *slice) + d.releaseSlice(slice) + s.cursor++ + return nil + case ',': + idx++ + case nul: + if s.read() { + goto RETRY + } + slice.cap = capacity + slice.data = data + d.releaseSlice(slice) + goto ERROR + default: + slice.cap = capacity + slice.data = data + d.releaseSlice(slice) + goto ERROR + } + s.cursor++ + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return d.errNumber(s.totalOffset()) + case nul: + if s.read() { + continue + } + goto ERROR + default: + goto ERROR + } + } +ERROR: + return errors.ErrUnexpectedEndOfJSON("slice", s.totalOffset()) +} + +func (d *sliceDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + depth++ + if depth > maxDecodeNestingDepth { + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + + for { + switch buf[cursor] { + case ' ', '\n', '\t', '\r': + cursor++ + continue + case 'n': + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + *(*unsafe.Pointer)(p) = nil + return cursor, nil + case '[': + cursor++ + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == ']' { + dst := (*sliceHeader)(p) + if dst.data == nil { + dst.data = newArray(d.elemType, 0) + } else { + dst.len = 0 + } + cursor++ + return cursor, nil + } + idx := 0 + slice := d.newSlice((*sliceHeader)(p)) + srcLen := slice.len + capacity := slice.cap + data := slice.data + for { + if capacity <= idx { + src := sliceHeader{data: data, len: idx, cap: capacity} + capacity *= 2 + data = newArray(d.elemType, capacity) + dst := sliceHeader{data: data, len: idx, cap: capacity} + copySlice(d.elemType, dst, src) + } + ep := unsafe.Pointer(uintptr(data) + uintptr(idx)*d.size) + // if srcLen is greater than idx, keep the original reference + if srcLen <= idx { + if d.isElemPointerType { + **(**unsafe.Pointer)(unsafe.Pointer(&ep)) = nil // initialize elem pointer + } else { + // assign new element to the slice + typedmemmove(d.elemType, ep, unsafe_New(d.elemType)) + } + } + c, err := d.valueDecoder.Decode(ctx, cursor, depth, ep) + if err != nil { + return 0, err + } + cursor = c + cursor = skipWhiteSpace(buf, cursor) + switch buf[cursor] { + case ']': + slice.cap = capacity + slice.len = idx + 1 + slice.data = data + dst := (*sliceHeader)(p) + dst.len = idx + 1 + if dst.len > dst.cap { + dst.data = newArray(d.elemType, dst.len) + dst.cap = dst.len + } + copySlice(d.elemType, *dst, *slice) + d.releaseSlice(slice) + cursor++ + return cursor, nil + case ',': + idx++ + default: + slice.cap = capacity + slice.data = data + d.releaseSlice(slice) + return 0, errors.ErrInvalidCharacter(buf[cursor], "slice", cursor) + } + cursor++ + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return 0, d.errNumber(cursor) + default: + return 0, errors.ErrUnexpectedEndOfJSON("slice", cursor) + } + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/stream.go b/vendor/github.com/goccy/go-json/internal/decoder/stream.go new file mode 100644 index 00000000..c2746834 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/stream.go @@ -0,0 +1,554 @@ +package decoder + +import ( + "bytes" + "encoding/json" + "io" + "strconv" + "unsafe" + + "github.com/goccy/go-json/internal/errors" +) + +const ( + initBufSize = 512 +) + +type Stream struct { + buf []byte + bufSize int64 + length int64 + r io.Reader + offset int64 + cursor int64 + filledBuffer bool + allRead bool + UseNumber bool + DisallowUnknownFields bool + Option *Option +} + +func NewStream(r io.Reader) *Stream { + return &Stream{ + r: r, + bufSize: initBufSize, + buf: make([]byte, initBufSize), + Option: &Option{}, + } +} + +func (s *Stream) TotalOffset() int64 { + return s.totalOffset() +} + +func (s *Stream) Buffered() io.Reader { + buflen := int64(len(s.buf)) + for i := s.cursor; i < buflen; i++ { + if s.buf[i] == nul { + return bytes.NewReader(s.buf[s.cursor:i]) + } + } + return bytes.NewReader(s.buf[s.cursor:]) +} + +func (s *Stream) PrepareForDecode() error { + for { + switch s.char() { + case ' ', '\t', '\r', '\n': + s.cursor++ + continue + case ',', ':': + s.cursor++ + return nil + case nul: + if s.read() { + continue + } + return io.EOF + } + break + } + return nil +} + +func (s *Stream) totalOffset() int64 { + return s.offset + s.cursor +} + +func (s *Stream) char() byte { + return s.buf[s.cursor] +} + +func (s *Stream) equalChar(c byte) bool { + cur := s.buf[s.cursor] + if cur == nul { + s.read() + cur = s.buf[s.cursor] + } + return cur == c +} + +func (s *Stream) stat() ([]byte, int64, unsafe.Pointer) { + return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data +} + +func (s *Stream) bufptr() unsafe.Pointer { + return (*sliceHeader)(unsafe.Pointer(&s.buf)).data +} + +func (s *Stream) statForRetry() ([]byte, int64, unsafe.Pointer) { + s.cursor-- // for retry ( because caller progress cursor position in each loop ) + return s.buf, s.cursor, (*sliceHeader)(unsafe.Pointer(&s.buf)).data +} + +func (s *Stream) Reset() { + s.reset() + s.bufSize = initBufSize +} + +func (s *Stream) More() bool { + for { + switch s.char() { + case ' ', '\n', '\r', '\t': + s.cursor++ + continue + case '}', ']': + return false + case nul: + if s.read() { + continue + } + return false + } + break + } + return true +} + +func (s *Stream) Token() (interface{}, error) { + for { + c := s.char() + switch c { + case ' ', '\n', '\r', '\t': + s.cursor++ + case '{', '[', ']', '}': + s.cursor++ + return json.Delim(c), nil + case ',', ':': + s.cursor++ + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + bytes := floatBytes(s) + s := *(*string)(unsafe.Pointer(&bytes)) + f64, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, err + } + return f64, nil + case '"': + bytes, err := stringBytes(s) + if err != nil { + return nil, err + } + return string(bytes), nil + case 't': + if err := trueBytes(s); err != nil { + return nil, err + } + return true, nil + case 'f': + if err := falseBytes(s); err != nil { + return nil, err + } + return false, nil + case 'n': + if err := nullBytes(s); err != nil { + return nil, err + } + return nil, nil + case nul: + if s.read() { + continue + } + goto END + default: + return nil, errors.ErrInvalidCharacter(s.char(), "token", s.totalOffset()) + } + } +END: + return nil, io.EOF +} + +func (s *Stream) reset() { + s.offset += s.cursor + s.buf = s.buf[s.cursor:] + s.length -= s.cursor + s.cursor = 0 +} + +func (s *Stream) readBuf() []byte { + if s.filledBuffer { + s.bufSize *= 2 + remainBuf := s.buf + s.buf = make([]byte, s.bufSize) + copy(s.buf, remainBuf) + } + remainLen := s.length - s.cursor + remainNotNulCharNum := int64(0) + for i := int64(0); i < remainLen; i++ { + if s.buf[s.cursor+i] == nul { + break + } + remainNotNulCharNum++ + } + s.length = s.cursor + remainNotNulCharNum + return s.buf[s.cursor+remainNotNulCharNum:] +} + +func (s *Stream) read() bool { + if s.allRead { + return false + } + buf := s.readBuf() + last := len(buf) - 1 + buf[last] = nul + n, err := s.r.Read(buf[:last]) + s.length += int64(n) + if n == last { + s.filledBuffer = true + } else { + s.filledBuffer = false + } + if err == io.EOF { + s.allRead = true + } else if err != nil { + return false + } + return true +} + +func (s *Stream) skipWhiteSpace() byte { + p := s.bufptr() +LOOP: + c := char(p, s.cursor) + switch c { + case ' ', '\n', '\t', '\r': + s.cursor++ + goto LOOP + case nul: + if s.read() { + p = s.bufptr() + goto LOOP + } + } + return c +} + +func (s *Stream) skipObject(depth int64) error { + braceCount := 1 + _, cursor, p := s.stat() + for { + switch char(p, cursor) { + case '{': + braceCount++ + depth++ + if depth > maxDecodeNestingDepth { + return errors.ErrExceededMaxDepth(s.char(), s.cursor) + } + case '}': + braceCount-- + depth-- + if braceCount == 0 { + s.cursor = cursor + 1 + return nil + } + case '[': + depth++ + if depth > maxDecodeNestingDepth { + return errors.ErrExceededMaxDepth(s.char(), s.cursor) + } + case ']': + depth-- + case '"': + for { + cursor++ + switch char(p, cursor) { + case '\\': + cursor++ + if char(p, cursor) == nul { + s.cursor = cursor + if s.read() { + _, cursor, p = s.statForRetry() + continue + } + return errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + case '"': + goto SWITCH_OUT + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.statForRetry() + continue + } + return errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + } + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + return errors.ErrUnexpectedEndOfJSON("object of object", cursor) + } + SWITCH_OUT: + cursor++ + } +} + +func (s *Stream) skipArray(depth int64) error { + bracketCount := 1 + _, cursor, p := s.stat() + for { + switch char(p, cursor) { + case '[': + bracketCount++ + depth++ + if depth > maxDecodeNestingDepth { + return errors.ErrExceededMaxDepth(s.char(), s.cursor) + } + case ']': + bracketCount-- + depth-- + if bracketCount == 0 { + s.cursor = cursor + 1 + return nil + } + case '{': + depth++ + if depth > maxDecodeNestingDepth { + return errors.ErrExceededMaxDepth(s.char(), s.cursor) + } + case '}': + depth-- + case '"': + for { + cursor++ + switch char(p, cursor) { + case '\\': + cursor++ + if char(p, cursor) == nul { + s.cursor = cursor + if s.read() { + _, cursor, p = s.statForRetry() + continue + } + return errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + case '"': + goto SWITCH_OUT + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.statForRetry() + continue + } + return errors.ErrUnexpectedEndOfJSON("string of object", cursor) + } + } + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + return errors.ErrUnexpectedEndOfJSON("array of object", cursor) + } + SWITCH_OUT: + cursor++ + } +} + +func (s *Stream) skipValue(depth int64) error { + _, cursor, p := s.stat() + for { + switch char(p, cursor) { + case ' ', '\n', '\t', '\r': + cursor++ + continue + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + return errors.ErrUnexpectedEndOfJSON("value of object", s.totalOffset()) + case '{': + s.cursor = cursor + 1 + return s.skipObject(depth + 1) + case '[': + s.cursor = cursor + 1 + return s.skipArray(depth + 1) + case '"': + for { + cursor++ + switch char(p, cursor) { + case '\\': + cursor++ + if char(p, cursor) == nul { + s.cursor = cursor + if s.read() { + _, cursor, p = s.statForRetry() + continue + } + return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset()) + } + case '"': + s.cursor = cursor + 1 + return nil + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.statForRetry() + continue + } + return errors.ErrUnexpectedEndOfJSON("value of string", s.totalOffset()) + } + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + for { + cursor++ + c := char(p, cursor) + if floatTable[c] { + continue + } else if c == nul { + if s.read() { + s.cursor-- // for retry current character + _, cursor, p = s.stat() + continue + } + } + s.cursor = cursor + return nil + } + case 't': + s.cursor = cursor + if err := trueBytes(s); err != nil { + return err + } + return nil + case 'f': + s.cursor = cursor + if err := falseBytes(s); err != nil { + return err + } + return nil + case 'n': + s.cursor = cursor + if err := nullBytes(s); err != nil { + return err + } + return nil + } + cursor++ + } +} + +func nullBytes(s *Stream) error { + // current cursor's character is 'n' + s.cursor++ + if s.char() != 'u' { + if err := retryReadNull(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'l' { + if err := retryReadNull(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'l' { + if err := retryReadNull(s); err != nil { + return err + } + } + s.cursor++ + return nil +} + +func retryReadNull(s *Stream) error { + if s.char() == nul && s.read() { + return nil + } + return errors.ErrInvalidCharacter(s.char(), "null", s.totalOffset()) +} + +func trueBytes(s *Stream) error { + // current cursor's character is 't' + s.cursor++ + if s.char() != 'r' { + if err := retryReadTrue(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'u' { + if err := retryReadTrue(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'e' { + if err := retryReadTrue(s); err != nil { + return err + } + } + s.cursor++ + return nil +} + +func retryReadTrue(s *Stream) error { + if s.char() == nul && s.read() { + return nil + } + return errors.ErrInvalidCharacter(s.char(), "bool(true)", s.totalOffset()) +} + +func falseBytes(s *Stream) error { + // current cursor's character is 'f' + s.cursor++ + if s.char() != 'a' { + if err := retryReadFalse(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'l' { + if err := retryReadFalse(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 's' { + if err := retryReadFalse(s); err != nil { + return err + } + } + s.cursor++ + if s.char() != 'e' { + if err := retryReadFalse(s); err != nil { + return err + } + } + s.cursor++ + return nil +} + +func retryReadFalse(s *Stream) error { + if s.char() == nul && s.read() { + return nil + } + return errors.ErrInvalidCharacter(s.char(), "bool(false)", s.totalOffset()) +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/string.go b/vendor/github.com/goccy/go-json/internal/decoder/string.go new file mode 100644 index 00000000..1e1ce157 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/string.go @@ -0,0 +1,361 @@ +package decoder + +import ( + "reflect" + "unicode" + "unicode/utf16" + "unicode/utf8" + "unsafe" + + "github.com/goccy/go-json/internal/errors" +) + +type stringDecoder struct { + structName string + fieldName string +} + +func newStringDecoder(structName, fieldName string) *stringDecoder { + return &stringDecoder{ + structName: structName, + fieldName: fieldName, + } +} + +func (d *stringDecoder) errUnmarshalType(typeName string, offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ + Value: typeName, + Type: reflect.TypeOf(""), + Offset: offset, + Struct: d.structName, + Field: d.fieldName, + } +} + +func (d *stringDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + bytes, err := d.decodeStreamByte(s) + if err != nil { + return err + } + if bytes == nil { + return nil + } + **(**string)(unsafe.Pointer(&p)) = *(*string)(unsafe.Pointer(&bytes)) + s.reset() + return nil +} + +func (d *stringDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + bytes, c, err := d.decodeByte(ctx.Buf, cursor) + if err != nil { + return 0, err + } + if bytes == nil { + return c, nil + } + cursor = c + **(**string)(unsafe.Pointer(&p)) = *(*string)(unsafe.Pointer(&bytes)) + return cursor, nil +} + +var ( + hexToInt = [256]int{ + '0': 0, + '1': 1, + '2': 2, + '3': 3, + '4': 4, + '5': 5, + '6': 6, + '7': 7, + '8': 8, + '9': 9, + 'A': 10, + 'B': 11, + 'C': 12, + 'D': 13, + 'E': 14, + 'F': 15, + 'a': 10, + 'b': 11, + 'c': 12, + 'd': 13, + 'e': 14, + 'f': 15, + } +) + +func unicodeToRune(code []byte) rune { + var r rune + for i := 0; i < len(code); i++ { + r = r*16 + rune(hexToInt[code[i]]) + } + return r +} + +func decodeUnicodeRune(s *Stream, p unsafe.Pointer) (rune, int64, unsafe.Pointer, error) { + const defaultOffset = 5 + const surrogateOffset = 11 + + if s.cursor+defaultOffset >= s.length { + if !s.read() { + return rune(0), 0, nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset()) + } + p = s.bufptr() + } + + r := unicodeToRune(s.buf[s.cursor+1 : s.cursor+defaultOffset]) + if utf16.IsSurrogate(r) { + if s.cursor+surrogateOffset >= s.length { + s.read() + p = s.bufptr() + } + if s.cursor+surrogateOffset >= s.length || s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' { + return unicode.ReplacementChar, defaultOffset, p, nil + } + r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset]) + if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar { + return r, surrogateOffset, p, nil + } + } + return r, defaultOffset, p, nil +} + +func decodeUnicode(s *Stream, p unsafe.Pointer) (unsafe.Pointer, error) { + const backSlashAndULen = 2 // length of \u + + r, offset, pp, err := decodeUnicodeRune(s, p) + if err != nil { + return nil, err + } + unicode := []byte(string(r)) + unicodeLen := int64(len(unicode)) + s.buf = append(append(s.buf[:s.cursor-1], unicode...), s.buf[s.cursor+offset:]...) + unicodeOrgLen := offset - 1 + s.length = s.length - (backSlashAndULen + (unicodeOrgLen - unicodeLen)) + s.cursor = s.cursor - backSlashAndULen + unicodeLen + return pp, nil +} + +func decodeEscapeString(s *Stream, p unsafe.Pointer) (unsafe.Pointer, error) { + s.cursor++ +RETRY: + switch s.buf[s.cursor] { + case '"': + s.buf[s.cursor] = '"' + case '\\': + s.buf[s.cursor] = '\\' + case '/': + s.buf[s.cursor] = '/' + case 'b': + s.buf[s.cursor] = '\b' + case 'f': + s.buf[s.cursor] = '\f' + case 'n': + s.buf[s.cursor] = '\n' + case 'r': + s.buf[s.cursor] = '\r' + case 't': + s.buf[s.cursor] = '\t' + case 'u': + return decodeUnicode(s, p) + case nul: + if !s.read() { + return nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset()) + } + goto RETRY + default: + return nil, errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) + } + s.buf = append(s.buf[:s.cursor-1], s.buf[s.cursor:]...) + s.length-- + s.cursor-- + return p, nil +} + +var ( + runeErrBytes = []byte(string(utf8.RuneError)) + runeErrBytesLen = int64(len(runeErrBytes)) +) + +func stringBytes(s *Stream) ([]byte, error) { + _, cursor, p := s.stat() + cursor++ // skip double quote char + start := cursor + for { + switch char(p, cursor) { + case '\\': + s.cursor = cursor + pp, err := decodeEscapeString(s, p) + if err != nil { + return nil, err + } + p = pp + cursor = s.cursor + case '"': + literal := s.buf[start:cursor] + cursor++ + s.cursor = cursor + return literal, nil + case + // 0x00 is nul, 0x5c is '\\', 0x22 is '"' . + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // 0x00-0x0F + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // 0x10-0x1F + 0x20, 0x21 /*0x22,*/, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // 0x20-0x2F + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // 0x30-0x3F + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // 0x40-0x4F + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B /*0x5C,*/, 0x5D, 0x5E, 0x5F, // 0x50-0x5F + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // 0x60-0x6F + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F: // 0x70-0x7F + // character is ASCII. skip to next char + case + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // 0x80-0x8F + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, // 0x90-0x9F + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, // 0xA0-0xAF + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // 0xB0-0xBF + 0xC0, 0xC1, // 0xC0-0xC1 + 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF: // 0xF5-0xFE + // character is invalid + s.buf = append(append(append([]byte{}, s.buf[:cursor]...), runeErrBytes...), s.buf[cursor+1:]...) + _, _, p = s.stat() + cursor += runeErrBytesLen + s.length += runeErrBytesLen + continue + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + goto ERROR + case 0xEF: + // RuneError is {0xEF, 0xBF, 0xBD} + if s.buf[cursor+1] == 0xBF && s.buf[cursor+2] == 0xBD { + // found RuneError: skip + cursor += 2 + break + } + fallthrough + default: + // multi bytes character + r, _ := utf8.DecodeRune(s.buf[cursor:]) + b := []byte(string(r)) + if r == utf8.RuneError { + s.buf = append(append(append([]byte{}, s.buf[:cursor]...), b...), s.buf[cursor+1:]...) + _, _, p = s.stat() + } + cursor += int64(len(b)) + s.length += int64(len(b)) + continue + } + cursor++ + } +ERROR: + return nil, errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) +} + +func (d *stringDecoder) decodeStreamByte(s *Stream) ([]byte, error) { + for { + switch s.char() { + case ' ', '\n', '\t', '\r': + s.cursor++ + continue + case '[': + return nil, d.errUnmarshalType("array", s.totalOffset()) + case '{': + return nil, d.errUnmarshalType("object", s.totalOffset()) + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return nil, d.errUnmarshalType("number", s.totalOffset()) + case '"': + return stringBytes(s) + case 'n': + if err := nullBytes(s); err != nil { + return nil, err + } + return nil, nil + case nul: + if s.read() { + continue + } + } + break + } + return nil, errors.ErrNotAtBeginningOfValue(s.totalOffset()) +} + +func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { + for { + switch buf[cursor] { + case ' ', '\n', '\t', '\r': + cursor++ + case '[': + return nil, 0, d.errUnmarshalType("array", cursor) + case '{': + return nil, 0, d.errUnmarshalType("object", cursor) + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return nil, 0, d.errUnmarshalType("number", cursor) + case '"': + cursor++ + start := cursor + b := (*sliceHeader)(unsafe.Pointer(&buf)).data + for { + switch char(b, cursor) { + case '\\': + cursor++ + switch char(b, cursor) { + case '"': + buf[cursor] = '"' + buf = append(buf[:cursor-1], buf[cursor:]...) + case '\\': + buf[cursor] = '\\' + buf = append(buf[:cursor-1], buf[cursor:]...) + case '/': + buf[cursor] = '/' + buf = append(buf[:cursor-1], buf[cursor:]...) + case 'b': + buf[cursor] = '\b' + buf = append(buf[:cursor-1], buf[cursor:]...) + case 'f': + buf[cursor] = '\f' + buf = append(buf[:cursor-1], buf[cursor:]...) + case 'n': + buf[cursor] = '\n' + buf = append(buf[:cursor-1], buf[cursor:]...) + case 'r': + buf[cursor] = '\r' + buf = append(buf[:cursor-1], buf[cursor:]...) + case 't': + buf[cursor] = '\t' + buf = append(buf[:cursor-1], buf[cursor:]...) + case 'u': + buflen := int64(len(buf)) + if cursor+5 >= buflen { + return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) + } + code := unicodeToRune(buf[cursor+1 : cursor+5]) + unicode := []byte(string(code)) + buf = append(append(buf[:cursor-1], unicode...), buf[cursor+5:]...) + default: + return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) + } + continue + case '"': + literal := buf[start:cursor] + cursor++ + return literal, cursor, nil + case nul: + return nil, 0, errors.ErrUnexpectedEndOfJSON("string", cursor) + } + cursor++ + } + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return nil, cursor, nil + default: + return nil, 0, errors.ErrNotAtBeginningOfValue(cursor) + } + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/struct.go b/vendor/github.com/goccy/go-json/internal/decoder/struct.go new file mode 100644 index 00000000..d467b0d2 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/struct.go @@ -0,0 +1,819 @@ +package decoder + +import ( + "fmt" + "math" + "math/bits" + "sort" + "strings" + "unicode" + "unicode/utf16" + "unsafe" + + "github.com/goccy/go-json/internal/errors" +) + +type structFieldSet struct { + dec Decoder + offset uintptr + isTaggedKey bool + fieldIdx int + key string + keyLen int64 + err error +} + +type structDecoder struct { + fieldMap map[string]*structFieldSet + fieldUniqueNameNum int + stringDecoder *stringDecoder + structName string + fieldName string + isTriedOptimize bool + keyBitmapUint8 [][256]uint8 + keyBitmapUint16 [][256]uint16 + sortedFieldSets []*structFieldSet + keyDecoder func(*structDecoder, []byte, int64) (int64, *structFieldSet, error) + keyStreamDecoder func(*structDecoder, *Stream) (*structFieldSet, string, error) +} + +var ( + largeToSmallTable [256]byte +) + +func init() { + for i := 0; i < 256; i++ { + c := i + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + largeToSmallTable[i] = byte(c) + } +} + +func newStructDecoder(structName, fieldName string, fieldMap map[string]*structFieldSet) *structDecoder { + return &structDecoder{ + fieldMap: fieldMap, + stringDecoder: newStringDecoder(structName, fieldName), + structName: structName, + fieldName: fieldName, + keyDecoder: decodeKey, + keyStreamDecoder: decodeKeyStream, + } +} + +const ( + allowOptimizeMaxKeyLen = 64 + allowOptimizeMaxFieldLen = 16 +) + +func (d *structDecoder) tryOptimize() { + fieldUniqueNameMap := map[string]int{} + fieldIdx := -1 + for k, v := range d.fieldMap { + lower := strings.ToLower(k) + idx, exists := fieldUniqueNameMap[lower] + if exists { + v.fieldIdx = idx + } else { + fieldIdx++ + v.fieldIdx = fieldIdx + } + fieldUniqueNameMap[lower] = fieldIdx + } + d.fieldUniqueNameNum = len(fieldUniqueNameMap) + + if d.isTriedOptimize { + return + } + fieldMap := map[string]*structFieldSet{} + conflicted := map[string]struct{}{} + for k, v := range d.fieldMap { + key := strings.ToLower(k) + if key != k { + // already exists same key (e.g. Hello and HELLO has same lower case key + if _, exists := conflicted[key]; exists { + d.isTriedOptimize = true + return + } + conflicted[key] = struct{}{} + } + if field, exists := fieldMap[key]; exists { + if field != v { + d.isTriedOptimize = true + return + } + } + fieldMap[key] = v + } + + if len(fieldMap) > allowOptimizeMaxFieldLen { + d.isTriedOptimize = true + return + } + + var maxKeyLen int + sortedKeys := []string{} + for key := range fieldMap { + keyLen := len(key) + if keyLen > allowOptimizeMaxKeyLen { + d.isTriedOptimize = true + return + } + if maxKeyLen < keyLen { + maxKeyLen = keyLen + } + sortedKeys = append(sortedKeys, key) + } + sort.Strings(sortedKeys) + + // By allocating one extra capacity than `maxKeyLen`, + // it is possible to avoid the process of comparing the index of the key with the length of the bitmap each time. + bitmapLen := maxKeyLen + 1 + if len(sortedKeys) <= 8 { + keyBitmap := make([][256]uint8, bitmapLen) + for i, key := range sortedKeys { + for j := 0; j < len(key); j++ { + c := key[j] + keyBitmap[j][c] |= (1 << uint(i)) + } + d.sortedFieldSets = append(d.sortedFieldSets, fieldMap[key]) + } + d.keyBitmapUint8 = keyBitmap + d.keyDecoder = decodeKeyByBitmapUint8 + d.keyStreamDecoder = decodeKeyByBitmapUint8Stream + } else { + keyBitmap := make([][256]uint16, bitmapLen) + for i, key := range sortedKeys { + for j := 0; j < len(key); j++ { + c := key[j] + keyBitmap[j][c] |= (1 << uint(i)) + } + d.sortedFieldSets = append(d.sortedFieldSets, fieldMap[key]) + } + d.keyBitmapUint16 = keyBitmap + d.keyDecoder = decodeKeyByBitmapUint16 + d.keyStreamDecoder = decodeKeyByBitmapUint16Stream + } +} + +// decode from '\uXXXX' +func decodeKeyCharByUnicodeRune(buf []byte, cursor int64) ([]byte, int64) { + const defaultOffset = 4 + const surrogateOffset = 6 + + r := unicodeToRune(buf[cursor : cursor+defaultOffset]) + if utf16.IsSurrogate(r) { + cursor += defaultOffset + if cursor+surrogateOffset >= int64(len(buf)) || buf[cursor] != '\\' || buf[cursor+1] != 'u' { + return []byte(string(unicode.ReplacementChar)), cursor + defaultOffset - 1 + } + cursor += 2 + r2 := unicodeToRune(buf[cursor : cursor+defaultOffset]) + if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar { + return []byte(string(r)), cursor + defaultOffset - 1 + } + } + return []byte(string(r)), cursor + defaultOffset - 1 +} + +func decodeKeyCharByEscapedChar(buf []byte, cursor int64) ([]byte, int64) { + c := buf[cursor] + cursor++ + switch c { + case '"': + return []byte{'"'}, cursor + case '\\': + return []byte{'\\'}, cursor + case '/': + return []byte{'/'}, cursor + case 'b': + return []byte{'\b'}, cursor + case 'f': + return []byte{'\f'}, cursor + case 'n': + return []byte{'\n'}, cursor + case 'r': + return []byte{'\r'}, cursor + case 't': + return []byte{'\t'}, cursor + case 'u': + return decodeKeyCharByUnicodeRune(buf, cursor) + } + return nil, cursor +} + +func decodeKeyByBitmapUint8(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) { + var ( + curBit uint8 = math.MaxUint8 + ) + b := (*sliceHeader)(unsafe.Pointer(&buf)).data + for { + switch char(b, cursor) { + case ' ', '\n', '\t', '\r': + cursor++ + case '"': + cursor++ + c := char(b, cursor) + switch c { + case '"': + cursor++ + return cursor, nil, nil + case nul: + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) + } + keyIdx := 0 + bitmap := d.keyBitmapUint8 + start := cursor + for { + c := char(b, cursor) + switch c { + case '"': + fieldSetIndex := bits.TrailingZeros8(curBit) + field := d.sortedFieldSets[fieldSetIndex] + keyLen := cursor - start + cursor++ + if keyLen < field.keyLen { + // early match + return cursor, nil, nil + } + return cursor, field, nil + case nul: + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) + case '\\': + cursor++ + chars, nextCursor := decodeKeyCharByEscapedChar(buf, cursor) + for _, c := range chars { + curBit &= bitmap[keyIdx][largeToSmallTable[c]] + if curBit == 0 { + return decodeKeyNotFound(b, cursor) + } + keyIdx++ + } + cursor = nextCursor + default: + curBit &= bitmap[keyIdx][largeToSmallTable[c]] + if curBit == 0 { + return decodeKeyNotFound(b, cursor) + } + keyIdx++ + } + cursor++ + } + default: + return cursor, nil, errors.ErrNotAtBeginningOfValue(cursor) + } + } +} + +func decodeKeyByBitmapUint16(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) { + var ( + curBit uint16 = math.MaxUint16 + ) + b := (*sliceHeader)(unsafe.Pointer(&buf)).data + for { + switch char(b, cursor) { + case ' ', '\n', '\t', '\r': + cursor++ + case '"': + cursor++ + c := char(b, cursor) + switch c { + case '"': + cursor++ + return cursor, nil, nil + case nul: + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) + } + keyIdx := 0 + bitmap := d.keyBitmapUint16 + start := cursor + for { + c := char(b, cursor) + switch c { + case '"': + fieldSetIndex := bits.TrailingZeros16(curBit) + field := d.sortedFieldSets[fieldSetIndex] + keyLen := cursor - start + cursor++ + if keyLen < field.keyLen { + // early match + return cursor, nil, nil + } + return cursor, field, nil + case nul: + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) + case '\\': + cursor++ + chars, nextCursor := decodeKeyCharByEscapedChar(buf, cursor) + for _, c := range chars { + curBit &= bitmap[keyIdx][largeToSmallTable[c]] + if curBit == 0 { + return decodeKeyNotFound(b, cursor) + } + keyIdx++ + } + cursor = nextCursor + default: + curBit &= bitmap[keyIdx][largeToSmallTable[c]] + if curBit == 0 { + return decodeKeyNotFound(b, cursor) + } + keyIdx++ + } + cursor++ + } + default: + return cursor, nil, errors.ErrNotAtBeginningOfValue(cursor) + } + } +} + +func decodeKeyNotFound(b unsafe.Pointer, cursor int64) (int64, *structFieldSet, error) { + for { + cursor++ + switch char(b, cursor) { + case '"': + cursor++ + return cursor, nil, nil + case '\\': + cursor++ + if char(b, cursor) == nul { + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) + } + case nul: + return 0, nil, errors.ErrUnexpectedEndOfJSON("string", cursor) + } + } +} + +func decodeKey(d *structDecoder, buf []byte, cursor int64) (int64, *structFieldSet, error) { + key, c, err := d.stringDecoder.decodeByte(buf, cursor) + if err != nil { + return 0, nil, err + } + cursor = c + k := *(*string)(unsafe.Pointer(&key)) + field, exists := d.fieldMap[k] + if !exists { + return cursor, nil, nil + } + return cursor, field, nil +} + +func decodeKeyByBitmapUint8Stream(d *structDecoder, s *Stream) (*structFieldSet, string, error) { + var ( + curBit uint8 = math.MaxUint8 + ) + _, cursor, p := s.stat() + for { + switch char(p, cursor) { + case ' ', '\n', '\t', '\r': + cursor++ + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) + case '"': + cursor++ + FIRST_CHAR: + start := cursor + switch char(p, cursor) { + case '"': + cursor++ + s.cursor = cursor + return nil, "", nil + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + goto FIRST_CHAR + } + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) + } + keyIdx := 0 + bitmap := d.keyBitmapUint8 + for { + c := char(p, cursor) + switch c { + case '"': + fieldSetIndex := bits.TrailingZeros8(curBit) + field := d.sortedFieldSets[fieldSetIndex] + keyLen := cursor - start + cursor++ + s.cursor = cursor + if keyLen < field.keyLen { + // early match + return nil, field.key, nil + } + return field, field.key, nil + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) + case '\\': + s.cursor = cursor + 1 // skip '\' char + chars, err := decodeKeyCharByEscapeCharStream(s) + if err != nil { + return nil, "", err + } + cursor = s.cursor + for _, c := range chars { + curBit &= bitmap[keyIdx][largeToSmallTable[c]] + if curBit == 0 { + s.cursor = cursor + return decodeKeyNotFoundStream(s, start) + } + keyIdx++ + } + default: + curBit &= bitmap[keyIdx][largeToSmallTable[c]] + if curBit == 0 { + s.cursor = cursor + return decodeKeyNotFoundStream(s, start) + } + keyIdx++ + } + cursor++ + } + default: + return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) + } + } +} + +func decodeKeyByBitmapUint16Stream(d *structDecoder, s *Stream) (*structFieldSet, string, error) { + var ( + curBit uint16 = math.MaxUint16 + ) + _, cursor, p := s.stat() + for { + switch char(p, cursor) { + case ' ', '\n', '\t', '\r': + cursor++ + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) + case '"': + cursor++ + FIRST_CHAR: + start := cursor + switch char(p, cursor) { + case '"': + cursor++ + s.cursor = cursor + return nil, "", nil + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + goto FIRST_CHAR + } + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) + } + keyIdx := 0 + bitmap := d.keyBitmapUint16 + for { + c := char(p, cursor) + switch c { + case '"': + fieldSetIndex := bits.TrailingZeros16(curBit) + field := d.sortedFieldSets[fieldSetIndex] + keyLen := cursor - start + cursor++ + s.cursor = cursor + if keyLen < field.keyLen { + // early match + return nil, field.key, nil + } + return field, field.key, nil + case nul: + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) + case '\\': + s.cursor = cursor + 1 // skip '\' char + chars, err := decodeKeyCharByEscapeCharStream(s) + if err != nil { + return nil, "", err + } + cursor = s.cursor + for _, c := range chars { + curBit &= bitmap[keyIdx][largeToSmallTable[c]] + if curBit == 0 { + s.cursor = cursor + return decodeKeyNotFoundStream(s, start) + } + keyIdx++ + } + default: + curBit &= bitmap[keyIdx][largeToSmallTable[c]] + if curBit == 0 { + s.cursor = cursor + return decodeKeyNotFoundStream(s, start) + } + keyIdx++ + } + cursor++ + } + default: + return nil, "", errors.ErrNotAtBeginningOfValue(s.totalOffset()) + } + } +} + +// decode from '\uXXXX' +func decodeKeyCharByUnicodeRuneStream(s *Stream) ([]byte, error) { + const defaultOffset = 4 + const surrogateOffset = 6 + + if s.cursor+defaultOffset >= s.length { + if !s.read() { + return nil, errors.ErrInvalidCharacter(s.char(), "escaped unicode char", s.totalOffset()) + } + } + + r := unicodeToRune(s.buf[s.cursor : s.cursor+defaultOffset]) + if utf16.IsSurrogate(r) { + s.cursor += defaultOffset + if s.cursor+surrogateOffset >= s.length { + s.read() + } + if s.cursor+surrogateOffset >= s.length || s.buf[s.cursor] != '\\' || s.buf[s.cursor+1] != 'u' { + s.cursor += defaultOffset - 1 + return []byte(string(unicode.ReplacementChar)), nil + } + r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset]) + if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar { + s.cursor += defaultOffset - 1 + return []byte(string(r)), nil + } + } + s.cursor += defaultOffset - 1 + return []byte(string(r)), nil +} + +func decodeKeyCharByEscapeCharStream(s *Stream) ([]byte, error) { + c := s.buf[s.cursor] + s.cursor++ +RETRY: + switch c { + case '"': + return []byte{'"'}, nil + case '\\': + return []byte{'\\'}, nil + case '/': + return []byte{'/'}, nil + case 'b': + return []byte{'\b'}, nil + case 'f': + return []byte{'\f'}, nil + case 'n': + return []byte{'\n'}, nil + case 'r': + return []byte{'\r'}, nil + case 't': + return []byte{'\t'}, nil + case 'u': + return decodeKeyCharByUnicodeRuneStream(s) + case nul: + if !s.read() { + return nil, errors.ErrInvalidCharacter(s.char(), "escaped char", s.totalOffset()) + } + goto RETRY + default: + return nil, errors.ErrUnexpectedEndOfJSON("struct field", s.totalOffset()) + } +} + +func decodeKeyNotFoundStream(s *Stream, start int64) (*structFieldSet, string, error) { + buf, cursor, p := s.stat() + for { + cursor++ + switch char(p, cursor) { + case '"': + b := buf[start:cursor] + key := *(*string)(unsafe.Pointer(&b)) + cursor++ + s.cursor = cursor + return nil, key, nil + case '\\': + cursor++ + if char(p, cursor) == nul { + s.cursor = cursor + if !s.read() { + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) + } + buf, cursor, p = s.statForRetry() + } + case nul: + s.cursor = cursor + if !s.read() { + return nil, "", errors.ErrUnexpectedEndOfJSON("string", s.totalOffset()) + } + buf, cursor, p = s.statForRetry() + } + } +} + +func decodeKeyStream(d *structDecoder, s *Stream) (*structFieldSet, string, error) { + key, err := d.stringDecoder.decodeStreamByte(s) + if err != nil { + return nil, "", err + } + k := *(*string)(unsafe.Pointer(&key)) + return d.fieldMap[k], k, nil +} + +func (d *structDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + depth++ + if depth > maxDecodeNestingDepth { + return errors.ErrExceededMaxDepth(s.char(), s.cursor) + } + + c := s.skipWhiteSpace() + switch c { + case 'n': + if err := nullBytes(s); err != nil { + return err + } + return nil + default: + if s.char() != '{' { + return errors.ErrNotAtBeginningOfValue(s.totalOffset()) + } + } + s.cursor++ + if s.skipWhiteSpace() == '}' { + s.cursor++ + return nil + } + var ( + seenFields map[int]struct{} + seenFieldNum int + ) + firstWin := (s.Option.Flags & FirstWinOption) != 0 + if firstWin { + seenFields = make(map[int]struct{}, d.fieldUniqueNameNum) + } + for { + s.reset() + field, key, err := d.keyStreamDecoder(d, s) + if err != nil { + return err + } + if s.skipWhiteSpace() != ':' { + return errors.ErrExpected("colon after object key", s.totalOffset()) + } + s.cursor++ + if field != nil { + if field.err != nil { + return field.err + } + if firstWin { + if _, exists := seenFields[field.fieldIdx]; exists { + if err := s.skipValue(depth); err != nil { + return err + } + } else { + if err := field.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil { + return err + } + seenFieldNum++ + if d.fieldUniqueNameNum <= seenFieldNum { + return s.skipObject(depth) + } + seenFields[field.fieldIdx] = struct{}{} + } + } else { + if err := field.dec.DecodeStream(s, depth, unsafe.Pointer(uintptr(p)+field.offset)); err != nil { + return err + } + } + } else if s.DisallowUnknownFields { + return fmt.Errorf("json: unknown field %q", key) + } else { + if err := s.skipValue(depth); err != nil { + return err + } + } + c := s.skipWhiteSpace() + if c == '}' { + s.cursor++ + return nil + } + if c != ',' { + return errors.ErrExpected("comma after object element", s.totalOffset()) + } + s.cursor++ + } +} + +func (d *structDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + depth++ + if depth > maxDecodeNestingDepth { + return 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + buflen := int64(len(buf)) + cursor = skipWhiteSpace(buf, cursor) + b := (*sliceHeader)(unsafe.Pointer(&buf)).data + switch char(b, cursor) { + case 'n': + if err := validateNull(buf, cursor); err != nil { + return 0, err + } + cursor += 4 + return cursor, nil + case '{': + default: + return 0, errors.ErrNotAtBeginningOfValue(cursor) + } + cursor++ + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == '}' { + cursor++ + return cursor, nil + } + var ( + seenFields map[int]struct{} + seenFieldNum int + ) + firstWin := (ctx.Option.Flags & FirstWinOption) != 0 + if firstWin { + seenFields = make(map[int]struct{}, d.fieldUniqueNameNum) + } + for { + c, field, err := d.keyDecoder(d, buf, cursor) + if err != nil { + return 0, err + } + cursor = skipWhiteSpace(buf, c) + if char(b, cursor) != ':' { + return 0, errors.ErrExpected("colon after object key", cursor) + } + cursor++ + if cursor >= buflen { + return 0, errors.ErrExpected("object value after colon", cursor) + } + if field != nil { + if field.err != nil { + return 0, field.err + } + if firstWin { + if _, exists := seenFields[field.fieldIdx]; exists { + c, err := skipValue(buf, cursor, depth) + if err != nil { + return 0, err + } + cursor = c + } else { + c, err := field.dec.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+field.offset)) + if err != nil { + return 0, err + } + cursor = c + seenFieldNum++ + if d.fieldUniqueNameNum <= seenFieldNum { + return skipObject(buf, cursor, depth) + } + seenFields[field.fieldIdx] = struct{}{} + } + } else { + c, err := field.dec.Decode(ctx, cursor, depth, unsafe.Pointer(uintptr(p)+field.offset)) + if err != nil { + return 0, err + } + cursor = c + } + } else { + c, err := skipValue(buf, cursor, depth) + if err != nil { + return 0, err + } + cursor = c + } + cursor = skipWhiteSpace(buf, cursor) + if char(b, cursor) == '}' { + cursor++ + return cursor, nil + } + if char(b, cursor) != ',' { + return 0, errors.ErrExpected("comma after object element", cursor) + } + cursor++ + } +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/type.go b/vendor/github.com/goccy/go-json/internal/decoder/type.go new file mode 100644 index 00000000..70e9907c --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/type.go @@ -0,0 +1,29 @@ +package decoder + +import ( + "context" + "encoding" + "encoding/json" + "reflect" + "unsafe" +) + +type Decoder interface { + Decode(*RuntimeContext, int64, int64, unsafe.Pointer) (int64, error) + DecodeStream(*Stream, int64, unsafe.Pointer) error +} + +const ( + nul = '\000' + maxDecodeNestingDepth = 10000 +) + +type unmarshalerContext interface { + UnmarshalJSON(context.Context, []byte) error +} + +var ( + unmarshalJSONType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + unmarshalJSONContextType = reflect.TypeOf((*unmarshalerContext)(nil)).Elem() + unmarshalTextType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() +) diff --git a/vendor/github.com/goccy/go-json/internal/decoder/uint.go b/vendor/github.com/goccy/go-json/internal/decoder/uint.go new file mode 100644 index 00000000..a62c5149 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/uint.go @@ -0,0 +1,190 @@ +package decoder + +import ( + "fmt" + "reflect" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type uintDecoder struct { + typ *runtime.Type + kind reflect.Kind + op func(unsafe.Pointer, uint64) + structName string + fieldName string +} + +func newUintDecoder(typ *runtime.Type, structName, fieldName string, op func(unsafe.Pointer, uint64)) *uintDecoder { + return &uintDecoder{ + typ: typ, + kind: typ.Kind(), + op: op, + structName: structName, + fieldName: fieldName, + } +} + +func (d *uintDecoder) typeError(buf []byte, offset int64) *errors.UnmarshalTypeError { + return &errors.UnmarshalTypeError{ + Value: fmt.Sprintf("number %s", string(buf)), + Type: runtime.RType2Type(d.typ), + Offset: offset, + } +} + +var ( + pow10u64 = [...]uint64{ + 1e00, 1e01, 1e02, 1e03, 1e04, 1e05, 1e06, 1e07, 1e08, 1e09, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + } + pow10u64Len = len(pow10u64) +) + +func (d *uintDecoder) parseUint(b []byte) (uint64, error) { + maxDigit := len(b) + if maxDigit > pow10u64Len { + return 0, fmt.Errorf("invalid length of number") + } + sum := uint64(0) + for i := 0; i < maxDigit; i++ { + c := uint64(b[i]) - 48 + digitValue := pow10u64[maxDigit-i-1] + sum += c * digitValue + } + return sum, nil +} + +func (d *uintDecoder) decodeStreamByte(s *Stream) ([]byte, error) { + for { + switch s.char() { + case ' ', '\n', '\t', '\r': + s.cursor++ + continue + case '0': + s.cursor++ + return numZeroBuf, nil + case '1', '2', '3', '4', '5', '6', '7', '8', '9': + start := s.cursor + for { + s.cursor++ + if numTable[s.char()] { + continue + } else if s.char() == nul { + if s.read() { + s.cursor-- // for retry current character + continue + } + } + break + } + num := s.buf[start:s.cursor] + return num, nil + case 'n': + if err := nullBytes(s); err != nil { + return nil, err + } + return nil, nil + case nul: + if s.read() { + continue + } + default: + return nil, d.typeError([]byte{s.char()}, s.totalOffset()) + } + break + } + return nil, errors.ErrUnexpectedEndOfJSON("number(unsigned integer)", s.totalOffset()) +} + +func (d *uintDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { + for { + switch buf[cursor] { + case ' ', '\n', '\t', '\r': + cursor++ + continue + case '0': + cursor++ + return numZeroBuf, cursor, nil + case '1', '2', '3', '4', '5', '6', '7', '8', '9': + start := cursor + cursor++ + for numTable[buf[cursor]] { + cursor++ + } + num := buf[start:cursor] + return num, cursor, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return nil, cursor, nil + default: + return nil, 0, d.typeError([]byte{buf[cursor]}, cursor) + } + } +} + +func (d *uintDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + bytes, err := d.decodeStreamByte(s) + if err != nil { + return err + } + if bytes == nil { + return nil + } + u64, err := d.parseUint(bytes) + if err != nil { + return d.typeError(bytes, s.totalOffset()) + } + switch d.kind { + case reflect.Uint8: + if (1 << 8) <= u64 { + return d.typeError(bytes, s.totalOffset()) + } + case reflect.Uint16: + if (1 << 16) <= u64 { + return d.typeError(bytes, s.totalOffset()) + } + case reflect.Uint32: + if (1 << 32) <= u64 { + return d.typeError(bytes, s.totalOffset()) + } + } + d.op(p, u64) + return nil +} + +func (d *uintDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + bytes, c, err := d.decodeByte(ctx.Buf, cursor) + if err != nil { + return 0, err + } + if bytes == nil { + return c, nil + } + cursor = c + u64, err := d.parseUint(bytes) + if err != nil { + return 0, d.typeError(bytes, cursor) + } + switch d.kind { + case reflect.Uint8: + if (1 << 8) <= u64 { + return 0, d.typeError(bytes, cursor) + } + case reflect.Uint16: + if (1 << 16) <= u64 { + return 0, d.typeError(bytes, cursor) + } + case reflect.Uint32: + if (1 << 32) <= u64 { + return 0, d.typeError(bytes, cursor) + } + } + d.op(p, u64) + return cursor, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go new file mode 100644 index 00000000..d90f39cc --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go @@ -0,0 +1,91 @@ +package decoder + +import ( + "encoding/json" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type unmarshalJSONDecoder struct { + typ *runtime.Type + structName string + fieldName string +} + +func newUnmarshalJSONDecoder(typ *runtime.Type, structName, fieldName string) *unmarshalJSONDecoder { + return &unmarshalJSONDecoder{ + typ: typ, + structName: structName, + fieldName: fieldName, + } +} + +func (d *unmarshalJSONDecoder) annotateError(cursor int64, err error) { + switch e := err.(type) { + case *errors.UnmarshalTypeError: + e.Struct = d.structName + e.Field = d.fieldName + case *errors.SyntaxError: + e.Offset = cursor + } +} + +func (d *unmarshalJSONDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + s.skipWhiteSpace() + start := s.cursor + if err := s.skipValue(depth); err != nil { + return err + } + src := s.buf[start:s.cursor] + dst := make([]byte, len(src)) + copy(dst, src) + + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: d.typ, + ptr: p, + })) + if (s.Option.Flags & ContextOption) != 0 { + if err := v.(unmarshalerContext).UnmarshalJSON(s.Option.Context, dst); err != nil { + d.annotateError(s.cursor, err) + return err + } + } else { + if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil { + d.annotateError(s.cursor, err) + return err + } + } + return nil +} + +func (d *unmarshalJSONDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + cursor = skipWhiteSpace(buf, cursor) + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return 0, err + } + src := buf[start:end] + dst := make([]byte, len(src)) + copy(dst, src) + + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: d.typ, + ptr: p, + })) + if (ctx.Option.Flags & ContextOption) != 0 { + if err := v.(unmarshalerContext).UnmarshalJSON(ctx.Option.Context, dst); err != nil { + d.annotateError(cursor, err) + return 0, err + } + } else { + if err := v.(json.Unmarshaler).UnmarshalJSON(dst); err != nil { + d.annotateError(cursor, err) + return 0, err + } + } + return end, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go new file mode 100644 index 00000000..1ef28778 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go @@ -0,0 +1,280 @@ +package decoder + +import ( + "bytes" + "encoding" + "unicode" + "unicode/utf16" + "unicode/utf8" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type unmarshalTextDecoder struct { + typ *runtime.Type + structName string + fieldName string +} + +func newUnmarshalTextDecoder(typ *runtime.Type, structName, fieldName string) *unmarshalTextDecoder { + return &unmarshalTextDecoder{ + typ: typ, + structName: structName, + fieldName: fieldName, + } +} + +func (d *unmarshalTextDecoder) annotateError(cursor int64, err error) { + switch e := err.(type) { + case *errors.UnmarshalTypeError: + e.Struct = d.structName + e.Field = d.fieldName + case *errors.SyntaxError: + e.Offset = cursor + } +} + +var ( + nullbytes = []byte(`null`) +) + +func (d *unmarshalTextDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + s.skipWhiteSpace() + start := s.cursor + if err := s.skipValue(depth); err != nil { + return err + } + src := s.buf[start:s.cursor] + if len(src) > 0 { + switch src[0] { + case '[': + return &errors.UnmarshalTypeError{ + Value: "array", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + case '{': + return &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return &errors.UnmarshalTypeError{ + Value: "number", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + case 'n': + if bytes.Equal(src, nullbytes) { + *(*unsafe.Pointer)(p) = nil + return nil + } + } + } + dst := make([]byte, len(src)) + copy(dst, src) + + if b, ok := unquoteBytes(dst); ok { + dst = b + } + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: d.typ, + ptr: p, + })) + if err := v.(encoding.TextUnmarshaler).UnmarshalText(dst); err != nil { + d.annotateError(s.cursor, err) + return err + } + return nil +} + +func (d *unmarshalTextDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + buf := ctx.Buf + cursor = skipWhiteSpace(buf, cursor) + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return 0, err + } + src := buf[start:end] + if len(src) > 0 { + switch src[0] { + case '[': + return 0, &errors.UnmarshalTypeError{ + Value: "array", + Type: runtime.RType2Type(d.typ), + Offset: start, + } + case '{': + return 0, &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(d.typ), + Offset: start, + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return 0, &errors.UnmarshalTypeError{ + Value: "number", + Type: runtime.RType2Type(d.typ), + Offset: start, + } + case 'n': + if bytes.Equal(src, nullbytes) { + *(*unsafe.Pointer)(p) = nil + return end, nil + } + } + } + + if s, ok := unquoteBytes(src); ok { + src = s + } + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: d.typ, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) + if err := v.(encoding.TextUnmarshaler).UnmarshalText(src); err != nil { + d.annotateError(cursor, err) + return 0, err + } + return end, nil +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + length := len(s) + if length < 2 || s[0] != '"' || s[length-1] != '"' { + return + } + s = s[1 : length-1] + length -= 2 + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < length { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == length { + return s, true + } + + b := make([]byte, length+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < length { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= length { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} + +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + var r rune + for _, c := range s[2:6] { + switch { + case '0' <= c && c <= '9': + c = c - '0' + case 'a' <= c && c <= 'f': + c = c - 'a' + 10 + case 'A' <= c && c <= 'F': + c = c - 'A' + 10 + default: + return -1 + } + r = r*16 + rune(c) + } + return r +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go b/vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go new file mode 100644 index 00000000..66227ae0 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go @@ -0,0 +1,68 @@ +package decoder + +import ( + "reflect" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +type wrappedStringDecoder struct { + typ *runtime.Type + dec Decoder + stringDecoder *stringDecoder + structName string + fieldName string + isPtrType bool +} + +func newWrappedStringDecoder(typ *runtime.Type, dec Decoder, structName, fieldName string) *wrappedStringDecoder { + return &wrappedStringDecoder{ + typ: typ, + dec: dec, + stringDecoder: newStringDecoder(structName, fieldName), + structName: structName, + fieldName: fieldName, + isPtrType: typ.Kind() == reflect.Ptr, + } +} + +func (d *wrappedStringDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + bytes, err := d.stringDecoder.decodeStreamByte(s) + if err != nil { + return err + } + if bytes == nil { + if d.isPtrType { + *(*unsafe.Pointer)(p) = nil + } + return nil + } + b := make([]byte, len(bytes)+1) + copy(b, bytes) + if _, err := d.dec.Decode(&RuntimeContext{Buf: b}, 0, depth, p); err != nil { + return err + } + return nil +} + +func (d *wrappedStringDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + bytes, c, err := d.stringDecoder.decodeByte(ctx.Buf, cursor) + if err != nil { + return 0, err + } + if bytes == nil { + if d.isPtrType { + *(*unsafe.Pointer)(p) = nil + } + return c, nil + } + bytes = append(bytes, nul) + oldBuf := ctx.Buf + ctx.Buf = bytes + if _, err := d.dec.Decode(ctx, 0, depth, p); err != nil { + return 0, err + } + ctx.Buf = oldBuf + return c, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/compact.go b/vendor/github.com/goccy/go-json/internal/encoder/compact.go new file mode 100644 index 00000000..0eb9545d --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/compact.go @@ -0,0 +1,286 @@ +package encoder + +import ( + "bytes" + "fmt" + "strconv" + "unsafe" + + "github.com/goccy/go-json/internal/errors" +) + +var ( + isWhiteSpace = [256]bool{ + ' ': true, + '\n': true, + '\t': true, + '\r': true, + } + isHTMLEscapeChar = [256]bool{ + '<': true, + '>': true, + '&': true, + } + nul = byte('\000') +) + +func Compact(buf *bytes.Buffer, src []byte, escape bool) error { + if len(src) == 0 { + return errors.ErrUnexpectedEndOfJSON("", 0) + } + buf.Grow(len(src)) + dst := buf.Bytes() + + ctx := TakeRuntimeContext() + ctxBuf := ctx.Buf[:0] + ctxBuf = append(append(ctxBuf, src...), nul) + ctx.Buf = ctxBuf + + if err := compactAndWrite(buf, dst, ctxBuf, escape); err != nil { + ReleaseRuntimeContext(ctx) + return err + } + ReleaseRuntimeContext(ctx) + return nil +} + +func compactAndWrite(buf *bytes.Buffer, dst []byte, src []byte, escape bool) error { + dst, err := compact(dst, src, escape) + if err != nil { + return err + } + if _, err := buf.Write(dst); err != nil { + return err + } + return nil +} + +func compact(dst, src []byte, escape bool) ([]byte, error) { + buf, cursor, err := compactValue(dst, src, 0, escape) + if err != nil { + return nil, err + } + if err := validateEndBuf(src, cursor); err != nil { + return nil, err + } + return buf, nil +} + +func validateEndBuf(src []byte, cursor int64) error { + for { + switch src[cursor] { + case ' ', '\t', '\n', '\r': + cursor++ + continue + case nul: + return nil + } + return errors.ErrSyntax( + fmt.Sprintf("invalid character '%c' after top-level value", src[cursor]), + cursor+1, + ) + } +} + +func skipWhiteSpace(buf []byte, cursor int64) int64 { +LOOP: + if isWhiteSpace[buf[cursor]] { + cursor++ + goto LOOP + } + return cursor +} + +func compactValue(dst, src []byte, cursor int64, escape bool) ([]byte, int64, error) { + for { + switch src[cursor] { + case ' ', '\t', '\n', '\r': + cursor++ + continue + case '{': + return compactObject(dst, src, cursor, escape) + case '}': + return nil, 0, errors.ErrSyntax("unexpected character '}'", cursor) + case '[': + return compactArray(dst, src, cursor, escape) + case ']': + return nil, 0, errors.ErrSyntax("unexpected character ']'", cursor) + case '"': + return compactString(dst, src, cursor, escape) + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return compactNumber(dst, src, cursor) + case 't': + return compactTrue(dst, src, cursor) + case 'f': + return compactFalse(dst, src, cursor) + case 'n': + return compactNull(dst, src, cursor) + default: + return nil, 0, errors.ErrSyntax(fmt.Sprintf("unexpected character '%c'", src[cursor]), cursor) + } + } +} + +func compactObject(dst, src []byte, cursor int64, escape bool) ([]byte, int64, error) { + if src[cursor] == '{' { + dst = append(dst, '{') + } else { + return nil, 0, errors.ErrExpected("expected { character for object value", cursor) + } + cursor = skipWhiteSpace(src, cursor+1) + if src[cursor] == '}' { + dst = append(dst, '}') + return dst, cursor + 1, nil + } + var err error + for { + cursor = skipWhiteSpace(src, cursor) + dst, cursor, err = compactString(dst, src, cursor, escape) + if err != nil { + return nil, 0, err + } + cursor = skipWhiteSpace(src, cursor) + if src[cursor] != ':' { + return nil, 0, errors.ErrExpected("colon after object key", cursor) + } + dst = append(dst, ':') + dst, cursor, err = compactValue(dst, src, cursor+1, escape) + if err != nil { + return nil, 0, err + } + cursor = skipWhiteSpace(src, cursor) + switch src[cursor] { + case '}': + dst = append(dst, '}') + cursor++ + return dst, cursor, nil + case ',': + dst = append(dst, ',') + default: + return nil, 0, errors.ErrExpected("comma after object value", cursor) + } + cursor++ + } +} + +func compactArray(dst, src []byte, cursor int64, escape bool) ([]byte, int64, error) { + if src[cursor] == '[' { + dst = append(dst, '[') + } else { + return nil, 0, errors.ErrExpected("expected [ character for array value", cursor) + } + cursor = skipWhiteSpace(src, cursor+1) + if src[cursor] == ']' { + dst = append(dst, ']') + return dst, cursor + 1, nil + } + var err error + for { + dst, cursor, err = compactValue(dst, src, cursor, escape) + if err != nil { + return nil, 0, err + } + cursor = skipWhiteSpace(src, cursor) + switch src[cursor] { + case ']': + dst = append(dst, ']') + cursor++ + return dst, cursor, nil + case ',': + dst = append(dst, ',') + default: + return nil, 0, errors.ErrExpected("comma after array value", cursor) + } + cursor++ + } +} + +func compactString(dst, src []byte, cursor int64, escape bool) ([]byte, int64, error) { + if src[cursor] != '"' { + return nil, 0, errors.ErrInvalidCharacter(src[cursor], "string", cursor) + } + start := cursor + for { + cursor++ + c := src[cursor] + if escape { + if isHTMLEscapeChar[c] { + dst = append(dst, src[start:cursor]...) + dst = append(dst, `\u00`...) + dst = append(dst, hex[c>>4], hex[c&0xF]) + start = cursor + 1 + } else if c == 0xE2 && cursor+2 < int64(len(src)) && src[cursor+1] == 0x80 && src[cursor+2]&^1 == 0xA8 { + dst = append(dst, src[start:cursor]...) + dst = append(dst, `\u202`...) + dst = append(dst, hex[src[cursor+2]&0xF]) + cursor += 2 + start = cursor + 3 + } + } + switch c { + case '\\': + cursor++ + if src[cursor] == nul { + return nil, 0, errors.ErrUnexpectedEndOfJSON("string", int64(len(src))) + } + case '"': + cursor++ + return append(dst, src[start:cursor]...), cursor, nil + case nul: + return nil, 0, errors.ErrUnexpectedEndOfJSON("string", int64(len(src))) + } + } +} + +func compactNumber(dst, src []byte, cursor int64) ([]byte, int64, error) { + start := cursor + for { + cursor++ + if floatTable[src[cursor]] { + continue + } + break + } + num := src[start:cursor] + if _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&num)), 64); err != nil { + return nil, 0, err + } + dst = append(dst, num...) + return dst, cursor, nil +} + +func compactTrue(dst, src []byte, cursor int64) ([]byte, int64, error) { + if cursor+3 >= int64(len(src)) { + return nil, 0, errors.ErrUnexpectedEndOfJSON("true", cursor) + } + if !bytes.Equal(src[cursor:cursor+4], []byte(`true`)) { + return nil, 0, errors.ErrInvalidCharacter(src[cursor], "true", cursor) + } + dst = append(dst, "true"...) + cursor += 4 + return dst, cursor, nil +} + +func compactFalse(dst, src []byte, cursor int64) ([]byte, int64, error) { + if cursor+4 >= int64(len(src)) { + return nil, 0, errors.ErrUnexpectedEndOfJSON("false", cursor) + } + if !bytes.Equal(src[cursor:cursor+5], []byte(`false`)) { + return nil, 0, errors.ErrInvalidCharacter(src[cursor], "false", cursor) + } + dst = append(dst, "false"...) + cursor += 5 + return dst, cursor, nil +} + +func compactNull(dst, src []byte, cursor int64) ([]byte, int64, error) { + if cursor+3 >= int64(len(src)) { + return nil, 0, errors.ErrUnexpectedEndOfJSON("null", cursor) + } + if !bytes.Equal(src[cursor:cursor+4], []byte(`null`)) { + return nil, 0, errors.ErrInvalidCharacter(src[cursor], "null", cursor) + } + dst = append(dst, "null"...) + cursor += 4 + return dst, cursor, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/compiler.go b/vendor/github.com/goccy/go-json/internal/encoder/compiler.go new file mode 100644 index 00000000..01a5d4b2 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/compiler.go @@ -0,0 +1,1569 @@ +package encoder + +import ( + "context" + "encoding" + "encoding/json" + "fmt" + "reflect" + "strings" + "sync/atomic" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type marshalerContext interface { + MarshalJSON(context.Context) ([]byte, error) +} + +var ( + marshalJSONType = reflect.TypeOf((*json.Marshaler)(nil)).Elem() + marshalJSONContextType = reflect.TypeOf((*marshalerContext)(nil)).Elem() + marshalTextType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() + jsonNumberType = reflect.TypeOf(json.Number("")) + cachedOpcodeSets []*OpcodeSet + cachedOpcodeMap unsafe.Pointer // map[uintptr]*OpcodeSet + typeAddr *runtime.TypeAddr +) + +func init() { + typeAddr = runtime.AnalyzeTypeAddr() + if typeAddr == nil { + typeAddr = &runtime.TypeAddr{} + } + cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift) +} + +func loadOpcodeMap() map[uintptr]*OpcodeSet { + p := atomic.LoadPointer(&cachedOpcodeMap) + return *(*map[uintptr]*OpcodeSet)(unsafe.Pointer(&p)) +} + +func storeOpcodeSet(typ uintptr, set *OpcodeSet, m map[uintptr]*OpcodeSet) { + newOpcodeMap := make(map[uintptr]*OpcodeSet, len(m)+1) + newOpcodeMap[typ] = set + + for k, v := range m { + newOpcodeMap[k] = v + } + + atomic.StorePointer(&cachedOpcodeMap, *(*unsafe.Pointer)(unsafe.Pointer(&newOpcodeMap))) +} + +func compileToGetCodeSetSlowPath(typeptr uintptr) (*OpcodeSet, error) { + opcodeMap := loadOpcodeMap() + if codeSet, exists := opcodeMap[typeptr]; exists { + return codeSet, nil + } + + // noescape trick for header.typ ( reflect.*rtype ) + copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr)) + + noescapeKeyCode, err := compileHead(&compileContext{ + typ: copiedType, + structTypeToCompiledCode: map[uintptr]*CompiledCode{}, + }) + if err != nil { + return nil, err + } + escapeKeyCode, err := compileHead(&compileContext{ + typ: copiedType, + structTypeToCompiledCode: map[uintptr]*CompiledCode{}, + escapeKey: true, + }) + if err != nil { + return nil, err + } + noescapeKeyCode = copyOpcode(noescapeKeyCode) + escapeKeyCode = copyOpcode(escapeKeyCode) + setTotalLengthToInterfaceOp(noescapeKeyCode) + setTotalLengthToInterfaceOp(escapeKeyCode) + interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode) + interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode) + codeLength := noescapeKeyCode.TotalLength() + codeSet := &OpcodeSet{ + Type: copiedType, + NoescapeKeyCode: noescapeKeyCode, + EscapeKeyCode: escapeKeyCode, + InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode, + InterfaceEscapeKeyCode: interfaceEscapeKeyCode, + CodeLength: codeLength, + EndCode: ToEndCode(interfaceNoescapeKeyCode), + } + storeOpcodeSet(typeptr, codeSet, opcodeMap) + return codeSet, nil +} + +func compileHead(ctx *compileContext) (*Opcode, error) { + typ := ctx.typ + switch { + case implementsMarshalJSON(typ): + return compileMarshalJSON(ctx) + case implementsMarshalText(typ): + return compileMarshalText(ctx) + } + + isPtr := false + orgType := typ + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + isPtr = true + } + switch { + case implementsMarshalJSON(typ): + return compileMarshalJSON(ctx) + case implementsMarshalText(typ): + return compileMarshalText(ctx) + } + switch typ.Kind() { + case reflect.Slice: + ctx := ctx.withType(typ) + elem := typ.Elem() + if elem.Kind() == reflect.Uint8 { + p := runtime.PtrTo(elem) + if !implementsMarshalJSONType(p) && !p.Implements(marshalTextType) { + if isPtr { + return compileBytesPtr(ctx) + } + return compileBytes(ctx) + } + } + code, err := compileSlice(ctx) + if err != nil { + return nil, err + } + optimizeStructEnd(code) + linkRecursiveCode(code) + return code, nil + case reflect.Map: + if isPtr { + return compilePtr(ctx.withType(runtime.PtrTo(typ))) + } + code, err := compileMap(ctx.withType(typ)) + if err != nil { + return nil, err + } + optimizeStructEnd(code) + linkRecursiveCode(code) + return code, nil + case reflect.Struct: + code, err := compileStruct(ctx.withType(typ), isPtr) + if err != nil { + return nil, err + } + optimizeStructEnd(code) + linkRecursiveCode(code) + return code, nil + case reflect.Int: + ctx := ctx.withType(typ) + if isPtr { + return compileIntPtr(ctx) + } + return compileInt(ctx) + case reflect.Int8: + ctx := ctx.withType(typ) + if isPtr { + return compileInt8Ptr(ctx) + } + return compileInt8(ctx) + case reflect.Int16: + ctx := ctx.withType(typ) + if isPtr { + return compileInt16Ptr(ctx) + } + return compileInt16(ctx) + case reflect.Int32: + ctx := ctx.withType(typ) + if isPtr { + return compileInt32Ptr(ctx) + } + return compileInt32(ctx) + case reflect.Int64: + ctx := ctx.withType(typ) + if isPtr { + return compileInt64Ptr(ctx) + } + return compileInt64(ctx) + case reflect.Uint, reflect.Uintptr: + ctx := ctx.withType(typ) + if isPtr { + return compileUintPtr(ctx) + } + return compileUint(ctx) + case reflect.Uint8: + ctx := ctx.withType(typ) + if isPtr { + return compileUint8Ptr(ctx) + } + return compileUint8(ctx) + case reflect.Uint16: + ctx := ctx.withType(typ) + if isPtr { + return compileUint16Ptr(ctx) + } + return compileUint16(ctx) + case reflect.Uint32: + ctx := ctx.withType(typ) + if isPtr { + return compileUint32Ptr(ctx) + } + return compileUint32(ctx) + case reflect.Uint64: + ctx := ctx.withType(typ) + if isPtr { + return compileUint64Ptr(ctx) + } + return compileUint64(ctx) + case reflect.Float32: + ctx := ctx.withType(typ) + if isPtr { + return compileFloat32Ptr(ctx) + } + return compileFloat32(ctx) + case reflect.Float64: + ctx := ctx.withType(typ) + if isPtr { + return compileFloat64Ptr(ctx) + } + return compileFloat64(ctx) + case reflect.String: + ctx := ctx.withType(typ) + if isPtr { + return compileStringPtr(ctx) + } + return compileString(ctx) + case reflect.Bool: + ctx := ctx.withType(typ) + if isPtr { + return compileBoolPtr(ctx) + } + return compileBool(ctx) + case reflect.Interface: + ctx := ctx.withType(typ) + if isPtr { + return compileInterfacePtr(ctx) + } + return compileInterface(ctx) + default: + if isPtr && typ.Implements(marshalTextType) { + typ = orgType + } + code, err := compile(ctx.withType(typ), isPtr) + if err != nil { + return nil, err + } + optimizeStructEnd(code) + linkRecursiveCode(code) + return code, nil + } +} + +func linkRecursiveCode(c *Opcode) { + for code := c; code.Op != OpEnd && code.Op != OpRecursiveEnd; { + switch code.Op { + case OpRecursive, OpRecursivePtr: + if code.Jmp.Linked { + code = code.Next + continue + } + code.Jmp.Code = copyOpcode(code.Jmp.Code) + + c := code.Jmp.Code + c.End.Next = newEndOp(&compileContext{}) + c.Op = c.Op.PtrHeadToHead() + + beforeLastCode := c.End + lastCode := beforeLastCode.Next + + lastCode.Idx = beforeLastCode.Idx + uintptrSize + lastCode.ElemIdx = lastCode.Idx + uintptrSize + lastCode.Length = lastCode.Idx + 2*uintptrSize + + // extend length to alloc slot for elemIdx + length + totalLength := uintptr(code.TotalLength() + 3) + nextTotalLength := uintptr(c.TotalLength() + 3) + + c.End.Next.Op = OpRecursiveEnd + + code.Jmp.CurLen = totalLength + code.Jmp.NextLen = nextTotalLength + code.Jmp.Linked = true + + linkRecursiveCode(code.Jmp.Code) + + code = code.Next + continue + } + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } +} + +func optimizeStructEnd(c *Opcode) { + for code := c; code.Op != OpEnd; { + if code.Op == OpRecursive || code.Op == OpRecursivePtr { + // ignore if exists recursive operation + return + } + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } + + for code := c; code.Op != OpEnd; { + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + case CodeStructEnd: + switch code.Op { + case OpStructEnd: + prev := code.PrevField + prevOp := prev.Op.String() + if strings.Contains(prevOp, "Head") || + strings.Contains(prevOp, "Slice") || + strings.Contains(prevOp, "Array") || + strings.Contains(prevOp, "Map") || + strings.Contains(prevOp, "MarshalJSON") || + strings.Contains(prevOp, "MarshalText") { + // not exists field + code = code.Next + break + } + if prev.Op != prev.Op.FieldToEnd() { + prev.Op = prev.Op.FieldToEnd() + prev.Next = code.Next + } + code = code.Next + default: + code = code.Next + } + default: + code = code.Next + } + } +} + +func implementsMarshalJSON(typ *runtime.Type) bool { + if !implementsMarshalJSONType(typ) { + return false + } + if typ.Kind() != reflect.Ptr { + return true + } + // type kind is reflect.Ptr + if !implementsMarshalJSONType(typ.Elem()) { + return true + } + // needs to dereference + return false +} + +func implementsMarshalText(typ *runtime.Type) bool { + if !typ.Implements(marshalTextType) { + return false + } + if typ.Kind() != reflect.Ptr { + return true + } + // type kind is reflect.Ptr + if !typ.Elem().Implements(marshalTextType) { + return true + } + // needs to dereference + return false +} + +func compile(ctx *compileContext, isPtr bool) (*Opcode, error) { + typ := ctx.typ + switch { + case implementsMarshalJSON(typ): + return compileMarshalJSON(ctx) + case implementsMarshalText(typ): + return compileMarshalText(ctx) + } + switch typ.Kind() { + case reflect.Ptr: + return compilePtr(ctx) + case reflect.Slice: + elem := typ.Elem() + if elem.Kind() == reflect.Uint8 { + p := runtime.PtrTo(elem) + if !implementsMarshalJSONType(p) && !p.Implements(marshalTextType) { + return compileBytes(ctx) + } + } + return compileSlice(ctx) + case reflect.Array: + return compileArray(ctx) + case reflect.Map: + return compileMap(ctx) + case reflect.Struct: + return compileStruct(ctx, isPtr) + case reflect.Interface: + return compileInterface(ctx) + case reflect.Int: + return compileInt(ctx) + case reflect.Int8: + return compileInt8(ctx) + case reflect.Int16: + return compileInt16(ctx) + case reflect.Int32: + return compileInt32(ctx) + case reflect.Int64: + return compileInt64(ctx) + case reflect.Uint: + return compileUint(ctx) + case reflect.Uint8: + return compileUint8(ctx) + case reflect.Uint16: + return compileUint16(ctx) + case reflect.Uint32: + return compileUint32(ctx) + case reflect.Uint64: + return compileUint64(ctx) + case reflect.Uintptr: + return compileUint(ctx) + case reflect.Float32: + return compileFloat32(ctx) + case reflect.Float64: + return compileFloat64(ctx) + case reflect.String: + return compileString(ctx) + case reflect.Bool: + return compileBool(ctx) + } + return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)} +} + +func convertPtrOp(code *Opcode) OpType { + ptrHeadOp := code.Op.HeadToPtrHead() + if code.Op != ptrHeadOp { + if code.PtrNum > 0 { + // ptr field and ptr head + code.PtrNum-- + } + return ptrHeadOp + } + switch code.Op { + case OpInt: + return OpIntPtr + case OpUint: + return OpUintPtr + case OpFloat32: + return OpFloat32Ptr + case OpFloat64: + return OpFloat64Ptr + case OpString: + return OpStringPtr + case OpBool: + return OpBoolPtr + case OpBytes: + return OpBytesPtr + case OpNumber: + return OpNumberPtr + case OpArray: + return OpArrayPtr + case OpSlice: + return OpSlicePtr + case OpMap: + return OpMapPtr + case OpMarshalJSON: + return OpMarshalJSONPtr + case OpMarshalText: + return OpMarshalTextPtr + case OpInterface: + return OpInterfacePtr + case OpRecursive: + return OpRecursivePtr + } + return code.Op +} + +func compileKey(ctx *compileContext) (*Opcode, error) { + typ := ctx.typ + switch { + case implementsMarshalJSON(typ): + return compileMarshalJSON(ctx) + case implementsMarshalText(typ): + return compileMarshalText(ctx) + } + switch typ.Kind() { + case reflect.Ptr: + return compilePtr(ctx) + case reflect.String: + return compileString(ctx) + case reflect.Int: + return compileIntString(ctx) + case reflect.Int8: + return compileInt8String(ctx) + case reflect.Int16: + return compileInt16String(ctx) + case reflect.Int32: + return compileInt32String(ctx) + case reflect.Int64: + return compileInt64String(ctx) + case reflect.Uint: + return compileUintString(ctx) + case reflect.Uint8: + return compileUint8String(ctx) + case reflect.Uint16: + return compileUint16String(ctx) + case reflect.Uint32: + return compileUint32String(ctx) + case reflect.Uint64: + return compileUint64String(ctx) + case reflect.Uintptr: + return compileUintString(ctx) + } + return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)} +} + +func compilePtr(ctx *compileContext) (*Opcode, error) { + code, err := compile(ctx.withType(ctx.typ.Elem()), true) + if err != nil { + return nil, err + } + code.Op = convertPtrOp(code) + code.PtrNum++ + return code, nil +} + +func compileMarshalJSON(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpMarshalJSON) + typ := ctx.typ + if isPtrMarshalJSONType(typ) { + code.Flags |= AddrForMarshalerFlags + } + if typ.Implements(marshalJSONContextType) || runtime.PtrTo(typ).Implements(marshalJSONContextType) { + code.Flags |= MarshalerContextFlags + } + if isNilableType(typ) { + code.Flags |= IsNilableTypeFlags + } else { + code.Flags &= ^IsNilableTypeFlags + } + ctx.incIndex() + return code, nil +} + +func compileMarshalText(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpMarshalText) + typ := ctx.typ + if !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType) { + code.Flags |= AddrForMarshalerFlags + } + if isNilableType(typ) { + code.Flags |= IsNilableTypeFlags + } else { + code.Flags &= ^IsNilableTypeFlags + } + ctx.incIndex() + return code, nil +} + +const intSize = 32 << (^uint(0) >> 63) + +func compileInt(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.NumBitSize = intSize + ctx.incIndex() + return code, nil +} + +func compileIntPtr(ctx *compileContext) (*Opcode, error) { + code, err := compileInt(ctx) + if err != nil { + return nil, err + } + code.Op = OpIntPtr + return code, nil +} + +func compileInt8(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.NumBitSize = 8 + ctx.incIndex() + return code, nil +} + +func compileInt8Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileInt8(ctx) + if err != nil { + return nil, err + } + code.Op = OpIntPtr + return code, nil +} + +func compileInt16(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.NumBitSize = 16 + ctx.incIndex() + return code, nil +} + +func compileInt16Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileInt16(ctx) + if err != nil { + return nil, err + } + code.Op = OpIntPtr + return code, nil +} + +func compileInt32(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.NumBitSize = 32 + ctx.incIndex() + return code, nil +} + +func compileInt32Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileInt32(ctx) + if err != nil { + return nil, err + } + code.Op = OpIntPtr + return code, nil +} + +func compileInt64(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpInt) + code.NumBitSize = 64 + ctx.incIndex() + return code, nil +} + +func compileInt64Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileInt64(ctx) + if err != nil { + return nil, err + } + code.Op = OpIntPtr + return code, nil +} + +func compileUint(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.NumBitSize = intSize + ctx.incIndex() + return code, nil +} + +func compileUintPtr(ctx *compileContext) (*Opcode, error) { + code, err := compileUint(ctx) + if err != nil { + return nil, err + } + code.Op = OpUintPtr + return code, nil +} + +func compileUint8(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.NumBitSize = 8 + ctx.incIndex() + return code, nil +} + +func compileUint8Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileUint8(ctx) + if err != nil { + return nil, err + } + code.Op = OpUintPtr + return code, nil +} + +func compileUint16(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.NumBitSize = 16 + ctx.incIndex() + return code, nil +} + +func compileUint16Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileUint16(ctx) + if err != nil { + return nil, err + } + code.Op = OpUintPtr + return code, nil +} + +func compileUint32(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.NumBitSize = 32 + ctx.incIndex() + return code, nil +} + +func compileUint32Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileUint32(ctx) + if err != nil { + return nil, err + } + code.Op = OpUintPtr + return code, nil +} + +func compileUint64(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUint) + code.NumBitSize = 64 + ctx.incIndex() + return code, nil +} + +func compileUint64Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileUint64(ctx) + if err != nil { + return nil, err + } + code.Op = OpUintPtr + return code, nil +} + +func compileIntString(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.NumBitSize = intSize + ctx.incIndex() + return code, nil +} + +func compileInt8String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.NumBitSize = 8 + ctx.incIndex() + return code, nil +} + +func compileInt16String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.NumBitSize = 16 + ctx.incIndex() + return code, nil +} + +func compileInt32String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.NumBitSize = 32 + ctx.incIndex() + return code, nil +} + +func compileInt64String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpIntString) + code.NumBitSize = 64 + ctx.incIndex() + return code, nil +} + +func compileUintString(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.NumBitSize = intSize + ctx.incIndex() + return code, nil +} + +func compileUint8String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.NumBitSize = 8 + ctx.incIndex() + return code, nil +} + +func compileUint16String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.NumBitSize = 16 + ctx.incIndex() + return code, nil +} + +func compileUint32String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.NumBitSize = 32 + ctx.incIndex() + return code, nil +} + +func compileUint64String(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpUintString) + code.NumBitSize = 64 + ctx.incIndex() + return code, nil +} + +func compileFloat32(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpFloat32) + ctx.incIndex() + return code, nil +} + +func compileFloat32Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileFloat32(ctx) + if err != nil { + return nil, err + } + code.Op = OpFloat32Ptr + return code, nil +} + +func compileFloat64(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpFloat64) + ctx.incIndex() + return code, nil +} + +func compileFloat64Ptr(ctx *compileContext) (*Opcode, error) { + code, err := compileFloat64(ctx) + if err != nil { + return nil, err + } + code.Op = OpFloat64Ptr + return code, nil +} + +func compileString(ctx *compileContext) (*Opcode, error) { + var op OpType + if ctx.typ == runtime.Type2RType(jsonNumberType) { + op = OpNumber + } else { + op = OpString + } + code := newOpCode(ctx, op) + ctx.incIndex() + return code, nil +} + +func compileStringPtr(ctx *compileContext) (*Opcode, error) { + code, err := compileString(ctx) + if err != nil { + return nil, err + } + if code.Op == OpNumber { + code.Op = OpNumberPtr + } else { + code.Op = OpStringPtr + } + return code, nil +} + +func compileBool(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpBool) + ctx.incIndex() + return code, nil +} + +func compileBoolPtr(ctx *compileContext) (*Opcode, error) { + code, err := compileBool(ctx) + if err != nil { + return nil, err + } + code.Op = OpBoolPtr + return code, nil +} + +func compileBytes(ctx *compileContext) (*Opcode, error) { + code := newOpCode(ctx, OpBytes) + ctx.incIndex() + return code, nil +} + +func compileBytesPtr(ctx *compileContext) (*Opcode, error) { + code, err := compileBytes(ctx) + if err != nil { + return nil, err + } + code.Op = OpBytesPtr + return code, nil +} + +func compileInterface(ctx *compileContext) (*Opcode, error) { + code := newInterfaceCode(ctx) + ctx.incIndex() + return code, nil +} + +func compileInterfacePtr(ctx *compileContext) (*Opcode, error) { + code, err := compileInterface(ctx) + if err != nil { + return nil, err + } + code.Op = OpInterfacePtr + return code, nil +} + +func compileSlice(ctx *compileContext) (*Opcode, error) { + elem := ctx.typ.Elem() + size := elem.Size() + + header := newSliceHeaderCode(ctx) + ctx.incIndex() + + code, err := compileListElem(ctx.withType(elem).incIndent()) + if err != nil { + return nil, err + } + code.Flags |= IndirectFlags + + // header => opcode => elem => end + // ^ | + // |________| + + elemCode := newSliceElemCode(ctx, header, size) + ctx.incIndex() + + end := newOpCode(ctx, OpSliceEnd) + ctx.incIndex() + + header.End = end + header.Next = code + code.BeforeLastCode().Next = (*Opcode)(unsafe.Pointer(elemCode)) + elemCode.Next = code + elemCode.End = end + return (*Opcode)(unsafe.Pointer(header)), nil +} + +func compileListElem(ctx *compileContext) (*Opcode, error) { + typ := ctx.typ + switch { + case isPtrMarshalJSONType(typ): + return compileMarshalJSON(ctx) + case !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType): + return compileMarshalText(ctx) + case typ.Kind() == reflect.Map: + return compilePtr(ctx.withType(runtime.PtrTo(typ))) + default: + code, err := compile(ctx, false) + if err != nil { + return nil, err + } + if code.Op == OpMapPtr { + code.PtrNum++ + } + return code, nil + } +} + +func compileArray(ctx *compileContext) (*Opcode, error) { + typ := ctx.typ + elem := typ.Elem() + alen := typ.Len() + size := elem.Size() + + header := newArrayHeaderCode(ctx, alen) + ctx.incIndex() + + code, err := compileListElem(ctx.withType(elem).incIndent()) + if err != nil { + return nil, err + } + code.Flags |= IndirectFlags + // header => opcode => elem => end + // ^ | + // |________| + + elemCode := newArrayElemCode(ctx, header, alen, size) + ctx.incIndex() + + end := newOpCode(ctx, OpArrayEnd) + ctx.incIndex() + + header.End = end + header.Next = code + code.BeforeLastCode().Next = (*Opcode)(unsafe.Pointer(elemCode)) + elemCode.Next = code + elemCode.End = end + return (*Opcode)(unsafe.Pointer(header)), nil +} + +func compileMap(ctx *compileContext) (*Opcode, error) { + // header => code => value => code => key => code => value => code => end + // ^ | + // |_______________________| + ctx = ctx.incIndent() + header := newMapHeaderCode(ctx) + ctx.incIndex() + + typ := ctx.typ + keyType := ctx.typ.Key() + keyCode, err := compileKey(ctx.withType(keyType)) + if err != nil { + return nil, err + } + + value := newMapValueCode(ctx, header) + ctx.incIndex() + + valueCode, err := compileMapValue(ctx.withType(typ.Elem())) + if err != nil { + return nil, err + } + valueCode.Flags |= IndirectFlags + + key := newMapKeyCode(ctx, header) + ctx.incIndex() + + ctx = ctx.decIndent() + + end := newMapEndCode(ctx, header) + ctx.incIndex() + + header.Next = keyCode + keyCode.BeforeLastCode().Next = (*Opcode)(unsafe.Pointer(value)) + value.Next = valueCode + valueCode.BeforeLastCode().Next = (*Opcode)(unsafe.Pointer(key)) + key.Next = keyCode + + header.End = end + key.End = end + value.End = end + + return (*Opcode)(unsafe.Pointer(header)), nil +} + +func compileMapValue(ctx *compileContext) (*Opcode, error) { + switch ctx.typ.Kind() { + case reflect.Map: + return compilePtr(ctx.withType(runtime.PtrTo(ctx.typ))) + default: + code, err := compile(ctx, false) + if err != nil { + return nil, err + } + if code.Op == OpMapPtr { + code.PtrNum++ + } + return code, nil + } +} + +func optimizeStructHeader(code *Opcode, tag *runtime.StructTag) OpType { + headType := code.ToHeaderType(tag.IsString) + if tag.IsOmitEmpty { + headType = headType.HeadToOmitEmptyHead() + } + return headType +} + +func optimizeStructField(code *Opcode, tag *runtime.StructTag) OpType { + fieldType := code.ToFieldType(tag.IsString) + if tag.IsOmitEmpty { + fieldType = fieldType.FieldToOmitEmptyField() + } + return fieldType +} + +func recursiveCode(ctx *compileContext, jmp *CompiledCode) *Opcode { + code := newRecursiveCode(ctx, jmp) + ctx.incIndex() + return code +} + +func compiledCode(ctx *compileContext) *Opcode { + typ := ctx.typ + typeptr := uintptr(unsafe.Pointer(typ)) + if cc, exists := ctx.structTypeToCompiledCode[typeptr]; exists { + return recursiveCode(ctx, cc) + } + return nil +} + +func structHeader(ctx *compileContext, fieldCode *Opcode, valueCode *Opcode, tag *runtime.StructTag) *Opcode { + op := optimizeStructHeader(valueCode, tag) + fieldCode.Op = op + fieldCode.NumBitSize = valueCode.NumBitSize + fieldCode.PtrNum = valueCode.PtrNum + if op.IsMultipleOpHead() { + return valueCode.BeforeLastCode() + } + ctx.decOpcodeIndex() + return fieldCode +} + +func structField(ctx *compileContext, fieldCode *Opcode, valueCode *Opcode, tag *runtime.StructTag) *Opcode { + op := optimizeStructField(valueCode, tag) + fieldCode.Op = op + fieldCode.NumBitSize = valueCode.NumBitSize + fieldCode.PtrNum = valueCode.PtrNum + if op.IsMultipleOpField() { + return valueCode.BeforeLastCode() + } + ctx.decIndex() + return fieldCode +} + +func isNotExistsField(head *Opcode) bool { + if head == nil { + return false + } + if head.Op != OpStructHead { + return false + } + if (head.Flags & AnonymousHeadFlags) == 0 { + return false + } + if head.Next == nil { + return false + } + if head.NextField == nil { + return false + } + if head.NextField.Op != OpStructAnonymousEnd { + return false + } + if head.Next.Op == OpStructAnonymousEnd { + return true + } + if head.Next.Op.CodeType() != CodeStructField { + return false + } + return isNotExistsField(head.Next) +} + +func optimizeAnonymousFields(head *Opcode) { + code := head + var prev *Opcode + removedFields := map[*Opcode]struct{}{} + for { + if code.Op == OpStructEnd { + break + } + if code.Op == OpStructField { + codeType := code.Next.Op.CodeType() + if codeType == CodeStructField { + if isNotExistsField(code.Next) { + code.Next = code.NextField + diff := code.Next.DisplayIdx - code.DisplayIdx + for i := uint32(0); i < diff; i++ { + code.Next.decOpcodeIndex() + } + linkPrevToNextField(code, removedFields) + code = prev + } + } + } + prev = code + code = code.NextField + } +} + +type structFieldPair struct { + prevField *Opcode + curField *Opcode + isTaggedKey bool + linked bool +} + +func anonymousStructFieldPairMap(tags runtime.StructTags, named string, valueCode *Opcode) map[string][]structFieldPair { + anonymousFields := map[string][]structFieldPair{} + f := valueCode + var prevAnonymousField *Opcode + removedFields := map[*Opcode]struct{}{} + for { + existsKey := tags.ExistsKey(f.DisplayKey) + isHeadOp := strings.Contains(f.Op.String(), "Head") + if existsKey && f.Next != nil && strings.Contains(f.Next.Op.String(), "Recursive") { + // through + } else if isHeadOp && (f.Flags&AnonymousHeadFlags) == 0 { + if existsKey { + // TODO: need to remove this head + f.Op = OpStructHead + f.Flags |= AnonymousKeyFlags + f.Flags |= AnonymousHeadFlags + } else if named == "" { + f.Flags |= AnonymousHeadFlags + } + } else if named == "" && f.Op == OpStructEnd { + f.Op = OpStructAnonymousEnd + } else if existsKey { + diff := f.NextField.DisplayIdx - f.DisplayIdx + for i := uint32(0); i < diff; i++ { + f.NextField.decOpcodeIndex() + } + linkPrevToNextField(f, removedFields) + } + + if f.DisplayKey == "" { + if f.NextField == nil { + break + } + prevAnonymousField = f + f = f.NextField + continue + } + + key := fmt.Sprintf("%s.%s", named, f.DisplayKey) + anonymousFields[key] = append(anonymousFields[key], structFieldPair{ + prevField: prevAnonymousField, + curField: f, + isTaggedKey: (f.Flags & IsTaggedKeyFlags) != 0, + }) + if f.Next != nil && f.NextField != f.Next && f.Next.Op.CodeType() == CodeStructField { + for k, v := range anonymousFieldPairRecursively(named, f.Next) { + anonymousFields[k] = append(anonymousFields[k], v...) + } + } + if f.NextField == nil { + break + } + prevAnonymousField = f + f = f.NextField + } + return anonymousFields +} + +func anonymousFieldPairRecursively(named string, valueCode *Opcode) map[string][]structFieldPair { + anonymousFields := map[string][]structFieldPair{} + f := valueCode + var prevAnonymousField *Opcode + for { + if f.DisplayKey != "" && (f.Flags&AnonymousHeadFlags) != 0 { + key := fmt.Sprintf("%s.%s", named, f.DisplayKey) + anonymousFields[key] = append(anonymousFields[key], structFieldPair{ + prevField: prevAnonymousField, + curField: f, + isTaggedKey: (f.Flags & IsTaggedKeyFlags) != 0, + }) + if f.Next != nil && f.NextField != f.Next && f.Next.Op.CodeType() == CodeStructField { + for k, v := range anonymousFieldPairRecursively(named, f.Next) { + anonymousFields[k] = append(anonymousFields[k], v...) + } + } + } + if f.NextField == nil { + break + } + prevAnonymousField = f + f = f.NextField + } + return anonymousFields +} + +func optimizeConflictAnonymousFields(anonymousFields map[string][]structFieldPair) { + removedFields := map[*Opcode]struct{}{} + for _, fieldPairs := range anonymousFields { + if len(fieldPairs) == 1 { + continue + } + // conflict anonymous fields + taggedPairs := []structFieldPair{} + for _, fieldPair := range fieldPairs { + if fieldPair.isTaggedKey { + taggedPairs = append(taggedPairs, fieldPair) + } else { + if !fieldPair.linked { + if fieldPair.prevField == nil { + // head operation + fieldPair.curField.Op = OpStructHead + fieldPair.curField.Flags |= AnonymousHeadFlags + fieldPair.curField.Flags |= AnonymousKeyFlags + } else { + diff := fieldPair.curField.NextField.DisplayIdx - fieldPair.curField.DisplayIdx + for i := uint32(0); i < diff; i++ { + fieldPair.curField.NextField.decOpcodeIndex() + } + removedFields[fieldPair.curField] = struct{}{} + linkPrevToNextField(fieldPair.curField, removedFields) + } + fieldPair.linked = true + } + } + } + if len(taggedPairs) > 1 { + for _, fieldPair := range taggedPairs { + if !fieldPair.linked { + if fieldPair.prevField == nil { + // head operation + fieldPair.curField.Op = OpStructHead + fieldPair.curField.Flags |= AnonymousHeadFlags + fieldPair.curField.Flags |= AnonymousKeyFlags + } else { + diff := fieldPair.curField.NextField.DisplayIdx - fieldPair.curField.DisplayIdx + removedFields[fieldPair.curField] = struct{}{} + for i := uint32(0); i < diff; i++ { + fieldPair.curField.NextField.decOpcodeIndex() + } + linkPrevToNextField(fieldPair.curField, removedFields) + } + fieldPair.linked = true + } + } + } else { + for _, fieldPair := range taggedPairs { + fieldPair.curField.Flags &= ^IsTaggedKeyFlags + } + } + } +} + +func isNilableType(typ *runtime.Type) bool { + switch typ.Kind() { + case reflect.Ptr: + return true + case reflect.Map: + return true + case reflect.Func: + return true + default: + return false + } +} + +func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { + if code := compiledCode(ctx); code != nil { + return code, nil + } + typ := ctx.typ + typeptr := uintptr(unsafe.Pointer(typ)) + compiled := &CompiledCode{} + ctx.structTypeToCompiledCode[typeptr] = compiled + // header => code => structField => code => end + // ^ | + // |__________| + fieldNum := typ.NumField() + indirect := runtime.IfaceIndir(typ) + fieldIdx := 0 + disableIndirectConversion := false + var ( + head *Opcode + code *Opcode + prevField *Opcode + ) + ctx = ctx.incIndent() + tags := runtime.StructTags{} + anonymousFields := map[string][]structFieldPair{} + for i := 0; i < fieldNum; i++ { + field := typ.Field(i) + if runtime.IsIgnoredStructField(field) { + continue + } + tags = append(tags, runtime.StructTagFromField(field)) + } + for i, tag := range tags { + field := tag.Field + fieldType := runtime.Type2RType(field.Type) + fieldOpcodeIndex := ctx.opcodeIndex + fieldPtrIndex := ctx.ptrIndex + ctx.incIndex() + + nilcheck := true + addrForMarshaler := false + isIndirectSpecialCase := isPtr && i == 0 && fieldNum == 1 + isNilableType := isNilableType(fieldType) + + var valueCode *Opcode + switch { + case isIndirectSpecialCase && !isNilableType && isPtrMarshalJSONType(fieldType): + // *struct{ field T } => struct { field *T } + // func (*T) MarshalJSON() ([]byte, error) + // move pointer position from head to first field + code, err := compileMarshalJSON(ctx.withType(fieldType)) + if err != nil { + return nil, err + } + addrForMarshaler = true + valueCode = code + nilcheck = false + indirect = false + disableIndirectConversion = true + case isIndirectSpecialCase && !isNilableType && isPtrMarshalTextType(fieldType): + // *struct{ field T } => struct { field *T } + // func (*T) MarshalText() ([]byte, error) + // move pointer position from head to first field + code, err := compileMarshalText(ctx.withType(fieldType)) + if err != nil { + return nil, err + } + addrForMarshaler = true + valueCode = code + nilcheck = false + indirect = false + disableIndirectConversion = true + case isPtr && isPtrMarshalJSONType(fieldType): + // *struct{ field T } + // func (*T) MarshalJSON() ([]byte, error) + code, err := compileMarshalJSON(ctx.withType(fieldType)) + if err != nil { + return nil, err + } + addrForMarshaler = true + nilcheck = false + valueCode = code + case isPtr && isPtrMarshalTextType(fieldType): + // *struct{ field T } + // func (*T) MarshalText() ([]byte, error) + code, err := compileMarshalText(ctx.withType(fieldType)) + if err != nil { + return nil, err + } + addrForMarshaler = true + nilcheck = false + valueCode = code + default: + code, err := compile(ctx.withType(fieldType), isPtr) + if err != nil { + return nil, err + } + valueCode = code + } + + if field.Anonymous { + tagKey := "" + if tag.IsTaggedKey { + tagKey = tag.Key + } + for k, v := range anonymousStructFieldPairMap(tags, tagKey, valueCode) { + anonymousFields[k] = append(anonymousFields[k], v...) + } + valueCode.decIndent() + + // fix issue144 + if !(isPtr && strings.Contains(valueCode.Op.String(), "Marshal")) { + if indirect { + valueCode.Flags |= IndirectFlags + } else { + valueCode.Flags &= ^IndirectFlags + } + } + } else { + if indirect { + // if parent is indirect type, set child indirect property to true + valueCode.Flags |= IndirectFlags + } else { + // if parent is not indirect type, set child indirect property to false. + // but if parent's indirect is false and isPtr is true, then indirect must be true. + // Do this only if indirectConversion is enabled at the end of compileStruct. + if i == 0 { + valueCode.Flags &= ^IndirectFlags + } + } + } + var flags OpFlags + if indirect { + flags |= IndirectFlags + } + if field.Anonymous { + flags |= AnonymousKeyFlags + } + if tag.IsTaggedKey { + flags |= IsTaggedKeyFlags + } + if nilcheck { + flags |= NilCheckFlags + } + if addrForMarshaler { + flags |= AddrForMarshalerFlags + } + if strings.Contains(valueCode.Op.String(), "Ptr") || valueCode.Op == OpInterface { + flags |= IsNextOpPtrTypeFlags + } + if isNilableType { + flags |= IsNilableTypeFlags + } + var key string + if ctx.escapeKey { + rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}} + key = fmt.Sprintf(`%s:`, string(AppendString(rctx, []byte{}, tag.Key))) + } else { + key = fmt.Sprintf(`"%s":`, tag.Key) + } + fieldCode := &Opcode{ + Idx: opcodeOffset(fieldPtrIndex), + Next: valueCode, + Flags: flags, + Key: key, + Offset: uint32(field.Offset), + Type: valueCode.Type, + DisplayIdx: fieldOpcodeIndex, + Indent: ctx.indent, + DisplayKey: tag.Key, + } + if fieldIdx == 0 { + code = structHeader(ctx, fieldCode, valueCode, tag) + head = fieldCode + prevField = fieldCode + } else { + fieldCode.Idx = head.Idx + code.Next = fieldCode + code = structField(ctx, fieldCode, valueCode, tag) + prevField.NextField = fieldCode + fieldCode.PrevField = prevField + prevField = fieldCode + } + fieldIdx++ + } + + structEndCode := &Opcode{ + Op: OpStructEnd, + Next: newEndOp(ctx), + Type: nil, + Indent: ctx.indent, + } + + ctx = ctx.decIndent() + + // no struct field + if head == nil { + head = &Opcode{ + Op: OpStructHead, + Idx: opcodeOffset(ctx.ptrIndex), + NextField: structEndCode, + Type: typ, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } + structEndCode.PrevField = head + ctx.incIndex() + code = head + } + + structEndCode.DisplayIdx = ctx.opcodeIndex + structEndCode.Idx = opcodeOffset(ctx.ptrIndex) + ctx.incIndex() + + if prevField != nil && prevField.NextField == nil { + prevField.NextField = structEndCode + structEndCode.PrevField = prevField + } + + head.End = structEndCode + code.Next = structEndCode + optimizeConflictAnonymousFields(anonymousFields) + optimizeAnonymousFields(head) + ret := (*Opcode)(unsafe.Pointer(head)) + compiled.Code = ret + + delete(ctx.structTypeToCompiledCode, typeptr) + + if !disableIndirectConversion && (head.Flags&IndirectFlags == 0) && isPtr { + headCode := head + for strings.Contains(headCode.Op.String(), "Head") { + headCode.Flags |= IndirectFlags + headCode = headCode.Next + } + } + + return ret, nil +} + +func implementsMarshalJSONType(typ *runtime.Type) bool { + return typ.Implements(marshalJSONType) || typ.Implements(marshalJSONContextType) +} + +func isPtrMarshalJSONType(typ *runtime.Type) bool { + return !implementsMarshalJSONType(typ) && implementsMarshalJSONType(runtime.PtrTo(typ)) +} + +func isPtrMarshalTextType(typ *runtime.Type) bool { + return !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType) +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/compiler_norace.go b/vendor/github.com/goccy/go-json/internal/encoder/compiler_norace.go new file mode 100644 index 00000000..9d337f12 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/compiler_norace.go @@ -0,0 +1,56 @@ +// +build !race + +package encoder + +import ( + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) { + if typeptr > typeAddr.MaxTypeAddr { + return compileToGetCodeSetSlowPath(typeptr) + } + index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift + if codeSet := cachedOpcodeSets[index]; codeSet != nil { + return codeSet, nil + } + + // noescape trick for header.typ ( reflect.*rtype ) + copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr)) + + noescapeKeyCode, err := compileHead(&compileContext{ + typ: copiedType, + structTypeToCompiledCode: map[uintptr]*CompiledCode{}, + }) + if err != nil { + return nil, err + } + escapeKeyCode, err := compileHead(&compileContext{ + typ: copiedType, + structTypeToCompiledCode: map[uintptr]*CompiledCode{}, + escapeKey: true, + }) + if err != nil { + return nil, err + } + noescapeKeyCode = copyOpcode(noescapeKeyCode) + escapeKeyCode = copyOpcode(escapeKeyCode) + setTotalLengthToInterfaceOp(noescapeKeyCode) + setTotalLengthToInterfaceOp(escapeKeyCode) + interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode) + interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode) + codeLength := noescapeKeyCode.TotalLength() + codeSet := &OpcodeSet{ + Type: copiedType, + NoescapeKeyCode: noescapeKeyCode, + EscapeKeyCode: escapeKeyCode, + InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode, + InterfaceEscapeKeyCode: interfaceEscapeKeyCode, + CodeLength: codeLength, + EndCode: ToEndCode(interfaceNoescapeKeyCode), + } + cachedOpcodeSets[index] = codeSet + return codeSet, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/compiler_race.go b/vendor/github.com/goccy/go-json/internal/encoder/compiler_race.go new file mode 100644 index 00000000..3a239e9d --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/compiler_race.go @@ -0,0 +1,65 @@ +// +build race + +package encoder + +import ( + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +var setsMu sync.RWMutex + +func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) { + if typeptr > typeAddr.MaxTypeAddr { + return compileToGetCodeSetSlowPath(typeptr) + } + index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift + setsMu.RLock() + if codeSet := cachedOpcodeSets[index]; codeSet != nil { + setsMu.RUnlock() + return codeSet, nil + } + setsMu.RUnlock() + + // noescape trick for header.typ ( reflect.*rtype ) + copiedType := *(**runtime.Type)(unsafe.Pointer(&typeptr)) + + noescapeKeyCode, err := compileHead(&compileContext{ + typ: copiedType, + structTypeToCompiledCode: map[uintptr]*CompiledCode{}, + }) + if err != nil { + return nil, err + } + escapeKeyCode, err := compileHead(&compileContext{ + typ: copiedType, + structTypeToCompiledCode: map[uintptr]*CompiledCode{}, + escapeKey: true, + }) + if err != nil { + return nil, err + } + + noescapeKeyCode = copyOpcode(noescapeKeyCode) + escapeKeyCode = copyOpcode(escapeKeyCode) + setTotalLengthToInterfaceOp(noescapeKeyCode) + setTotalLengthToInterfaceOp(escapeKeyCode) + interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode) + interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode) + codeLength := noescapeKeyCode.TotalLength() + codeSet := &OpcodeSet{ + Type: copiedType, + NoescapeKeyCode: noescapeKeyCode, + EscapeKeyCode: escapeKeyCode, + InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode, + InterfaceEscapeKeyCode: interfaceEscapeKeyCode, + CodeLength: codeLength, + EndCode: ToEndCode(interfaceNoescapeKeyCode), + } + setsMu.Lock() + cachedOpcodeSets[index] = codeSet + setsMu.Unlock() + return codeSet, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/context.go b/vendor/github.com/goccy/go-json/internal/encoder/context.go new file mode 100644 index 00000000..61b89080 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/context.go @@ -0,0 +1,141 @@ +package encoder + +import ( + "context" + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +type compileContext struct { + typ *runtime.Type + opcodeIndex uint32 + ptrIndex int + indent uint32 + escapeKey bool + structTypeToCompiledCode map[uintptr]*CompiledCode + + parent *compileContext +} + +func (c *compileContext) context() *compileContext { + return &compileContext{ + typ: c.typ, + opcodeIndex: c.opcodeIndex, + ptrIndex: c.ptrIndex, + indent: c.indent, + escapeKey: c.escapeKey, + structTypeToCompiledCode: c.structTypeToCompiledCode, + parent: c, + } +} + +func (c *compileContext) withType(typ *runtime.Type) *compileContext { + ctx := c.context() + ctx.typ = typ + return ctx +} + +func (c *compileContext) incIndent() *compileContext { + ctx := c.context() + ctx.indent++ + return ctx +} + +func (c *compileContext) decIndent() *compileContext { + ctx := c.context() + ctx.indent-- + return ctx +} + +func (c *compileContext) incIndex() { + c.incOpcodeIndex() + c.incPtrIndex() +} + +func (c *compileContext) decIndex() { + c.decOpcodeIndex() + c.decPtrIndex() +} + +func (c *compileContext) incOpcodeIndex() { + c.opcodeIndex++ + if c.parent != nil { + c.parent.incOpcodeIndex() + } +} + +func (c *compileContext) decOpcodeIndex() { + c.opcodeIndex-- + if c.parent != nil { + c.parent.decOpcodeIndex() + } +} + +func (c *compileContext) incPtrIndex() { + c.ptrIndex++ + if c.parent != nil { + c.parent.incPtrIndex() + } +} + +func (c *compileContext) decPtrIndex() { + c.ptrIndex-- + if c.parent != nil { + c.parent.decPtrIndex() + } +} + +const ( + bufSize = 1024 +) + +var ( + runtimeContextPool = sync.Pool{ + New: func() interface{} { + return &RuntimeContext{ + Buf: make([]byte, 0, bufSize), + Ptrs: make([]uintptr, 128), + KeepRefs: make([]unsafe.Pointer, 0, 8), + Option: &Option{}, + } + }, + } +) + +type RuntimeContext struct { + Context context.Context + Buf []byte + MarshalBuf []byte + Ptrs []uintptr + KeepRefs []unsafe.Pointer + SeenPtr []uintptr + BaseIndent uint32 + Prefix []byte + IndentStr []byte + Option *Option +} + +func (c *RuntimeContext) Init(p uintptr, codelen int) { + if len(c.Ptrs) < codelen { + c.Ptrs = make([]uintptr, codelen) + } + c.Ptrs[0] = p + c.KeepRefs = c.KeepRefs[:0] + c.SeenPtr = c.SeenPtr[:0] + c.BaseIndent = 0 +} + +func (c *RuntimeContext) Ptr() uintptr { + header := (*runtime.SliceHeader)(unsafe.Pointer(&c.Ptrs)) + return uintptr(header.Data) +} + +func TakeRuntimeContext() *RuntimeContext { + return runtimeContextPool.Get().(*RuntimeContext) +} + +func ReleaseRuntimeContext(ctx *RuntimeContext) { + runtimeContextPool.Put(ctx) +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/encoder.go b/vendor/github.com/goccy/go-json/internal/encoder/encoder.go new file mode 100644 index 00000000..b7fa99a9 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/encoder.go @@ -0,0 +1,551 @@ +package encoder + +import ( + "bytes" + "encoding" + "encoding/base64" + "encoding/json" + "fmt" + "math" + "reflect" + "strconv" + "strings" + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +func (t OpType) IsMultipleOpHead() bool { + switch t { + case OpStructHead: + return true + case OpStructHeadSlice: + return true + case OpStructHeadArray: + return true + case OpStructHeadMap: + return true + case OpStructHeadStruct: + return true + case OpStructHeadOmitEmpty: + return true + case OpStructHeadOmitEmptySlice: + return true + case OpStructHeadOmitEmptyArray: + return true + case OpStructHeadOmitEmptyMap: + return true + case OpStructHeadOmitEmptyStruct: + return true + case OpStructHeadSlicePtr: + return true + case OpStructHeadOmitEmptySlicePtr: + return true + case OpStructHeadArrayPtr: + return true + case OpStructHeadOmitEmptyArrayPtr: + return true + case OpStructHeadMapPtr: + return true + case OpStructHeadOmitEmptyMapPtr: + return true + } + return false +} + +func (t OpType) IsMultipleOpField() bool { + switch t { + case OpStructField: + return true + case OpStructFieldSlice: + return true + case OpStructFieldArray: + return true + case OpStructFieldMap: + return true + case OpStructFieldStruct: + return true + case OpStructFieldOmitEmpty: + return true + case OpStructFieldOmitEmptySlice: + return true + case OpStructFieldOmitEmptyArray: + return true + case OpStructFieldOmitEmptyMap: + return true + case OpStructFieldOmitEmptyStruct: + return true + case OpStructFieldSlicePtr: + return true + case OpStructFieldOmitEmptySlicePtr: + return true + case OpStructFieldArrayPtr: + return true + case OpStructFieldOmitEmptyArrayPtr: + return true + case OpStructFieldMapPtr: + return true + case OpStructFieldOmitEmptyMapPtr: + return true + } + return false +} + +type OpcodeSet struct { + Type *runtime.Type + NoescapeKeyCode *Opcode + EscapeKeyCode *Opcode + InterfaceNoescapeKeyCode *Opcode + InterfaceEscapeKeyCode *Opcode + CodeLength int + EndCode *Opcode +} + +type CompiledCode struct { + Code *Opcode + Linked bool // whether recursive code already have linked + CurLen uintptr + NextLen uintptr +} + +const StartDetectingCyclesAfter = 1000 + +func Load(base uintptr, idx uintptr) uintptr { + addr := base + idx + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func Store(base uintptr, idx uintptr, p uintptr) { + addr := base + idx + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func LoadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr { + addr := base + idx + p := **(**uintptr)(unsafe.Pointer(&addr)) + if p == 0 { + return 0 + } + return PtrToPtr(p) + /* + for i := 0; i < ptrNum; i++ { + if p == 0 { + return p + } + p = PtrToPtr(p) + } + return p + */ +} + +func PtrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func PtrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func PtrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func PtrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func PtrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func PtrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func PtrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func PtrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func PtrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func PtrToNPtr(p uintptr, ptrNum int) uintptr { + for i := 0; i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = PtrToPtr(p) + } + return p +} + +func PtrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func PtrToInterface(code *Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func ErrUnsupportedValue(code *Opcode, ptr uintptr) *errors.UnsupportedValueError { + v := *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)), + })) + return &errors.UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: fmt.Sprintf("encountered a cycle via %s", code.Type), + } +} + +func ErrUnsupportedFloat(v float64) *errors.UnsupportedValueError { + return &errors.UnsupportedValueError{ + Value: reflect.ValueOf(v), + Str: strconv.FormatFloat(v, 'g', -1, 64), + } +} + +func ErrMarshalerWithCode(code *Opcode, err error) *errors.MarshalerError { + return &errors.MarshalerError{ + Type: runtime.RType2Type(code.Type), + Err: err, + } +} + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +type MapItem struct { + Key []byte + Value []byte +} + +type Mapslice struct { + Items []MapItem +} + +func (m *Mapslice) Len() int { + return len(m.Items) +} + +func (m *Mapslice) Less(i, j int) bool { + return bytes.Compare(m.Items[i].Key, m.Items[j].Key) < 0 +} + +func (m *Mapslice) Swap(i, j int) { + m.Items[i], m.Items[j] = m.Items[j], m.Items[i] +} + +type MapContext struct { + Pos []int + Slice *Mapslice + Buf []byte +} + +var mapContextPool = sync.Pool{ + New: func() interface{} { + return &MapContext{} + }, +} + +func NewMapContext(mapLen int) *MapContext { + ctx := mapContextPool.Get().(*MapContext) + if ctx.Slice == nil { + ctx.Slice = &Mapslice{ + Items: make([]MapItem, 0, mapLen), + } + } + if cap(ctx.Pos) < (mapLen*2 + 1) { + ctx.Pos = make([]int, 0, mapLen*2+1) + ctx.Slice.Items = make([]MapItem, 0, mapLen) + } else { + ctx.Pos = ctx.Pos[:0] + ctx.Slice.Items = ctx.Slice.Items[:0] + } + ctx.Buf = ctx.Buf[:0] + return ctx +} + +func ReleaseMapContext(c *MapContext) { + mapContextPool.Put(c) +} + +//go:linkname MapIterInit reflect.mapiterinit +//go:noescape +func MapIterInit(mapType *runtime.Type, m unsafe.Pointer) unsafe.Pointer + +//go:linkname MapIterKey reflect.mapiterkey +//go:noescape +func MapIterKey(it unsafe.Pointer) unsafe.Pointer + +//go:linkname MapIterNext reflect.mapiternext +//go:noescape +func MapIterNext(it unsafe.Pointer) + +//go:linkname MapLen reflect.maplen +//go:noescape +func MapLen(m unsafe.Pointer) int + +func AppendByteSlice(_ *RuntimeContext, b []byte, src []byte) []byte { + if src == nil { + return append(b, `null`...) + } + encodedLen := base64.StdEncoding.EncodedLen(len(src)) + b = append(b, '"') + pos := len(b) + remainLen := cap(b[pos:]) + var buf []byte + if remainLen > encodedLen { + buf = b[pos : pos+encodedLen] + } else { + buf = make([]byte, encodedLen) + } + base64.StdEncoding.Encode(buf, src) + return append(append(b, buf...), '"') +} + +func AppendFloat32(_ *RuntimeContext, b []byte, v float32) []byte { + f64 := float64(v) + abs := math.Abs(f64) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + f32 := float32(abs) + if f32 < 1e-6 || f32 >= 1e21 { + fmt = 'e' + } + } + return strconv.AppendFloat(b, f64, fmt, -1, 32) +} + +func AppendFloat64(_ *RuntimeContext, b []byte, v float64) []byte { + abs := math.Abs(v) + fmt := byte('f') + // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right. + if abs != 0 { + if abs < 1e-6 || abs >= 1e21 { + fmt = 'e' + } + } + return strconv.AppendFloat(b, v, fmt, -1, 64) +} + +func AppendBool(_ *RuntimeContext, b []byte, v bool) []byte { + if v { + return append(b, "true"...) + } + return append(b, "false"...) +} + +var ( + floatTable = [256]bool{ + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + '.': true, + 'e': true, + 'E': true, + '+': true, + '-': true, + } +) + +func AppendNumber(_ *RuntimeContext, b []byte, n json.Number) ([]byte, error) { + if len(n) == 0 { + return append(b, '0'), nil + } + for i := 0; i < len(n); i++ { + if !floatTable[n[i]] { + return nil, fmt.Errorf("json: invalid number literal %q", n) + } + } + b = append(b, n...) + return b, nil +} + +func AppendMarshalJSON(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if (code.Flags & AddrForMarshalerFlags) != 0 { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + var bb []byte + if (code.Flags & MarshalerContextFlags) != 0 { + marshaler, ok := v.(marshalerContext) + if !ok { + return AppendNull(ctx, b), nil + } + b, err := marshaler.MarshalJSON(ctx.Option.Context) + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + bb = b + } else { + marshaler, ok := v.(json.Marshaler) + if !ok { + return AppendNull(ctx, b), nil + } + b, err := marshaler.MarshalJSON() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + bb = b + } + marshalBuf := ctx.MarshalBuf[:0] + marshalBuf = append(append(marshalBuf, bb...), nul) + compactedBuf, err := compact(b, marshalBuf, (ctx.Option.Flag&HTMLEscapeOption) != 0) + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + ctx.MarshalBuf = marshalBuf + return compactedBuf, nil +} + +func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if (code.Flags & AddrForMarshalerFlags) != 0 { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + var bb []byte + if (code.Flags & MarshalerContextFlags) != 0 { + marshaler, ok := v.(marshalerContext) + if !ok { + return AppendNull(ctx, b), nil + } + b, err := marshaler.MarshalJSON(ctx.Option.Context) + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + bb = b + } else { + marshaler, ok := v.(json.Marshaler) + if !ok { + return AppendNull(ctx, b), nil + } + b, err := marshaler.MarshalJSON() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + bb = b + } + marshalBuf := ctx.MarshalBuf[:0] + marshalBuf = append(append(marshalBuf, bb...), nul) + indentedBuf, err := doIndent( + b, + marshalBuf, + string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), int(ctx.BaseIndent+code.Indent)), + string(ctx.IndentStr), + (ctx.Option.Flag&HTMLEscapeOption) != 0, + ) + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + ctx.MarshalBuf = marshalBuf + return indentedBuf, nil +} + +func AppendMarshalText(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if (code.Flags & AddrForMarshalerFlags) != 0 { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + marshaler, ok := v.(encoding.TextMarshaler) + if !ok { + return AppendNull(ctx, b), nil + } + bytes, err := marshaler.MarshalText() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil +} + +func AppendMarshalTextIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) { + rv := reflect.ValueOf(v) // convert by dynamic interface type + if (code.Flags & AddrForMarshalerFlags) != 0 { + if rv.CanAddr() { + rv = rv.Addr() + } else { + newV := reflect.New(rv.Type()) + newV.Elem().Set(rv) + rv = newV + } + } + v = rv.Interface() + marshaler, ok := v.(encoding.TextMarshaler) + if !ok { + return AppendNull(ctx, b), nil + } + bytes, err := marshaler.MarshalText() + if err != nil { + return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} + } + return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil +} + +func AppendNull(_ *RuntimeContext, b []byte) []byte { + return append(b, "null"...) +} + +func AppendComma(_ *RuntimeContext, b []byte) []byte { + return append(b, ',') +} + +func AppendCommaIndent(_ *RuntimeContext, b []byte) []byte { + return append(b, ',', '\n') +} + +func AppendStructEnd(_ *RuntimeContext, b []byte) []byte { + return append(b, '}', ',') +} + +func AppendStructEndIndent(ctx *RuntimeContext, code *Opcode, b []byte) []byte { + b = append(b, '\n') + b = append(b, ctx.Prefix...) + indentNum := ctx.BaseIndent + code.Indent - 1 + for i := uint32(0); i < indentNum; i++ { + b = append(b, ctx.IndentStr...) + } + return append(b, '}', ',', '\n') +} + +func AppendIndent(ctx *RuntimeContext, b []byte, indent uint32) []byte { + b = append(b, ctx.Prefix...) + indentNum := ctx.BaseIndent + indent + for i := uint32(0); i < indentNum; i++ { + b = append(b, ctx.IndentStr...) + } + return b +} + +func IsNilForMarshaler(v interface{}) bool { + rv := reflect.ValueOf(v) + switch rv.Kind() { + case reflect.Bool: + return !rv.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return rv.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return rv.Uint() == 0 + case reflect.Float32, reflect.Float64: + return math.Float64bits(rv.Float()) == 0 + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Func: + return rv.IsNil() + case reflect.Slice: + return rv.IsNil() || rv.Len() == 0 + } + return false +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/indent.go b/vendor/github.com/goccy/go-json/internal/encoder/indent.go new file mode 100644 index 00000000..dfe04b5e --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/indent.go @@ -0,0 +1,211 @@ +package encoder + +import ( + "bytes" + "fmt" + + "github.com/goccy/go-json/internal/errors" +) + +func takeIndentSrcRuntimeContext(src []byte) (*RuntimeContext, []byte) { + ctx := TakeRuntimeContext() + buf := ctx.Buf[:0] + buf = append(append(buf, src...), nul) + ctx.Buf = buf + return ctx, buf +} + +func Indent(buf *bytes.Buffer, src []byte, prefix, indentStr string) error { + if len(src) == 0 { + return errors.ErrUnexpectedEndOfJSON("", 0) + } + + srcCtx, srcBuf := takeIndentSrcRuntimeContext(src) + dstCtx := TakeRuntimeContext() + dst := dstCtx.Buf[:0] + + dst, err := indentAndWrite(buf, dst, srcBuf, prefix, indentStr) + if err != nil { + ReleaseRuntimeContext(srcCtx) + ReleaseRuntimeContext(dstCtx) + return err + } + dstCtx.Buf = dst + ReleaseRuntimeContext(srcCtx) + ReleaseRuntimeContext(dstCtx) + return nil +} + +func indentAndWrite(buf *bytes.Buffer, dst []byte, src []byte, prefix, indentStr string) ([]byte, error) { + dst, err := doIndent(dst, src, prefix, indentStr, false) + if err != nil { + return nil, err + } + if _, err := buf.Write(dst); err != nil { + return nil, err + } + return dst, nil +} + +func doIndent(dst, src []byte, prefix, indentStr string, escape bool) ([]byte, error) { + buf, cursor, err := indentValue(dst, src, 0, 0, []byte(prefix), []byte(indentStr), escape) + if err != nil { + return nil, err + } + if err := validateEndBuf(src, cursor); err != nil { + return nil, err + } + return buf, nil +} + +func indentValue( + dst []byte, + src []byte, + indentNum int, + cursor int64, + prefix []byte, + indentBytes []byte, + escape bool) ([]byte, int64, error) { + for { + switch src[cursor] { + case ' ', '\t', '\n', '\r': + cursor++ + continue + case '{': + return indentObject(dst, src, indentNum, cursor, prefix, indentBytes, escape) + case '}': + return nil, 0, errors.ErrSyntax("unexpected character '}'", cursor) + case '[': + return indentArray(dst, src, indentNum, cursor, prefix, indentBytes, escape) + case ']': + return nil, 0, errors.ErrSyntax("unexpected character ']'", cursor) + case '"': + return compactString(dst, src, cursor, escape) + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return compactNumber(dst, src, cursor) + case 't': + return compactTrue(dst, src, cursor) + case 'f': + return compactFalse(dst, src, cursor) + case 'n': + return compactNull(dst, src, cursor) + default: + return nil, 0, errors.ErrSyntax(fmt.Sprintf("unexpected character '%c'", src[cursor]), cursor) + } + } +} + +func indentObject( + dst []byte, + src []byte, + indentNum int, + cursor int64, + prefix []byte, + indentBytes []byte, + escape bool) ([]byte, int64, error) { + if src[cursor] == '{' { + dst = append(dst, '{') + } else { + return nil, 0, errors.ErrExpected("expected { character for object value", cursor) + } + cursor = skipWhiteSpace(src, cursor+1) + if src[cursor] == '}' { + dst = append(dst, '}') + return dst, cursor + 1, nil + } + indentNum++ + var err error + for { + dst = append(append(dst, '\n'), prefix...) + for i := 0; i < indentNum; i++ { + dst = append(dst, indentBytes...) + } + cursor = skipWhiteSpace(src, cursor) + dst, cursor, err = compactString(dst, src, cursor, escape) + if err != nil { + return nil, 0, err + } + cursor = skipWhiteSpace(src, cursor) + if src[cursor] != ':' { + return nil, 0, errors.ErrSyntax( + fmt.Sprintf("invalid character '%c' after object key", src[cursor]), + cursor+1, + ) + } + dst = append(dst, ':', ' ') + dst, cursor, err = indentValue(dst, src, indentNum, cursor+1, prefix, indentBytes, escape) + if err != nil { + return nil, 0, err + } + cursor = skipWhiteSpace(src, cursor) + switch src[cursor] { + case '}': + dst = append(append(dst, '\n'), prefix...) + for i := 0; i < indentNum-1; i++ { + dst = append(dst, indentBytes...) + } + dst = append(dst, '}') + cursor++ + return dst, cursor, nil + case ',': + dst = append(dst, ',') + default: + return nil, 0, errors.ErrSyntax( + fmt.Sprintf("invalid character '%c' after object key:value pair", src[cursor]), + cursor+1, + ) + } + cursor++ + } +} + +func indentArray( + dst []byte, + src []byte, + indentNum int, + cursor int64, + prefix []byte, + indentBytes []byte, + escape bool) ([]byte, int64, error) { + if src[cursor] == '[' { + dst = append(dst, '[') + } else { + return nil, 0, errors.ErrExpected("expected [ character for array value", cursor) + } + cursor = skipWhiteSpace(src, cursor+1) + if src[cursor] == ']' { + dst = append(dst, ']') + return dst, cursor + 1, nil + } + indentNum++ + var err error + for { + dst = append(append(dst, '\n'), prefix...) + for i := 0; i < indentNum; i++ { + dst = append(dst, indentBytes...) + } + dst, cursor, err = indentValue(dst, src, indentNum, cursor, prefix, indentBytes, escape) + if err != nil { + return nil, 0, err + } + cursor = skipWhiteSpace(src, cursor) + switch src[cursor] { + case ']': + dst = append(append(dst, '\n'), prefix...) + for i := 0; i < indentNum-1; i++ { + dst = append(dst, indentBytes...) + } + dst = append(dst, ']') + cursor++ + return dst, cursor, nil + case ',': + dst = append(dst, ',') + default: + return nil, 0, errors.ErrSyntax( + fmt.Sprintf("invalid character '%c' after array value", src[cursor]), + cursor+1, + ) + } + cursor++ + } +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/int.go b/vendor/github.com/goccy/go-json/internal/encoder/int.go new file mode 100644 index 00000000..3a3482d5 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/int.go @@ -0,0 +1,130 @@ +package encoder + +import ( + "unsafe" +) + +var endianness int + +func init() { + var b [2]byte + *(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD) + + switch b[0] { + case 0xCD: + endianness = 0 // LE + case 0xAB: + endianness = 1 // BE + default: + panic("could not determine endianness") + } +} + +// "00010203...96979899" cast to []uint16 +var intLELookup = [100]uint16{ + 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, + 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, + 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, + 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, + 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, + 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, + 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, + 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, + 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, + 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939, +} + +var intBELookup = [100]uint16{ + 0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039, + 0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139, + 0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239, + 0x3330, 0x3331, 0x3332, 0x3333, 0x3334, 0x3335, 0x3336, 0x3337, 0x3338, 0x3339, + 0x3430, 0x3431, 0x3432, 0x3433, 0x3434, 0x3435, 0x3436, 0x3437, 0x3438, 0x3439, + 0x3530, 0x3531, 0x3532, 0x3533, 0x3534, 0x3535, 0x3536, 0x3537, 0x3538, 0x3539, + 0x3630, 0x3631, 0x3632, 0x3633, 0x3634, 0x3635, 0x3636, 0x3637, 0x3638, 0x3639, + 0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739, + 0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839, + 0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939, +} + +var intLookup = [2]*[100]uint16{&intLELookup, &intBELookup} + +func numMask(numBitSize uint8) uint64 { + return 1<>(code.NumBitSize-1))&1 == 1 + if !negative { + if n < 10 { + return append(out, byte(n+'0')) + } else if n < 100 { + u := intLELookup[n] + return append(out, byte(u), byte(u>>8)) + } + } else { + n = -n & mask + } + + lookup := intLookup[endianness] + + var b [22]byte + u := (*[11]uint16)(unsafe.Pointer(&b)) + i := 11 + + for n >= 100 { + j := n % 100 + n /= 100 + i-- + u[i] = lookup[j] + } + + i-- + u[i] = lookup[n] + + i *= 2 // convert to byte index + if n < 10 { + i++ // remove leading zero + } + if negative { + i-- + b[i] = '-' + } + + return append(out, b[i:]...) +} + +func AppendUint(_ *RuntimeContext, out []byte, u64 uint64, code *Opcode) []byte { + mask := numMask(code.NumBitSize) + n := u64 & mask + if n < 10 { + return append(out, byte(n+'0')) + } else if n < 100 { + u := intLELookup[n] + return append(out, byte(u), byte(u>>8)) + } + + lookup := intLookup[endianness] + + var b [22]byte + u := (*[11]uint16)(unsafe.Pointer(&b)) + i := 11 + + for n >= 100 { + j := n % 100 + n /= 100 + i-- + u[i] = lookup[j] + } + + i-- + u[i] = lookup[n] + + i *= 2 // convert to byte index + if n < 10 { + i++ // remove leading zero + } + return append(out, b[i:]...) +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/map112.go b/vendor/github.com/goccy/go-json/internal/encoder/map112.go new file mode 100644 index 00000000..31858d00 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/map112.go @@ -0,0 +1,8 @@ +// +build !go1.13 + +package encoder + +import "unsafe" + +//go:linkname MapIterValue reflect.mapitervalue +func MapIterValue(it unsafe.Pointer) unsafe.Pointer diff --git a/vendor/github.com/goccy/go-json/internal/encoder/map113.go b/vendor/github.com/goccy/go-json/internal/encoder/map113.go new file mode 100644 index 00000000..f49c27be --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/map113.go @@ -0,0 +1,8 @@ +// +build go1.13 + +package encoder + +import "unsafe" + +//go:linkname MapIterValue reflect.mapiterelem +func MapIterValue(it unsafe.Pointer) unsafe.Pointer diff --git a/vendor/github.com/goccy/go-json/internal/encoder/opcode.go b/vendor/github.com/goccy/go-json/internal/encoder/opcode.go new file mode 100644 index 00000000..c23a90b2 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/opcode.go @@ -0,0 +1,766 @@ +package encoder + +import ( + "fmt" + "strings" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) + +type OpFlags uint16 + +const ( + AnonymousHeadFlags OpFlags = 1 << 0 + AnonymousKeyFlags OpFlags = 1 << 1 + IndirectFlags OpFlags = 1 << 2 + IsTaggedKeyFlags OpFlags = 1 << 3 + NilCheckFlags OpFlags = 1 << 4 + AddrForMarshalerFlags OpFlags = 1 << 5 + IsNextOpPtrTypeFlags OpFlags = 1 << 6 + IsNilableTypeFlags OpFlags = 1 << 7 + MarshalerContextFlags OpFlags = 1 << 8 +) + +type Opcode struct { + Op OpType // operation type + Idx uint32 // offset to access ptr + Next *Opcode // next opcode + End *Opcode // array/slice/struct/map end + NextField *Opcode // next struct field + Key string // struct field key + Offset uint32 // offset size from struct header + PtrNum uint8 // pointer number: e.g. double pointer is 2. + NumBitSize uint8 + Flags OpFlags + + Type *runtime.Type // go type + PrevField *Opcode // prev struct field + Jmp *CompiledCode // for recursive call + ElemIdx uint32 // offset to access array/slice/map elem + Length uint32 // offset to access slice/map length or array length + MapIter uint32 // offset to access map iterator + MapPos uint32 // offset to access position list for sorted map + Indent uint32 // indent number + Size uint32 // array/slice elem size + DisplayIdx uint32 // opcode index + DisplayKey string // key text to display +} + +func (c *Opcode) MaxIdx() uint32 { + max := uint32(0) + for _, value := range []uint32{ + c.Idx, + c.ElemIdx, + c.Length, + c.MapIter, + c.MapPos, + c.Size, + } { + if max < value { + max = value + } + } + return max +} + +func (c *Opcode) ToHeaderType(isString bool) OpType { + switch c.Op { + case OpInt: + if isString { + return OpStructHeadIntString + } + return OpStructHeadInt + case OpIntPtr: + if isString { + return OpStructHeadIntPtrString + } + return OpStructHeadIntPtr + case OpUint: + if isString { + return OpStructHeadUintString + } + return OpStructHeadUint + case OpUintPtr: + if isString { + return OpStructHeadUintPtrString + } + return OpStructHeadUintPtr + case OpFloat32: + if isString { + return OpStructHeadFloat32String + } + return OpStructHeadFloat32 + case OpFloat32Ptr: + if isString { + return OpStructHeadFloat32PtrString + } + return OpStructHeadFloat32Ptr + case OpFloat64: + if isString { + return OpStructHeadFloat64String + } + return OpStructHeadFloat64 + case OpFloat64Ptr: + if isString { + return OpStructHeadFloat64PtrString + } + return OpStructHeadFloat64Ptr + case OpString: + if isString { + return OpStructHeadStringString + } + return OpStructHeadString + case OpStringPtr: + if isString { + return OpStructHeadStringPtrString + } + return OpStructHeadStringPtr + case OpNumber: + if isString { + return OpStructHeadNumberString + } + return OpStructHeadNumber + case OpNumberPtr: + if isString { + return OpStructHeadNumberPtrString + } + return OpStructHeadNumberPtr + case OpBool: + if isString { + return OpStructHeadBoolString + } + return OpStructHeadBool + case OpBoolPtr: + if isString { + return OpStructHeadBoolPtrString + } + return OpStructHeadBoolPtr + case OpBytes: + return OpStructHeadBytes + case OpBytesPtr: + return OpStructHeadBytesPtr + case OpMap: + return OpStructHeadMap + case OpMapPtr: + c.Op = OpMap + return OpStructHeadMapPtr + case OpArray: + return OpStructHeadArray + case OpArrayPtr: + c.Op = OpArray + return OpStructHeadArrayPtr + case OpSlice: + return OpStructHeadSlice + case OpSlicePtr: + c.Op = OpSlice + return OpStructHeadSlicePtr + case OpMarshalJSON: + return OpStructHeadMarshalJSON + case OpMarshalJSONPtr: + return OpStructHeadMarshalJSONPtr + case OpMarshalText: + return OpStructHeadMarshalText + case OpMarshalTextPtr: + return OpStructHeadMarshalTextPtr + } + return OpStructHead +} + +func (c *Opcode) ToFieldType(isString bool) OpType { + switch c.Op { + case OpInt: + if isString { + return OpStructFieldIntString + } + return OpStructFieldInt + case OpIntPtr: + if isString { + return OpStructFieldIntPtrString + } + return OpStructFieldIntPtr + case OpUint: + if isString { + return OpStructFieldUintString + } + return OpStructFieldUint + case OpUintPtr: + if isString { + return OpStructFieldUintPtrString + } + return OpStructFieldUintPtr + case OpFloat32: + if isString { + return OpStructFieldFloat32String + } + return OpStructFieldFloat32 + case OpFloat32Ptr: + if isString { + return OpStructFieldFloat32PtrString + } + return OpStructFieldFloat32Ptr + case OpFloat64: + if isString { + return OpStructFieldFloat64String + } + return OpStructFieldFloat64 + case OpFloat64Ptr: + if isString { + return OpStructFieldFloat64PtrString + } + return OpStructFieldFloat64Ptr + case OpString: + if isString { + return OpStructFieldStringString + } + return OpStructFieldString + case OpStringPtr: + if isString { + return OpStructFieldStringPtrString + } + return OpStructFieldStringPtr + case OpNumber: + if isString { + return OpStructFieldNumberString + } + return OpStructFieldNumber + case OpNumberPtr: + if isString { + return OpStructFieldNumberPtrString + } + return OpStructFieldNumberPtr + case OpBool: + if isString { + return OpStructFieldBoolString + } + return OpStructFieldBool + case OpBoolPtr: + if isString { + return OpStructFieldBoolPtrString + } + return OpStructFieldBoolPtr + case OpBytes: + return OpStructFieldBytes + case OpBytesPtr: + return OpStructFieldBytesPtr + case OpMap: + return OpStructFieldMap + case OpMapPtr: + c.Op = OpMap + return OpStructFieldMapPtr + case OpArray: + return OpStructFieldArray + case OpArrayPtr: + c.Op = OpArray + return OpStructFieldArrayPtr + case OpSlice: + return OpStructFieldSlice + case OpSlicePtr: + c.Op = OpSlice + return OpStructFieldSlicePtr + case OpMarshalJSON: + return OpStructFieldMarshalJSON + case OpMarshalJSONPtr: + return OpStructFieldMarshalJSONPtr + case OpMarshalText: + return OpStructFieldMarshalText + case OpMarshalTextPtr: + return OpStructFieldMarshalTextPtr + } + return OpStructField +} + +func newOpCode(ctx *compileContext, op OpType) *Opcode { + return newOpCodeWithNext(ctx, op, newEndOp(ctx)) +} + +func opcodeOffset(idx int) uint32 { + return uint32(idx) * uintptrSize +} + +func copyOpcode(code *Opcode) *Opcode { + codeMap := map[uintptr]*Opcode{} + return code.copy(codeMap) +} + +func setTotalLengthToInterfaceOp(code *Opcode) { + c := code + for c.Op != OpEnd && c.Op != OpInterfaceEnd { + if c.Op == OpInterface { + c.Length = uint32(code.TotalLength()) + } + switch c.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + c = c.End + default: + c = c.Next + } + } +} + +func ToEndCode(code *Opcode) *Opcode { + c := code + for c.Op != OpEnd && c.Op != OpInterfaceEnd { + switch c.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + c = c.End + default: + c = c.Next + } + } + return c +} + +func copyToInterfaceOpcode(code *Opcode) *Opcode { + copied := copyOpcode(code) + c := copied + c = ToEndCode(c) + c.Idx += uintptrSize + c.ElemIdx = c.Idx + uintptrSize + c.Length = c.Idx + 2*uintptrSize + c.Op = OpInterfaceEnd + return copied +} + +func newOpCodeWithNext(ctx *compileContext, op OpType, next *Opcode) *Opcode { + return &Opcode{ + Op: op, + Idx: opcodeOffset(ctx.ptrIndex), + Next: next, + Type: ctx.typ, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } +} + +func newEndOp(ctx *compileContext) *Opcode { + return newOpCodeWithNext(ctx, OpEnd, nil) +} + +func (c *Opcode) copy(codeMap map[uintptr]*Opcode) *Opcode { + if c == nil { + return nil + } + addr := uintptr(unsafe.Pointer(c)) + if code, exists := codeMap[addr]; exists { + return code + } + copied := &Opcode{ + Op: c.Op, + Key: c.Key, + PtrNum: c.PtrNum, + NumBitSize: c.NumBitSize, + Flags: c.Flags, + Idx: c.Idx, + Offset: c.Offset, + Type: c.Type, + DisplayIdx: c.DisplayIdx, + DisplayKey: c.DisplayKey, + ElemIdx: c.ElemIdx, + Length: c.Length, + MapIter: c.MapIter, + MapPos: c.MapPos, + Size: c.Size, + Indent: c.Indent, + } + codeMap[addr] = copied + copied.End = c.End.copy(codeMap) + copied.PrevField = c.PrevField.copy(codeMap) + copied.NextField = c.NextField.copy(codeMap) + copied.Next = c.Next.copy(codeMap) + copied.Jmp = c.Jmp + return copied +} + +func (c *Opcode) BeforeLastCode() *Opcode { + code := c + for { + var nextCode *Opcode + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + nextCode = code.End + default: + nextCode = code.Next + } + if nextCode.Op == OpEnd { + return code + } + code = nextCode + } +} + +func (c *Opcode) TotalLength() int { + var idx int + code := c + for code.Op != OpEnd && code.Op != OpInterfaceEnd { + maxIdx := int(code.MaxIdx() / uintptrSize) + if idx < maxIdx { + idx = maxIdx + } + if code.Op == OpRecursiveEnd { + break + } + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } + maxIdx := int(code.MaxIdx() / uintptrSize) + if idx < maxIdx { + idx = maxIdx + } + return idx + 1 +} + +func (c *Opcode) decOpcodeIndex() { + for code := c; code.Op != OpEnd; { + code.DisplayIdx-- + if code.Idx > 0 { + code.Idx -= uintptrSize + } + if code.ElemIdx > 0 { + code.ElemIdx -= uintptrSize + } + if code.MapIter > 0 { + code.MapIter -= uintptrSize + } + if code.Length > 0 && code.Op.CodeType() != CodeArrayHead && code.Op.CodeType() != CodeArrayElem { + code.Length -= uintptrSize + } + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } +} + +func (c *Opcode) decIndent() { + for code := c; code.Op != OpEnd; { + code.Indent-- + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + code = code.End + default: + code = code.Next + } + } +} + +func (c *Opcode) dumpHead(code *Opcode) string { + var length uint32 + if code.Op.CodeType() == CodeArrayHead { + length = code.Length + } else { + length = code.Length / uintptrSize + } + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + code.ElemIdx/uintptrSize, + length, + ) +} + +func (c *Opcode) dumpMapHead(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + code.ElemIdx/uintptrSize, + code.Length/uintptrSize, + code.MapIter/uintptrSize, + ) +} + +func (c *Opcode) dumpMapEnd(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][mapPos:%d][length:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + code.MapPos/uintptrSize, + code.Length/uintptrSize, + ) +} + +func (c *Opcode) dumpElem(code *Opcode) string { + var length uint32 + if code.Op.CodeType() == CodeArrayElem { + length = code.Length + } else { + length = code.Length / uintptrSize + } + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][size:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + code.ElemIdx/uintptrSize, + length, + code.Size, + ) +} + +func (c *Opcode) dumpField(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][key:%s][offset:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + code.DisplayKey, + code.Offset, + ) +} + +func (c *Opcode) dumpKey(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + code.ElemIdx/uintptrSize, + code.Length/uintptrSize, + code.MapIter/uintptrSize, + ) +} + +func (c *Opcode) dumpValue(code *Opcode) string { + return fmt.Sprintf( + `[%d]%s%s ([idx:%d][mapIter:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + code.MapIter/uintptrSize, + ) +} + +func (c *Opcode) Dump() string { + codes := []string{} + for code := c; code.Op != OpEnd && code.Op != OpInterfaceEnd; { + switch code.Op.CodeType() { + case CodeSliceHead: + codes = append(codes, c.dumpHead(code)) + code = code.Next + case CodeMapHead: + codes = append(codes, c.dumpMapHead(code)) + code = code.Next + case CodeArrayElem, CodeSliceElem: + codes = append(codes, c.dumpElem(code)) + code = code.End + case CodeMapKey: + codes = append(codes, c.dumpKey(code)) + code = code.End + case CodeMapValue: + codes = append(codes, c.dumpValue(code)) + code = code.Next + case CodeMapEnd: + codes = append(codes, c.dumpMapEnd(code)) + code = code.Next + case CodeStructField: + codes = append(codes, c.dumpField(code)) + code = code.Next + case CodeStructEnd: + codes = append(codes, c.dumpField(code)) + code = code.Next + default: + codes = append(codes, fmt.Sprintf( + "[%d]%s%s ([idx:%d])", + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + )) + code = code.Next + } + } + return strings.Join(codes, "\n") +} + +func prevField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode { + if _, exists := removedFields[code]; exists { + return prevField(code.PrevField, removedFields) + } + return code +} + +func nextField(code *Opcode, removedFields map[*Opcode]struct{}) *Opcode { + if _, exists := removedFields[code]; exists { + return nextField(code.NextField, removedFields) + } + return code +} + +func linkPrevToNextField(cur *Opcode, removedFields map[*Opcode]struct{}) { + prev := prevField(cur.PrevField, removedFields) + prev.NextField = nextField(cur.NextField, removedFields) + code := prev + fcode := cur + for { + var nextCode *Opcode + switch code.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + nextCode = code.End + default: + nextCode = code.Next + } + if nextCode == fcode { + code.Next = fcode.Next + break + } else if nextCode.Op == OpEnd { + break + } + code = nextCode + } +} + +func newSliceHeaderCode(ctx *compileContext) *Opcode { + idx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + elemIdx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + length := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpSlice, + Idx: idx, + DisplayIdx: ctx.opcodeIndex, + ElemIdx: elemIdx, + Length: length, + Indent: ctx.indent, + } +} + +func newSliceElemCode(ctx *compileContext, head *Opcode, size uintptr) *Opcode { + return &Opcode{ + Op: OpSliceElem, + Idx: head.Idx, + DisplayIdx: ctx.opcodeIndex, + ElemIdx: head.ElemIdx, + Length: head.Length, + Indent: ctx.indent, + Size: uint32(size), + } +} + +func newArrayHeaderCode(ctx *compileContext, alen int) *Opcode { + idx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + elemIdx := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpArray, + Idx: idx, + DisplayIdx: ctx.opcodeIndex, + ElemIdx: elemIdx, + Indent: ctx.indent, + Length: uint32(alen), + } +} + +func newArrayElemCode(ctx *compileContext, head *Opcode, length int, size uintptr) *Opcode { + return &Opcode{ + Op: OpArrayElem, + Idx: head.Idx, + DisplayIdx: ctx.opcodeIndex, + ElemIdx: head.ElemIdx, + Length: uint32(length), + Indent: ctx.indent, + Size: uint32(size), + } +} + +func newMapHeaderCode(ctx *compileContext) *Opcode { + idx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + elemIdx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + length := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + mapIter := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpMap, + Idx: idx, + Type: ctx.typ, + DisplayIdx: ctx.opcodeIndex, + ElemIdx: elemIdx, + Length: length, + MapIter: mapIter, + Indent: ctx.indent, + } +} + +func newMapKeyCode(ctx *compileContext, head *Opcode) *Opcode { + return &Opcode{ + Op: OpMapKey, + Idx: opcodeOffset(ctx.ptrIndex), + DisplayIdx: ctx.opcodeIndex, + ElemIdx: head.ElemIdx, + Length: head.Length, + MapIter: head.MapIter, + Indent: ctx.indent, + } +} + +func newMapValueCode(ctx *compileContext, head *Opcode) *Opcode { + return &Opcode{ + Op: OpMapValue, + Idx: opcodeOffset(ctx.ptrIndex), + DisplayIdx: ctx.opcodeIndex, + ElemIdx: head.ElemIdx, + Length: head.Length, + MapIter: head.MapIter, + Indent: ctx.indent, + } +} + +func newMapEndCode(ctx *compileContext, head *Opcode) *Opcode { + mapPos := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + idx := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpMapEnd, + Idx: idx, + Next: newEndOp(ctx), + DisplayIdx: ctx.opcodeIndex, + Length: head.Length, + MapPos: mapPos, + Indent: ctx.indent, + } +} + +func newInterfaceCode(ctx *compileContext) *Opcode { + return &Opcode{ + Op: OpInterface, + Idx: opcodeOffset(ctx.ptrIndex), + Next: newEndOp(ctx), + Type: ctx.typ, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } +} + +func newRecursiveCode(ctx *compileContext, jmp *CompiledCode) *Opcode { + return &Opcode{ + Op: OpRecursive, + Idx: opcodeOffset(ctx.ptrIndex), + Next: newEndOp(ctx), + Type: ctx.typ, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + Jmp: jmp, + } +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/option.go b/vendor/github.com/goccy/go-json/internal/encoder/option.go new file mode 100644 index 00000000..f5f1f044 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/option.go @@ -0,0 +1,41 @@ +package encoder + +import "context" + +type OptionFlag uint8 + +const ( + HTMLEscapeOption OptionFlag = 1 << iota + IndentOption + UnorderedMapOption + DebugOption + ColorizeOption + ContextOption +) + +type Option struct { + Flag OptionFlag + ColorScheme *ColorScheme + Context context.Context +} + +type EncodeFormat struct { + Header string + Footer string +} + +type EncodeFormatScheme struct { + Int EncodeFormat + Uint EncodeFormat + Float EncodeFormat + Bool EncodeFormat + String EncodeFormat + Binary EncodeFormat + ObjectKey EncodeFormat + Null EncodeFormat +} + +type ( + ColorScheme = EncodeFormatScheme + ColorFormat = EncodeFormat +) diff --git a/vendor/github.com/goccy/go-json/internal/encoder/optype.go b/vendor/github.com/goccy/go-json/internal/encoder/optype.go new file mode 100644 index 00000000..335fc043 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/optype.go @@ -0,0 +1,934 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package encoder + +import ( + "strings" +) + +type CodeType int + +const ( + CodeOp CodeType = 0 + CodeArrayHead CodeType = 1 + CodeArrayElem CodeType = 2 + CodeSliceHead CodeType = 3 + CodeSliceElem CodeType = 4 + CodeMapHead CodeType = 5 + CodeMapKey CodeType = 6 + CodeMapValue CodeType = 7 + CodeMapEnd CodeType = 8 + CodeRecursive CodeType = 9 + CodeStructField CodeType = 10 + CodeStructEnd CodeType = 11 +) + +var opTypeStrings = [401]string{ + "End", + "Interface", + "Ptr", + "SliceElem", + "SliceEnd", + "ArrayElem", + "ArrayEnd", + "MapKey", + "MapValue", + "MapEnd", + "Recursive", + "RecursivePtr", + "RecursiveEnd", + "InterfaceEnd", + "StructAnonymousEnd", + "Int", + "Uint", + "Float32", + "Float64", + "Bool", + "String", + "Bytes", + "Number", + "Array", + "Map", + "Slice", + "Struct", + "MarshalJSON", + "MarshalText", + "IntString", + "UintString", + "Float32String", + "Float64String", + "BoolString", + "StringString", + "NumberString", + "IntPtr", + "UintPtr", + "Float32Ptr", + "Float64Ptr", + "BoolPtr", + "StringPtr", + "BytesPtr", + "NumberPtr", + "ArrayPtr", + "MapPtr", + "SlicePtr", + "MarshalJSONPtr", + "MarshalTextPtr", + "InterfacePtr", + "IntPtrString", + "UintPtrString", + "Float32PtrString", + "Float64PtrString", + "BoolPtrString", + "StringPtrString", + "NumberPtrString", + "StructHeadInt", + "StructHeadOmitEmptyInt", + "StructPtrHeadInt", + "StructPtrHeadOmitEmptyInt", + "StructHeadUint", + "StructHeadOmitEmptyUint", + "StructPtrHeadUint", + "StructPtrHeadOmitEmptyUint", + "StructHeadFloat32", + "StructHeadOmitEmptyFloat32", + "StructPtrHeadFloat32", + "StructPtrHeadOmitEmptyFloat32", + "StructHeadFloat64", + "StructHeadOmitEmptyFloat64", + "StructPtrHeadFloat64", + "StructPtrHeadOmitEmptyFloat64", + "StructHeadBool", + "StructHeadOmitEmptyBool", + "StructPtrHeadBool", + "StructPtrHeadOmitEmptyBool", + "StructHeadString", + "StructHeadOmitEmptyString", + "StructPtrHeadString", + "StructPtrHeadOmitEmptyString", + "StructHeadBytes", + "StructHeadOmitEmptyBytes", + "StructPtrHeadBytes", + "StructPtrHeadOmitEmptyBytes", + "StructHeadNumber", + "StructHeadOmitEmptyNumber", + "StructPtrHeadNumber", + "StructPtrHeadOmitEmptyNumber", + "StructHeadArray", + "StructHeadOmitEmptyArray", + "StructPtrHeadArray", + "StructPtrHeadOmitEmptyArray", + "StructHeadMap", + "StructHeadOmitEmptyMap", + "StructPtrHeadMap", + "StructPtrHeadOmitEmptyMap", + "StructHeadSlice", + "StructHeadOmitEmptySlice", + "StructPtrHeadSlice", + "StructPtrHeadOmitEmptySlice", + "StructHeadStruct", + "StructHeadOmitEmptyStruct", + "StructPtrHeadStruct", + "StructPtrHeadOmitEmptyStruct", + "StructHeadMarshalJSON", + "StructHeadOmitEmptyMarshalJSON", + "StructPtrHeadMarshalJSON", + "StructPtrHeadOmitEmptyMarshalJSON", + "StructHeadMarshalText", + "StructHeadOmitEmptyMarshalText", + "StructPtrHeadMarshalText", + "StructPtrHeadOmitEmptyMarshalText", + "StructHeadIntString", + "StructHeadOmitEmptyIntString", + "StructPtrHeadIntString", + "StructPtrHeadOmitEmptyIntString", + "StructHeadUintString", + "StructHeadOmitEmptyUintString", + "StructPtrHeadUintString", + "StructPtrHeadOmitEmptyUintString", + "StructHeadFloat32String", + "StructHeadOmitEmptyFloat32String", + "StructPtrHeadFloat32String", + "StructPtrHeadOmitEmptyFloat32String", + "StructHeadFloat64String", + "StructHeadOmitEmptyFloat64String", + "StructPtrHeadFloat64String", + "StructPtrHeadOmitEmptyFloat64String", + "StructHeadBoolString", + "StructHeadOmitEmptyBoolString", + "StructPtrHeadBoolString", + "StructPtrHeadOmitEmptyBoolString", + "StructHeadStringString", + "StructHeadOmitEmptyStringString", + "StructPtrHeadStringString", + "StructPtrHeadOmitEmptyStringString", + "StructHeadNumberString", + "StructHeadOmitEmptyNumberString", + "StructPtrHeadNumberString", + "StructPtrHeadOmitEmptyNumberString", + "StructHeadIntPtr", + "StructHeadOmitEmptyIntPtr", + "StructPtrHeadIntPtr", + "StructPtrHeadOmitEmptyIntPtr", + "StructHeadUintPtr", + "StructHeadOmitEmptyUintPtr", + "StructPtrHeadUintPtr", + "StructPtrHeadOmitEmptyUintPtr", + "StructHeadFloat32Ptr", + "StructHeadOmitEmptyFloat32Ptr", + "StructPtrHeadFloat32Ptr", + "StructPtrHeadOmitEmptyFloat32Ptr", + "StructHeadFloat64Ptr", + "StructHeadOmitEmptyFloat64Ptr", + "StructPtrHeadFloat64Ptr", + "StructPtrHeadOmitEmptyFloat64Ptr", + "StructHeadBoolPtr", + "StructHeadOmitEmptyBoolPtr", + "StructPtrHeadBoolPtr", + "StructPtrHeadOmitEmptyBoolPtr", + "StructHeadStringPtr", + "StructHeadOmitEmptyStringPtr", + "StructPtrHeadStringPtr", + "StructPtrHeadOmitEmptyStringPtr", + "StructHeadBytesPtr", + "StructHeadOmitEmptyBytesPtr", + "StructPtrHeadBytesPtr", + "StructPtrHeadOmitEmptyBytesPtr", + "StructHeadNumberPtr", + "StructHeadOmitEmptyNumberPtr", + "StructPtrHeadNumberPtr", + "StructPtrHeadOmitEmptyNumberPtr", + "StructHeadArrayPtr", + "StructHeadOmitEmptyArrayPtr", + "StructPtrHeadArrayPtr", + "StructPtrHeadOmitEmptyArrayPtr", + "StructHeadMapPtr", + "StructHeadOmitEmptyMapPtr", + "StructPtrHeadMapPtr", + "StructPtrHeadOmitEmptyMapPtr", + "StructHeadSlicePtr", + "StructHeadOmitEmptySlicePtr", + "StructPtrHeadSlicePtr", + "StructPtrHeadOmitEmptySlicePtr", + "StructHeadMarshalJSONPtr", + "StructHeadOmitEmptyMarshalJSONPtr", + "StructPtrHeadMarshalJSONPtr", + "StructPtrHeadOmitEmptyMarshalJSONPtr", + "StructHeadMarshalTextPtr", + "StructHeadOmitEmptyMarshalTextPtr", + "StructPtrHeadMarshalTextPtr", + "StructPtrHeadOmitEmptyMarshalTextPtr", + "StructHeadInterfacePtr", + "StructHeadOmitEmptyInterfacePtr", + "StructPtrHeadInterfacePtr", + "StructPtrHeadOmitEmptyInterfacePtr", + "StructHeadIntPtrString", + "StructHeadOmitEmptyIntPtrString", + "StructPtrHeadIntPtrString", + "StructPtrHeadOmitEmptyIntPtrString", + "StructHeadUintPtrString", + "StructHeadOmitEmptyUintPtrString", + "StructPtrHeadUintPtrString", + "StructPtrHeadOmitEmptyUintPtrString", + "StructHeadFloat32PtrString", + "StructHeadOmitEmptyFloat32PtrString", + "StructPtrHeadFloat32PtrString", + "StructPtrHeadOmitEmptyFloat32PtrString", + "StructHeadFloat64PtrString", + "StructHeadOmitEmptyFloat64PtrString", + "StructPtrHeadFloat64PtrString", + "StructPtrHeadOmitEmptyFloat64PtrString", + "StructHeadBoolPtrString", + "StructHeadOmitEmptyBoolPtrString", + "StructPtrHeadBoolPtrString", + "StructPtrHeadOmitEmptyBoolPtrString", + "StructHeadStringPtrString", + "StructHeadOmitEmptyStringPtrString", + "StructPtrHeadStringPtrString", + "StructPtrHeadOmitEmptyStringPtrString", + "StructHeadNumberPtrString", + "StructHeadOmitEmptyNumberPtrString", + "StructPtrHeadNumberPtrString", + "StructPtrHeadOmitEmptyNumberPtrString", + "StructHead", + "StructHeadOmitEmpty", + "StructPtrHead", + "StructPtrHeadOmitEmpty", + "StructFieldInt", + "StructFieldOmitEmptyInt", + "StructEndInt", + "StructEndOmitEmptyInt", + "StructFieldUint", + "StructFieldOmitEmptyUint", + "StructEndUint", + "StructEndOmitEmptyUint", + "StructFieldFloat32", + "StructFieldOmitEmptyFloat32", + "StructEndFloat32", + "StructEndOmitEmptyFloat32", + "StructFieldFloat64", + "StructFieldOmitEmptyFloat64", + "StructEndFloat64", + "StructEndOmitEmptyFloat64", + "StructFieldBool", + "StructFieldOmitEmptyBool", + "StructEndBool", + "StructEndOmitEmptyBool", + "StructFieldString", + "StructFieldOmitEmptyString", + "StructEndString", + "StructEndOmitEmptyString", + "StructFieldBytes", + "StructFieldOmitEmptyBytes", + "StructEndBytes", + "StructEndOmitEmptyBytes", + "StructFieldNumber", + "StructFieldOmitEmptyNumber", + "StructEndNumber", + "StructEndOmitEmptyNumber", + "StructFieldArray", + "StructFieldOmitEmptyArray", + "StructEndArray", + "StructEndOmitEmptyArray", + "StructFieldMap", + "StructFieldOmitEmptyMap", + "StructEndMap", + "StructEndOmitEmptyMap", + "StructFieldSlice", + "StructFieldOmitEmptySlice", + "StructEndSlice", + "StructEndOmitEmptySlice", + "StructFieldStruct", + "StructFieldOmitEmptyStruct", + "StructEndStruct", + "StructEndOmitEmptyStruct", + "StructFieldMarshalJSON", + "StructFieldOmitEmptyMarshalJSON", + "StructEndMarshalJSON", + "StructEndOmitEmptyMarshalJSON", + "StructFieldMarshalText", + "StructFieldOmitEmptyMarshalText", + "StructEndMarshalText", + "StructEndOmitEmptyMarshalText", + "StructFieldIntString", + "StructFieldOmitEmptyIntString", + "StructEndIntString", + "StructEndOmitEmptyIntString", + "StructFieldUintString", + "StructFieldOmitEmptyUintString", + "StructEndUintString", + "StructEndOmitEmptyUintString", + "StructFieldFloat32String", + "StructFieldOmitEmptyFloat32String", + "StructEndFloat32String", + "StructEndOmitEmptyFloat32String", + "StructFieldFloat64String", + "StructFieldOmitEmptyFloat64String", + "StructEndFloat64String", + "StructEndOmitEmptyFloat64String", + "StructFieldBoolString", + "StructFieldOmitEmptyBoolString", + "StructEndBoolString", + "StructEndOmitEmptyBoolString", + "StructFieldStringString", + "StructFieldOmitEmptyStringString", + "StructEndStringString", + "StructEndOmitEmptyStringString", + "StructFieldNumberString", + "StructFieldOmitEmptyNumberString", + "StructEndNumberString", + "StructEndOmitEmptyNumberString", + "StructFieldIntPtr", + "StructFieldOmitEmptyIntPtr", + "StructEndIntPtr", + "StructEndOmitEmptyIntPtr", + "StructFieldUintPtr", + "StructFieldOmitEmptyUintPtr", + "StructEndUintPtr", + "StructEndOmitEmptyUintPtr", + "StructFieldFloat32Ptr", + "StructFieldOmitEmptyFloat32Ptr", + "StructEndFloat32Ptr", + "StructEndOmitEmptyFloat32Ptr", + "StructFieldFloat64Ptr", + "StructFieldOmitEmptyFloat64Ptr", + "StructEndFloat64Ptr", + "StructEndOmitEmptyFloat64Ptr", + "StructFieldBoolPtr", + "StructFieldOmitEmptyBoolPtr", + "StructEndBoolPtr", + "StructEndOmitEmptyBoolPtr", + "StructFieldStringPtr", + "StructFieldOmitEmptyStringPtr", + "StructEndStringPtr", + "StructEndOmitEmptyStringPtr", + "StructFieldBytesPtr", + "StructFieldOmitEmptyBytesPtr", + "StructEndBytesPtr", + "StructEndOmitEmptyBytesPtr", + "StructFieldNumberPtr", + "StructFieldOmitEmptyNumberPtr", + "StructEndNumberPtr", + "StructEndOmitEmptyNumberPtr", + "StructFieldArrayPtr", + "StructFieldOmitEmptyArrayPtr", + "StructEndArrayPtr", + "StructEndOmitEmptyArrayPtr", + "StructFieldMapPtr", + "StructFieldOmitEmptyMapPtr", + "StructEndMapPtr", + "StructEndOmitEmptyMapPtr", + "StructFieldSlicePtr", + "StructFieldOmitEmptySlicePtr", + "StructEndSlicePtr", + "StructEndOmitEmptySlicePtr", + "StructFieldMarshalJSONPtr", + "StructFieldOmitEmptyMarshalJSONPtr", + "StructEndMarshalJSONPtr", + "StructEndOmitEmptyMarshalJSONPtr", + "StructFieldMarshalTextPtr", + "StructFieldOmitEmptyMarshalTextPtr", + "StructEndMarshalTextPtr", + "StructEndOmitEmptyMarshalTextPtr", + "StructFieldInterfacePtr", + "StructFieldOmitEmptyInterfacePtr", + "StructEndInterfacePtr", + "StructEndOmitEmptyInterfacePtr", + "StructFieldIntPtrString", + "StructFieldOmitEmptyIntPtrString", + "StructEndIntPtrString", + "StructEndOmitEmptyIntPtrString", + "StructFieldUintPtrString", + "StructFieldOmitEmptyUintPtrString", + "StructEndUintPtrString", + "StructEndOmitEmptyUintPtrString", + "StructFieldFloat32PtrString", + "StructFieldOmitEmptyFloat32PtrString", + "StructEndFloat32PtrString", + "StructEndOmitEmptyFloat32PtrString", + "StructFieldFloat64PtrString", + "StructFieldOmitEmptyFloat64PtrString", + "StructEndFloat64PtrString", + "StructEndOmitEmptyFloat64PtrString", + "StructFieldBoolPtrString", + "StructFieldOmitEmptyBoolPtrString", + "StructEndBoolPtrString", + "StructEndOmitEmptyBoolPtrString", + "StructFieldStringPtrString", + "StructFieldOmitEmptyStringPtrString", + "StructEndStringPtrString", + "StructEndOmitEmptyStringPtrString", + "StructFieldNumberPtrString", + "StructFieldOmitEmptyNumberPtrString", + "StructEndNumberPtrString", + "StructEndOmitEmptyNumberPtrString", + "StructField", + "StructFieldOmitEmpty", + "StructEnd", + "StructEndOmitEmpty", +} + +type OpType uint16 + +const ( + OpEnd OpType = 0 + OpInterface OpType = 1 + OpPtr OpType = 2 + OpSliceElem OpType = 3 + OpSliceEnd OpType = 4 + OpArrayElem OpType = 5 + OpArrayEnd OpType = 6 + OpMapKey OpType = 7 + OpMapValue OpType = 8 + OpMapEnd OpType = 9 + OpRecursive OpType = 10 + OpRecursivePtr OpType = 11 + OpRecursiveEnd OpType = 12 + OpInterfaceEnd OpType = 13 + OpStructAnonymousEnd OpType = 14 + OpInt OpType = 15 + OpUint OpType = 16 + OpFloat32 OpType = 17 + OpFloat64 OpType = 18 + OpBool OpType = 19 + OpString OpType = 20 + OpBytes OpType = 21 + OpNumber OpType = 22 + OpArray OpType = 23 + OpMap OpType = 24 + OpSlice OpType = 25 + OpStruct OpType = 26 + OpMarshalJSON OpType = 27 + OpMarshalText OpType = 28 + OpIntString OpType = 29 + OpUintString OpType = 30 + OpFloat32String OpType = 31 + OpFloat64String OpType = 32 + OpBoolString OpType = 33 + OpStringString OpType = 34 + OpNumberString OpType = 35 + OpIntPtr OpType = 36 + OpUintPtr OpType = 37 + OpFloat32Ptr OpType = 38 + OpFloat64Ptr OpType = 39 + OpBoolPtr OpType = 40 + OpStringPtr OpType = 41 + OpBytesPtr OpType = 42 + OpNumberPtr OpType = 43 + OpArrayPtr OpType = 44 + OpMapPtr OpType = 45 + OpSlicePtr OpType = 46 + OpMarshalJSONPtr OpType = 47 + OpMarshalTextPtr OpType = 48 + OpInterfacePtr OpType = 49 + OpIntPtrString OpType = 50 + OpUintPtrString OpType = 51 + OpFloat32PtrString OpType = 52 + OpFloat64PtrString OpType = 53 + OpBoolPtrString OpType = 54 + OpStringPtrString OpType = 55 + OpNumberPtrString OpType = 56 + OpStructHeadInt OpType = 57 + OpStructHeadOmitEmptyInt OpType = 58 + OpStructPtrHeadInt OpType = 59 + OpStructPtrHeadOmitEmptyInt OpType = 60 + OpStructHeadUint OpType = 61 + OpStructHeadOmitEmptyUint OpType = 62 + OpStructPtrHeadUint OpType = 63 + OpStructPtrHeadOmitEmptyUint OpType = 64 + OpStructHeadFloat32 OpType = 65 + OpStructHeadOmitEmptyFloat32 OpType = 66 + OpStructPtrHeadFloat32 OpType = 67 + OpStructPtrHeadOmitEmptyFloat32 OpType = 68 + OpStructHeadFloat64 OpType = 69 + OpStructHeadOmitEmptyFloat64 OpType = 70 + OpStructPtrHeadFloat64 OpType = 71 + OpStructPtrHeadOmitEmptyFloat64 OpType = 72 + OpStructHeadBool OpType = 73 + OpStructHeadOmitEmptyBool OpType = 74 + OpStructPtrHeadBool OpType = 75 + OpStructPtrHeadOmitEmptyBool OpType = 76 + OpStructHeadString OpType = 77 + OpStructHeadOmitEmptyString OpType = 78 + OpStructPtrHeadString OpType = 79 + OpStructPtrHeadOmitEmptyString OpType = 80 + OpStructHeadBytes OpType = 81 + OpStructHeadOmitEmptyBytes OpType = 82 + OpStructPtrHeadBytes OpType = 83 + OpStructPtrHeadOmitEmptyBytes OpType = 84 + OpStructHeadNumber OpType = 85 + OpStructHeadOmitEmptyNumber OpType = 86 + OpStructPtrHeadNumber OpType = 87 + OpStructPtrHeadOmitEmptyNumber OpType = 88 + OpStructHeadArray OpType = 89 + OpStructHeadOmitEmptyArray OpType = 90 + OpStructPtrHeadArray OpType = 91 + OpStructPtrHeadOmitEmptyArray OpType = 92 + OpStructHeadMap OpType = 93 + OpStructHeadOmitEmptyMap OpType = 94 + OpStructPtrHeadMap OpType = 95 + OpStructPtrHeadOmitEmptyMap OpType = 96 + OpStructHeadSlice OpType = 97 + OpStructHeadOmitEmptySlice OpType = 98 + OpStructPtrHeadSlice OpType = 99 + OpStructPtrHeadOmitEmptySlice OpType = 100 + OpStructHeadStruct OpType = 101 + OpStructHeadOmitEmptyStruct OpType = 102 + OpStructPtrHeadStruct OpType = 103 + OpStructPtrHeadOmitEmptyStruct OpType = 104 + OpStructHeadMarshalJSON OpType = 105 + OpStructHeadOmitEmptyMarshalJSON OpType = 106 + OpStructPtrHeadMarshalJSON OpType = 107 + OpStructPtrHeadOmitEmptyMarshalJSON OpType = 108 + OpStructHeadMarshalText OpType = 109 + OpStructHeadOmitEmptyMarshalText OpType = 110 + OpStructPtrHeadMarshalText OpType = 111 + OpStructPtrHeadOmitEmptyMarshalText OpType = 112 + OpStructHeadIntString OpType = 113 + OpStructHeadOmitEmptyIntString OpType = 114 + OpStructPtrHeadIntString OpType = 115 + OpStructPtrHeadOmitEmptyIntString OpType = 116 + OpStructHeadUintString OpType = 117 + OpStructHeadOmitEmptyUintString OpType = 118 + OpStructPtrHeadUintString OpType = 119 + OpStructPtrHeadOmitEmptyUintString OpType = 120 + OpStructHeadFloat32String OpType = 121 + OpStructHeadOmitEmptyFloat32String OpType = 122 + OpStructPtrHeadFloat32String OpType = 123 + OpStructPtrHeadOmitEmptyFloat32String OpType = 124 + OpStructHeadFloat64String OpType = 125 + OpStructHeadOmitEmptyFloat64String OpType = 126 + OpStructPtrHeadFloat64String OpType = 127 + OpStructPtrHeadOmitEmptyFloat64String OpType = 128 + OpStructHeadBoolString OpType = 129 + OpStructHeadOmitEmptyBoolString OpType = 130 + OpStructPtrHeadBoolString OpType = 131 + OpStructPtrHeadOmitEmptyBoolString OpType = 132 + OpStructHeadStringString OpType = 133 + OpStructHeadOmitEmptyStringString OpType = 134 + OpStructPtrHeadStringString OpType = 135 + OpStructPtrHeadOmitEmptyStringString OpType = 136 + OpStructHeadNumberString OpType = 137 + OpStructHeadOmitEmptyNumberString OpType = 138 + OpStructPtrHeadNumberString OpType = 139 + OpStructPtrHeadOmitEmptyNumberString OpType = 140 + OpStructHeadIntPtr OpType = 141 + OpStructHeadOmitEmptyIntPtr OpType = 142 + OpStructPtrHeadIntPtr OpType = 143 + OpStructPtrHeadOmitEmptyIntPtr OpType = 144 + OpStructHeadUintPtr OpType = 145 + OpStructHeadOmitEmptyUintPtr OpType = 146 + OpStructPtrHeadUintPtr OpType = 147 + OpStructPtrHeadOmitEmptyUintPtr OpType = 148 + OpStructHeadFloat32Ptr OpType = 149 + OpStructHeadOmitEmptyFloat32Ptr OpType = 150 + OpStructPtrHeadFloat32Ptr OpType = 151 + OpStructPtrHeadOmitEmptyFloat32Ptr OpType = 152 + OpStructHeadFloat64Ptr OpType = 153 + OpStructHeadOmitEmptyFloat64Ptr OpType = 154 + OpStructPtrHeadFloat64Ptr OpType = 155 + OpStructPtrHeadOmitEmptyFloat64Ptr OpType = 156 + OpStructHeadBoolPtr OpType = 157 + OpStructHeadOmitEmptyBoolPtr OpType = 158 + OpStructPtrHeadBoolPtr OpType = 159 + OpStructPtrHeadOmitEmptyBoolPtr OpType = 160 + OpStructHeadStringPtr OpType = 161 + OpStructHeadOmitEmptyStringPtr OpType = 162 + OpStructPtrHeadStringPtr OpType = 163 + OpStructPtrHeadOmitEmptyStringPtr OpType = 164 + OpStructHeadBytesPtr OpType = 165 + OpStructHeadOmitEmptyBytesPtr OpType = 166 + OpStructPtrHeadBytesPtr OpType = 167 + OpStructPtrHeadOmitEmptyBytesPtr OpType = 168 + OpStructHeadNumberPtr OpType = 169 + OpStructHeadOmitEmptyNumberPtr OpType = 170 + OpStructPtrHeadNumberPtr OpType = 171 + OpStructPtrHeadOmitEmptyNumberPtr OpType = 172 + OpStructHeadArrayPtr OpType = 173 + OpStructHeadOmitEmptyArrayPtr OpType = 174 + OpStructPtrHeadArrayPtr OpType = 175 + OpStructPtrHeadOmitEmptyArrayPtr OpType = 176 + OpStructHeadMapPtr OpType = 177 + OpStructHeadOmitEmptyMapPtr OpType = 178 + OpStructPtrHeadMapPtr OpType = 179 + OpStructPtrHeadOmitEmptyMapPtr OpType = 180 + OpStructHeadSlicePtr OpType = 181 + OpStructHeadOmitEmptySlicePtr OpType = 182 + OpStructPtrHeadSlicePtr OpType = 183 + OpStructPtrHeadOmitEmptySlicePtr OpType = 184 + OpStructHeadMarshalJSONPtr OpType = 185 + OpStructHeadOmitEmptyMarshalJSONPtr OpType = 186 + OpStructPtrHeadMarshalJSONPtr OpType = 187 + OpStructPtrHeadOmitEmptyMarshalJSONPtr OpType = 188 + OpStructHeadMarshalTextPtr OpType = 189 + OpStructHeadOmitEmptyMarshalTextPtr OpType = 190 + OpStructPtrHeadMarshalTextPtr OpType = 191 + OpStructPtrHeadOmitEmptyMarshalTextPtr OpType = 192 + OpStructHeadInterfacePtr OpType = 193 + OpStructHeadOmitEmptyInterfacePtr OpType = 194 + OpStructPtrHeadInterfacePtr OpType = 195 + OpStructPtrHeadOmitEmptyInterfacePtr OpType = 196 + OpStructHeadIntPtrString OpType = 197 + OpStructHeadOmitEmptyIntPtrString OpType = 198 + OpStructPtrHeadIntPtrString OpType = 199 + OpStructPtrHeadOmitEmptyIntPtrString OpType = 200 + OpStructHeadUintPtrString OpType = 201 + OpStructHeadOmitEmptyUintPtrString OpType = 202 + OpStructPtrHeadUintPtrString OpType = 203 + OpStructPtrHeadOmitEmptyUintPtrString OpType = 204 + OpStructHeadFloat32PtrString OpType = 205 + OpStructHeadOmitEmptyFloat32PtrString OpType = 206 + OpStructPtrHeadFloat32PtrString OpType = 207 + OpStructPtrHeadOmitEmptyFloat32PtrString OpType = 208 + OpStructHeadFloat64PtrString OpType = 209 + OpStructHeadOmitEmptyFloat64PtrString OpType = 210 + OpStructPtrHeadFloat64PtrString OpType = 211 + OpStructPtrHeadOmitEmptyFloat64PtrString OpType = 212 + OpStructHeadBoolPtrString OpType = 213 + OpStructHeadOmitEmptyBoolPtrString OpType = 214 + OpStructPtrHeadBoolPtrString OpType = 215 + OpStructPtrHeadOmitEmptyBoolPtrString OpType = 216 + OpStructHeadStringPtrString OpType = 217 + OpStructHeadOmitEmptyStringPtrString OpType = 218 + OpStructPtrHeadStringPtrString OpType = 219 + OpStructPtrHeadOmitEmptyStringPtrString OpType = 220 + OpStructHeadNumberPtrString OpType = 221 + OpStructHeadOmitEmptyNumberPtrString OpType = 222 + OpStructPtrHeadNumberPtrString OpType = 223 + OpStructPtrHeadOmitEmptyNumberPtrString OpType = 224 + OpStructHead OpType = 225 + OpStructHeadOmitEmpty OpType = 226 + OpStructPtrHead OpType = 227 + OpStructPtrHeadOmitEmpty OpType = 228 + OpStructFieldInt OpType = 229 + OpStructFieldOmitEmptyInt OpType = 230 + OpStructEndInt OpType = 231 + OpStructEndOmitEmptyInt OpType = 232 + OpStructFieldUint OpType = 233 + OpStructFieldOmitEmptyUint OpType = 234 + OpStructEndUint OpType = 235 + OpStructEndOmitEmptyUint OpType = 236 + OpStructFieldFloat32 OpType = 237 + OpStructFieldOmitEmptyFloat32 OpType = 238 + OpStructEndFloat32 OpType = 239 + OpStructEndOmitEmptyFloat32 OpType = 240 + OpStructFieldFloat64 OpType = 241 + OpStructFieldOmitEmptyFloat64 OpType = 242 + OpStructEndFloat64 OpType = 243 + OpStructEndOmitEmptyFloat64 OpType = 244 + OpStructFieldBool OpType = 245 + OpStructFieldOmitEmptyBool OpType = 246 + OpStructEndBool OpType = 247 + OpStructEndOmitEmptyBool OpType = 248 + OpStructFieldString OpType = 249 + OpStructFieldOmitEmptyString OpType = 250 + OpStructEndString OpType = 251 + OpStructEndOmitEmptyString OpType = 252 + OpStructFieldBytes OpType = 253 + OpStructFieldOmitEmptyBytes OpType = 254 + OpStructEndBytes OpType = 255 + OpStructEndOmitEmptyBytes OpType = 256 + OpStructFieldNumber OpType = 257 + OpStructFieldOmitEmptyNumber OpType = 258 + OpStructEndNumber OpType = 259 + OpStructEndOmitEmptyNumber OpType = 260 + OpStructFieldArray OpType = 261 + OpStructFieldOmitEmptyArray OpType = 262 + OpStructEndArray OpType = 263 + OpStructEndOmitEmptyArray OpType = 264 + OpStructFieldMap OpType = 265 + OpStructFieldOmitEmptyMap OpType = 266 + OpStructEndMap OpType = 267 + OpStructEndOmitEmptyMap OpType = 268 + OpStructFieldSlice OpType = 269 + OpStructFieldOmitEmptySlice OpType = 270 + OpStructEndSlice OpType = 271 + OpStructEndOmitEmptySlice OpType = 272 + OpStructFieldStruct OpType = 273 + OpStructFieldOmitEmptyStruct OpType = 274 + OpStructEndStruct OpType = 275 + OpStructEndOmitEmptyStruct OpType = 276 + OpStructFieldMarshalJSON OpType = 277 + OpStructFieldOmitEmptyMarshalJSON OpType = 278 + OpStructEndMarshalJSON OpType = 279 + OpStructEndOmitEmptyMarshalJSON OpType = 280 + OpStructFieldMarshalText OpType = 281 + OpStructFieldOmitEmptyMarshalText OpType = 282 + OpStructEndMarshalText OpType = 283 + OpStructEndOmitEmptyMarshalText OpType = 284 + OpStructFieldIntString OpType = 285 + OpStructFieldOmitEmptyIntString OpType = 286 + OpStructEndIntString OpType = 287 + OpStructEndOmitEmptyIntString OpType = 288 + OpStructFieldUintString OpType = 289 + OpStructFieldOmitEmptyUintString OpType = 290 + OpStructEndUintString OpType = 291 + OpStructEndOmitEmptyUintString OpType = 292 + OpStructFieldFloat32String OpType = 293 + OpStructFieldOmitEmptyFloat32String OpType = 294 + OpStructEndFloat32String OpType = 295 + OpStructEndOmitEmptyFloat32String OpType = 296 + OpStructFieldFloat64String OpType = 297 + OpStructFieldOmitEmptyFloat64String OpType = 298 + OpStructEndFloat64String OpType = 299 + OpStructEndOmitEmptyFloat64String OpType = 300 + OpStructFieldBoolString OpType = 301 + OpStructFieldOmitEmptyBoolString OpType = 302 + OpStructEndBoolString OpType = 303 + OpStructEndOmitEmptyBoolString OpType = 304 + OpStructFieldStringString OpType = 305 + OpStructFieldOmitEmptyStringString OpType = 306 + OpStructEndStringString OpType = 307 + OpStructEndOmitEmptyStringString OpType = 308 + OpStructFieldNumberString OpType = 309 + OpStructFieldOmitEmptyNumberString OpType = 310 + OpStructEndNumberString OpType = 311 + OpStructEndOmitEmptyNumberString OpType = 312 + OpStructFieldIntPtr OpType = 313 + OpStructFieldOmitEmptyIntPtr OpType = 314 + OpStructEndIntPtr OpType = 315 + OpStructEndOmitEmptyIntPtr OpType = 316 + OpStructFieldUintPtr OpType = 317 + OpStructFieldOmitEmptyUintPtr OpType = 318 + OpStructEndUintPtr OpType = 319 + OpStructEndOmitEmptyUintPtr OpType = 320 + OpStructFieldFloat32Ptr OpType = 321 + OpStructFieldOmitEmptyFloat32Ptr OpType = 322 + OpStructEndFloat32Ptr OpType = 323 + OpStructEndOmitEmptyFloat32Ptr OpType = 324 + OpStructFieldFloat64Ptr OpType = 325 + OpStructFieldOmitEmptyFloat64Ptr OpType = 326 + OpStructEndFloat64Ptr OpType = 327 + OpStructEndOmitEmptyFloat64Ptr OpType = 328 + OpStructFieldBoolPtr OpType = 329 + OpStructFieldOmitEmptyBoolPtr OpType = 330 + OpStructEndBoolPtr OpType = 331 + OpStructEndOmitEmptyBoolPtr OpType = 332 + OpStructFieldStringPtr OpType = 333 + OpStructFieldOmitEmptyStringPtr OpType = 334 + OpStructEndStringPtr OpType = 335 + OpStructEndOmitEmptyStringPtr OpType = 336 + OpStructFieldBytesPtr OpType = 337 + OpStructFieldOmitEmptyBytesPtr OpType = 338 + OpStructEndBytesPtr OpType = 339 + OpStructEndOmitEmptyBytesPtr OpType = 340 + OpStructFieldNumberPtr OpType = 341 + OpStructFieldOmitEmptyNumberPtr OpType = 342 + OpStructEndNumberPtr OpType = 343 + OpStructEndOmitEmptyNumberPtr OpType = 344 + OpStructFieldArrayPtr OpType = 345 + OpStructFieldOmitEmptyArrayPtr OpType = 346 + OpStructEndArrayPtr OpType = 347 + OpStructEndOmitEmptyArrayPtr OpType = 348 + OpStructFieldMapPtr OpType = 349 + OpStructFieldOmitEmptyMapPtr OpType = 350 + OpStructEndMapPtr OpType = 351 + OpStructEndOmitEmptyMapPtr OpType = 352 + OpStructFieldSlicePtr OpType = 353 + OpStructFieldOmitEmptySlicePtr OpType = 354 + OpStructEndSlicePtr OpType = 355 + OpStructEndOmitEmptySlicePtr OpType = 356 + OpStructFieldMarshalJSONPtr OpType = 357 + OpStructFieldOmitEmptyMarshalJSONPtr OpType = 358 + OpStructEndMarshalJSONPtr OpType = 359 + OpStructEndOmitEmptyMarshalJSONPtr OpType = 360 + OpStructFieldMarshalTextPtr OpType = 361 + OpStructFieldOmitEmptyMarshalTextPtr OpType = 362 + OpStructEndMarshalTextPtr OpType = 363 + OpStructEndOmitEmptyMarshalTextPtr OpType = 364 + OpStructFieldInterfacePtr OpType = 365 + OpStructFieldOmitEmptyInterfacePtr OpType = 366 + OpStructEndInterfacePtr OpType = 367 + OpStructEndOmitEmptyInterfacePtr OpType = 368 + OpStructFieldIntPtrString OpType = 369 + OpStructFieldOmitEmptyIntPtrString OpType = 370 + OpStructEndIntPtrString OpType = 371 + OpStructEndOmitEmptyIntPtrString OpType = 372 + OpStructFieldUintPtrString OpType = 373 + OpStructFieldOmitEmptyUintPtrString OpType = 374 + OpStructEndUintPtrString OpType = 375 + OpStructEndOmitEmptyUintPtrString OpType = 376 + OpStructFieldFloat32PtrString OpType = 377 + OpStructFieldOmitEmptyFloat32PtrString OpType = 378 + OpStructEndFloat32PtrString OpType = 379 + OpStructEndOmitEmptyFloat32PtrString OpType = 380 + OpStructFieldFloat64PtrString OpType = 381 + OpStructFieldOmitEmptyFloat64PtrString OpType = 382 + OpStructEndFloat64PtrString OpType = 383 + OpStructEndOmitEmptyFloat64PtrString OpType = 384 + OpStructFieldBoolPtrString OpType = 385 + OpStructFieldOmitEmptyBoolPtrString OpType = 386 + OpStructEndBoolPtrString OpType = 387 + OpStructEndOmitEmptyBoolPtrString OpType = 388 + OpStructFieldStringPtrString OpType = 389 + OpStructFieldOmitEmptyStringPtrString OpType = 390 + OpStructEndStringPtrString OpType = 391 + OpStructEndOmitEmptyStringPtrString OpType = 392 + OpStructFieldNumberPtrString OpType = 393 + OpStructFieldOmitEmptyNumberPtrString OpType = 394 + OpStructEndNumberPtrString OpType = 395 + OpStructEndOmitEmptyNumberPtrString OpType = 396 + OpStructField OpType = 397 + OpStructFieldOmitEmpty OpType = 398 + OpStructEnd OpType = 399 + OpStructEndOmitEmpty OpType = 400 +) + +func (t OpType) String() string { + if int(t) >= 401 { + return "" + } + return opTypeStrings[int(t)] +} + +func (t OpType) CodeType() CodeType { + if strings.Contains(t.String(), "Struct") { + if strings.Contains(t.String(), "End") { + return CodeStructEnd + } + return CodeStructField + } + switch t { + case OpArray, OpArrayPtr: + return CodeArrayHead + case OpArrayElem: + return CodeArrayElem + case OpSlice, OpSlicePtr: + return CodeSliceHead + case OpSliceElem: + return CodeSliceElem + case OpMap, OpMapPtr: + return CodeMapHead + case OpMapKey: + return CodeMapKey + case OpMapValue: + return CodeMapValue + case OpMapEnd: + return CodeMapEnd + } + + return CodeOp +} + +func (t OpType) HeadToPtrHead() OpType { + if strings.Index(t.String(), "PtrHead") > 0 { + return t + } + + idx := strings.Index(t.String(), "Head") + if idx == -1 { + return t + } + suffix := "PtrHead" + t.String()[idx+len("Head"):] + + const toPtrOffset = 2 + if strings.Contains(OpType(int(t)+toPtrOffset).String(), suffix) { + return OpType(int(t) + toPtrOffset) + } + return t +} + +func (t OpType) HeadToOmitEmptyHead() OpType { + const toOmitEmptyOffset = 1 + if strings.Contains(OpType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) + } + + return t +} + +func (t OpType) PtrHeadToHead() OpType { + idx := strings.Index(t.String(), "Ptr") + if idx == -1 { + return t + } + suffix := t.String()[idx+len("Ptr"):] + + const toPtrOffset = 2 + if strings.Contains(OpType(int(t)-toPtrOffset).String(), suffix) { + return OpType(int(t) - toPtrOffset) + } + return t +} + +func (t OpType) FieldToEnd() OpType { + idx := strings.Index(t.String(), "Field") + if idx == -1 { + return t + } + suffix := t.String()[idx+len("Field"):] + if suffix == "" || suffix == "OmitEmpty" { + return t + } + const toEndOffset = 2 + if strings.Contains(OpType(int(t)+toEndOffset).String(), "End"+suffix) { + return OpType(int(t) + toEndOffset) + } + return t +} + +func (t OpType) FieldToOmitEmptyField() OpType { + const toOmitEmptyOffset = 1 + if strings.Contains(OpType(int(t)+toOmitEmptyOffset).String(), "OmitEmpty") { + return OpType(int(t) + toOmitEmptyOffset) + } + return t +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/string.go b/vendor/github.com/goccy/go-json/internal/encoder/string.go new file mode 100644 index 00000000..a699dba1 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/string.go @@ -0,0 +1,640 @@ +package encoder + +import ( + "math/bits" + "reflect" + "unicode/utf8" + "unsafe" +) + +const ( + lsb = 0x0101010101010101 + msb = 0x8080808080808080 +) + +var needEscapeWithHTML = [256]bool{ + '"': true, + '&': true, + '<': true, + '>': true, + '\\': true, + 0x00: true, + 0x01: true, + 0x02: true, + 0x03: true, + 0x04: true, + 0x05: true, + 0x06: true, + 0x07: true, + 0x08: true, + 0x09: true, + 0x0a: true, + 0x0b: true, + 0x0c: true, + 0x0d: true, + 0x0e: true, + 0x0f: true, + 0x10: true, + 0x11: true, + 0x12: true, + 0x13: true, + 0x14: true, + 0x15: true, + 0x16: true, + 0x17: true, + 0x18: true, + 0x19: true, + 0x1a: true, + 0x1b: true, + 0x1c: true, + 0x1d: true, + 0x1e: true, + 0x1f: true, + /* 0x20 - 0x7f */ + 0x80: true, + 0x81: true, + 0x82: true, + 0x83: true, + 0x84: true, + 0x85: true, + 0x86: true, + 0x87: true, + 0x88: true, + 0x89: true, + 0x8a: true, + 0x8b: true, + 0x8c: true, + 0x8d: true, + 0x8e: true, + 0x8f: true, + 0x90: true, + 0x91: true, + 0x92: true, + 0x93: true, + 0x94: true, + 0x95: true, + 0x96: true, + 0x97: true, + 0x98: true, + 0x99: true, + 0x9a: true, + 0x9b: true, + 0x9c: true, + 0x9d: true, + 0x9e: true, + 0x9f: true, + 0xa0: true, + 0xa1: true, + 0xa2: true, + 0xa3: true, + 0xa4: true, + 0xa5: true, + 0xa6: true, + 0xa7: true, + 0xa8: true, + 0xa9: true, + 0xaa: true, + 0xab: true, + 0xac: true, + 0xad: true, + 0xae: true, + 0xaf: true, + 0xb0: true, + 0xb1: true, + 0xb2: true, + 0xb3: true, + 0xb4: true, + 0xb5: true, + 0xb6: true, + 0xb7: true, + 0xb8: true, + 0xb9: true, + 0xba: true, + 0xbb: true, + 0xbc: true, + 0xbd: true, + 0xbe: true, + 0xbf: true, + 0xc0: true, + 0xc1: true, + 0xc2: true, + 0xc3: true, + 0xc4: true, + 0xc5: true, + 0xc6: true, + 0xc7: true, + 0xc8: true, + 0xc9: true, + 0xca: true, + 0xcb: true, + 0xcc: true, + 0xcd: true, + 0xce: true, + 0xcf: true, + 0xd0: true, + 0xd1: true, + 0xd2: true, + 0xd3: true, + 0xd4: true, + 0xd5: true, + 0xd6: true, + 0xd7: true, + 0xd8: true, + 0xd9: true, + 0xda: true, + 0xdb: true, + 0xdc: true, + 0xdd: true, + 0xde: true, + 0xdf: true, + 0xe0: true, + 0xe1: true, + 0xe2: true, + 0xe3: true, + 0xe4: true, + 0xe5: true, + 0xe6: true, + 0xe7: true, + 0xe8: true, + 0xe9: true, + 0xea: true, + 0xeb: true, + 0xec: true, + 0xed: true, + 0xee: true, + 0xef: true, + 0xf0: true, + 0xf1: true, + 0xf2: true, + 0xf3: true, + 0xf4: true, + 0xf5: true, + 0xf6: true, + 0xf7: true, + 0xf8: true, + 0xf9: true, + 0xfa: true, + 0xfb: true, + 0xfc: true, + 0xfd: true, + 0xfe: true, + 0xff: true, +} + +var needEscape = [256]bool{ + '"': true, + '\\': true, + 0x00: true, + 0x01: true, + 0x02: true, + 0x03: true, + 0x04: true, + 0x05: true, + 0x06: true, + 0x07: true, + 0x08: true, + 0x09: true, + 0x0a: true, + 0x0b: true, + 0x0c: true, + 0x0d: true, + 0x0e: true, + 0x0f: true, + 0x10: true, + 0x11: true, + 0x12: true, + 0x13: true, + 0x14: true, + 0x15: true, + 0x16: true, + 0x17: true, + 0x18: true, + 0x19: true, + 0x1a: true, + 0x1b: true, + 0x1c: true, + 0x1d: true, + 0x1e: true, + 0x1f: true, + /* 0x20 - 0x7f */ + 0x80: true, + 0x81: true, + 0x82: true, + 0x83: true, + 0x84: true, + 0x85: true, + 0x86: true, + 0x87: true, + 0x88: true, + 0x89: true, + 0x8a: true, + 0x8b: true, + 0x8c: true, + 0x8d: true, + 0x8e: true, + 0x8f: true, + 0x90: true, + 0x91: true, + 0x92: true, + 0x93: true, + 0x94: true, + 0x95: true, + 0x96: true, + 0x97: true, + 0x98: true, + 0x99: true, + 0x9a: true, + 0x9b: true, + 0x9c: true, + 0x9d: true, + 0x9e: true, + 0x9f: true, + 0xa0: true, + 0xa1: true, + 0xa2: true, + 0xa3: true, + 0xa4: true, + 0xa5: true, + 0xa6: true, + 0xa7: true, + 0xa8: true, + 0xa9: true, + 0xaa: true, + 0xab: true, + 0xac: true, + 0xad: true, + 0xae: true, + 0xaf: true, + 0xb0: true, + 0xb1: true, + 0xb2: true, + 0xb3: true, + 0xb4: true, + 0xb5: true, + 0xb6: true, + 0xb7: true, + 0xb8: true, + 0xb9: true, + 0xba: true, + 0xbb: true, + 0xbc: true, + 0xbd: true, + 0xbe: true, + 0xbf: true, + 0xc0: true, + 0xc1: true, + 0xc2: true, + 0xc3: true, + 0xc4: true, + 0xc5: true, + 0xc6: true, + 0xc7: true, + 0xc8: true, + 0xc9: true, + 0xca: true, + 0xcb: true, + 0xcc: true, + 0xcd: true, + 0xce: true, + 0xcf: true, + 0xd0: true, + 0xd1: true, + 0xd2: true, + 0xd3: true, + 0xd4: true, + 0xd5: true, + 0xd6: true, + 0xd7: true, + 0xd8: true, + 0xd9: true, + 0xda: true, + 0xdb: true, + 0xdc: true, + 0xdd: true, + 0xde: true, + 0xdf: true, + 0xe0: true, + 0xe1: true, + 0xe2: true, + 0xe3: true, + 0xe4: true, + 0xe5: true, + 0xe6: true, + 0xe7: true, + 0xe8: true, + 0xe9: true, + 0xea: true, + 0xeb: true, + 0xec: true, + 0xed: true, + 0xee: true, + 0xef: true, + 0xf0: true, + 0xf1: true, + 0xf2: true, + 0xf3: true, + 0xf4: true, + 0xf5: true, + 0xf6: true, + 0xf7: true, + 0xf8: true, + 0xf9: true, + 0xfa: true, + 0xfb: true, + 0xfc: true, + 0xfd: true, + 0xfe: true, + 0xff: true, +} + +var hex = "0123456789abcdef" + +// escapeIndex finds the index of the first char in `s` that requires escaping. +// A char requires escaping if it's outside of the range of [0x20, 0x7F] or if +// it includes a double quote or backslash. +// If no chars in `s` require escaping, the return value is -1. +func escapeIndex(s string) int { + chunks := stringToUint64Slice(s) + for _, n := range chunks { + // combine masks before checking for the MSB of each byte. We include + // `n` in the mask to check whether any of the *input* byte MSBs were + // set (i.e. the byte was outside the ASCII range). + mask := n | below(n, 0x20) | contains(n, '"') | contains(n, '\\') + if (mask & msb) != 0 { + return bits.TrailingZeros64(mask&msb) / 8 + } + } + + valLen := len(s) + for i := len(chunks) * 8; i < valLen; i++ { + if needEscape[s[i]] { + return i + } + } + + return -1 +} + +// below return a mask that can be used to determine if any of the bytes +// in `n` are below `b`. If a byte's MSB is set in the mask then that byte was +// below `b`. The result is only valid if `b`, and each byte in `n`, is below +// 0x80. +func below(n uint64, b byte) uint64 { + return n - expand(b) +} + +// contains returns a mask that can be used to determine if any of the +// bytes in `n` are equal to `b`. If a byte's MSB is set in the mask then +// that byte is equal to `b`. The result is only valid if `b`, and each +// byte in `n`, is below 0x80. +func contains(n uint64, b byte) uint64 { + return (n ^ expand(b)) - lsb +} + +// expand puts the specified byte into each of the 8 bytes of a uint64. +func expand(b byte) uint64 { + return lsb * uint64(b) +} + +//nolint:govet +func stringToUint64Slice(s string) []uint64 { + return *(*[]uint64)(unsafe.Pointer(&reflect.SliceHeader{ + Data: ((*reflect.StringHeader)(unsafe.Pointer(&s))).Data, + Len: len(s) / 8, + Cap: len(s) / 8, + })) +} + +func AppendString(ctx *RuntimeContext, buf []byte, s string) []byte { + if ctx.Option.Flag&HTMLEscapeOption == 0 { + return appendString(buf, s) + } + valLen := len(s) + if valLen == 0 { + return append(buf, `""`...) + } + buf = append(buf, '"') + var ( + i, j int + ) + if valLen >= 8 { + chunks := stringToUint64Slice(s) + for _, n := range chunks { + // combine masks before checking for the MSB of each byte. We include + // `n` in the mask to check whether any of the *input* byte MSBs were + // set (i.e. the byte was outside the ASCII range). + mask := n | (n - (lsb * 0x20)) | + ((n ^ (lsb * '"')) - lsb) | + ((n ^ (lsb * '\\')) - lsb) | + ((n ^ (lsb * '<')) - lsb) | + ((n ^ (lsb * '>')) - lsb) | + ((n ^ (lsb * '&')) - lsb) + if (mask & msb) != 0 { + j = bits.TrailingZeros64(mask&msb) / 8 + goto ESCAPE_END + } + } + for i := len(chunks) * 8; i < valLen; i++ { + if needEscapeWithHTML[s[i]] { + j = i + goto ESCAPE_END + } + } + // no found any escape characters. + return append(append(buf, s...), '"') + } +ESCAPE_END: + for j < valLen { + c := s[j] + + if !needEscapeWithHTML[c] { + // fast path: most of the time, printable ascii characters are used + j++ + continue + } + + switch c { + case '\\', '"': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', c) + i = j + 1 + j = j + 1 + continue + + case '\n': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'n') + i = j + 1 + j = j + 1 + continue + + case '\r': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'r') + i = j + 1 + j = j + 1 + continue + + case '\t': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 't') + i = j + 1 + j = j + 1 + continue + + case '<', '>', '&': + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + // This encodes bytes < 0x20 except for \t, \n and \r. + if c < 0x20 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + r, size := utf8.DecodeRuneInString(s[j:]) + + if r == utf8.RuneError && size == 1 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\ufffd`...) + i = j + size + j = j + size + continue + } + + switch r { + case '\u2028', '\u2029': + // U+2028 is LINE SEPARATOR. + // U+2029 is PARAGRAPH SEPARATOR. + // They are both technically valid characters in JSON strings, + // but don't work in JSONP, which has to be evaluated as JavaScript, + // and can lead to security holes there. It is valid JSON to + // escape them, so we do so unconditionally. + // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. + buf = append(buf, s[i:j]...) + buf = append(buf, `\u202`...) + buf = append(buf, hex[r&0xF]) + i = j + size + j = j + size + continue + } + + j += size + } + + return append(append(buf, s[i:]...), '"') +} + +func appendString(buf []byte, s string) []byte { + valLen := len(s) + if valLen == 0 { + return append(buf, `""`...) + } + buf = append(buf, '"') + var escapeIdx int + if valLen >= 8 { + if escapeIdx = escapeIndex(s); escapeIdx < 0 { + return append(append(buf, s...), '"') + } + } + + i := 0 + j := escapeIdx + for j < valLen { + c := s[j] + + if c >= 0x20 && c <= 0x7f && c != '\\' && c != '"' { + // fast path: most of the time, printable ascii characters are used + j++ + continue + } + + switch c { + case '\\', '"': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', c) + i = j + 1 + j = j + 1 + continue + + case '\n': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'n') + i = j + 1 + j = j + 1 + continue + + case '\r': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 'r') + i = j + 1 + j = j + 1 + continue + + case '\t': + buf = append(buf, s[i:j]...) + buf = append(buf, '\\', 't') + i = j + 1 + j = j + 1 + continue + + case '<', '>', '&': + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + // This encodes bytes < 0x20 except for \t, \n and \r. + if c < 0x20 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\u00`...) + buf = append(buf, hex[c>>4], hex[c&0xF]) + i = j + 1 + j = j + 1 + continue + } + + r, size := utf8.DecodeRuneInString(s[j:]) + + if r == utf8.RuneError && size == 1 { + buf = append(buf, s[i:j]...) + buf = append(buf, `\ufffd`...) + i = j + size + j = j + size + continue + } + + switch r { + case '\u2028', '\u2029': + // U+2028 is LINE SEPARATOR. + // U+2029 is PARAGRAPH SEPARATOR. + // They are both technically valid characters in JSON strings, + // but don't work in JSONP, which has to be evaluated as JavaScript, + // and can lead to security holes there. It is valid JSON to + // escape them, so we do so unconditionally. + // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion. + buf = append(buf, s[i:j]...) + buf = append(buf, `\u202`...) + buf = append(buf, hex[r&0xF]) + i = j + size + j = j + size + continue + } + + j += size + } + + return append(append(buf, s[i:]...), '"') +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go new file mode 100644 index 00000000..05509fed --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go @@ -0,0 +1,34 @@ +package vm + +import ( + "fmt" + + "github.com/goccy/go-json/internal/encoder" +) + +func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { + defer func() { + var code *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + code = codeSet.EscapeKeyCode + } else { + code = codeSet.NoescapeKeyCode + } + + if err := recover(); err != nil { + fmt.Println("=============[DEBUG]===============") + fmt.Println("* [TYPE]") + fmt.Println(codeSet.Type) + fmt.Printf("\n") + fmt.Println("* [ALL OPCODE]") + fmt.Println(code.Dump()) + fmt.Printf("\n") + fmt.Println("* [CONTEXT]") + fmt.Printf("%+v\n", ctx) + fmt.Println("===================================") + panic(err) + } + }() + + return Run(ctx, b, codeSet) +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm/hack.go b/vendor/github.com/goccy/go-json/internal/encoder/vm/hack.go new file mode 100644 index 00000000..65252b4a --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/hack.go @@ -0,0 +1,9 @@ +package vm + +import ( + // HACK: compile order + // `vm`, `vm_indent`, `vm_color`, `vm_color_indent` packages uses a lot of memory to compile, + // so forcibly make dependencies and avoid compiling in concurrent. + // dependency order: vm => vm_indent => vm_color => vm_color_indent + _ "github.com/goccy/go-json/internal/encoder/vm_indent" +) diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm/util.go new file mode 100644 index 00000000..c5594479 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/util.go @@ -0,0 +1,182 @@ +package vm + +import ( + "encoding/json" + "fmt" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) + +var ( + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendString + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func errUnimplementedOp(op encoder.OpType) error { + return fmt.Errorf("encoder: opcode %s has not been implemented", op) +} + +func load(base uintptr, idx uint32) uintptr { + addr := base + uintptr(idx) + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func store(base uintptr, idx uint32, p uintptr) { + addr := base + uintptr(idx) + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr { + addr := base + uintptr(idx) + p := **(**uintptr)(unsafe.Pointer(&addr)) + for i := uint8(0); i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func ptrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func ptrToNPtr(p uintptr, ptrNum uint8) uintptr { + for i := uint8(0); i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func appendBool(_ *encoder.RuntimeContext, b []byte, v bool) []byte { + if v { + return append(b, "true"...) + } + return append(b, "false"...) +} + +func appendNull(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, "null"...) +} + +func appendComma(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, ',') +} + +func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { + last := len(b) - 1 + b[last] = ':' + return b +} + +func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte { + b = append(b, key...) + b[len(b)-1] = ':' + return append(b, value...) +} + +func appendMapEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + b[len(b)-1] = '}' + b = append(b, ',') + return b +} + +func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalJSON(ctx, code, b, v) +} + +func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalText(ctx, code, b, v) +} + +func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + return append(b, '[') +} + +func appendArrayEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + b[last] = ']' + return append(b, ',') +} + +func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '[', ']', ',') +} + +func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '{', '}', ',') +} + +func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + b[last] = '}' + return append(b, ',') +} + +func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '{') +} + +func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + return append(b, code.Key...) +} + +func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + return append(b, '}', ',') +} + +func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + return appendComma(ctx, b) + } + return appendStructEnd(ctx, code, b) +} + +func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {} +func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {} +func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } +func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go new file mode 100644 index 00000000..78da5e44 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go @@ -0,0 +1,5041 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package vm + +import ( + "math" + "sort" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" +) + +func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { + recursiveLevel := 0 + ptrOffset := uintptr(0) + ctxptr := ctx.Ptr() + var code *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + code = codeSet.EscapeKeyCode + } else { + code = codeSet.NoescapeKeyCode + } + + for { + switch code.Op { + default: + return nil, errUnimplementedOp(code.Op) + case encoder.OpPtr: + p := load(ctxptr, code.Idx) + code = code.Next + store(ctxptr, code.Idx, ptrToPtr(p)) + case encoder.OpIntPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpUintPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpUintString: + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpFloat32Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat32: + b = appendFloat32(ctx, b, ptrToFloat32(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpFloat64Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat64: + v := ptrToFloat64(load(ctxptr, code.Idx)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStringPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpString: + b = appendString(ctx, b, ptrToString(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpBoolPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBool: + b = appendBool(ctx, b, ptrToBool(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpBytesPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBytes: + b = appendByteSlice(ctx, b, ptrToBytes(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpNumberPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpNumber: + bb, err := appendNumber(ctx, b, ptrToNumber(load(ctxptr, code.Idx))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpInterfacePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if p == seen { + return nil, errUnsupportedValue(code, p) + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, p) + iface := (*emptyInterface)(ptrToUnsafePtr(p)) + if iface.ptr == nil { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + if err != nil { + return nil, err + } + + totalLength := uintptr(code.Length) + 3 + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 3 + + var c *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + c = ifaceCodeSet.InterfaceEscapeKeyCode + } else { + c = ifaceCodeSet.InterfaceNoescapeKeyCode + } + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += totalLength * uintptrSize + oldBaseIndent := ctx.BaseIndent + indentDiffFromTop := c.Indent - 1 + ctx.BaseIndent += code.Indent - indentDiffFromTop + + newLen := offsetNum + totalLength + nextTotalLength + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + end := ifaceCodeSet.EndCode + store(ctxptr, c.Idx, uintptr(iface.ptr)) + store(ctxptr, end.Idx, oldOffset) + store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + storeIndent(ctxptr, end, uintptr(oldBaseIndent)) + code = c + recursiveLevel++ + case encoder.OpInterfaceEnd: + recursiveLevel-- + + // restore ctxptr + offset := load(ctxptr, code.Idx) + restoreIndent(ctx, code, ctxptr) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + if (code.Flags&encoder.IsNilableTypeFlags) != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p) + } + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + b = append(b, `""`...) + b = appendComma(ctx, b) + code = code.Next + break + } + if (code.Flags&encoder.IsNilableTypeFlags) != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p) + } + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpSlicePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpSlice: + p := load(ctxptr, code.Idx) + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(slice.Len)) + store(ctxptr, code.Idx, uintptr(slice.Data)) + if slice.Len > 0 { + b = appendArrayHead(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, uintptr(slice.Data)) + } else { + b = appendEmptyArray(ctx, b) + code = code.End.Next + } + case encoder.OpSliceElem: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if idx < length { + b = appendArrayElemIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + data := load(ctxptr, code.Idx) + size := uintptr(code.Size) + code = code.Next + store(ctxptr, code.Idx, data+idx*size) + } else { + b = appendArrayEnd(ctx, code, b) + code = code.End.Next + } + case encoder.OpArrayPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpArray: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + if code.Length > 0 { + b = appendArrayHead(ctx, code, b) + store(ctxptr, code.ElemIdx, 0) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + b = appendEmptyArray(ctx, b) + code = code.End.Next + } + case encoder.OpArrayElem: + idx := load(ctxptr, code.ElemIdx) + idx++ + if idx < uintptr(code.Length) { + b = appendArrayElemIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + p := load(ctxptr, code.Idx) + size := uintptr(code.Size) + code = code.Next + store(ctxptr, code.Idx, p+idx*size) + } else { + b = appendArrayEnd(ctx, code, b) + code = code.End.Next + } + case encoder.OpMapPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpMap: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + uptr := ptrToUnsafePtr(p) + mlen := maplen(uptr) + if mlen <= 0 { + b = appendEmptyObject(ctx, b) + code = code.End.Next + break + } + b = appendStructHead(ctx, b) + iter := mapiterinit(code.Type, uptr) + ctx.KeepRefs = append(ctx.KeepRefs, iter) + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(mlen)) + store(ctxptr, code.MapIter, uintptr(iter)) + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendMapKeyIndent(ctx, code.Next, b) + } else { + mapCtx := encoder.NewMapContext(mlen) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx))) + } + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + if idx < length { + b = appendMapKeyIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + b = appendObjectEnd(ctx, code, b) + code = code.End.Next + } + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendColon(ctx, b) + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + } + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + value := mapitervalue(iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + length := int(load(ctxptr, code.Length)) + ptr := load(ctxptr, code.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + pos := mapCtx.Pos + for i := 0; i < length; i++ { + startKey := pos[i*2] + startValue := pos[i*2+1] + var endValue int + if i+1 < length { + endValue = pos[i*2+2] + } else { + endValue = len(b) + } + mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{ + Key: b[startKey:startValue], + Value: b[startValue:endValue], + }) + } + sort.Sort(mapCtx.Slice) + buf := mapCtx.Buf + for _, item := range mapCtx.Slice.Items { + buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value) + } + buf = appendMapEnd(ctx, code, buf) + b = b[:pos[0]] + b = append(b, buf...) + mapCtx.Buf = buf + encoder.ReleaseMapContext(mapCtx) + code = code.Next + case encoder.OpRecursivePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpRecursive: + ptr := load(ctxptr, code.Idx) + if ptr != 0 { + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if ptr == seen { + return nil, errUnsupportedValue(code, ptr) + } + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, ptr) + c := code.Jmp.Code + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += code.Jmp.CurLen * uintptrSize + oldBaseIndent := ctx.BaseIndent + indentDiffFromTop := c.Indent - 1 + ctx.BaseIndent += code.Indent - indentDiffFromTop + + newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + store(ctxptr, c.Idx, ptr) + store(ctxptr, c.End.Next.Idx, oldOffset) + store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + storeIndent(ctxptr, c.End.Next, uintptr(oldBaseIndent)) + code = c + recursiveLevel++ + case encoder.OpRecursiveEnd: + recursiveLevel-- + + // restore ctxptr + restoreIndent(ctx, code, ctxptr) + offset := load(ctxptr, code.Idx) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpStructPtrHead: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHead: + p := load(ctxptr, code.Idx) + if p == 0 && ((code.Flags&encoder.IndirectFlags) != 0 || code.Next.Op == encoder.OpStructEnd) { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { + b = appendStructKey(ctx, code, b) + } + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 && ((code.Flags&encoder.IndirectFlags) != 0 || code.Next.Op == encoder.OpStructEnd) { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if p == 0 || (ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0) { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadInt: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyInt: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadIntString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadIntString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyIntString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadUint: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUint: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadUintString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUintString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUintString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat32: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat32(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat32String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat32(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat64: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat64String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToString(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadStringString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p+uintptr(code.Offset))))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyStringString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToString(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBool: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBool: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadBoolString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBoolString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBytes: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytes: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadNumber: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumber: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToNumber(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + } + case encoder.OpStructPtrHeadNumberString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumberString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToNumber(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructPtrHeadNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadSlice: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadArray, encoder.OpStructHeadSlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyArray: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyArray: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptySlice: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptySlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + slice := ptrToSlice(p) + if slice.Len == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + } else { + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMap: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if p != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p + uintptr(code.Offset)) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p + uintptr(code.Offset)) + } + if maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + } else { + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + code = code.NextField + } else { + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalJSON { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + iface := ptrToInterface(code, p) + if (code.Flags&encoder.NilCheckFlags) != 0 && encoder.IsNilForMarshaler(iface) { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, iface) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalText { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructField: + if code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } + p := load(ctxptr, code.Idx) + uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmpty: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldInt: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyInt: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUint: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUint: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32String: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringString: + p := load(ctxptr, code.Idx) + s := ptrToString(p + uintptr(code.Offset)) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, s))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBool: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBool: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBytes: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytes: + p := load(ctxptr, code.Idx) + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) > 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldNumber: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumber: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldNumberString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldMarshalJSON: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + break + } + iface := ptrToInterface(code, p) + if (code.Flags&encoder.NilCheckFlags) != 0 && encoder.IsNilForMarshaler(iface) { + code = code.NextField + break + } + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, iface) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldMarshalJSONPtr: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldMarshalText: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + break + } + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldMarshalTextPtr: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldArray: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArray: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldArrayPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArrayPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldSlice: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlice: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + slice := ptrToSlice(p) + if slice.Len == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldSlicePtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldMap: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMap: + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldMapPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldStruct: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyStruct: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructAnonymousEnd: + code = code.Next + case encoder.OpStructEnd: + b = appendStructEndSkipLast(ctx, code, b) + code = code.Next + case encoder.OpStructEndInt: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyInt: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUint: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUint: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32String: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32Ptr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32PtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64Ptr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendStructEnd(ctx, code, b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64PtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + s := ptrToString(p + uintptr(code.Offset)) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, s))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBool: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBool: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBytes: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytes: + p := load(ctxptr, code.Idx) + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) > 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBytesPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumber: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + code = code.Next + case encoder.OpStructEndOmitEmptyNumber: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpEnd: + goto END + } + } +END: + return b, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color/debug_vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/debug_vm.go new file mode 100644 index 00000000..6a6a33d2 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/debug_vm.go @@ -0,0 +1,34 @@ +package vm_color + +import ( + "fmt" + + "github.com/goccy/go-json/internal/encoder" +) + +func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { + var code *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + code = codeSet.EscapeKeyCode + } else { + code = codeSet.NoescapeKeyCode + } + + defer func() { + if err := recover(); err != nil { + fmt.Println("=============[DEBUG]===============") + fmt.Println("* [TYPE]") + fmt.Println(codeSet.Type) + fmt.Printf("\n") + fmt.Println("* [ALL OPCODE]") + fmt.Println(code.Dump()) + fmt.Printf("\n") + fmt.Println("* [CONTEXT]") + fmt.Printf("%+v\n", ctx) + fmt.Println("===================================") + panic(err) + } + }() + + return Run(ctx, b, codeSet) +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color/hack.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/hack.go new file mode 100644 index 00000000..12ec56c5 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/hack.go @@ -0,0 +1,9 @@ +package vm_color + +import ( + // HACK: compile order + // `vm`, `vm_indent`, `vm_color`, `vm_color_indent` packages uses a lot of memory to compile, + // so forcibly make dependencies and avoid compiling in concurrent. + // dependency order: vm => vm_indent => vm_color => vm_color_indent + _ "github.com/goccy/go-json/internal/encoder/vm_color_indent" +) diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go new file mode 100644 index 00000000..516536d7 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go @@ -0,0 +1,246 @@ +package vm_color + +import ( + "encoding/json" + "fmt" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) + +var ( + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func errUnimplementedOp(op encoder.OpType) error { + return fmt.Errorf("encoder: opcode %s has not been implemented", op) +} + +func load(base uintptr, idx uint32) uintptr { + addr := base + uintptr(idx) + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func store(base uintptr, idx uint32, p uintptr) { + addr := base + uintptr(idx) + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr { + addr := base + uintptr(idx) + p := **(**uintptr)(unsafe.Pointer(&addr)) + for i := uint8(0); i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func ptrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func ptrToNPtr(p uintptr, ptrNum uint8) uintptr { + for i := uint8(0); i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func appendInt(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte { + format := ctx.Option.ColorScheme.Int + b = append(b, format.Header...) + b = encoder.AppendInt(ctx, b, v, code) + return append(b, format.Footer...) +} + +func appendUint(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte { + format := ctx.Option.ColorScheme.Uint + b = append(b, format.Header...) + b = encoder.AppendUint(ctx, b, v, code) + return append(b, format.Footer...) +} + +func appendFloat32(ctx *encoder.RuntimeContext, b []byte, v float32) []byte { + format := ctx.Option.ColorScheme.Float + b = append(b, format.Header...) + b = encoder.AppendFloat32(ctx, b, v) + return append(b, format.Footer...) +} + +func appendFloat64(ctx *encoder.RuntimeContext, b []byte, v float64) []byte { + format := ctx.Option.ColorScheme.Float + b = append(b, format.Header...) + b = encoder.AppendFloat64(ctx, b, v) + return append(b, format.Footer...) +} + +func appendString(ctx *encoder.RuntimeContext, b []byte, v string) []byte { + format := ctx.Option.ColorScheme.String + b = append(b, format.Header...) + b = encoder.AppendString(ctx, b, v) + return append(b, format.Footer...) +} + +func appendByteSlice(ctx *encoder.RuntimeContext, b []byte, src []byte) []byte { + format := ctx.Option.ColorScheme.Binary + b = append(b, format.Header...) + b = encoder.AppendByteSlice(ctx, b, src) + return append(b, format.Footer...) +} + +func appendNumber(ctx *encoder.RuntimeContext, b []byte, n json.Number) ([]byte, error) { + format := ctx.Option.ColorScheme.Int + b = append(b, format.Header...) + bb, err := encoder.AppendNumber(ctx, b, n) + if err != nil { + return nil, err + } + return append(bb, format.Footer...), nil +} + +func appendBool(ctx *encoder.RuntimeContext, b []byte, v bool) []byte { + format := ctx.Option.ColorScheme.Bool + b = append(b, format.Header...) + if v { + b = append(b, "true"...) + } else { + b = append(b, "false"...) + } + return append(b, format.Footer...) +} + +func appendNull(ctx *encoder.RuntimeContext, b []byte) []byte { + format := ctx.Option.ColorScheme.Null + b = append(b, format.Header...) + b = append(b, "null"...) + return append(b, format.Footer...) +} + +func appendComma(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, ',') +} + +func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { + last := len(b) - 1 + b[last] = ':' + return b +} + +func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte { + b = append(b, key[:len(key)-1]...) + b = append(b, ':') + return append(b, value...) +} + +func appendMapEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + b[last] = '}' + b = append(b, ',') + return b +} + +func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalJSON(ctx, code, b, v) +} + +func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + format := ctx.Option.ColorScheme.String + b = append(b, format.Header...) + bb, err := encoder.AppendMarshalText(ctx, code, b, v) + if err != nil { + return nil, err + } + return append(bb, format.Footer...), nil +} + +func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + return append(b, '[') +} + +func appendArrayEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + b[last] = ']' + return append(b, ',') +} + +func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '[', ']', ',') +} + +func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '{', '}', ',') +} + +func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + b[last] = '}' + return append(b, ',') +} + +func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '{') +} + +func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + format := ctx.Option.ColorScheme.ObjectKey + b = append(b, format.Header...) + b = append(b, code.Key[:len(code.Key)-1]...) + b = append(b, format.Footer...) + + return append(b, ':') +} + +func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + return append(b, '}', ',') +} + +func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + if b[last] == ',' { + b[last] = '}' + return appendComma(ctx, b) + } + return appendStructEnd(ctx, code, b) +} + +func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {} +func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {} +func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } +func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go new file mode 100644 index 00000000..0d4c472a --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go @@ -0,0 +1,5041 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package vm_color + +import ( + "math" + "sort" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" +) + +func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { + recursiveLevel := 0 + ptrOffset := uintptr(0) + ctxptr := ctx.Ptr() + var code *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + code = codeSet.EscapeKeyCode + } else { + code = codeSet.NoescapeKeyCode + } + + for { + switch code.Op { + default: + return nil, errUnimplementedOp(code.Op) + case encoder.OpPtr: + p := load(ctxptr, code.Idx) + code = code.Next + store(ctxptr, code.Idx, ptrToPtr(p)) + case encoder.OpIntPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpUintPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpUintString: + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpFloat32Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat32: + b = appendFloat32(ctx, b, ptrToFloat32(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpFloat64Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat64: + v := ptrToFloat64(load(ctxptr, code.Idx)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStringPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpString: + b = appendString(ctx, b, ptrToString(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpBoolPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBool: + b = appendBool(ctx, b, ptrToBool(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpBytesPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBytes: + b = appendByteSlice(ctx, b, ptrToBytes(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpNumberPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpNumber: + bb, err := appendNumber(ctx, b, ptrToNumber(load(ctxptr, code.Idx))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpInterfacePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if p == seen { + return nil, errUnsupportedValue(code, p) + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, p) + iface := (*emptyInterface)(ptrToUnsafePtr(p)) + if iface.ptr == nil { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + if err != nil { + return nil, err + } + + totalLength := uintptr(code.Length) + 3 + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 3 + + var c *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + c = ifaceCodeSet.InterfaceEscapeKeyCode + } else { + c = ifaceCodeSet.InterfaceNoescapeKeyCode + } + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += totalLength * uintptrSize + oldBaseIndent := ctx.BaseIndent + indentDiffFromTop := c.Indent - 1 + ctx.BaseIndent += code.Indent - indentDiffFromTop + + newLen := offsetNum + totalLength + nextTotalLength + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + end := ifaceCodeSet.EndCode + store(ctxptr, c.Idx, uintptr(iface.ptr)) + store(ctxptr, end.Idx, oldOffset) + store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + storeIndent(ctxptr, end, uintptr(oldBaseIndent)) + code = c + recursiveLevel++ + case encoder.OpInterfaceEnd: + recursiveLevel-- + + // restore ctxptr + offset := load(ctxptr, code.Idx) + restoreIndent(ctx, code, ctxptr) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + if (code.Flags&encoder.IsNilableTypeFlags) != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p) + } + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + b = append(b, `""`...) + b = appendComma(ctx, b) + code = code.Next + break + } + if (code.Flags&encoder.IsNilableTypeFlags) != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p) + } + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpSlicePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpSlice: + p := load(ctxptr, code.Idx) + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(slice.Len)) + store(ctxptr, code.Idx, uintptr(slice.Data)) + if slice.Len > 0 { + b = appendArrayHead(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, uintptr(slice.Data)) + } else { + b = appendEmptyArray(ctx, b) + code = code.End.Next + } + case encoder.OpSliceElem: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if idx < length { + b = appendArrayElemIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + data := load(ctxptr, code.Idx) + size := uintptr(code.Size) + code = code.Next + store(ctxptr, code.Idx, data+idx*size) + } else { + b = appendArrayEnd(ctx, code, b) + code = code.End.Next + } + case encoder.OpArrayPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpArray: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + if code.Length > 0 { + b = appendArrayHead(ctx, code, b) + store(ctxptr, code.ElemIdx, 0) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + b = appendEmptyArray(ctx, b) + code = code.End.Next + } + case encoder.OpArrayElem: + idx := load(ctxptr, code.ElemIdx) + idx++ + if idx < uintptr(code.Length) { + b = appendArrayElemIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + p := load(ctxptr, code.Idx) + size := uintptr(code.Size) + code = code.Next + store(ctxptr, code.Idx, p+idx*size) + } else { + b = appendArrayEnd(ctx, code, b) + code = code.End.Next + } + case encoder.OpMapPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpMap: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + uptr := ptrToUnsafePtr(p) + mlen := maplen(uptr) + if mlen <= 0 { + b = appendEmptyObject(ctx, b) + code = code.End.Next + break + } + b = appendStructHead(ctx, b) + iter := mapiterinit(code.Type, uptr) + ctx.KeepRefs = append(ctx.KeepRefs, iter) + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(mlen)) + store(ctxptr, code.MapIter, uintptr(iter)) + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendMapKeyIndent(ctx, code.Next, b) + } else { + mapCtx := encoder.NewMapContext(mlen) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx))) + } + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + if idx < length { + b = appendMapKeyIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + b = appendObjectEnd(ctx, code, b) + code = code.End.Next + } + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendColon(ctx, b) + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + } + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + value := mapitervalue(iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + length := int(load(ctxptr, code.Length)) + ptr := load(ctxptr, code.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + pos := mapCtx.Pos + for i := 0; i < length; i++ { + startKey := pos[i*2] + startValue := pos[i*2+1] + var endValue int + if i+1 < length { + endValue = pos[i*2+2] + } else { + endValue = len(b) + } + mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{ + Key: b[startKey:startValue], + Value: b[startValue:endValue], + }) + } + sort.Sort(mapCtx.Slice) + buf := mapCtx.Buf + for _, item := range mapCtx.Slice.Items { + buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value) + } + buf = appendMapEnd(ctx, code, buf) + b = b[:pos[0]] + b = append(b, buf...) + mapCtx.Buf = buf + encoder.ReleaseMapContext(mapCtx) + code = code.Next + case encoder.OpRecursivePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpRecursive: + ptr := load(ctxptr, code.Idx) + if ptr != 0 { + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if ptr == seen { + return nil, errUnsupportedValue(code, ptr) + } + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, ptr) + c := code.Jmp.Code + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += code.Jmp.CurLen * uintptrSize + oldBaseIndent := ctx.BaseIndent + indentDiffFromTop := c.Indent - 1 + ctx.BaseIndent += code.Indent - indentDiffFromTop + + newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + store(ctxptr, c.Idx, ptr) + store(ctxptr, c.End.Next.Idx, oldOffset) + store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + storeIndent(ctxptr, c.End.Next, uintptr(oldBaseIndent)) + code = c + recursiveLevel++ + case encoder.OpRecursiveEnd: + recursiveLevel-- + + // restore ctxptr + restoreIndent(ctx, code, ctxptr) + offset := load(ctxptr, code.Idx) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpStructPtrHead: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHead: + p := load(ctxptr, code.Idx) + if p == 0 && ((code.Flags&encoder.IndirectFlags) != 0 || code.Next.Op == encoder.OpStructEnd) { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { + b = appendStructKey(ctx, code, b) + } + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 && ((code.Flags&encoder.IndirectFlags) != 0 || code.Next.Op == encoder.OpStructEnd) { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if p == 0 || (ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0) { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadInt: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyInt: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadIntString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadIntString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyIntString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadUint: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUint: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadUintString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUintString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUintString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat32: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat32(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat32String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat32(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat64: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat64String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToString(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadStringString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p+uintptr(code.Offset))))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyStringString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToString(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBool: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBool: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadBoolString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBoolString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBytes: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytes: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadNumber: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumber: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToNumber(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + } + case encoder.OpStructPtrHeadNumberString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumberString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToNumber(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructPtrHeadNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadSlice: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadArray, encoder.OpStructHeadSlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyArray: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyArray: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptySlice: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptySlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + slice := ptrToSlice(p) + if slice.Len == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + } else { + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMap: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if p != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p + uintptr(code.Offset)) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p + uintptr(code.Offset)) + } + if maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + } else { + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + code = code.NextField + } else { + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalJSON { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + iface := ptrToInterface(code, p) + if (code.Flags&encoder.NilCheckFlags) != 0 && encoder.IsNilForMarshaler(iface) { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, iface) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalText { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructField: + if code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } + p := load(ctxptr, code.Idx) + uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmpty: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldInt: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyInt: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUint: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUint: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32String: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringString: + p := load(ctxptr, code.Idx) + s := ptrToString(p + uintptr(code.Offset)) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, s))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBool: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBool: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBytes: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytes: + p := load(ctxptr, code.Idx) + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) > 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldNumber: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumber: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldNumberString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldMarshalJSON: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + break + } + iface := ptrToInterface(code, p) + if (code.Flags&encoder.NilCheckFlags) != 0 && encoder.IsNilForMarshaler(iface) { + code = code.NextField + break + } + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, iface) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldMarshalJSONPtr: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldMarshalText: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + break + } + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldMarshalTextPtr: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldArray: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArray: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldArrayPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArrayPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldSlice: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlice: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + slice := ptrToSlice(p) + if slice.Len == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldSlicePtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldMap: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMap: + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldMapPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldStruct: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyStruct: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructAnonymousEnd: + code = code.Next + case encoder.OpStructEnd: + b = appendStructEndSkipLast(ctx, code, b) + code = code.Next + case encoder.OpStructEndInt: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyInt: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUint: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUint: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32String: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32Ptr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32PtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64Ptr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendStructEnd(ctx, code, b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64PtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + s := ptrToString(p + uintptr(code.Offset)) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, s))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBool: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBool: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBytes: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytes: + p := load(ctxptr, code.Idx) + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) > 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBytesPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumber: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + code = code.Next + case encoder.OpStructEndOmitEmptyNumber: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpEnd: + goto END + } + } +END: + return b, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/debug_vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/debug_vm.go new file mode 100644 index 00000000..a68bbf6b --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/debug_vm.go @@ -0,0 +1,34 @@ +package vm_color_indent + +import ( + "fmt" + + "github.com/goccy/go-json/internal/encoder" +) + +func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { + var code *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + code = codeSet.EscapeKeyCode + } else { + code = codeSet.NoescapeKeyCode + } + + defer func() { + if err := recover(); err != nil { + fmt.Println("=============[DEBUG]===============") + fmt.Println("* [TYPE]") + fmt.Println(codeSet.Type) + fmt.Printf("\n") + fmt.Println("* [ALL OPCODE]") + fmt.Println(code.Dump()) + fmt.Printf("\n") + fmt.Println("* [CONTEXT]") + fmt.Printf("%+v\n", ctx) + fmt.Println("===================================") + panic(err) + } + }() + + return Run(ctx, b, codeSet) +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go new file mode 100644 index 00000000..9f98781b --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go @@ -0,0 +1,267 @@ +package vm_color_indent + +import ( + "encoding/json" + "fmt" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) + +var ( + appendIndent = encoder.AppendIndent + appendStructEnd = encoder.AppendStructEndIndent + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func errUnimplementedOp(op encoder.OpType) error { + return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op) +} + +func load(base uintptr, idx uint32) uintptr { + addr := base + uintptr(idx) + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func store(base uintptr, idx uint32, p uintptr) { + addr := base + uintptr(idx) + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr { + addr := base + uintptr(idx) + p := **(**uintptr)(unsafe.Pointer(&addr)) + for i := uint8(0); i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func ptrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func ptrToNPtr(p uintptr, ptrNum uint8) uintptr { + for i := uint8(0); i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func appendInt(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte { + format := ctx.Option.ColorScheme.Int + b = append(b, format.Header...) + b = encoder.AppendInt(ctx, b, v, code) + return append(b, format.Footer...) +} + +func appendUint(ctx *encoder.RuntimeContext, b []byte, v uint64, code *encoder.Opcode) []byte { + format := ctx.Option.ColorScheme.Uint + b = append(b, format.Header...) + b = encoder.AppendUint(ctx, b, v, code) + return append(b, format.Footer...) +} + +func appendFloat32(ctx *encoder.RuntimeContext, b []byte, v float32) []byte { + format := ctx.Option.ColorScheme.Float + b = append(b, format.Header...) + b = encoder.AppendFloat32(ctx, b, v) + return append(b, format.Footer...) +} + +func appendFloat64(ctx *encoder.RuntimeContext, b []byte, v float64) []byte { + format := ctx.Option.ColorScheme.Float + b = append(b, format.Header...) + b = encoder.AppendFloat64(ctx, b, v) + return append(b, format.Footer...) +} + +func appendString(ctx *encoder.RuntimeContext, b []byte, v string) []byte { + format := ctx.Option.ColorScheme.String + b = append(b, format.Header...) + b = encoder.AppendString(ctx, b, v) + return append(b, format.Footer...) +} + +func appendByteSlice(ctx *encoder.RuntimeContext, b []byte, src []byte) []byte { + format := ctx.Option.ColorScheme.Binary + b = append(b, format.Header...) + b = encoder.AppendByteSlice(ctx, b, src) + return append(b, format.Footer...) +} + +func appendNumber(ctx *encoder.RuntimeContext, b []byte, n json.Number) ([]byte, error) { + format := ctx.Option.ColorScheme.Int + b = append(b, format.Header...) + bb, err := encoder.AppendNumber(ctx, b, n) + if err != nil { + return nil, err + } + return append(bb, format.Footer...), nil +} + +func appendBool(ctx *encoder.RuntimeContext, b []byte, v bool) []byte { + format := ctx.Option.ColorScheme.Bool + b = append(b, format.Header...) + if v { + b = append(b, "true"...) + } else { + b = append(b, "false"...) + } + return append(b, format.Footer...) +} + +func appendNull(ctx *encoder.RuntimeContext, b []byte) []byte { + format := ctx.Option.ColorScheme.Null + b = append(b, format.Header...) + b = append(b, "null"...) + return append(b, format.Footer...) +} + +func appendComma(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, ',', '\n') +} + +func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, ':', ' ') +} + +func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, key...) + b[len(b)-2] = ':' + b[len(b)-1] = ' ' + return append(b, value...) +} + +func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + b = b[:len(b)-2] + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + return append(b, '}', ',', '\n') +} + +func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + b = append(b, '[', '\n') + return appendIndent(ctx, b, code.Indent+1) +} + +func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + b = b[:len(b)-2] + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + return append(b, ']', ',', '\n') +} + +func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '[', ']', ',', '\n') +} + +func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '{', '}', ',', '\n') +} + +func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + b[last] = '\n' + b = appendIndent(ctx, b, code.Indent-1) + return append(b, '}', ',', '\n') +} + +func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalJSONIndent(ctx, code, b, v) +} + +func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + format := ctx.Option.ColorScheme.String + b = append(b, format.Header...) + bb, err := encoder.AppendMarshalTextIndent(ctx, code, b, v) + if err != nil { + return nil, err + } + return append(bb, format.Footer...), nil +} + +func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '{', '\n') +} + +func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + b = appendIndent(ctx, b, code.Indent) + + format := ctx.Option.ColorScheme.ObjectKey + b = append(b, format.Header...) + b = append(b, code.Key[:len(code.Key)-1]...) + b = append(b, format.Footer...) + + return append(b, ':', ' ') +} + +func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + return appendComma(ctx, b) +} + +func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) { + ctx.BaseIndent = uint32(load(ctxptr, code.Length)) +} + +func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) { + store(ctxptr, code.Length, indent) +} + +func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + return appendIndent(ctx, b, code.Indent+1) +} + +func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + return appendIndent(ctx, b, code.Indent) +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go new file mode 100644 index 00000000..de8b858f --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go @@ -0,0 +1,5041 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package vm_color_indent + +import ( + "math" + "sort" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" +) + +func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { + recursiveLevel := 0 + ptrOffset := uintptr(0) + ctxptr := ctx.Ptr() + var code *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + code = codeSet.EscapeKeyCode + } else { + code = codeSet.NoescapeKeyCode + } + + for { + switch code.Op { + default: + return nil, errUnimplementedOp(code.Op) + case encoder.OpPtr: + p := load(ctxptr, code.Idx) + code = code.Next + store(ctxptr, code.Idx, ptrToPtr(p)) + case encoder.OpIntPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpUintPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpUintString: + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpFloat32Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat32: + b = appendFloat32(ctx, b, ptrToFloat32(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpFloat64Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat64: + v := ptrToFloat64(load(ctxptr, code.Idx)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStringPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpString: + b = appendString(ctx, b, ptrToString(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpBoolPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBool: + b = appendBool(ctx, b, ptrToBool(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpBytesPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBytes: + b = appendByteSlice(ctx, b, ptrToBytes(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpNumberPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpNumber: + bb, err := appendNumber(ctx, b, ptrToNumber(load(ctxptr, code.Idx))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpInterfacePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if p == seen { + return nil, errUnsupportedValue(code, p) + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, p) + iface := (*emptyInterface)(ptrToUnsafePtr(p)) + if iface.ptr == nil { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + if err != nil { + return nil, err + } + + totalLength := uintptr(code.Length) + 3 + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 3 + + var c *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + c = ifaceCodeSet.InterfaceEscapeKeyCode + } else { + c = ifaceCodeSet.InterfaceNoescapeKeyCode + } + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += totalLength * uintptrSize + oldBaseIndent := ctx.BaseIndent + indentDiffFromTop := c.Indent - 1 + ctx.BaseIndent += code.Indent - indentDiffFromTop + + newLen := offsetNum + totalLength + nextTotalLength + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + end := ifaceCodeSet.EndCode + store(ctxptr, c.Idx, uintptr(iface.ptr)) + store(ctxptr, end.Idx, oldOffset) + store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + storeIndent(ctxptr, end, uintptr(oldBaseIndent)) + code = c + recursiveLevel++ + case encoder.OpInterfaceEnd: + recursiveLevel-- + + // restore ctxptr + offset := load(ctxptr, code.Idx) + restoreIndent(ctx, code, ctxptr) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + if (code.Flags&encoder.IsNilableTypeFlags) != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p) + } + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + b = append(b, `""`...) + b = appendComma(ctx, b) + code = code.Next + break + } + if (code.Flags&encoder.IsNilableTypeFlags) != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p) + } + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpSlicePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpSlice: + p := load(ctxptr, code.Idx) + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(slice.Len)) + store(ctxptr, code.Idx, uintptr(slice.Data)) + if slice.Len > 0 { + b = appendArrayHead(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, uintptr(slice.Data)) + } else { + b = appendEmptyArray(ctx, b) + code = code.End.Next + } + case encoder.OpSliceElem: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if idx < length { + b = appendArrayElemIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + data := load(ctxptr, code.Idx) + size := uintptr(code.Size) + code = code.Next + store(ctxptr, code.Idx, data+idx*size) + } else { + b = appendArrayEnd(ctx, code, b) + code = code.End.Next + } + case encoder.OpArrayPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpArray: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + if code.Length > 0 { + b = appendArrayHead(ctx, code, b) + store(ctxptr, code.ElemIdx, 0) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + b = appendEmptyArray(ctx, b) + code = code.End.Next + } + case encoder.OpArrayElem: + idx := load(ctxptr, code.ElemIdx) + idx++ + if idx < uintptr(code.Length) { + b = appendArrayElemIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + p := load(ctxptr, code.Idx) + size := uintptr(code.Size) + code = code.Next + store(ctxptr, code.Idx, p+idx*size) + } else { + b = appendArrayEnd(ctx, code, b) + code = code.End.Next + } + case encoder.OpMapPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpMap: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + uptr := ptrToUnsafePtr(p) + mlen := maplen(uptr) + if mlen <= 0 { + b = appendEmptyObject(ctx, b) + code = code.End.Next + break + } + b = appendStructHead(ctx, b) + iter := mapiterinit(code.Type, uptr) + ctx.KeepRefs = append(ctx.KeepRefs, iter) + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(mlen)) + store(ctxptr, code.MapIter, uintptr(iter)) + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendMapKeyIndent(ctx, code.Next, b) + } else { + mapCtx := encoder.NewMapContext(mlen) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx))) + } + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + if idx < length { + b = appendMapKeyIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + b = appendObjectEnd(ctx, code, b) + code = code.End.Next + } + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendColon(ctx, b) + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + } + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + value := mapitervalue(iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + length := int(load(ctxptr, code.Length)) + ptr := load(ctxptr, code.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + pos := mapCtx.Pos + for i := 0; i < length; i++ { + startKey := pos[i*2] + startValue := pos[i*2+1] + var endValue int + if i+1 < length { + endValue = pos[i*2+2] + } else { + endValue = len(b) + } + mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{ + Key: b[startKey:startValue], + Value: b[startValue:endValue], + }) + } + sort.Sort(mapCtx.Slice) + buf := mapCtx.Buf + for _, item := range mapCtx.Slice.Items { + buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value) + } + buf = appendMapEnd(ctx, code, buf) + b = b[:pos[0]] + b = append(b, buf...) + mapCtx.Buf = buf + encoder.ReleaseMapContext(mapCtx) + code = code.Next + case encoder.OpRecursivePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpRecursive: + ptr := load(ctxptr, code.Idx) + if ptr != 0 { + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if ptr == seen { + return nil, errUnsupportedValue(code, ptr) + } + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, ptr) + c := code.Jmp.Code + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += code.Jmp.CurLen * uintptrSize + oldBaseIndent := ctx.BaseIndent + indentDiffFromTop := c.Indent - 1 + ctx.BaseIndent += code.Indent - indentDiffFromTop + + newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + store(ctxptr, c.Idx, ptr) + store(ctxptr, c.End.Next.Idx, oldOffset) + store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + storeIndent(ctxptr, c.End.Next, uintptr(oldBaseIndent)) + code = c + recursiveLevel++ + case encoder.OpRecursiveEnd: + recursiveLevel-- + + // restore ctxptr + restoreIndent(ctx, code, ctxptr) + offset := load(ctxptr, code.Idx) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpStructPtrHead: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHead: + p := load(ctxptr, code.Idx) + if p == 0 && ((code.Flags&encoder.IndirectFlags) != 0 || code.Next.Op == encoder.OpStructEnd) { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { + b = appendStructKey(ctx, code, b) + } + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 && ((code.Flags&encoder.IndirectFlags) != 0 || code.Next.Op == encoder.OpStructEnd) { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if p == 0 || (ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0) { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadInt: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyInt: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadIntString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadIntString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyIntString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadUint: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUint: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadUintString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUintString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUintString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat32: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat32(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat32String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat32(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat64: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat64String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToString(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadStringString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p+uintptr(code.Offset))))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyStringString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToString(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBool: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBool: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadBoolString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBoolString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBytes: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytes: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadNumber: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumber: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToNumber(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + } + case encoder.OpStructPtrHeadNumberString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumberString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToNumber(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructPtrHeadNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadSlice: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadArray, encoder.OpStructHeadSlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyArray: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyArray: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptySlice: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptySlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + slice := ptrToSlice(p) + if slice.Len == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + } else { + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMap: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if p != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p + uintptr(code.Offset)) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p + uintptr(code.Offset)) + } + if maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + } else { + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + code = code.NextField + } else { + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalJSON { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + iface := ptrToInterface(code, p) + if (code.Flags&encoder.NilCheckFlags) != 0 && encoder.IsNilForMarshaler(iface) { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, iface) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalText { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructField: + if code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } + p := load(ctxptr, code.Idx) + uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmpty: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldInt: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyInt: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUint: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUint: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32String: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringString: + p := load(ctxptr, code.Idx) + s := ptrToString(p + uintptr(code.Offset)) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, s))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBool: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBool: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBytes: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytes: + p := load(ctxptr, code.Idx) + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) > 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldNumber: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumber: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldNumberString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldMarshalJSON: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + break + } + iface := ptrToInterface(code, p) + if (code.Flags&encoder.NilCheckFlags) != 0 && encoder.IsNilForMarshaler(iface) { + code = code.NextField + break + } + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, iface) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldMarshalJSONPtr: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldMarshalText: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + break + } + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldMarshalTextPtr: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldArray: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArray: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldArrayPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArrayPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldSlice: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlice: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + slice := ptrToSlice(p) + if slice.Len == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldSlicePtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldMap: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMap: + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldMapPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldStruct: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyStruct: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructAnonymousEnd: + code = code.Next + case encoder.OpStructEnd: + b = appendStructEndSkipLast(ctx, code, b) + code = code.Next + case encoder.OpStructEndInt: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyInt: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUint: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUint: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32String: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32Ptr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32PtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64Ptr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendStructEnd(ctx, code, b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64PtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + s := ptrToString(p + uintptr(code.Offset)) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, s))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBool: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBool: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBytes: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytes: + p := load(ctxptr, code.Idx) + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) > 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBytesPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumber: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + code = code.Next + case encoder.OpStructEndOmitEmptyNumber: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpEnd: + goto END + } + } +END: + return b, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/debug_vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/debug_vm.go new file mode 100644 index 00000000..4cfd17ab --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/debug_vm.go @@ -0,0 +1,34 @@ +package vm_indent + +import ( + "fmt" + + "github.com/goccy/go-json/internal/encoder" +) + +func DebugRun(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { + var code *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + code = codeSet.EscapeKeyCode + } else { + code = codeSet.NoescapeKeyCode + } + + defer func() { + if err := recover(); err != nil { + fmt.Println("=============[DEBUG]===============") + fmt.Println("* [TYPE]") + fmt.Println(codeSet.Type) + fmt.Printf("\n") + fmt.Println("* [ALL OPCODE]") + fmt.Println(code.Dump()) + fmt.Printf("\n") + fmt.Println("* [CONTEXT]") + fmt.Printf("%+v\n", ctx) + fmt.Println("===================================") + panic(err) + } + }() + + return Run(ctx, b, codeSet) +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/hack.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/hack.go new file mode 100644 index 00000000..9e245bfe --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/hack.go @@ -0,0 +1,9 @@ +package vm_indent + +import ( + // HACK: compile order + // `vm`, `vm_indent`, `vm_color`, `vm_color_indent` packages uses a lot of memory to compile, + // so forcibly make dependencies and avoid compiling in concurrent. + // dependency order: vm => vm_indent => vm_color => vm_color_indent + _ "github.com/goccy/go-json/internal/encoder/vm_color" +) diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go new file mode 100644 index 00000000..5f5d8a58 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go @@ -0,0 +1,204 @@ +package vm_indent + +import ( + "encoding/json" + "fmt" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +const uintptrSize = 4 << (^uintptr(0) >> 63) + +var ( + appendInt = encoder.AppendInt + appendUint = encoder.AppendUint + appendFloat32 = encoder.AppendFloat32 + appendFloat64 = encoder.AppendFloat64 + appendString = encoder.AppendString + appendByteSlice = encoder.AppendByteSlice + appendNumber = encoder.AppendNumber + appendStructEnd = encoder.AppendStructEndIndent + appendIndent = encoder.AppendIndent + errUnsupportedValue = encoder.ErrUnsupportedValue + errUnsupportedFloat = encoder.ErrUnsupportedFloat + mapiterinit = encoder.MapIterInit + mapiterkey = encoder.MapIterKey + mapitervalue = encoder.MapIterValue + mapiternext = encoder.MapIterNext + maplen = encoder.MapLen +) + +type emptyInterface struct { + typ *runtime.Type + ptr unsafe.Pointer +} + +func errUnimplementedOp(op encoder.OpType) error { + return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op) +} + +func load(base uintptr, idx uint32) uintptr { + addr := base + uintptr(idx) + return **(**uintptr)(unsafe.Pointer(&addr)) +} + +func store(base uintptr, idx uint32, p uintptr) { + addr := base + uintptr(idx) + **(**uintptr)(unsafe.Pointer(&addr)) = p +} + +func loadNPtr(base uintptr, idx uint32, ptrNum uint8) uintptr { + addr := base + uintptr(idx) + p := **(**uintptr)(unsafe.Pointer(&addr)) + for i := uint8(0); i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) } +func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) } +func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) } +func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) } +func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) } +func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) } +func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) } +func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) } +func ptrToPtr(p uintptr) uintptr { + return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p))) +} +func ptrToNPtr(p uintptr, ptrNum uint8) uintptr { + for i := uint8(0); i < ptrNum; i++ { + if p == 0 { + return 0 + } + p = ptrToPtr(p) + } + return p +} + +func ptrToUnsafePtr(p uintptr) unsafe.Pointer { + return *(*unsafe.Pointer)(unsafe.Pointer(&p)) +} +func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} { + return *(*interface{})(unsafe.Pointer(&emptyInterface{ + typ: code.Type, + ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)), + })) +} + +func appendBool(_ *encoder.RuntimeContext, b []byte, v bool) []byte { + if v { + return append(b, "true"...) + } + return append(b, "false"...) +} + +func appendNull(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, "null"...) +} + +func appendComma(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, ',', '\n') +} + +func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, ':', ' ') +} + +func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte { + b = appendIndent(ctx, b, code.Indent+1) + b = append(b, key...) + b[len(b)-2] = ':' + b[len(b)-1] = ' ' + return append(b, value...) +} + +func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + b = b[:len(b)-2] + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + return append(b, '}', ',', '\n') +} + +func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + b = append(b, '[', '\n') + return appendIndent(ctx, b, code.Indent+1) +} + +func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + b = b[:len(b)-2] + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent) + return append(b, ']', ',', '\n') +} + +func appendEmptyArray(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '[', ']', ',', '\n') +} + +func appendEmptyObject(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '{', '}', ',', '\n') +} + +func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + b[last] = '\n' + b = appendIndent(ctx, b, code.Indent-1) + return append(b, '}', ',', '\n') +} + +func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalJSONIndent(ctx, code, b, v) +} + +func appendMarshalText(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalTextIndent(ctx, code, b, v) +} + +func appendStructHead(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, '{', '\n') +} + +func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + b = appendIndent(ctx, b, code.Indent) + b = append(b, code.Key...) + return append(b, ' ') +} + +func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + last := len(b) - 1 + if b[last-1] == '{' { + b[last] = '}' + } else { + if b[last] == '\n' { + // to remove ',' and '\n' characters + b = b[:len(b)-2] + } + b = append(b, '\n') + b = appendIndent(ctx, b, code.Indent-1) + b = append(b, '}') + } + return appendComma(ctx, b) +} + +func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) { + ctx.BaseIndent = uint32(load(ctxptr, code.Length)) +} + +func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) { + store(ctxptr, code.Length, indent) +} + +func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + return appendIndent(ctx, b, code.Indent+1) +} + +func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { + return appendIndent(ctx, b, code.Indent) +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go new file mode 100644 index 00000000..d10ce75c --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go @@ -0,0 +1,5041 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package vm_indent + +import ( + "math" + "sort" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" +) + +func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) { + recursiveLevel := 0 + ptrOffset := uintptr(0) + ctxptr := ctx.Ptr() + var code *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + code = codeSet.EscapeKeyCode + } else { + code = codeSet.NoescapeKeyCode + } + + for { + switch code.Op { + default: + return nil, errUnimplementedOp(code.Op) + case encoder.OpPtr: + p := load(ctxptr, code.Idx) + code = code.Next + store(ctxptr, code.Idx, ptrToPtr(p)) + case encoder.OpIntPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpUintPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpUintString: + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(load(ctxptr, code.Idx)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpFloat32Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat32: + b = appendFloat32(ctx, b, ptrToFloat32(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpFloat64Ptr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpFloat64: + v := ptrToFloat64(load(ctxptr, code.Idx)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStringPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpString: + b = appendString(ctx, b, ptrToString(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpBoolPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBool: + b = appendBool(ctx, b, ptrToBool(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpBytesPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpBytes: + b = appendByteSlice(ctx, b, ptrToBytes(load(ctxptr, code.Idx))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpNumberPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpNumber: + bb, err := appendNumber(ctx, b, ptrToNumber(load(ctxptr, code.Idx))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpInterfacePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if p == seen { + return nil, errUnsupportedValue(code, p) + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, p) + iface := (*emptyInterface)(ptrToUnsafePtr(p)) + if iface.ptr == nil { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface)) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ))) + if err != nil { + return nil, err + } + + totalLength := uintptr(code.Length) + 3 + nextTotalLength := uintptr(ifaceCodeSet.CodeLength) + 3 + + var c *encoder.Opcode + if (ctx.Option.Flag & encoder.HTMLEscapeOption) != 0 { + c = ifaceCodeSet.InterfaceEscapeKeyCode + } else { + c = ifaceCodeSet.InterfaceNoescapeKeyCode + } + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += totalLength * uintptrSize + oldBaseIndent := ctx.BaseIndent + indentDiffFromTop := c.Indent - 1 + ctx.BaseIndent += code.Indent - indentDiffFromTop + + newLen := offsetNum + totalLength + nextTotalLength + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + end := ifaceCodeSet.EndCode + store(ctxptr, c.Idx, uintptr(iface.ptr)) + store(ctxptr, end.Idx, oldOffset) + store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + storeIndent(ctxptr, end, uintptr(oldBaseIndent)) + code = c + recursiveLevel++ + case encoder.OpInterfaceEnd: + recursiveLevel-- + + // restore ctxptr + offset := load(ctxptr, code.Idx) + restoreIndent(ctx, code, ctxptr) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + if (code.Flags&encoder.IsNilableTypeFlags) != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p) + } + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToPtr(p)) + fallthrough + case encoder.OpMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + b = append(b, `""`...) + b = appendComma(ctx, b) + code = code.Next + break + } + if (code.Flags&encoder.IsNilableTypeFlags) != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p) + } + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpSlicePtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpSlice: + p := load(ctxptr, code.Idx) + slice := ptrToSlice(p) + if p == 0 || slice.Data == nil { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(slice.Len)) + store(ctxptr, code.Idx, uintptr(slice.Data)) + if slice.Len > 0 { + b = appendArrayHead(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, uintptr(slice.Data)) + } else { + b = appendEmptyArray(ctx, b) + code = code.End.Next + } + case encoder.OpSliceElem: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if idx < length { + b = appendArrayElemIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + data := load(ctxptr, code.Idx) + size := uintptr(code.Size) + code = code.Next + store(ctxptr, code.Idx, data+idx*size) + } else { + b = appendArrayEnd(ctx, code, b) + code = code.End.Next + } + case encoder.OpArrayPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpArray: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + if code.Length > 0 { + b = appendArrayHead(ctx, code, b) + store(ctxptr, code.ElemIdx, 0) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + b = appendEmptyArray(ctx, b) + code = code.End.Next + } + case encoder.OpArrayElem: + idx := load(ctxptr, code.ElemIdx) + idx++ + if idx < uintptr(code.Length) { + b = appendArrayElemIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + p := load(ctxptr, code.Idx) + size := uintptr(code.Size) + code = code.Next + store(ctxptr, code.Idx, p+idx*size) + } else { + b = appendArrayEnd(ctx, code, b) + code = code.End.Next + } + case encoder.OpMapPtr: + p := loadNPtr(ctxptr, code.Idx, code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpMap: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.End.Next + break + } + uptr := ptrToUnsafePtr(p) + mlen := maplen(uptr) + if mlen <= 0 { + b = appendEmptyObject(ctx, b) + code = code.End.Next + break + } + b = appendStructHead(ctx, b) + iter := mapiterinit(code.Type, uptr) + ctx.KeepRefs = append(ctx.KeepRefs, iter) + store(ctxptr, code.ElemIdx, 0) + store(ctxptr, code.Length, uintptr(mlen)) + store(ctxptr, code.MapIter, uintptr(iter)) + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendMapKeyIndent(ctx, code.Next, b) + } else { + mapCtx := encoder.NewMapContext(mlen) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx))) + } + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + idx := load(ctxptr, code.ElemIdx) + length := load(ctxptr, code.Length) + idx++ + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + if idx < length { + b = appendMapKeyIndent(ctx, code, b) + store(ctxptr, code.ElemIdx, idx) + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + b = appendObjectEnd(ctx, code, b) + code = code.End.Next + } + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + if idx < length { + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + store(ctxptr, code.ElemIdx, idx) + key := mapiterkey(iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendColon(ctx, b) + } else { + ptr := load(ctxptr, code.End.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + mapCtx.Pos = append(mapCtx.Pos, len(b)) + } + ptr := load(ctxptr, code.MapIter) + iter := ptrToUnsafePtr(ptr) + value := mapitervalue(iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + length := int(load(ctxptr, code.Length)) + ptr := load(ctxptr, code.MapPos) + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr)) + pos := mapCtx.Pos + for i := 0; i < length; i++ { + startKey := pos[i*2] + startValue := pos[i*2+1] + var endValue int + if i+1 < length { + endValue = pos[i*2+2] + } else { + endValue = len(b) + } + mapCtx.Slice.Items = append(mapCtx.Slice.Items, encoder.MapItem{ + Key: b[startKey:startValue], + Value: b[startValue:endValue], + }) + } + sort.Sort(mapCtx.Slice) + buf := mapCtx.Buf + for _, item := range mapCtx.Slice.Items { + buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value) + } + buf = appendMapEnd(ctx, code, buf) + b = b[:pos[0]] + b = append(b, buf...) + mapCtx.Buf = buf + encoder.ReleaseMapContext(mapCtx) + code = code.Next + case encoder.OpRecursivePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + code = code.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpRecursive: + ptr := load(ctxptr, code.Idx) + if ptr != 0 { + if recursiveLevel > encoder.StartDetectingCyclesAfter { + for _, seen := range ctx.SeenPtr { + if ptr == seen { + return nil, errUnsupportedValue(code, ptr) + } + } + } + } + ctx.SeenPtr = append(ctx.SeenPtr, ptr) + c := code.Jmp.Code + curlen := uintptr(len(ctx.Ptrs)) + offsetNum := ptrOffset / uintptrSize + oldOffset := ptrOffset + ptrOffset += code.Jmp.CurLen * uintptrSize + oldBaseIndent := ctx.BaseIndent + indentDiffFromTop := c.Indent - 1 + ctx.BaseIndent += code.Indent - indentDiffFromTop + + newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen + if curlen < newLen { + ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...) + } + ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr + + store(ctxptr, c.Idx, ptr) + store(ctxptr, c.End.Next.Idx, oldOffset) + store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next))) + storeIndent(ctxptr, c.End.Next, uintptr(oldBaseIndent)) + code = c + recursiveLevel++ + case encoder.OpRecursiveEnd: + recursiveLevel-- + + // restore ctxptr + restoreIndent(ctx, code, ctxptr) + offset := load(ctxptr, code.Idx) + ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1] + + codePtr := load(ctxptr, code.ElemIdx) + code = (*encoder.Opcode)(ptrToUnsafePtr(codePtr)) + ctxptr = ctx.Ptr() + offset + ptrOffset = offset + case encoder.OpStructPtrHead: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHead: + p := load(ctxptr, code.Idx) + if p == 0 && ((code.Flags&encoder.IndirectFlags) != 0 || code.Next.Op == encoder.OpStructEnd) { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags&encoder.AnonymousKeyFlags) == 0 && len(code.Key) > 0 { + b = appendStructKey(ctx, code, b) + } + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmpty: + p := load(ctxptr, code.Idx) + if p == 0 && ((code.Flags&encoder.IndirectFlags) != 0 || code.Next.Op == encoder.OpStructEnd) { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if p == 0 || (ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0) { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadInt: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyInt: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyInt: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadIntString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadIntString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyIntString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadUint: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUint: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUint: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadUintString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadUintString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyUintString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat32: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat32(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat32String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat32String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat32(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat64: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat64String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadFloat64String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64String: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToFloat64(p + uintptr(code.Offset)) + if v == 0 { + code = code.NextField + } else { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToString(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadStringString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadStringString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p+uintptr(code.Offset))))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyStringString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToString(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBool: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBool: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBool: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadBoolString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBoolString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + } else { + code = code.NextField + } + case encoder.OpStructPtrHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadBytes: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytes: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyBytes: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadNumber: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumber: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumber: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToNumber(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + } + case encoder.OpStructPtrHeadNumberString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadNumberString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberString: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + v := ptrToNumber(p + uintptr(code.Offset)) + if v == "" { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructPtrHeadNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructPtrHeadArray, encoder.OpStructPtrHeadSlice: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadArray, encoder.OpStructHeadSlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyArray: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyArray: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptySlice: + if (code.Flags & encoder.IndirectFlags) != 0 { + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptySlice: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + slice := ptrToSlice(p) + if slice.Len == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadArrayPtr, encoder.OpStructPtrHeadSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadArrayPtr, encoder.OpStructHeadSlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + } else { + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyArrayPtr, encoder.OpStructPtrHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyArrayPtr, encoder.OpStructHeadOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMap: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if p != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p + uintptr(code.Offset)) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructPtrHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMap: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p != 0 && (code.Flags&encoder.IndirectFlags) != 0 { + p = ptrToPtr(p + uintptr(code.Offset)) + } + if maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.NextField + } else { + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + code = code.NextField + } else { + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructPtrHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalJSON { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + iface := ptrToInterface(code, p) + if (code.Flags&encoder.NilCheckFlags) != 0 && encoder.IsNilForMarshaler(iface) { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, iface) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalText { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + } + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p + uintptr(code.Offset)) + } + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructPtrHeadMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + b = appendStructKey(ctx, code, b) + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructPtrHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + store(ctxptr, code.Idx, ptrToNPtr(p, code.PtrNum)) + fallthrough + case encoder.OpStructHeadOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + if p == 0 && (code.Flags&encoder.IndirectFlags) != 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + } + code = code.End.Next + break + } + if (code.Flags & encoder.IndirectFlags) != 0 { + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if p == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + b = appendComma(ctx, b) + code = code.Next + } + case encoder.OpStructField: + if code.Flags&encoder.AnonymousKeyFlags == 0 { + b = appendStructKey(ctx, code, b) + } + p := load(ctxptr, code.Idx) + uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmpty: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldInt: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyInt: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUint: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUint: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32String: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + b = appendComma(ctx, b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringString: + p := load(ctxptr, code.Idx) + s := ptrToString(p + uintptr(code.Offset)) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, s))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBool: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBool: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBytes: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytes: + p := load(ctxptr, code.Idx) + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) > 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldNumber: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumber: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldNumberString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + b = appendStructKey(ctx, code, b) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendComma(ctx, b) + } + code = code.Next + case encoder.OpStructFieldMarshalJSON: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + break + } + iface := ptrToInterface(code, p) + if (code.Flags&encoder.NilCheckFlags) != 0 && encoder.IsNilForMarshaler(iface) { + code = code.NextField + break + } + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, iface) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldMarshalJSONPtr: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalJSONPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldMarshalText: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + p = ptrToPtr(p) + } + if p == 0 && (code.Flags&encoder.NilCheckFlags) != 0 { + code = code.NextField + break + } + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + code = code.Next + case encoder.OpStructFieldMarshalTextPtr: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendComma(ctx, b) + code = code.Next + case encoder.OpStructFieldOmitEmptyMarshalTextPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendMarshalText(ctx, code, b, ptrToInterface(code, p)) + if err != nil { + return nil, err + } + b = appendComma(ctx, bb) + } + code = code.Next + case encoder.OpStructFieldArray: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArray: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldArrayPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyArrayPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldSlice: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlice: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + slice := ptrToSlice(p) + if slice.Len == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldSlicePtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptySlicePtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldMap: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMap: + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 || maplen(ptrToUnsafePtr(p)) == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructFieldMapPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyMapPtr: + p := load(ctxptr, code.Idx) + p = ptrToPtr(p + uintptr(code.Offset)) + if p != 0 { + p = ptrToNPtr(p, code.PtrNum) + } + if p != 0 { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } else { + code = code.NextField + } + case encoder.OpStructFieldStruct: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + code = code.Next + store(ctxptr, code.Idx, p) + case encoder.OpStructFieldOmitEmptyStruct: + p := load(ctxptr, code.Idx) + p += uintptr(code.Offset) + if ptrToPtr(p) == 0 && (code.Flags&encoder.IsNextOpPtrTypeFlags) != 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + code = code.Next + store(ctxptr, code.Idx, p) + } + case encoder.OpStructAnonymousEnd: + code = code.Next + case encoder.OpStructEnd: + b = appendStructEndSkipLast(ctx, code, b) + code = code.Next + case encoder.OpStructEndInt: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyInt: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, u64, code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, u64, code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendInt(ctx, b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, ptrToUint64(p), code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndIntPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyIntPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUint: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUint: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, u64, code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p+uintptr(code.Offset)), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintString: + p := load(ctxptr, code.Idx) + u64 := ptrToUint64(p + uintptr(code.Offset)) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, u64, code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendUint(ctx, b, ptrToUint64(p), code) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, ptrToUint64(p), code) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndUintPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyUintPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, ptrToUint64(p), code) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32String: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32String: + p := load(ctxptr, code.Idx) + v := ptrToFloat32(p + uintptr(code.Offset)) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32Ptr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendFloat32(ctx, b, ptrToFloat32(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat32PtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat32PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat32(ctx, b, ptrToFloat32(p)) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64String: + p := load(ctxptr, code.Idx) + v := ptrToFloat64(p + uintptr(code.Offset)) + if v != 0 { + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64Ptr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + b = appendStructEnd(ctx, code, b) + code = code.Next + break + } + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64Ptr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndFloat64PtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = appendFloat64(ctx, b, v) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyFloat64PtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + v := ptrToFloat64(p) + if math.IsInf(v, 0) || math.IsNaN(v) { + return nil, errUnsupportedFloat(v) + } + b = append(b, '"') + b = appendFloat64(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + s := ptrToString(p + uintptr(code.Offset)) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, s))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringString: + p := load(ctxptr, code.Idx) + v := ptrToString(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, v))) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, ptrToString(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, ptrToString(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndStringPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyStringPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendString(ctx, b, string(appendString(ctx, []byte{}, ptrToString(p)))) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBool: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBool: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p+uintptr(code.Offset))) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolString: + p := load(ctxptr, code.Idx) + v := ptrToBool(p + uintptr(code.Offset)) + if v { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, v) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendBool(ctx, b, ptrToBool(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendBool(ctx, b, ptrToBool(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBoolPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBoolPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendBool(ctx, b, ptrToBool(p)) + b = append(b, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBytes: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p+uintptr(code.Offset))) + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytes: + p := load(ctxptr, code.Idx) + v := ptrToBytes(p + uintptr(code.Offset)) + if len(v) > 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, v) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndBytesPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = appendByteSlice(ctx, b, ptrToBytes(p)) + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyBytesPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = appendByteSlice(ctx, b, ptrToBytes(p)) + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumber: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + code = code.Next + case encoder.OpStructEndOmitEmptyNumber: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberString: + p := load(ctxptr, code.Idx) + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p+uintptr(code.Offset))) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberString: + p := load(ctxptr, code.Idx) + v := ptrToNumber(p + uintptr(code.Offset)) + if v != "" { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, v) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberPtr: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = bb + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtr: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = appendStructEnd(ctx, code, bb) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpStructEndNumberPtrString: + b = appendStructKey(ctx, code, b) + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p == 0 { + b = appendNull(ctx, b) + } else { + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + } + b = appendStructEnd(ctx, code, b) + code = code.Next + case encoder.OpStructEndOmitEmptyNumberPtrString: + p := load(ctxptr, code.Idx) + p = ptrToNPtr(p+uintptr(code.Offset), code.PtrNum) + if p != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + bb, err := appendNumber(ctx, b, ptrToNumber(p)) + if err != nil { + return nil, err + } + b = append(bb, '"') + b = appendStructEnd(ctx, code, b) + } else { + b = appendStructEndSkipLast(ctx, code, b) + } + code = code.Next + case encoder.OpEnd: + goto END + } + } +END: + return b, nil +} diff --git a/vendor/github.com/goccy/go-json/internal/errors/error.go b/vendor/github.com/goccy/go-json/internal/errors/error.go new file mode 100644 index 00000000..329e2f12 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/errors/error.go @@ -0,0 +1,157 @@ +package errors + +import ( + "fmt" + "reflect" + "strconv" +) + +type InvalidUTF8Error struct { + S string // the whole string value that caused the error +} + +func (e *InvalidUTF8Error) Error() string { + return fmt.Sprintf("json: invalid UTF-8 in string: %s", strconv.Quote(e.S)) +} + +type InvalidUnmarshalError struct { + Type reflect.Type +} + +func (e *InvalidUnmarshalError) Error() string { + if e.Type == nil { + return "json: Unmarshal(nil)" + } + + if e.Type.Kind() != reflect.Ptr { + return fmt.Sprintf("json: Unmarshal(non-pointer %s)", e.Type) + } + return fmt.Sprintf("json: Unmarshal(nil %s)", e.Type) +} + +// A MarshalerError represents an error from calling a MarshalJSON or MarshalText method. +type MarshalerError struct { + Type reflect.Type + Err error + sourceFunc string +} + +func (e *MarshalerError) Error() string { + srcFunc := e.sourceFunc + if srcFunc == "" { + srcFunc = "MarshalJSON" + } + return fmt.Sprintf("json: error calling %s for type %s: %s", srcFunc, e.Type, e.Err.Error()) +} + +// Unwrap returns the underlying error. +func (e *MarshalerError) Unwrap() error { return e.Err } + +// A SyntaxError is a description of a JSON syntax error. +type SyntaxError struct { + msg string // description of error + Offset int64 // error occurred after reading Offset bytes +} + +func (e *SyntaxError) Error() string { return e.msg } + +// An UnmarshalFieldError describes a JSON object key that +// led to an unexported (and therefore unwritable) struct field. +// +// Deprecated: No longer used; kept for compatibility. +type UnmarshalFieldError struct { + Key string + Type reflect.Type + Field reflect.StructField +} + +func (e *UnmarshalFieldError) Error() string { + return fmt.Sprintf("json: cannot unmarshal object key %s into unexported field %s of type %s", + strconv.Quote(e.Key), e.Field.Name, e.Type.String(), + ) +} + +// An UnmarshalTypeError describes a JSON value that was +// not appropriate for a value of a specific Go type. +type UnmarshalTypeError struct { + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes + Struct string // name of the struct type containing the field + Field string // the full path from root node to the field +} + +func (e *UnmarshalTypeError) Error() string { + if e.Struct != "" || e.Field != "" { + return fmt.Sprintf("json: cannot unmarshal %s into Go struct field %s.%s of type %s", + e.Value, e.Struct, e.Field, e.Type, + ) + } + return fmt.Sprintf("json: cannot unmarshal %s into Go value of type %s", e.Value, e.Type) +} + +// An UnsupportedTypeError is returned by Marshal when attempting +// to encode an unsupported value type. +type UnsupportedTypeError struct { + Type reflect.Type +} + +func (e *UnsupportedTypeError) Error() string { + return fmt.Sprintf("json: unsupported type: %s", e.Type) +} + +type UnsupportedValueError struct { + Value reflect.Value + Str string +} + +func (e *UnsupportedValueError) Error() string { + return fmt.Sprintf("json: unsupported value: %s", e.Str) +} + +func ErrSyntax(msg string, offset int64) *SyntaxError { + return &SyntaxError{msg: msg, Offset: offset} +} + +func ErrMarshaler(typ reflect.Type, err error, msg string) *MarshalerError { + return &MarshalerError{ + Type: typ, + Err: err, + sourceFunc: msg, + } +} + +func ErrExceededMaxDepth(c byte, cursor int64) *SyntaxError { + return &SyntaxError{ + msg: fmt.Sprintf(`invalid character "%c" exceeded max depth`, c), + Offset: cursor, + } +} + +func ErrNotAtBeginningOfValue(cursor int64) *SyntaxError { + return &SyntaxError{msg: "not at beginning of value", Offset: cursor} +} + +func ErrUnexpectedEndOfJSON(msg string, cursor int64) *SyntaxError { + return &SyntaxError{ + msg: fmt.Sprintf("json: %s unexpected end of JSON input", msg), + Offset: cursor, + } +} + +func ErrExpected(msg string, cursor int64) *SyntaxError { + return &SyntaxError{msg: fmt.Sprintf("expected %s", msg), Offset: cursor} +} + +func ErrInvalidCharacter(c byte, context string, cursor int64) *SyntaxError { + if c == 0 { + return &SyntaxError{ + msg: fmt.Sprintf("json: invalid character as %s", context), + Offset: cursor, + } + } + return &SyntaxError{ + msg: fmt.Sprintf("json: invalid character %c as %s", c, context), + Offset: cursor, + } +} diff --git a/vendor/github.com/goccy/go-json/internal/runtime/rtype.go b/vendor/github.com/goccy/go-json/internal/runtime/rtype.go new file mode 100644 index 00000000..4db10deb --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/runtime/rtype.go @@ -0,0 +1,263 @@ +package runtime + +import ( + "reflect" + "unsafe" +) + +// Type representing reflect.rtype for noescape trick +type Type struct{} + +//go:linkname rtype_Align reflect.(*rtype).Align +//go:noescape +func rtype_Align(*Type) int + +func (t *Type) Align() int { + return rtype_Align(t) +} + +//go:linkname rtype_FieldAlign reflect.(*rtype).FieldAlign +//go:noescape +func rtype_FieldAlign(*Type) int + +func (t *Type) FieldAlign() int { + return rtype_FieldAlign(t) +} + +//go:linkname rtype_Method reflect.(*rtype).Method +//go:noescape +func rtype_Method(*Type, int) reflect.Method + +func (t *Type) Method(a0 int) reflect.Method { + return rtype_Method(t, a0) +} + +//go:linkname rtype_MethodByName reflect.(*rtype).MethodByName +//go:noescape +func rtype_MethodByName(*Type, string) (reflect.Method, bool) + +func (t *Type) MethodByName(a0 string) (reflect.Method, bool) { + return rtype_MethodByName(t, a0) +} + +//go:linkname rtype_NumMethod reflect.(*rtype).NumMethod +//go:noescape +func rtype_NumMethod(*Type) int + +func (t *Type) NumMethod() int { + return rtype_NumMethod(t) +} + +//go:linkname rtype_Name reflect.(*rtype).Name +//go:noescape +func rtype_Name(*Type) string + +func (t *Type) Name() string { + return rtype_Name(t) +} + +//go:linkname rtype_PkgPath reflect.(*rtype).PkgPath +//go:noescape +func rtype_PkgPath(*Type) string + +func (t *Type) PkgPath() string { + return rtype_PkgPath(t) +} + +//go:linkname rtype_Size reflect.(*rtype).Size +//go:noescape +func rtype_Size(*Type) uintptr + +func (t *Type) Size() uintptr { + return rtype_Size(t) +} + +//go:linkname rtype_String reflect.(*rtype).String +//go:noescape +func rtype_String(*Type) string + +func (t *Type) String() string { + return rtype_String(t) +} + +//go:linkname rtype_Kind reflect.(*rtype).Kind +//go:noescape +func rtype_Kind(*Type) reflect.Kind + +func (t *Type) Kind() reflect.Kind { + return rtype_Kind(t) +} + +//go:linkname rtype_Implements reflect.(*rtype).Implements +//go:noescape +func rtype_Implements(*Type, reflect.Type) bool + +func (t *Type) Implements(u reflect.Type) bool { + return rtype_Implements(t, u) +} + +//go:linkname rtype_AssignableTo reflect.(*rtype).AssignableTo +//go:noescape +func rtype_AssignableTo(*Type, reflect.Type) bool + +func (t *Type) AssignableTo(u reflect.Type) bool { + return rtype_AssignableTo(t, u) +} + +//go:linkname rtype_ConvertibleTo reflect.(*rtype).ConvertibleTo +//go:noescape +func rtype_ConvertibleTo(*Type, reflect.Type) bool + +func (t *Type) ConvertibleTo(u reflect.Type) bool { + return rtype_ConvertibleTo(t, u) +} + +//go:linkname rtype_Comparable reflect.(*rtype).Comparable +//go:noescape +func rtype_Comparable(*Type) bool + +func (t *Type) Comparable() bool { + return rtype_Comparable(t) +} + +//go:linkname rtype_Bits reflect.(*rtype).Bits +//go:noescape +func rtype_Bits(*Type) int + +func (t *Type) Bits() int { + return rtype_Bits(t) +} + +//go:linkname rtype_ChanDir reflect.(*rtype).ChanDir +//go:noescape +func rtype_ChanDir(*Type) reflect.ChanDir + +func (t *Type) ChanDir() reflect.ChanDir { + return rtype_ChanDir(t) +} + +//go:linkname rtype_IsVariadic reflect.(*rtype).IsVariadic +//go:noescape +func rtype_IsVariadic(*Type) bool + +func (t *Type) IsVariadic() bool { + return rtype_IsVariadic(t) +} + +//go:linkname rtype_Elem reflect.(*rtype).Elem +//go:noescape +func rtype_Elem(*Type) reflect.Type + +func (t *Type) Elem() *Type { + return Type2RType(rtype_Elem(t)) +} + +//go:linkname rtype_Field reflect.(*rtype).Field +//go:noescape +func rtype_Field(*Type, int) reflect.StructField + +func (t *Type) Field(i int) reflect.StructField { + return rtype_Field(t, i) +} + +//go:linkname rtype_FieldByIndex reflect.(*rtype).FieldByIndex +//go:noescape +func rtype_FieldByIndex(*Type, []int) reflect.StructField + +func (t *Type) FieldByIndex(index []int) reflect.StructField { + return rtype_FieldByIndex(t, index) +} + +//go:linkname rtype_FieldByName reflect.(*rtype).FieldByName +//go:noescape +func rtype_FieldByName(*Type, string) (reflect.StructField, bool) + +func (t *Type) FieldByName(name string) (reflect.StructField, bool) { + return rtype_FieldByName(t, name) +} + +//go:linkname rtype_FieldByNameFunc reflect.(*rtype).FieldByNameFunc +//go:noescape +func rtype_FieldByNameFunc(*Type, func(string) bool) (reflect.StructField, bool) + +func (t *Type) FieldByNameFunc(match func(string) bool) (reflect.StructField, bool) { + return rtype_FieldByNameFunc(t, match) +} + +//go:linkname rtype_In reflect.(*rtype).In +//go:noescape +func rtype_In(*Type, int) reflect.Type + +func (t *Type) In(i int) reflect.Type { + return rtype_In(t, i) +} + +//go:linkname rtype_Key reflect.(*rtype).Key +//go:noescape +func rtype_Key(*Type) reflect.Type + +func (t *Type) Key() *Type { + return Type2RType(rtype_Key(t)) +} + +//go:linkname rtype_Len reflect.(*rtype).Len +//go:noescape +func rtype_Len(*Type) int + +func (t *Type) Len() int { + return rtype_Len(t) +} + +//go:linkname rtype_NumField reflect.(*rtype).NumField +//go:noescape +func rtype_NumField(*Type) int + +func (t *Type) NumField() int { + return rtype_NumField(t) +} + +//go:linkname rtype_NumIn reflect.(*rtype).NumIn +//go:noescape +func rtype_NumIn(*Type) int + +func (t *Type) NumIn() int { + return rtype_NumIn(t) +} + +//go:linkname rtype_NumOut reflect.(*rtype).NumOut +//go:noescape +func rtype_NumOut(*Type) int + +func (t *Type) NumOut() int { + return rtype_NumOut(t) +} + +//go:linkname rtype_Out reflect.(*rtype).Out +//go:noescape +func rtype_Out(*Type, int) reflect.Type + +//go:linkname PtrTo reflect.(*rtype).ptrTo +//go:noescape +func PtrTo(*Type) *Type + +func (t *Type) Out(i int) reflect.Type { + return rtype_Out(t, i) +} + +//go:linkname IfaceIndir reflect.ifaceIndir +//go:noescape +func IfaceIndir(*Type) bool + +//go:linkname RType2Type reflect.toType +//go:noescape +func RType2Type(t *Type) reflect.Type + +//go:nolint structcheck +type emptyInterface struct { + _ *Type + ptr unsafe.Pointer +} + +func Type2RType(t reflect.Type) *Type { + return (*Type)(((*emptyInterface)(unsafe.Pointer(&t))).ptr) +} diff --git a/vendor/github.com/goccy/go-json/internal/runtime/struct_field.go b/vendor/github.com/goccy/go-json/internal/runtime/struct_field.go new file mode 100644 index 00000000..c321180a --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/runtime/struct_field.go @@ -0,0 +1,87 @@ +package runtime + +import ( + "reflect" + "strings" + "unicode" +) + +func getTag(field reflect.StructField) string { + return field.Tag.Get("json") +} + +func IsIgnoredStructField(field reflect.StructField) bool { + if field.PkgPath != "" { + if field.Anonymous { + if !(field.Type.Kind() == reflect.Ptr && field.Type.Elem().Kind() == reflect.Struct) && field.Type.Kind() != reflect.Struct { + return true + } + } else { + // private field + return true + } + } + tag := getTag(field) + return tag == "-" +} + +type StructTag struct { + Key string + IsTaggedKey bool + IsOmitEmpty bool + IsString bool + Field reflect.StructField +} + +type StructTags []*StructTag + +func (t StructTags) ExistsKey(key string) bool { + for _, tt := range t { + if tt.Key == key { + return true + } + } + return false +} + +func isValidTag(s string) bool { + if s == "" { + return false + } + for _, c := range s { + switch { + case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c): + // Backslash and quote chars are reserved, but + // otherwise any punctuation chars are allowed + // in a tag name. + case !unicode.IsLetter(c) && !unicode.IsDigit(c): + return false + } + } + return true +} + +func StructTagFromField(field reflect.StructField) *StructTag { + keyName := field.Name + tag := getTag(field) + st := &StructTag{Field: field} + opts := strings.Split(tag, ",") + if len(opts) > 0 { + if opts[0] != "" && isValidTag(opts[0]) { + keyName = opts[0] + st.IsTaggedKey = true + } + } + st.Key = keyName + if len(opts) > 1 { + for _, opt := range opts[1:] { + switch opt { + case "omitempty": + st.IsOmitEmpty = true + case "string": + st.IsString = true + } + } + } + return st +} diff --git a/vendor/github.com/goccy/go-json/internal/runtime/type.go b/vendor/github.com/goccy/go-json/internal/runtime/type.go new file mode 100644 index 00000000..0167cd2c --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/runtime/type.go @@ -0,0 +1,100 @@ +package runtime + +import ( + "reflect" + "unsafe" +) + +type SliceHeader struct { + Data unsafe.Pointer + Len int + Cap int +} + +const ( + maxAcceptableTypeAddrRange = 1024 * 1024 * 2 // 2 Mib +) + +type TypeAddr struct { + BaseTypeAddr uintptr + MaxTypeAddr uintptr + AddrRange uintptr + AddrShift uintptr +} + +var ( + typeAddr *TypeAddr + alreadyAnalyzed bool +) + +//go:linkname typelinks reflect.typelinks +func typelinks() ([]unsafe.Pointer, [][]int32) + +//go:linkname rtypeOff reflect.rtypeOff +func rtypeOff(unsafe.Pointer, int32) unsafe.Pointer + +func AnalyzeTypeAddr() *TypeAddr { + defer func() { + alreadyAnalyzed = true + }() + if alreadyAnalyzed { + return typeAddr + } + sections, offsets := typelinks() + if len(sections) != 1 { + return nil + } + if len(offsets) != 1 { + return nil + } + section := sections[0] + offset := offsets[0] + var ( + min uintptr = uintptr(^uint(0)) + max uintptr = 0 + isAligned64 = true + isAligned32 = true + ) + for i := 0; i < len(offset); i++ { + typ := (*Type)(rtypeOff(section, offset[i])) + addr := uintptr(unsafe.Pointer(typ)) + if min > addr { + min = addr + } + if max < addr { + max = addr + } + if typ.Kind() == reflect.Ptr { + addr = uintptr(unsafe.Pointer(typ.Elem())) + if min > addr { + min = addr + } + if max < addr { + max = addr + } + } + isAligned64 = isAligned64 && (addr-min)&63 == 0 + isAligned32 = isAligned32 && (addr-min)&31 == 0 + } + addrRange := max - min + if addrRange == 0 { + return nil + } + var addrShift uintptr + if isAligned64 { + addrShift = 6 + } else if isAligned32 { + addrShift = 5 + } + cacheSize := addrRange >> addrShift + if cacheSize > maxAcceptableTypeAddrRange { + return nil + } + typeAddr = &TypeAddr{ + BaseTypeAddr: min, + MaxTypeAddr: max, + AddrRange: addrRange, + AddrShift: addrShift, + } + return typeAddr +} diff --git a/vendor/github.com/goccy/go-json/json.go b/vendor/github.com/goccy/go-json/json.go new file mode 100644 index 00000000..5c9448d8 --- /dev/null +++ b/vendor/github.com/goccy/go-json/json.go @@ -0,0 +1,366 @@ +package json + +import ( + "bytes" + "context" + "encoding/json" + + "github.com/goccy/go-json/internal/encoder" +) + +// Marshaler is the interface implemented by types that +// can marshal themselves into valid JSON. +type Marshaler interface { + MarshalJSON() ([]byte, error) +} + +// MarshalerContext is the interface implemented by types that +// can marshal themselves into valid JSON with context.Context. +type MarshalerContext interface { + MarshalJSON(context.Context) ([]byte, error) +} + +// Unmarshaler is the interface implemented by types +// that can unmarshal a JSON description of themselves. +// The input can be assumed to be a valid encoding of +// a JSON value. UnmarshalJSON must copy the JSON data +// if it wishes to retain the data after returning. +// +// By convention, to approximate the behavior of Unmarshal itself, +// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. +type Unmarshaler interface { + UnmarshalJSON([]byte) error +} + +// UnmarshalerContext is the interface implemented by types +// that can unmarshal with context.Context a JSON description of themselves. +type UnmarshalerContext interface { + UnmarshalJSON(context.Context, []byte) error +} + +// Marshal returns the JSON encoding of v. +// +// Marshal traverses the value v recursively. +// If an encountered value implements the Marshaler interface +// and is not a nil pointer, Marshal calls its MarshalJSON method +// to produce JSON. If no MarshalJSON method is present but the +// value implements encoding.TextMarshaler instead, Marshal calls +// its MarshalText method and encodes the result as a JSON string. +// The nil pointer exception is not strictly necessary +// but mimics a similar, necessary exception in the behavior of +// UnmarshalJSON. +// +// Otherwise, Marshal uses the following type-dependent default encodings: +// +// Boolean values encode as JSON booleans. +// +// Floating point, integer, and Number values encode as JSON numbers. +// +// String values encode as JSON strings coerced to valid UTF-8, +// replacing invalid bytes with the Unicode replacement rune. +// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e" +// to keep some browsers from misinterpreting JSON output as HTML. +// Ampersand "&" is also escaped to "\u0026" for the same reason. +// This escaping can be disabled using an Encoder that had SetEscapeHTML(false) +// called on it. +// +// Array and slice values encode as JSON arrays, except that +// []byte encodes as a base64-encoded string, and a nil slice +// encodes as the null JSON value. +// +// Struct values encode as JSON objects. +// Each exported struct field becomes a member of the object, using the +// field name as the object key, unless the field is omitted for one of the +// reasons given below. +// +// The encoding of each struct field can be customized by the format string +// stored under the "json" key in the struct field's tag. +// The format string gives the name of the field, possibly followed by a +// comma-separated list of options. The name may be empty in order to +// specify options without overriding the default field name. +// +// The "omitempty" option specifies that the field should be omitted +// from the encoding if the field has an empty value, defined as +// false, 0, a nil pointer, a nil interface value, and any empty array, +// slice, map, or string. +// +// As a special case, if the field tag is "-", the field is always omitted. +// Note that a field with name "-" can still be generated using the tag "-,". +// +// Examples of struct field tags and their meanings: +// +// // Field appears in JSON as key "myName". +// Field int `json:"myName"` +// +// // Field appears in JSON as key "myName" and +// // the field is omitted from the object if its value is empty, +// // as defined above. +// Field int `json:"myName,omitempty"` +// +// // Field appears in JSON as key "Field" (the default), but +// // the field is skipped if empty. +// // Note the leading comma. +// Field int `json:",omitempty"` +// +// // Field is ignored by this package. +// Field int `json:"-"` +// +// // Field appears in JSON as key "-". +// Field int `json:"-,"` +// +// The "string" option signals that a field is stored as JSON inside a +// JSON-encoded string. It applies only to fields of string, floating point, +// integer, or boolean types. This extra level of encoding is sometimes used +// when communicating with JavaScript programs: +// +// Int64String int64 `json:",string"` +// +// The key name will be used if it's a non-empty string consisting of +// only Unicode letters, digits, and ASCII punctuation except quotation +// marks, backslash, and comma. +// +// Anonymous struct fields are usually marshaled as if their inner exported fields +// were fields in the outer struct, subject to the usual Go visibility rules amended +// as described in the next paragraph. +// An anonymous struct field with a name given in its JSON tag is treated as +// having that name, rather than being anonymous. +// An anonymous struct field of interface type is treated the same as having +// that type as its name, rather than being anonymous. +// +// The Go visibility rules for struct fields are amended for JSON when +// deciding which field to marshal or unmarshal. If there are +// multiple fields at the same level, and that level is the least +// nested (and would therefore be the nesting level selected by the +// usual Go rules), the following extra rules apply: +// +// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered, +// even if there are multiple untagged fields that would otherwise conflict. +// +// 2) If there is exactly one field (tagged or not according to the first rule), that is selected. +// +// 3) Otherwise there are multiple fields, and all are ignored; no error occurs. +// +// Handling of anonymous struct fields is new in Go 1.1. +// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of +// an anonymous struct field in both current and earlier versions, give the field +// a JSON tag of "-". +// +// Map values encode as JSON objects. The map's key type must either be a +// string, an integer type, or implement encoding.TextMarshaler. The map keys +// are sorted and used as JSON object keys by applying the following rules, +// subject to the UTF-8 coercion described for string values above: +// - string keys are used directly +// - encoding.TextMarshalers are marshaled +// - integer keys are converted to strings +// +// Pointer values encode as the value pointed to. +// A nil pointer encodes as the null JSON value. +// +// Interface values encode as the value contained in the interface. +// A nil interface value encodes as the null JSON value. +// +// Channel, complex, and function values cannot be encoded in JSON. +// Attempting to encode such a value causes Marshal to return +// an UnsupportedTypeError. +// +// JSON cannot represent cyclic data structures and Marshal does not +// handle them. Passing cyclic structures to Marshal will result in +// an infinite recursion. +// +func Marshal(v interface{}) ([]byte, error) { + return MarshalWithOption(v) +} + +// MarshalNoEscape returns the JSON encoding of v and doesn't escape v. +func MarshalNoEscape(v interface{}) ([]byte, error) { + return marshalNoEscape(v) +} + +// MarshalContext returns the JSON encoding of v with context.Context and EncodeOption. +func MarshalContext(ctx context.Context, v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) { + return marshalContext(ctx, v, optFuncs...) +} + +// MarshalWithOption returns the JSON encoding of v with EncodeOption. +func MarshalWithOption(v interface{}, optFuncs ...EncodeOptionFunc) ([]byte, error) { + return marshal(v, optFuncs...) +} + +// MarshalIndent is like Marshal but applies Indent to format the output. +// Each JSON element in the output will begin on a new line beginning with prefix +// followed by one or more copies of indent according to the indentation nesting. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + return MarshalIndentWithOption(v, prefix, indent) +} + +// MarshalIndentWithOption is like Marshal but applies Indent to format the output with EncodeOption. +func MarshalIndentWithOption(v interface{}, prefix, indent string, optFuncs ...EncodeOptionFunc) ([]byte, error) { + return marshalIndent(v, prefix, indent, optFuncs...) +} + +// Unmarshal parses the JSON-encoded data and stores the result +// in the value pointed to by v. If v is nil or not a pointer, +// Unmarshal returns an InvalidUnmarshalError. +// +// Unmarshal uses the inverse of the encodings that +// Marshal uses, allocating maps, slices, and pointers as necessary, +// with the following additional rules: +// +// To unmarshal JSON into a pointer, Unmarshal first handles the case of +// the JSON being the JSON literal null. In that case, Unmarshal sets +// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into +// the value pointed at by the pointer. If the pointer is nil, Unmarshal +// allocates a new value for it to point to. +// +// To unmarshal JSON into a value implementing the Unmarshaler interface, +// Unmarshal calls that value's UnmarshalJSON method, including +// when the input is a JSON null. +// Otherwise, if the value implements encoding.TextUnmarshaler +// and the input is a JSON quoted string, Unmarshal calls that value's +// UnmarshalText method with the unquoted form of the string. +// +// To unmarshal JSON into a struct, Unmarshal matches incoming object +// keys to the keys used by Marshal (either the struct field name or its tag), +// preferring an exact match but also accepting a case-insensitive match. By +// default, object keys which don't have a corresponding struct field are +// ignored (see Decoder.DisallowUnknownFields for an alternative). +// +// To unmarshal JSON into an interface value, +// Unmarshal stores one of these in the interface value: +// +// bool, for JSON booleans +// float64, for JSON numbers +// string, for JSON strings +// []interface{}, for JSON arrays +// map[string]interface{}, for JSON objects +// nil for JSON null +// +// To unmarshal a JSON array into a slice, Unmarshal resets the slice length +// to zero and then appends each element to the slice. +// As a special case, to unmarshal an empty JSON array into a slice, +// Unmarshal replaces the slice with a new empty slice. +// +// To unmarshal a JSON array into a Go array, Unmarshal decodes +// JSON array elements into corresponding Go array elements. +// If the Go array is smaller than the JSON array, +// the additional JSON array elements are discarded. +// If the JSON array is smaller than the Go array, +// the additional Go array elements are set to zero values. +// +// To unmarshal a JSON object into a map, Unmarshal first establishes a map to +// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal +// reuses the existing map, keeping existing entries. Unmarshal then stores +// key-value pairs from the JSON object into the map. The map's key type must +// either be any string type, an integer, implement json.Unmarshaler, or +// implement encoding.TextUnmarshaler. +// +// If a JSON value is not appropriate for a given target type, +// or if a JSON number overflows the target type, Unmarshal +// skips that field and completes the unmarshaling as best it can. +// If no more serious errors are encountered, Unmarshal returns +// an UnmarshalTypeError describing the earliest such error. In any +// case, it's not guaranteed that all the remaining fields following +// the problematic one will be unmarshaled into the target object. +// +// The JSON null value unmarshals into an interface, map, pointer, or slice +// by setting that Go value to nil. Because null is often used in JSON to mean +// ``not present,'' unmarshaling a JSON null into any other Go type has no effect +// on the value and produces no error. +// +// When unmarshaling quoted strings, invalid UTF-8 or +// invalid UTF-16 surrogate pairs are not treated as an error. +// Instead, they are replaced by the Unicode replacement +// character U+FFFD. +// +func Unmarshal(data []byte, v interface{}) error { + return unmarshal(data, v) +} + +// UnmarshalContext parses the JSON-encoded data and stores the result +// in the value pointed to by v. If you implement the UnmarshalerContext interface, +// call it with ctx as an argument. +func UnmarshalContext(ctx context.Context, data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { + return unmarshalContext(ctx, data, v) +} + +func UnmarshalWithOption(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { + return unmarshal(data, v, optFuncs...) +} + +func UnmarshalNoEscape(data []byte, v interface{}, optFuncs ...DecodeOptionFunc) error { + return unmarshalNoEscape(data, v, optFuncs...) +} + +// A Token holds a value of one of these types: +// +// Delim, for the four JSON delimiters [ ] { } +// bool, for JSON booleans +// float64, for JSON numbers +// Number, for JSON numbers +// string, for JSON string literals +// nil, for JSON null +// +type Token = json.Token + +// A Number represents a JSON number literal. +type Number = json.Number + +// RawMessage is a raw encoded JSON value. +// It implements Marshaler and Unmarshaler and can +// be used to delay JSON decoding or precompute a JSON encoding. +type RawMessage = json.RawMessage + +// A Delim is a JSON array or object delimiter, one of [ ] { or }. +type Delim = json.Delim + +// Compact appends to dst the JSON-encoded src with +// insignificant space characters elided. +func Compact(dst *bytes.Buffer, src []byte) error { + return encoder.Compact(dst, src, false) +} + +// Indent appends to dst an indented form of the JSON-encoded src. +// Each element in a JSON object or array begins on a new, +// indented line beginning with prefix followed by one or more +// copies of indent according to the indentation nesting. +// The data appended to dst does not begin with the prefix nor +// any indentation, to make it easier to embed inside other formatted JSON data. +// Although leading space characters (space, tab, carriage return, newline) +// at the beginning of src are dropped, trailing space characters +// at the end of src are preserved and copied to dst. +// For example, if src has no trailing spaces, neither will dst; +// if src ends in a trailing newline, so will dst. +func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error { + return encoder.Indent(dst, src, prefix, indent) +} + +// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 +// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 +// so that the JSON will be safe to embed inside HTML ` + + `` + + ``)) + data := struct { + URL string + SAMLResponse string + RelayState string + }{ + URL: req.ACSEndpoint.Location, + SAMLResponse: base64.StdEncoding.EncodeToString(responseBuf), + RelayState: req.RelayState, + } + + buf := bytes.NewBuffer(nil) + if err := tmpl.Execute(buf, data); err != nil { + return err + } + if _, err := io.Copy(w, buf); err != nil { + return err + } + return nil + + default: + return fmt.Errorf("%s: unsupported binding %s", + req.ServiceProviderMetadata.EntityID, + req.ACSEndpoint.Binding) + } +} + +// getSPEncryptionCert returns the certificate which we can use to encrypt things +// to the SP in PEM format, or nil if no such certificate is found. +func (req *IdpAuthnRequest) getSPEncryptionCert() (*x509.Certificate, error) { + certStr := "" + for _, keyDescriptor := range req.SPSSODescriptor.KeyDescriptors { + if keyDescriptor.Use == "encryption" { + certStr = keyDescriptor.KeyInfo.X509Data.X509Certificates[0].Data + break + } + } + + // If there are no certs explicitly labeled for encryption, return the first + // non-empty cert we find. + if certStr == "" { + for _, keyDescriptor := range req.SPSSODescriptor.KeyDescriptors { + if keyDescriptor.Use == "" && len(keyDescriptor.KeyInfo.X509Data.X509Certificates) != 0 && keyDescriptor.KeyInfo.X509Data.X509Certificates[0].Data != "" { + certStr = keyDescriptor.KeyInfo.X509Data.X509Certificates[0].Data + break + } + } + } + + if certStr == "" { + return nil, os.ErrNotExist + } + + // cleanup whitespace and re-encode a PEM + certStr = regexp.MustCompile(`\s+`).ReplaceAllString(certStr, "") + certBytes, err := base64.StdEncoding.DecodeString(certStr) + if err != nil { + return nil, fmt.Errorf("cannot decode certificate base64: %v", err) + } + cert, err := x509.ParseCertificate(certBytes) + if err != nil { + return nil, fmt.Errorf("cannot parse certificate: %v", err) + } + return cert, nil +} + +// unmarshalEtreeHack parses `el` and sets values in the structure `v`. +// +// This is a hack -- it first serializes the element, then uses xml.Unmarshal. +func unmarshalEtreeHack(el *etree.Element, v interface{}) error { + doc := etree.NewDocument() + doc.SetRoot(el) + buf, err := doc.WriteToBytes() + if err != nil { + return err + } + return xml.Unmarshal(buf, v) +} + +// MakeResponse creates and assigns a new SAML response in ResponseEl. `Assertion` must +// be non-nil. If MakeAssertionEl() has not been called, this function calls it for +// you. +func (req *IdpAuthnRequest) MakeResponse() error { + if req.AssertionEl == nil { + if err := req.MakeAssertionEl(); err != nil { + return err + } + } + + response := &Response{ + Destination: req.ACSEndpoint.Location, + ID: fmt.Sprintf("id-%x", randomBytes(20)), + InResponseTo: req.Request.ID, + IssueInstant: req.Now, + Version: "2.0", + Issuer: &Issuer{ + Format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity", + Value: req.IDP.MetadataURL.String(), + }, + Status: Status{ + StatusCode: StatusCode{ + Value: StatusSuccess, + }, + }, + } + + responseEl := response.Element() + responseEl.AddChild(req.AssertionEl) // AssertionEl either an EncryptedAssertion or Assertion element + + // Sign the response element (we've already signed the Assertion element) + { + keyPair := tls.Certificate{ + Certificate: [][]byte{req.IDP.Certificate.Raw}, + PrivateKey: req.IDP.Key, + Leaf: req.IDP.Certificate, + } + for _, cert := range req.IDP.Intermediates { + keyPair.Certificate = append(keyPair.Certificate, cert.Raw) + } + keyStore := dsig.TLSCertKeyStore(keyPair) + + signatureMethod := req.IDP.SignatureMethod + if signatureMethod == "" { + signatureMethod = dsig.RSASHA1SignatureMethod + } + + signingContext := dsig.NewDefaultSigningContext(keyStore) + signingContext.Canonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList(canonicalizerPrefixList) + if err := signingContext.SetSignatureMethod(signatureMethod); err != nil { + return err + } + + signedResponseEl, err := signingContext.SignEnveloped(responseEl) + if err != nil { + return err + } + + sigEl := signedResponseEl.ChildElements()[len(signedResponseEl.ChildElements())-1] + response.Signature = sigEl + responseEl = response.Element() + responseEl.AddChild(req.AssertionEl) + } + + req.ResponseEl = responseEl + return nil +} diff --git a/vendor/github.com/mickael-kerjean/saml/logger/logger.go b/vendor/github.com/mickael-kerjean/saml/logger/logger.go new file mode 100644 index 00000000..c211aba6 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/logger/logger.go @@ -0,0 +1,31 @@ +package logger + +import ( + "log" + "os" +) + +// Interface provides the minimal logging interface +type Interface interface { + // Printf prints to the logger using the format. + Printf(format string, v ...interface{}) + // Print prints to the logger. + Print(v ...interface{}) + // Println prints new line. + Println(v ...interface{}) + // Fatal is equivalent to Print() followed by a call to os.Exit(1). + Fatal(v ...interface{}) + // Fatalf is equivalent to Printf() followed by a call to os.Exit(1). + Fatalf(format string, v ...interface{}) + // Fatalln is equivalent to Println() followed by a call to os.Exit(1). + Fatalln(v ...interface{}) + // Panic is equivalent to Print() followed by a call to panic(). + Panic(v ...interface{}) + // Panicf is equivalent to Printf() followed by a call to panic(). + Panicf(format string, v ...interface{}) + // Panicln is equivalent to Println() followed by a call to panic(). + Panicln(v ...interface{}) +} + +// DefaultLogger logs messages to os.Stdout +var DefaultLogger = log.New(os.Stdout, "", log.LstdFlags) diff --git a/vendor/github.com/mickael-kerjean/saml/metadata.go b/vendor/github.com/mickael-kerjean/saml/metadata.go new file mode 100644 index 00000000..f7486d38 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/metadata.go @@ -0,0 +1,303 @@ +package saml + +import ( + "encoding/xml" + "time" + + "github.com/beevik/etree" +) + +// HTTPPostBinding is the official URN for the HTTP-POST binding (transport) +const HTTPPostBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" + +// HTTPRedirectBinding is the official URN for the HTTP-Redirect binding (transport) +const HTTPRedirectBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" + +// HTTPArtifactBinding is the official URN for the HTTP-Artifact binding (transport) +const HTTPArtifactBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" + +// SOAPBinding is the official URN for the SOAP binding (transport) +const SOAPBinding = "urn:oasis:names:tc:SAML:2.0:bindings:SOAP" + +// EntitiesDescriptor represents the SAML object of the same name. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.1 +type EntitiesDescriptor struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntitiesDescriptor"` + ID *string `xml:",attr,omitempty"` + ValidUntil *time.Time `xml:"validUntil,attr,omitempty"` + CacheDuration *time.Duration `xml:"cacheDuration,attr,omitempty"` + Name *string `xml:",attr,omitempty"` + Signature *etree.Element + EntitiesDescriptors []EntitiesDescriptor `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntitiesDescriptor"` + EntityDescriptors []EntityDescriptor `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntityDescriptor"` +} + +// Metadata as been renamed to EntityDescriptor +// +// This change was made to be consistent with the rest of the API which uses names +// from the SAML specification for types. +// +// This is a tombstone to help you discover this fact. You should update references +// to saml.Metadata to be saml.EntityDescriptor. +var Metadata = struct{}{} + +// EntityDescriptor represents the SAML EntityDescriptor object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.2 +type EntityDescriptor struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntityDescriptor"` + EntityID string `xml:"entityID,attr"` + ID string `xml:",attr,omitempty"` + ValidUntil time.Time `xml:"validUntil,attr,omitempty"` + CacheDuration time.Duration `xml:"cacheDuration,attr,omitempty"` + Signature *etree.Element + RoleDescriptors []RoleDescriptor `xml:"RoleDescriptor"` + IDPSSODescriptors []IDPSSODescriptor `xml:"IDPSSODescriptor"` + SPSSODescriptors []SPSSODescriptor `xml:"SPSSODescriptor"` + AuthnAuthorityDescriptors []AuthnAuthorityDescriptor `xml:"AuthnAuthorityDescriptor"` + AttributeAuthorityDescriptors []AttributeAuthorityDescriptor `xml:"AttributeAuthorityDescriptor"` + PDPDescriptors []PDPDescriptor `xml:"PDPDescriptor"` + AffiliationDescriptor *AffiliationDescriptor + Organization *Organization + ContactPerson *ContactPerson + AdditionalMetadataLocations []string `xml:"AdditionalMetadataLocation"` +} + +// MarshalXML implements xml.Marshaler +func (m EntityDescriptor) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias EntityDescriptor + aux := &struct { + ValidUntil RelaxedTime `xml:"validUntil,attr,omitempty"` + CacheDuration Duration `xml:"cacheDuration,attr,omitempty"` + *Alias + }{ + ValidUntil: RelaxedTime(m.ValidUntil), + CacheDuration: Duration(m.CacheDuration), + Alias: (*Alias)(&m), + } + return e.Encode(aux) +} + +// UnmarshalXML implements xml.Unmarshaler +func (m *EntityDescriptor) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias EntityDescriptor + aux := &struct { + ValidUntil RelaxedTime `xml:"validUntil,attr,omitempty"` + CacheDuration Duration `xml:"cacheDuration,attr,omitempty"` + *Alias + }{ + Alias: (*Alias)(m), + } + if err := d.DecodeElement(aux, &start); err != nil { + return err + } + m.ValidUntil = time.Time(aux.ValidUntil) + m.CacheDuration = time.Duration(aux.CacheDuration) + return nil +} + +// Organization represents the SAML Organization object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.2.1 +type Organization struct { + OrganizationNames []LocalizedName `xml:"OrganizationName"` + OrganizationDisplayNames []LocalizedName `xml:"OrganizationDisplayName"` + OrganizationURLs []LocalizedURI `xml:"OrganizationURL"` +} + +// LocalizedName represents the SAML type localizedNameType. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.4 +type LocalizedName struct { + Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr"` + Value string `xml:",chardata"` +} + +// LocalizedURI represents the SAML type localizedURIType. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.5 +type LocalizedURI struct { + Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr"` + Value string `xml:",chardata"` +} + +// ContactPerson represents the SAML element ContactPerson. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.3.2.2 +type ContactPerson struct { + ContactType string `xml:"contactType,attr"` + Company string + GivenName string + SurName string + EmailAddresses []string `xml:"EmailAddress"` + TelephoneNumbers []string `xml:"TelephoneNumber"` +} + +// RoleDescriptor represents the SAML element RoleDescriptor. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.1 +type RoleDescriptor struct { + ID string `xml:",attr,omitempty"` + ValidUntil *time.Time `xml:"validUntil,attr,omitempty"` + CacheDuration time.Duration `xml:"cacheDuration,attr,omitempty"` + ProtocolSupportEnumeration string `xml:"protocolSupportEnumeration,attr"` + ErrorURL string `xml:"errorURL,attr,omitempty"` + Signature *etree.Element + KeyDescriptors []KeyDescriptor `xml:"KeyDescriptor,omitempty"` + Organization *Organization `xml:"Organization,omitempty"` + ContactPeople []ContactPerson `xml:"ContactPerson,omitempty"` +} + +// KeyDescriptor represents the XMLSEC object of the same name +type KeyDescriptor struct { + Use string `xml:"use,attr"` + KeyInfo KeyInfo `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"` + EncryptionMethods []EncryptionMethod `xml:"EncryptionMethod"` +} + +// EncryptionMethod represents the XMLSEC object of the same name +type EncryptionMethod struct { + Algorithm string `xml:"Algorithm,attr"` +} + +// KeyInfo represents the XMLSEC object of the same name +type KeyInfo struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"` + X509Data X509Data `xml:"X509Data"` +} + +// X509Data represents the XMLSEC object of the same name +type X509Data struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"` + X509Certificates []X509Certificate `xml:"X509Certificate"` +} + +// X509Certificate represents the XMLSEC object of the same name +type X509Certificate struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Certificate"` + Data string `xml:",chardata"` +} + +// Endpoint represents the SAML EndpointType object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.2 +type Endpoint struct { + Binding string `xml:"Binding,attr"` + Location string `xml:"Location,attr"` + ResponseLocation string `xml:"ResponseLocation,attr,omitempty"` +} + +// IndexedEndpoint represents the SAML IndexedEndpointType object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.2.3 +type IndexedEndpoint struct { + Binding string `xml:"Binding,attr"` + Location string `xml:"Location,attr"` + ResponseLocation *string `xml:"ResponseLocation,attr,omitempty"` + Index int `xml:"index,attr"` + IsDefault *bool `xml:"isDefault,attr"` +} + +// SSODescriptor represents the SAML complex type SSODescriptor +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.2 +type SSODescriptor struct { + RoleDescriptor + ArtifactResolutionServices []IndexedEndpoint `xml:"ArtifactResolutionService"` + SingleLogoutServices []Endpoint `xml:"SingleLogoutService"` + ManageNameIDServices []Endpoint `xml:"ManageNameIDService"` + NameIDFormats []NameIDFormat `xml:"NameIDFormat"` +} + +// IDPSSODescriptor represents the SAML IDPSSODescriptorType object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.3 +type IDPSSODescriptor struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata IDPSSODescriptor"` + SSODescriptor + WantAuthnRequestsSigned *bool `xml:",attr"` + + SingleSignOnServices []Endpoint `xml:"SingleSignOnService"` + ArtifactResolutionServices []Endpoint `xml:"ArtifactResolutionService"` + NameIDMappingServices []Endpoint `xml:"NameIDMappingService"` + AssertionIDRequestServices []Endpoint `xml:"AssertionIDRequestService"` + AttributeProfiles []string `xml:"AttributeProfile"` + Attributes []Attribute `xml:"Attribute"` +} + +// SPSSODescriptor represents the SAML SPSSODescriptorType object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.2 +type SPSSODescriptor struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata SPSSODescriptor"` + SSODescriptor + AuthnRequestsSigned *bool `xml:",attr"` + WantAssertionsSigned *bool `xml:",attr"` + AssertionConsumerServices []IndexedEndpoint `xml:"AssertionConsumerService"` + AttributeConsumingServices []AttributeConsumingService `xml:"AttributeConsumingService"` +} + +// AttributeConsumingService represents the SAML AttributeConsumingService object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.4.1 +type AttributeConsumingService struct { + Index int `xml:"index,attr"` + IsDefault *bool `xml:"isDefault,attr"` + ServiceNames []LocalizedName `xml:"ServiceName"` + ServiceDescriptions []LocalizedName `xml:"ServiceDescription"` + RequestedAttributes []RequestedAttribute `xml:"RequestedAttribute"` +} + +// RequestedAttribute represents the SAML RequestedAttribute object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.4.2 +type RequestedAttribute struct { + Attribute + IsRequired *bool `xml:"isRequired,attr"` +} + +// AuthnAuthorityDescriptor represents the SAML AuthnAuthorityDescriptor object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.5 +type AuthnAuthorityDescriptor struct { + RoleDescriptor + AuthnQueryServices []Endpoint `xml:"AuthnQueryService"` + AssertionIDRequestServices []Endpoint `xml:"AssertionIDRequestService"` + NameIDFormats []NameIDFormat `xml:"NameIDFormat"` +} + +// PDPDescriptor represents the SAML PDPDescriptor object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.6 +type PDPDescriptor struct { + RoleDescriptor + AuthzServices []Endpoint `xml:"AuthzService"` + AssertionIDRequestServices []Endpoint `xml:"AssertionIDRequestService"` + NameIDFormats []NameIDFormat `xml:"NameIDFormat"` +} + +// AttributeAuthorityDescriptor represents the SAML AttributeAuthorityDescriptor object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.4.7 +type AttributeAuthorityDescriptor struct { + RoleDescriptor + AttributeServices []Endpoint `xml:"AttributeService"` + AssertionIDRequestServices []Endpoint `xml:"AssertionIDRequestService"` + NameIDFormats []NameIDFormat `xml:"NameIDFormat"` + AttributeProfiles []string `xml:"AttributeProfile"` + Attributes []Attribute `xml:"Attribute"` +} + +// AffiliationDescriptor represents the SAML AffiliationDescriptor object. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf §2.5 +type AffiliationDescriptor struct { + AffiliationOwnerID string `xml:"affiliationOwnerID,attr"` + ID string `xml:",attr"` + ValidUntil time.Time `xml:"validUntil,attr,omitempty"` + CacheDuration time.Duration `xml:"cacheDuration,attr"` + Signature *etree.Element + AffiliateMembers []string `xml:"AffiliateMember"` + KeyDescriptors []KeyDescriptor `xml:"KeyDescriptor"` +} diff --git a/vendor/github.com/mickael-kerjean/saml/saml.go b/vendor/github.com/mickael-kerjean/saml/saml.go new file mode 100644 index 00000000..950093b8 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/saml.go @@ -0,0 +1,177 @@ +// Package saml contains a partial implementation of the SAML standard in golang. +// SAML is a standard for identity federation, i.e. either allowing a third party to authenticate your users or allowing third parties to rely on us to authenticate their users. +// +// # Introduction +// +// In SAML parlance an Identity Provider (IDP) is a service that knows how to authenticate users. A Service Provider (SP) is a service that delegates authentication to an IDP. If you are building a service where users log in with someone else's credentials, then you are a Service Provider. This package supports implementing both service providers and identity providers. +// +// The core package contains the implementation of SAML. The package samlsp provides helper middleware suitable for use in Service Provider applications. The package samlidp provides a rudimentary IDP service that is useful for testing or as a starting point for other integrations. +// +// # Breaking Changes +// +// Version 0.4.0 introduces a few breaking changes to the _samlsp_ package in order to make the package more extensible, and to clean up the interfaces a bit. The default behavior remains the same, but you can now provide interface implementations of _RequestTracker_ (which tracks pending requests), _Session_ (which handles maintaining a session) and _OnError_ which handles reporting errors. +// +// Public fields of _samlsp.Middleware_ have changed, so some usages may require adjustment. See [issue 231](https://github.com/mickael-kerjean/saml/issues/231) for details. +// +// The option to provide an IDP metadata URL has been deprecated. Instead, we recommend that you use the `FetchMetadata()` function, or fetch the metadata yourself and use the new `ParseMetadata()` function, and pass the metadata in _samlsp.Options.IDPMetadata_. +// +// Similarly, the _HTTPClient_ field is now deprecated because it was only used for fetching metdata, which is no longer directly implemented. +// +// The fields that manage how cookies are set are deprecated as well. To customize how cookies are managed, provide custom implementation of _RequestTracker_ and/or _Session_, perhaps by extending the default implementations. +// +// The deprecated fields have not been removed from the Options structure, but will be in future. +// +// In particular we have deprecated the following fields in +// _samlsp.Options_: +// +// - `Logger` - This was used to emit errors while validating, which is an anti-pattern. +// - `IDPMetadataURL` - Instead use `FetchMetadata()` +// - `HTTPClient` - Instead pass httpClient to FetchMetadata +// - `CookieMaxAge` - Instead assign a custom CookieRequestTracker or CookieSessionProvider +// - `CookieName` - Instead assign a custom CookieRequestTracker or CookieSessionProvider +// - `CookieDomain` - Instead assign a custom CookieRequestTracker or CookieSessionProvider +// - `CookieDomain` - Instead assign a custom CookieRequestTracker or CookieSessionProvider +// +// # Getting Started as a Service Provider +// +// Let us assume we have a simple web application to protect. We'll modify this application so it uses SAML to authenticate users. +// +// ```golang +// package main +// +// import ( +// +// "fmt" +// "net/http" +// +// ) +// +// func hello(w http.ResponseWriter, r *http.Request) { +// fmt.Fprintf(w, "Hello, World!") +// } +// +// func main() { +// app := http.HandlerFunc(hello) +// http.Handle("/hello", app) +// http.ListenAndServe(":8000", nil) +// } +// +// ``` +// +// Each service provider must have an self-signed X.509 key pair established. You can generate your own with something like this: +// +// openssl req -x509 -newkey rsa:2048 -keyout myservice.key -out myservice.cert -days 365 -nodes -subj "/CN=myservice.example.com" +// +// We will use `samlsp.Middleware` to wrap the endpoint we want to protect. Middleware provides both an `http.Handler` to serve the SAML specific URLs and a set of wrappers to require the user to be logged in. We also provide the URL where the service provider can fetch the metadata from the IDP at startup. In our case, we'll use [samltest.id](https://samltest.id/), an identity provider designed for testing. +// +// ```golang +// package main +// +// import ( +// +// "crypto/rsa" +// "crypto/tls" +// "crypto/x509" +// "fmt" +// "net/http" +// "net/url" +// +// "github.com/mickael-kerjean/saml/samlsp" +// +// ) +// +// func hello(w http.ResponseWriter, r *http.Request) { +// fmt.Fprintf(w, "Hello, %s!", samlsp.Token(r.Context()).Attributes.Get("cn")) +// } +// +// func main() { +// keyPair, err := tls.LoadX509KeyPair("myservice.cert", "myservice.key") +// if err != nil { +// panic(err) // TODO handle error +// } +// keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0]) +// if err != nil { +// panic(err) // TODO handle error +// } +// +// idpMetadataURL, err := url.Parse("https://samltest.id/saml/idp") +// if err != nil { +// panic(err) // TODO handle error +// } +// +// rootURL, err := url.Parse("http://localhost:8000") +// if err != nil { +// panic(err) // TODO handle error +// } +// +// samlSP, _ := samlsp.New(samlsp.Options{ +// URL: *rootURL, +// Key: keyPair.PrivateKey.(*rsa.PrivateKey), +// Certificate: keyPair.Leaf, +// IDPMetadataURL: idpMetadataURL, +// }) +// app := http.HandlerFunc(hello) +// http.Handle("/hello", samlSP.RequireAccount(app)) +// http.Handle("/saml/", samlSP) +// http.ListenAndServe(":8000", nil) +// } +// +// ``` +// +// Next we'll have to register our service provider with the identity provider to establish trust from the service provider to the IDP. For [samltest.id](https://samltest.id/), you can do something like: +// +// mdpath=saml-test-$USER-$HOST.xml +// curl localhost:8000/saml/metadata > $mdpath +// +// Navigate to https://samltest.id/upload.php and upload the file you fetched. +// +// Now you should be able to authenticate. The flow should look like this: +// +// 1. You browse to `localhost:8000/hello` +// +// 1. The middleware redirects you to `https://samltest.id/idp/profile/SAML2/Redirect/SSO` +// +// 1. samltest.id prompts you for a username and password. +// +// 1. samltest.id returns you an HTML document which contains an HTML form setup to POST to `localhost:8000/saml/acs`. The form is automatically submitted if you have javascript enabled. +// +// 1. The local service validates the response, issues a session cookie, and redirects you to the original URL, `localhost:8000/hello`. +// +// 1. This time when `localhost:8000/hello` is requested there is a valid session and so the main content is served. +// +// # Getting Started as an Identity Provider +// +// Please see `example/idp/` for a substantially complete example of how to use the library and helpers to be an identity provider. +// +// # Support +// +// The SAML standard is huge and complex with many dark corners and strange, unused features. This package implements the most commonly used subset of these features required to provide a single sign on experience. The package supports at least the subset of SAML known as [interoperable SAML](http://saml2int.org). +// +// This package supports the Web SSO profile. Message flows from the service provider to the IDP are supported using the HTTP Redirect binding and the HTTP POST binding. Message flows from the IDP to the service provider are supported via the HTTP POST binding. +// +// The package can produce signed SAML assertions, and can validate both signed and encrypted SAML assertions. It does not support signed or encrypted requests. +// +// # RelayState +// +// The _RelayState_ parameter allows you to pass user state information across the authentication flow. The most common use for this is to allow a user to request a deep link into your site, be redirected through the SAML login flow, and upon successful completion, be directed to the originally requested link, rather than the root. +// +// Unfortunately, _RelayState_ is less useful than it could be. Firstly, it is not authenticated, so anything you supply must be signed to avoid XSS or CSRF. Secondly, it is limited to 80 bytes in length, which precludes signing. (See section 3.6.3.1 of SAMLProfiles.) +// +// # References +// +// The SAML specification is a collection of PDFs (sadly): +// +// - [SAMLCore](http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf) defines data types. +// +// - [SAMLBindings](http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf) defines the details of the HTTP requests in play. +// +// - [SAMLProfiles](http://docs.oasis-open.org/security/saml/v2.0/saml-profiles-2.0-os.pdf) describes data flows. +// +// - [SAMLConformance](http://docs.oasis-open.org/security/saml/v2.0/saml-conformance-2.0-os.pdf) includes a support matrix for various parts of the protocol. +// +// [SAMLtest](https://samltest.id/) is a testing ground for SAML service and identity providers. +// +// # Security Issues +// +// Please do not report security issues in the issue tracker. Rather, please contact me directly at ross@kndr.org ([PGP Key `78B6038B3B9DFB88`](https://keybase.io/crewjam)). +package saml diff --git a/vendor/github.com/mickael-kerjean/saml/saml_gen.go b/vendor/github.com/mickael-kerjean/saml/saml_gen.go new file mode 100644 index 00000000..f85a04a2 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/saml_gen.go @@ -0,0 +1,3 @@ +package saml + +//go:generate bash -c "(cat README.md | grep -E -v '^# SAML' | sed 's|^## ||g' | sed 's|\\*\\*||g' | sed 's|^|// |g'; echo 'package saml') > saml.go" diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/error.go b/vendor/github.com/mickael-kerjean/saml/samlsp/error.go new file mode 100644 index 00000000..cb475d4e --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/error.go @@ -0,0 +1,25 @@ +package samlsp + +import ( + "log" + "net/http" + + "github.com/mickael-kerjean/saml" +) + +// ErrorFunction is a callback that is invoked to return an error to the +// web user. +type ErrorFunction func(w http.ResponseWriter, r *http.Request, err error) + +// DefaultOnError is the default ErrorFunction implementation. It prints +// an message via the standard log package and returns a simple text +// "Forbidden" message to the user. +func DefaultOnError(w http.ResponseWriter, r *http.Request, err error) { + if parseErr, ok := err.(*saml.InvalidResponseError); ok { + log.Printf("WARNING: received invalid saml response: %s (now: %s) %s", + parseErr.Response, parseErr.Now, parseErr.PrivateErr) + } else { + log.Printf("ERROR: %s", err) + } + http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/fetch_metadata.go b/vendor/github.com/mickael-kerjean/saml/samlsp/fetch_metadata.go new file mode 100644 index 00000000..b357cd6f --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/fetch_metadata.go @@ -0,0 +1,75 @@ +package samlsp + +import ( + "bytes" + "context" + "encoding/xml" + "errors" + "io/ioutil" + "net/http" + "net/url" + + "github.com/crewjam/httperr" + xrv "github.com/mattermost/xml-roundtrip-validator" + + "github.com/mickael-kerjean/saml" +) + +// ParseMetadata parses arbitrary SAML IDP metadata. +// +// Note: this is needed because IDP metadata is sometimes wrapped in +// an , and sometimes the top level element is an +// . +func ParseMetadata(data []byte) (*saml.EntityDescriptor, error) { + entity := &saml.EntityDescriptor{} + + if err := xrv.Validate(bytes.NewBuffer(data)); err != nil { + return nil, err + } + + err := xml.Unmarshal(data, entity) + + // this comparison is ugly, but it is how the error is generated in encoding/xml + if err != nil && err.Error() == "expected element type but have " { + entities := &saml.EntitiesDescriptor{} + if err := xml.Unmarshal(data, entities); err != nil { + return nil, err + } + + for i, e := range entities.EntityDescriptors { + if len(e.IDPSSODescriptors) > 0 { + return &entities.EntityDescriptors[i], nil + } + } + return nil, errors.New("no entity found with IDPSSODescriptor") + } + if err != nil { + return nil, err + } + return entity, nil +} + +// FetchMetadata returns metadata from an IDP metadata URL. +func FetchMetadata(ctx context.Context, httpClient *http.Client, metadataURL url.URL) (*saml.EntityDescriptor, error) { + req, err := http.NewRequest("GET", metadataURL.String(), nil) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + + resp, err := httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode >= 400 { + return nil, httperr.Response(*resp) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return ParseMetadata(data) +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/middleware.go b/vendor/github.com/mickael-kerjean/saml/samlsp/middleware.go new file mode 100644 index 00000000..61e40562 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/middleware.go @@ -0,0 +1,233 @@ +package samlsp + +import ( + "encoding/xml" + "net/http" + + "github.com/mickael-kerjean/saml" +) + +// Middleware implements middleware than allows a web application +// to support SAML. +// +// It implements http.Handler so that it can provide the metadata and ACS endpoints, +// typically /saml/metadata and /saml/acs, respectively. +// +// It also provides middleware RequireAccount which redirects users to +// the auth process if they do not have session credentials. +// +// When redirecting the user through the SAML auth flow, the middleware assigns +// a temporary cookie with a random name beginning with "saml_". The value of +// the cookie is a signed JSON Web Token containing the original URL requested +// and the SAML request ID. The random part of the name corresponds to the +// RelayState parameter passed through the SAML flow. +// +// When validating the SAML response, the RelayState is used to look up the +// correct cookie, validate that the SAML request ID, and redirect the user +// back to their original URL. +// +// Sessions are established by issuing a JSON Web Token (JWT) as a session +// cookie once the SAML flow has succeeded. The JWT token contains the +// authenticated attributes from the SAML assertion. +// +// When the middleware receives a request with a valid session JWT it extracts +// the SAML attributes and modifies the http.Request object adding a Context +// object to the request context that contains attributes from the initial +// SAML assertion. +// +// When issuing JSON Web Tokens, a signing key is required. Because the +// SAML service provider already has a private key, we borrow that key +// to sign the JWTs as well. +type Middleware struct { + ServiceProvider saml.ServiceProvider + OnError func(w http.ResponseWriter, r *http.Request, err error) + Binding string // either saml.HTTPPostBinding or saml.HTTPRedirectBinding + ResponseBinding string // either saml.HTTPPostBinding or saml.HTTPArtifactBinding + RequestTracker RequestTracker + Session SessionProvider +} + +// ServeHTTP implements http.Handler and serves the SAML-specific HTTP endpoints +// on the URIs specified by m.ServiceProvider.MetadataURL and +// m.ServiceProvider.AcsURL. +func (m *Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == m.ServiceProvider.MetadataURL.Path { + m.ServeMetadata(w, r) + return + } + + if r.URL.Path == m.ServiceProvider.AcsURL.Path { + m.ServeACS(w, r) + return + } + + http.NotFoundHandler().ServeHTTP(w, r) +} + +// ServeMetadata handles requests for the SAML metadata endpoint. +func (m *Middleware) ServeMetadata(w http.ResponseWriter, r *http.Request) { + buf, _ := xml.MarshalIndent(m.ServiceProvider.Metadata(), "", " ") + w.Header().Set("Content-Type", "application/samlmetadata+xml") + w.Write(buf) + return +} + +// ServeACS handles requests for the SAML ACS endpoint. +func (m *Middleware) ServeACS(w http.ResponseWriter, r *http.Request) { + r.ParseForm() + + possibleRequestIDs := []string{} + if m.ServiceProvider.AllowIDPInitiated { + possibleRequestIDs = append(possibleRequestIDs, "") + } + + trackedRequests := m.RequestTracker.GetTrackedRequests(r) + for _, tr := range trackedRequests { + possibleRequestIDs = append(possibleRequestIDs, tr.SAMLRequestID) + } + + assertion, err := m.ServiceProvider.ParseResponse(r, possibleRequestIDs) + if err != nil { + m.OnError(w, r, err) + return + } + + m.CreateSessionFromAssertion(w, r, assertion, m.ServiceProvider.DefaultRedirectURI) + return +} + +// RequireAccount is HTTP middleware that requires that each request be +// associated with a valid session. If the request is not associated with a valid +// session, then rather than serve the request, the middleware redirects the user +// to start the SAML auth flow. +func (m *Middleware) RequireAccount(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + session, err := m.Session.GetSession(r) + if session != nil { + r = r.WithContext(ContextWithSession(r.Context(), session)) + handler.ServeHTTP(w, r) + return + } + if err == ErrNoSession { + m.HandleStartAuthFlow(w, r) + return + } + + m.OnError(w, r, err) + return + }) +} + +// HandleStartAuthFlow is called to start the SAML authentication process. +func (m *Middleware) HandleStartAuthFlow(w http.ResponseWriter, r *http.Request) { + // If we try to redirect when the original request is the ACS URL we'll + // end up in a loop. This is a programming error, so we panic here. In + // general this means a 500 to the user, which is preferable to a + // redirect loop. + if r.URL.Path == m.ServiceProvider.AcsURL.Path { + panic("don't wrap Middleware with RequireAccount") + } + + var binding, bindingLocation string + if m.Binding != "" { + binding = m.Binding + bindingLocation = m.ServiceProvider.GetSSOBindingLocation(binding) + } else { + binding = saml.HTTPRedirectBinding + bindingLocation = m.ServiceProvider.GetSSOBindingLocation(binding) + if bindingLocation == "" { + binding = saml.HTTPPostBinding + bindingLocation = m.ServiceProvider.GetSSOBindingLocation(binding) + } + } + + authReq, err := m.ServiceProvider.MakeAuthenticationRequest(bindingLocation, binding, m.ResponseBinding) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // relayState is limited to 80 bytes but also must be integrity protected. + // this means that we cannot use a JWT because it is way to long. Instead + // we set a signed cookie that encodes the original URL which we'll check + // against the SAML response when we get it. + relayState, err := m.RequestTracker.TrackRequest(w, r, authReq.ID) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if binding == saml.HTTPRedirectBinding { + redirectURL, err := authReq.Redirect(relayState, &m.ServiceProvider) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.Header().Add("Location", redirectURL.String()) + w.WriteHeader(http.StatusFound) + return + } + if binding == saml.HTTPPostBinding { + w.Header().Add("Content-Security-Policy", ""+ + "default-src; "+ + "script-src 'sha256-AjPdJSbZmeWHnEc5ykvJFay8FTWeTeRbs9dutfZ0HqE='; "+ + "reflected-xss block; referrer no-referrer;") + w.Header().Add("Content-type", "text/html") + w.Write([]byte(``)) + w.Write(authReq.Post(relayState)) + w.Write([]byte(``)) + return + } + panic("not reached") +} + +// CreateSessionFromAssertion is invoked by ServeHTTP when we have a new, valid SAML assertion. +func (m *Middleware) CreateSessionFromAssertion(w http.ResponseWriter, r *http.Request, assertion *saml.Assertion, redirectURI string) { + if trackedRequestIndex := r.Form.Get("RelayState"); trackedRequestIndex != "" { + trackedRequest, err := m.RequestTracker.GetTrackedRequest(r, trackedRequestIndex) + if err != nil { + m.OnError(w, r, err) + return + } + m.RequestTracker.StopTrackingRequest(w, r, trackedRequestIndex) + + redirectURI = trackedRequest.URI + } + + if err := m.Session.CreateSession(w, r, assertion); err != nil { + m.OnError(w, r, err) + return + } + + http.Redirect(w, r, redirectURI, http.StatusFound) +} + +// RequireAttribute returns a middleware function that requires that the +// SAML attribute `name` be set to `value`. This can be used to require +// that a remote user be a member of a group. It relies on the Claims assigned +// to to the context in RequireAccount. +// +// For example: +// +// goji.Use(m.RequireAccount) +// goji.Use(RequireAttributeMiddleware("eduPersonAffiliation", "Staff")) +func RequireAttribute(name, value string) func(http.Handler) http.Handler { + return func(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if session := SessionFromContext(r.Context()); session != nil { + // this will panic if we have the wrong type of Session, and that is OK. + sessionWithAttributes := session.(SessionWithAttributes) + attributes := sessionWithAttributes.GetAttributes() + if values, ok := attributes[name]; ok { + for _, v := range values { + if v == value { + handler.ServeHTTP(w, r) + return + } + } + } + } + http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) + }) + } +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/new.go b/vendor/github.com/mickael-kerjean/saml/samlsp/new.go new file mode 100644 index 00000000..665adf92 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/new.go @@ -0,0 +1,149 @@ +// Package samlsp provides helpers that can be used to protect web services using SAML. +package samlsp + +import ( + "crypto/rsa" + "crypto/x509" + "net/http" + "net/url" + + dsig "github.com/russellhaering/goxmldsig" + + "github.com/mickael-kerjean/saml" +) + +// Options represents the parameters for creating a new middleware +type Options struct { + EntityID string + URL url.URL + Key *rsa.PrivateKey + Certificate *x509.Certificate + Intermediates []*x509.Certificate + HTTPClient *http.Client + AllowIDPInitiated bool + DefaultRedirectURI string + IDPMetadata *saml.EntityDescriptor + SignRequest bool + UseArtifactResponse bool + ForceAuthn bool // TODO(ross): this should be *bool + RequestedAuthnContext *saml.RequestedAuthnContext + CookieSameSite http.SameSite + RelayStateFunc func(w http.ResponseWriter, r *http.Request) string + LogoutBindings []string +} + +// DefaultSessionCodec returns the default SessionCodec for the provided options, +// a JWTSessionCodec configured to issue signed tokens. +func DefaultSessionCodec(opts Options) JWTSessionCodec { + return JWTSessionCodec{ + SigningMethod: defaultJWTSigningMethod, + Audience: opts.URL.String(), + Issuer: opts.URL.String(), + MaxAge: defaultSessionMaxAge, + Key: opts.Key, + } +} + +// DefaultSessionProvider returns the default SessionProvider for the provided options, +// a CookieSessionProvider configured to store sessions in a cookie. +func DefaultSessionProvider(opts Options) CookieSessionProvider { + return CookieSessionProvider{ + Name: defaultSessionCookieName, + Domain: opts.URL.Host, + MaxAge: defaultSessionMaxAge, + HTTPOnly: true, + Secure: opts.URL.Scheme == "https", + SameSite: opts.CookieSameSite, + Codec: DefaultSessionCodec(opts), + } +} + +// DefaultTrackedRequestCodec returns a new TrackedRequestCodec for the provided +// options, a JWTTrackedRequestCodec that uses a JWT to encode TrackedRequests. +func DefaultTrackedRequestCodec(opts Options) JWTTrackedRequestCodec { + return JWTTrackedRequestCodec{ + SigningMethod: defaultJWTSigningMethod, + Audience: opts.URL.String(), + Issuer: opts.URL.String(), + MaxAge: saml.MaxIssueDelay, + Key: opts.Key, + } +} + +// DefaultRequestTracker returns a new RequestTracker for the provided options, +// a CookieRequestTracker which uses cookies to track pending requests. +func DefaultRequestTracker(opts Options, serviceProvider *saml.ServiceProvider) CookieRequestTracker { + return CookieRequestTracker{ + ServiceProvider: serviceProvider, + NamePrefix: "saml_", + Codec: DefaultTrackedRequestCodec(opts), + MaxAge: saml.MaxIssueDelay, + RelayStateFunc: opts.RelayStateFunc, + SameSite: opts.CookieSameSite, + } +} + +// DefaultServiceProvider returns the default saml.ServiceProvider for the provided +// options. +func DefaultServiceProvider(opts Options) saml.ServiceProvider { + metadataURL := opts.URL.ResolveReference(&url.URL{Path: "saml/metadata"}) + acsURL := opts.URL.ResolveReference(&url.URL{Path: "saml/acs"}) + sloURL := opts.URL.ResolveReference(&url.URL{Path: "saml/slo"}) + + var forceAuthn *bool + if opts.ForceAuthn { + forceAuthn = &opts.ForceAuthn + } + signatureMethod := dsig.RSASHA1SignatureMethod + if !opts.SignRequest { + signatureMethod = "" + } + + if opts.DefaultRedirectURI == "" { + opts.DefaultRedirectURI = "/" + } + + if len(opts.LogoutBindings) == 0 { + opts.LogoutBindings = []string{saml.HTTPPostBinding} + } + + return saml.ServiceProvider{ + EntityID: opts.EntityID, + Key: opts.Key, + Certificate: opts.Certificate, + HTTPClient: opts.HTTPClient, + Intermediates: opts.Intermediates, + MetadataURL: *metadataURL, + AcsURL: *acsURL, + SloURL: *sloURL, + IDPMetadata: opts.IDPMetadata, + ForceAuthn: forceAuthn, + RequestedAuthnContext: opts.RequestedAuthnContext, + SignatureMethod: signatureMethod, + AllowIDPInitiated: opts.AllowIDPInitiated, + DefaultRedirectURI: opts.DefaultRedirectURI, + LogoutBindings: opts.LogoutBindings, + } +} + +// New creates a new Middleware with the default providers for the +// given options. +// +// You can customize the behavior of the middleware in more detail by +// replacing and/or changing Session, RequestTracker, and ServiceProvider +// in the returned Middleware. +func New(opts Options) (*Middleware, error) { + m := &Middleware{ + ServiceProvider: DefaultServiceProvider(opts), + Binding: "", + ResponseBinding: saml.HTTPPostBinding, + OnError: DefaultOnError, + Session: DefaultSessionProvider(opts), + } + m.RequestTracker = DefaultRequestTracker(opts, &m.ServiceProvider) + if opts.UseArtifactResponse { + m.ResponseBinding = saml.HTTPArtifactBinding + } + + return m, nil +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker.go b/vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker.go new file mode 100644 index 00000000..f5477c8d --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker.go @@ -0,0 +1,46 @@ +package samlsp + +import ( + "net/http" +) + +// RequestTracker tracks pending authentication requests. +// +// There are two main reasons for this: +// +// 1. When the middleware initiates an authentication request it must track the original URL +// in order to redirect the user to the right place after the authentication completes. +// +// 2. After the authentication completes, we want to ensure that the user presenting the +// assertion is actually the one the request it, to mitigate request forgeries. +type RequestTracker interface { + // TrackRequest starts tracking the SAML request with the given ID. It returns an + // `index` that should be used as the RelayState in the SAMl request flow. + TrackRequest(w http.ResponseWriter, r *http.Request, samlRequestID string) (index string, err error) + + // StopTrackingRequest stops tracking the SAML request given by index, which is a string + // previously returned from TrackRequest + StopTrackingRequest(w http.ResponseWriter, r *http.Request, index string) error + + // GetTrackedRequests returns all the pending tracked requests + GetTrackedRequests(r *http.Request) []TrackedRequest + + // GetTrackedRequest returns a pending tracked request. + GetTrackedRequest(r *http.Request, index string) (*TrackedRequest, error) +} + +// TrackedRequest holds the data we store for each pending request. +type TrackedRequest struct { + Index string `json:"-"` + SAMLRequestID string `json:"id"` + URI string `json:"uri"` +} + +// TrackedRequestCodec handles encoding and decoding of a TrackedRequest. +type TrackedRequestCodec interface { + // Encode returns an encoded string representing the TrackedRequest. + Encode(value TrackedRequest) (string, error) + + // Decode returns a Tracked request from an encoded string. + Decode(signed string) (*TrackedRequest, error) +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker_cookie.go b/vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker_cookie.go new file mode 100644 index 00000000..324cc847 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker_cookie.go @@ -0,0 +1,111 @@ +package samlsp + +import ( + "encoding/base64" + "fmt" + "net/http" + "strings" + "time" + + "github.com/mickael-kerjean/saml" +) + +var _ RequestTracker = CookieRequestTracker{} + +// CookieRequestTracker tracks requests by setting a uniquely named +// cookie for each request. +type CookieRequestTracker struct { + ServiceProvider *saml.ServiceProvider + NamePrefix string + Codec TrackedRequestCodec + MaxAge time.Duration + RelayStateFunc func(w http.ResponseWriter, r *http.Request) string + SameSite http.SameSite +} + +// TrackRequest starts tracking the SAML request with the given ID. It returns an +// `index` that should be used as the RelayState in the SAMl request flow. +func (t CookieRequestTracker) TrackRequest(w http.ResponseWriter, r *http.Request, samlRequestID string) (string, error) { + trackedRequest := TrackedRequest{ + Index: base64.RawURLEncoding.EncodeToString(randomBytes(42)), + SAMLRequestID: samlRequestID, + URI: r.URL.String(), + } + + if t.RelayStateFunc != nil { + relayState := t.RelayStateFunc(w, r) + if relayState != "" { + trackedRequest.Index = relayState + } + } + + signedTrackedRequest, err := t.Codec.Encode(trackedRequest) + if err != nil { + return "", err + } + + http.SetCookie(w, &http.Cookie{ + Name: t.NamePrefix + trackedRequest.Index, + Value: signedTrackedRequest, + MaxAge: int(t.MaxAge.Seconds()), + HttpOnly: true, + SameSite: t.SameSite, + Secure: t.ServiceProvider.AcsURL.Scheme == "https", + Path: t.ServiceProvider.AcsURL.Path, + }) + + return trackedRequest.Index, nil +} + +// StopTrackingRequest stops tracking the SAML request given by index, which is a string +// previously returned from TrackRequest +func (t CookieRequestTracker) StopTrackingRequest(w http.ResponseWriter, r *http.Request, index string) error { + cookie, err := r.Cookie(t.NamePrefix + index) + if err != nil { + return err + } + cookie.Value = "" + cookie.Domain = t.ServiceProvider.AcsURL.Hostname() + cookie.Expires = time.Unix(1, 0) // past time as close to epoch as possible, but not zero time.Time{} + http.SetCookie(w, cookie) + return nil +} + +// GetTrackedRequests returns all the pending tracked requests +func (t CookieRequestTracker) GetTrackedRequests(r *http.Request) []TrackedRequest { + rv := []TrackedRequest{} + for _, cookie := range r.Cookies() { + if !strings.HasPrefix(cookie.Name, t.NamePrefix) { + continue + } + + trackedRequest, err := t.Codec.Decode(cookie.Value) + if err != nil { + continue + } + index := strings.TrimPrefix(cookie.Name, t.NamePrefix) + if index != trackedRequest.Index { + continue + } + + rv = append(rv, *trackedRequest) + } + return rv +} + +// GetTrackedRequest returns a pending tracked request. +func (t CookieRequestTracker) GetTrackedRequest(r *http.Request, index string) (*TrackedRequest, error) { + cookie, err := r.Cookie(t.NamePrefix + index) + if err != nil { + return nil, err + } + + trackedRequest, err := t.Codec.Decode(cookie.Value) + if err != nil { + return nil, err + } + if trackedRequest.Index != index { + return nil, fmt.Errorf("expected index %q, got %q", index, trackedRequest.Index) + } + return trackedRequest, nil +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker_jwt.go b/vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker_jwt.go new file mode 100644 index 00000000..a414465b --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/request_tracker_jwt.go @@ -0,0 +1,75 @@ +package samlsp + +import ( + "crypto/rsa" + "fmt" + "time" + + "github.com/golang-jwt/jwt/v4" + + "github.com/mickael-kerjean/saml" +) + +var defaultJWTSigningMethod = jwt.SigningMethodRS256 + +// JWTTrackedRequestCodec encodes TrackedRequests as signed JWTs +type JWTTrackedRequestCodec struct { + SigningMethod jwt.SigningMethod + Audience string + Issuer string + MaxAge time.Duration + Key *rsa.PrivateKey +} + +var _ TrackedRequestCodec = JWTTrackedRequestCodec{} + +// JWTTrackedRequestClaims represents the JWT claims for a tracked request. +type JWTTrackedRequestClaims struct { + jwt.StandardClaims + TrackedRequest + SAMLAuthnRequest bool `json:"saml-authn-request"` +} + +// Encode returns an encoded string representing the TrackedRequest. +func (s JWTTrackedRequestCodec) Encode(value TrackedRequest) (string, error) { + now := saml.TimeNow() + claims := JWTTrackedRequestClaims{ + StandardClaims: jwt.StandardClaims{ + Audience: s.Audience, + ExpiresAt: now.Add(s.MaxAge).Unix(), + IssuedAt: now.Unix(), + Issuer: s.Issuer, + NotBefore: now.Unix(), // TODO(ross): correct for clock skew + Subject: value.Index, + }, + TrackedRequest: value, + SAMLAuthnRequest: true, + } + token := jwt.NewWithClaims(s.SigningMethod, claims) + return token.SignedString(s.Key) +} + +// Decode returns a Tracked request from an encoded string. +func (s JWTTrackedRequestCodec) Decode(signed string) (*TrackedRequest, error) { + parser := jwt.Parser{ + ValidMethods: []string{s.SigningMethod.Alg()}, + } + claims := JWTTrackedRequestClaims{} + _, err := parser.ParseWithClaims(signed, &claims, func(*jwt.Token) (interface{}, error) { + return s.Key.Public(), nil + }) + if err != nil { + return nil, err + } + if !claims.VerifyAudience(s.Audience, true) { + return nil, fmt.Errorf("expected audience %q, got %q", s.Audience, claims.Audience) + } + if !claims.VerifyIssuer(s.Issuer, true) { + return nil, fmt.Errorf("expected issuer %q, got %q", s.Issuer, claims.Issuer) + } + if claims.SAMLAuthnRequest != true { + return nil, fmt.Errorf("expected saml-authn-request") + } + claims.TrackedRequest.Index = claims.Subject + return &claims.TrackedRequest, nil +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/session.go b/vendor/github.com/mickael-kerjean/saml/samlsp/session.go new file mode 100644 index 00000000..5c87afe5 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/session.go @@ -0,0 +1,89 @@ +package samlsp + +import ( + "context" + "errors" + "net/http" + + "github.com/mickael-kerjean/saml" +) + +// Session is an interface implemented to contain a session. +type Session interface{} + +// SessionWithAttributes is a session that can expose the +// attributes provided by the SAML identity provider. +type SessionWithAttributes interface { + Session + GetAttributes() Attributes +} + +// ErrNoSession is the error returned when the remote user does not have a session +var ErrNoSession = errors.New("saml: session not present") + +// SessionProvider is an interface implemented by types that can track +// the active session of a user. The default implementation is CookieSessionProvider +type SessionProvider interface { + // CreateSession is called when we have received a valid SAML assertion and + // should create a new session and modify the http response accordingly, e.g. by + // setting a cookie. + CreateSession(w http.ResponseWriter, r *http.Request, assertion *saml.Assertion) error + + // DeleteSession is called to modify the response such that it removed the current + // session, e.g. by deleting a cookie. + DeleteSession(w http.ResponseWriter, r *http.Request) error + + // GetSession returns the current Session associated with the request, or + // ErrNoSession if there is no valid session. + GetSession(r *http.Request) (Session, error) +} + +// SessionCodec is an interface to convert SAML assertions to a +// Session. The default implementation uses JWTs, JWTSessionCodec. +type SessionCodec interface { + // New creates a Session from the SAML assertion. + New(assertion *saml.Assertion) (Session, error) + + // Encode returns a serialized version of the Session. + // + // Note: When implementing this function, it is reasonable to expect that + // Session is of the exact type returned by New(), and panic if it is not. + Encode(s Session) (string, error) + + // Decode parses the serialized session that may have been returned by Encode + // and returns a Session. + Decode(string) (Session, error) +} + +type indexType int + +const sessionIndex indexType = iota + +// SessionFromContext returns the session associated with ctx, or nil +// if no session are associated +func SessionFromContext(ctx context.Context) Session { + v := ctx.Value(sessionIndex) + if v == nil { + return nil + } + return v.(Session) +} + +// ContextWithSession returns a new context with session associated +func ContextWithSession(ctx context.Context, session Session) context.Context { + return context.WithValue(ctx, sessionIndex, session) +} + +// AttributeFromContext is a convenience method that returns the named attribute +// from the session, if available. +func AttributeFromContext(ctx context.Context, name string) string { + s := SessionFromContext(ctx) + if s == nil { + return "" + } + sa, ok := s.(SessionWithAttributes) + if !ok { + return "" + } + return sa.GetAttributes().Get(name) +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/session_cookie.go b/vendor/github.com/mickael-kerjean/saml/samlsp/session_cookie.go new file mode 100644 index 00000000..dbdc6cd2 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/session_cookie.go @@ -0,0 +1,99 @@ +package samlsp + +import ( + "net" + "net/http" + "time" + + "github.com/mickael-kerjean/saml" +) + +const defaultSessionCookieName = "token" + +var _ SessionProvider = CookieSessionProvider{} + +// CookieSessionProvider is an implementation of SessionProvider that stores +// session tokens in an HTTP cookie. +type CookieSessionProvider struct { + Name string + Domain string + HTTPOnly bool + Secure bool + SameSite http.SameSite + MaxAge time.Duration + Codec SessionCodec +} + +// CreateSession is called when we have received a valid SAML assertion and +// should create a new session and modify the http response accordingly, e.g. by +// setting a cookie. +func (c CookieSessionProvider) CreateSession(w http.ResponseWriter, r *http.Request, assertion *saml.Assertion) error { + // Cookies should not have the port attached to them so strip it off + if domain, _, err := net.SplitHostPort(c.Domain); err == nil { + c.Domain = domain + } + + session, err := c.Codec.New(assertion) + if err != nil { + return err + } + + value, err := c.Codec.Encode(session) + if err != nil { + return err + } + + http.SetCookie(w, &http.Cookie{ + Name: c.Name, + Domain: c.Domain, + Value: value, + MaxAge: int(c.MaxAge.Seconds()), + HttpOnly: c.HTTPOnly, + Secure: c.Secure || r.URL.Scheme == "https", + SameSite: c.SameSite, + Path: "/", + }) + return nil +} + +// DeleteSession is called to modify the response such that it removed the current +// session, e.g. by deleting a cookie. +func (c CookieSessionProvider) DeleteSession(w http.ResponseWriter, r *http.Request) error { + // Cookies should not have the port attached to them so strip it off + if domain, _, err := net.SplitHostPort(c.Domain); err == nil { + c.Domain = domain + } + + cookie, err := r.Cookie(c.Name) + + if err == http.ErrNoCookie { + return nil + } + if err != nil { + return err + } + + cookie.Value = "" + cookie.Expires = time.Unix(1, 0) // past time as close to epoch as possible, but not zero time.Time{} + cookie.Path = "/" + cookie.Domain = c.Domain + http.SetCookie(w, cookie) + return nil +} + +// GetSession returns the current Session associated with the request, or +// ErrNoSession if there is no valid session. +func (c CookieSessionProvider) GetSession(r *http.Request) (Session, error) { + cookie, err := r.Cookie(c.Name) + if err == http.ErrNoCookie { + return nil, ErrNoSession + } else if err != nil { + return nil, err + } + + session, err := c.Codec.Decode(cookie.Value) + if err != nil { + return nil, ErrNoSession + } + return session, nil +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/session_jwt.go b/vendor/github.com/mickael-kerjean/saml/samlsp/session_jwt.go new file mode 100644 index 00000000..e6213bcd --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/session_jwt.go @@ -0,0 +1,143 @@ +package samlsp + +import ( + "crypto/rsa" + "errors" + "fmt" + "time" + + "github.com/golang-jwt/jwt/v4" + + "github.com/mickael-kerjean/saml" +) + +const ( + defaultSessionMaxAge = time.Hour + claimNameSessionIndex = "SessionIndex" +) + +// JWTSessionCodec implements SessionCoded to encode and decode Sessions from +// the corresponding JWT. +type JWTSessionCodec struct { + SigningMethod jwt.SigningMethod + Audience string + Issuer string + MaxAge time.Duration + Key *rsa.PrivateKey +} + +var _ SessionCodec = JWTSessionCodec{} + +// New creates a Session from the SAML assertion. +// +// The returned Session is a JWTSessionClaims. +func (c JWTSessionCodec) New(assertion *saml.Assertion) (Session, error) { + now := saml.TimeNow() + claims := JWTSessionClaims{} + claims.SAMLSession = true + claims.Audience = c.Audience + claims.Issuer = c.Issuer + claims.IssuedAt = now.Unix() + claims.ExpiresAt = now.Add(c.MaxAge).Unix() + claims.NotBefore = now.Unix() + + if sub := assertion.Subject; sub != nil { + if nameID := sub.NameID; nameID != nil { + claims.Subject = nameID.Value + } + } + + claims.Attributes = map[string][]string{} + + for _, attributeStatement := range assertion.AttributeStatements { + for _, attr := range attributeStatement.Attributes { + claimName := attr.FriendlyName + if claimName == "" { + claimName = attr.Name + } + for _, value := range attr.Values { + claims.Attributes[claimName] = append(claims.Attributes[claimName], value.Value) + } + } + } + + // add SessionIndex to claims Attributes + for _, authnStatement := range assertion.AuthnStatements { + claims.Attributes[claimNameSessionIndex] = append(claims.Attributes[claimNameSessionIndex], + authnStatement.SessionIndex) + } + + return claims, nil +} + +// Encode returns a serialized version of the Session. +// +// The provided session must be a JWTSessionClaims, otherwise this +// function will panic. +func (c JWTSessionCodec) Encode(s Session) (string, error) { + claims := s.(JWTSessionClaims) // this will panic if you pass the wrong kind of session + + token := jwt.NewWithClaims(c.SigningMethod, claims) + signedString, err := token.SignedString(c.Key) + if err != nil { + return "", err + } + + return signedString, nil +} + +// Decode parses the serialized session that may have been returned by Encode +// and returns a Session. +func (c JWTSessionCodec) Decode(signed string) (Session, error) { + parser := jwt.Parser{ + ValidMethods: []string{c.SigningMethod.Alg()}, + } + claims := JWTSessionClaims{} + _, err := parser.ParseWithClaims(signed, &claims, func(*jwt.Token) (interface{}, error) { + return c.Key.Public(), nil + }) + // TODO(ross): check for errors due to bad time and return ErrNoSession + if err != nil { + return nil, err + } + if !claims.VerifyAudience(c.Audience, true) { + return nil, fmt.Errorf("expected audience %q, got %q", c.Audience, claims.Audience) + } + if !claims.VerifyIssuer(c.Issuer, true) { + return nil, fmt.Errorf("expected issuer %q, got %q", c.Issuer, claims.Issuer) + } + if claims.SAMLSession != true { + return nil, errors.New("expected saml-session") + } + return claims, nil +} + +// JWTSessionClaims represents the JWT claims in the encoded session +type JWTSessionClaims struct { + jwt.StandardClaims + Attributes Attributes `json:"attr"` + SAMLSession bool `json:"saml-session"` +} + +var _ Session = JWTSessionClaims{} + +// GetAttributes implements SessionWithAttributes. It returns the SAMl attributes. +func (c JWTSessionClaims) GetAttributes() Attributes { + return c.Attributes +} + +// Attributes is a map of attributes provided in the SAML assertion +type Attributes map[string][]string + +// Get returns the first attribute named `key` or an empty string if +// no such attributes is present. +func (a Attributes) Get(key string) string { + if a == nil { + return "" + } + v := a[key] + if len(v) == 0 { + return "" + } + return v[0] +} diff --git a/vendor/github.com/mickael-kerjean/saml/samlsp/util.go b/vendor/github.com/mickael-kerjean/saml/samlsp/util.go new file mode 100644 index 00000000..e5c9cc9b --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/samlsp/util.go @@ -0,0 +1,16 @@ +package samlsp + +import ( + "io" + + "github.com/mickael-kerjean/saml" +) + +func randomBytes(n int) []byte { + rv := make([]byte, n) + + if _, err := io.ReadFull(saml.RandReader, rv); err != nil { + panic(err) + } + return rv +} diff --git a/vendor/github.com/mickael-kerjean/saml/schema.go b/vendor/github.com/mickael-kerjean/saml/schema.go new file mode 100644 index 00000000..e7771880 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/schema.go @@ -0,0 +1,1321 @@ +package saml + +import ( + "bytes" + "compress/flate" + "encoding/xml" + "strconv" + "time" + + "github.com/beevik/etree" + "github.com/russellhaering/goxmldsig/etreeutils" +) + +// RequestedAuthnContext represents the SAML object of the same name, an indication of the +// requirements on the authentication process. +type RequestedAuthnContext struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol RequestedAuthnContext"` + Comparison string `xml:",attr"` + AuthnContextClassRef string `xml:"urn:oasis:names:tc:SAML:2.0:assertion AuthnContextClassRef"` +} + +// Element returns an etree.Element representing the object in XML form. +func (r *RequestedAuthnContext) Element() *etree.Element { + el := etree.NewElement("samlp:RequestedAuthnContext") + el.CreateAttr("Comparison", r.Comparison) + elContext := etree.NewElement("saml:AuthnContextClassRef") + elContext.SetText(r.AuthnContextClassRef) + el.AddChild(elContext) + return el +} + +// AuthnRequest represents the SAML object of the same name, a request from a service provider +// to authenticate a user. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf +type AuthnRequest struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol AuthnRequest"` + + ID string `xml:",attr"` + Version string `xml:",attr"` + IssueInstant time.Time `xml:",attr"` + Destination string `xml:",attr"` + Consent string `xml:",attr"` + Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` + Signature *etree.Element + + Subject *Subject + NameIDPolicy *NameIDPolicy `xml:"urn:oasis:names:tc:SAML:2.0:protocol NameIDPolicy"` + Conditions *Conditions + RequestedAuthnContext *RequestedAuthnContext + //Scoping *Scoping // TODO + + ForceAuthn *bool `xml:",attr"` + IsPassive *bool `xml:",attr"` + AssertionConsumerServiceIndex string `xml:",attr"` + AssertionConsumerServiceURL string `xml:",attr"` + ProtocolBinding string `xml:",attr"` + AttributeConsumingServiceIndex string `xml:",attr"` + ProviderName string `xml:",attr"` +} + +// LogoutRequest represents the SAML object of the same name, a request from an IDP +// to destroy a user's session. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf +type LogoutRequest struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol LogoutRequest"` + + ID string `xml:",attr"` + Version string `xml:",attr"` + IssueInstant time.Time `xml:",attr"` + NotOnOrAfter *time.Time `xml:",attr"` + Destination string `xml:",attr"` + Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` + NameID *NameID + Signature *etree.Element + + SessionIndex *SessionIndex `xml:"SessionIndex"` +} + +// Element returns an etree.Element representing the object in XML form. +func (r *LogoutRequest) Element() *etree.Element { + el := etree.NewElement("samlp:LogoutRequest") + el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") + el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") + el.CreateAttr("ID", r.ID) + el.CreateAttr("Version", r.Version) + el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) + if r.NotOnOrAfter != nil { + el.CreateAttr("NotOnOrAfter", r.NotOnOrAfter.Format(timeFormat)) + } + if r.Destination != "" { + el.CreateAttr("Destination", r.Destination) + } + if r.Issuer != nil { + el.AddChild(r.Issuer.Element()) + } + if r.Signature != nil { + el.AddChild(r.Signature) + } + if r.NameID != nil { + el.AddChild(r.NameID.Element()) + } + if r.SessionIndex != nil { + el.AddChild(r.SessionIndex.Element()) + } + return el +} + +// MarshalXML implements xml.Marshaler +func (r *LogoutRequest) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias LogoutRequest + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + NotOnOrAfter *RelaxedTime `xml:",attr"` + *Alias + }{ + IssueInstant: RelaxedTime(r.IssueInstant), + NotOnOrAfter: (*RelaxedTime)(r.NotOnOrAfter), + Alias: (*Alias)(r), + } + return e.Encode(aux) +} + +// UnmarshalXML implements xml.Unmarshaler +func (r *LogoutRequest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias LogoutRequest + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + NotOnOrAfter *RelaxedTime `xml:",attr"` + *Alias + }{ + Alias: (*Alias)(r), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + r.IssueInstant = time.Time(aux.IssueInstant) + r.NotOnOrAfter = (*time.Time)(aux.NotOnOrAfter) + return nil +} + +// Bytes returns a byte array representation of the LogoutRequest +func (r *LogoutRequest) Bytes() ([]byte, error) { + doc := etree.NewDocument() + doc.SetRoot(r.Element()) + + buf, err := doc.WriteToBytes() + if err != nil { + return nil, err + } + + return buf, nil +} + +// Deflate returns a compressed byte array of the LogoutRequest +func (r *LogoutRequest) Deflate() ([]byte, error) { + buf, err := r.Bytes() + if err != nil { + return nil, err + } + + var b bytes.Buffer + writer, err := flate.NewWriter(&b, flate.DefaultCompression) + if err != nil { + return nil, err + } + + if _, err := writer.Write(buf); err != nil { + return nil, err + } + + if err := writer.Close(); err != nil { + return nil, err + } + + return b.Bytes(), nil +} + +// Element returns an etree.Element representing the object in XML form. +func (r *AuthnRequest) Element() *etree.Element { + el := etree.NewElement("samlp:AuthnRequest") + el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") + el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") + el.CreateAttr("ID", r.ID) + el.CreateAttr("Version", r.Version) + el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) + if r.Destination != "" { + el.CreateAttr("Destination", r.Destination) + } + if r.Consent != "" { + el.CreateAttr("Consent", r.Consent) + } + if r.Issuer != nil { + el.AddChild(r.Issuer.Element()) + } + if r.Signature != nil { + el.AddChild(r.Signature) + } + if r.Subject != nil { + el.AddChild(r.Subject.Element()) + } + if r.NameIDPolicy != nil { + el.AddChild(r.NameIDPolicy.Element()) + } + if r.Conditions != nil { + el.AddChild(r.Conditions.Element()) + } + if r.RequestedAuthnContext != nil { + el.AddChild(r.RequestedAuthnContext.Element()) + } + //if r.Scoping != nil { + // el.AddChild(r.Scoping.Element()) + //} + if r.ForceAuthn != nil { + el.CreateAttr("ForceAuthn", strconv.FormatBool(*r.ForceAuthn)) + } + if r.IsPassive != nil { + el.CreateAttr("IsPassive", strconv.FormatBool(*r.IsPassive)) + } + if r.AssertionConsumerServiceIndex != "" { + el.CreateAttr("AssertionConsumerServiceIndex", r.AssertionConsumerServiceIndex) + } + if r.AssertionConsumerServiceURL != "" { + el.CreateAttr("AssertionConsumerServiceURL", r.AssertionConsumerServiceURL) + } + if r.ProtocolBinding != "" { + el.CreateAttr("ProtocolBinding", r.ProtocolBinding) + } + if r.AttributeConsumingServiceIndex != "" { + el.CreateAttr("AttributeConsumingServiceIndex", r.AttributeConsumingServiceIndex) + } + if r.ProviderName != "" { + el.CreateAttr("ProviderName", r.ProviderName) + } + return el +} + +// MarshalXML implements xml.Marshaler +func (r *AuthnRequest) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias AuthnRequest + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + IssueInstant: RelaxedTime(r.IssueInstant), + Alias: (*Alias)(r), + } + return e.Encode(aux) +} + +// UnmarshalXML implements xml.Unmarshaler +func (r *AuthnRequest) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias AuthnRequest + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + Alias: (*Alias)(r), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + r.IssueInstant = time.Time(aux.IssueInstant) + return nil +} + +// Issuer represents the SAML object of the same name. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf +type Issuer struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` + NameQualifier string `xml:",attr"` + SPNameQualifier string `xml:",attr"` + Format string `xml:",attr"` + SPProvidedID string `xml:",attr"` + Value string `xml:",chardata"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *Issuer) Element() *etree.Element { + el := etree.NewElement("saml:Issuer") + if a.NameQualifier != "" { + el.CreateAttr("NameQualifier", a.NameQualifier) + } + if a.SPNameQualifier != "" { + el.CreateAttr("SPNameQualifier", a.SPNameQualifier) + } + if a.Format != "" { + el.CreateAttr("Format", a.Format) + } + if a.SPProvidedID != "" { + el.CreateAttr("SPProvidedID", a.SPProvidedID) + } + el.SetText(a.Value) + return el +} + +// NameIDPolicy represents the SAML object of the same name. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf +type NameIDPolicy struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol NameIDPolicy"` + Format *string `xml:",attr"` + SPNameQualifier *string `xml:",attr"` + AllowCreate *bool `xml:",attr"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *NameIDPolicy) Element() *etree.Element { + el := etree.NewElement("samlp:NameIDPolicy") + if a.Format != nil && *a.Format != "" { + el.CreateAttr("Format", *a.Format) + } + if a.SPNameQualifier != nil { + el.CreateAttr("SPNameQualifier", *a.SPNameQualifier) + } + if a.AllowCreate != nil { + el.CreateAttr("AllowCreate", strconv.FormatBool(*a.AllowCreate)) + } + return el +} + +// ArtifactResolve represents the SAML object of the same name. +type ArtifactResolve struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol ArtifactResolve"` + ID string `xml:",attr"` + Version string `xml:",attr"` + IssueInstant time.Time `xml:",attr"` + Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` + Signature *etree.Element + Artifact string `xml:"urn:oasis:names:tc:SAML:2.0:protocol Artifact"` +} + +// Element returns an etree.Element representing the object in XML form. +func (r *ArtifactResolve) Element() *etree.Element { + el := etree.NewElement("samlp:ArtifactResolve") + el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") + el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") + + // Note: This namespace is not used by any element or attribute name, but + // is required so that the AttributeValue type element can have a value like + // "xs:string". If we don't declare it here, then it will be stripped by the + // cannonicalizer. This could be avoided by providing a prefix list to the + // cannonicalizer, but prefix lists do not appear to be implemented correctly + // in some libraries, so the safest action is to always produce XML that is + // (a) in canonical form and (b) does not require prefix lists. + el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") + + el.CreateAttr("ID", r.ID) + el.CreateAttr("Version", r.Version) + el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) + if r.Issuer != nil { + el.AddChild(r.Issuer.Element()) + } + artifact := etree.NewElement("samlp:Artifact") + artifact.SetText(r.Artifact) + el.AddChild(artifact) + if r.Signature != nil { + el.AddChild(r.Signature) + } + return el +} + +// SoapRequest returns a SOAP Envelope contining the ArtifactResolve request +func (r *ArtifactResolve) SoapRequest() *etree.Element { + envelope := etree.NewElement("soapenv:Envelope") + envelope.CreateAttr("xmlns:soapenv", "http://schemas.xmlsoap.org/soap/envelope/") + envelope.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") + body := etree.NewElement("soapenv:Body") + envelope.AddChild(body) + body.AddChild(r.Element()) + return envelope +} + +// MarshalXML implements xml.Marshaler +func (r *ArtifactResolve) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias ArtifactResolve + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + IssueInstant: RelaxedTime(r.IssueInstant), + Alias: (*Alias)(r), + } + return e.Encode(aux) +} + +// UnmarshalXML implements xml.Unmarshaler +func (r *ArtifactResolve) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias ArtifactResolve + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + Alias: (*Alias)(r), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + r.IssueInstant = time.Time(aux.IssueInstant) + return nil +} + +// ArtifactResponse represents the SAML object of the same name. +type ArtifactResponse struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol ArtifactResponse"` + ID string `xml:",attr"` + InResponseTo string `xml:",attr"` + Version string `xml:",attr"` + IssueInstant time.Time `xml:",attr"` + Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` + Signature *etree.Element + Status Status `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"` + Response Response `xml:"urn:oasis:names:tc:SAML:2.0:protocol Response"` +} + +// Element returns an etree.Element representing the object in XML form. +func (r *ArtifactResponse) Element() *etree.Element { + el := etree.NewElement("samlp:ArtifactResponse") + el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") + el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") + + // Note: This namespace is not used by any element or attribute name, but + // is required so that the AttributeValue type element can have a value like + // "xs:string". If we don't declare it here, then it will be stripped by the + // cannonicalizer. This could be avoided by providing a prefix list to the + // cannonicalizer, but prefix lists do not appear to be implemented correctly + // in some libraries, so the safest action is to always produce XML that is + // (a) in canonical form and (b) does not require prefix lists. + el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") + + el.CreateAttr("ID", r.ID) + if r.InResponseTo != "" { + el.CreateAttr("InResponseTo", r.InResponseTo) + } + el.CreateAttr("Version", r.Version) + el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) + if r.Issuer != nil { + el.AddChild(r.Issuer.Element()) + } + if r.Signature != nil { + el.AddChild(r.Signature) + } + el.AddChild(r.Status.Element()) + el.AddChild(r.Response.Element()) + return el +} + +// MarshalXML implements xml.Marshaler +func (r *ArtifactResponse) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias ArtifactResponse + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + IssueInstant: RelaxedTime(r.IssueInstant), + Alias: (*Alias)(r), + } + return e.Encode(aux) +} + +// UnmarshalXML implements xml.Unmarshaler +func (r *ArtifactResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias ArtifactResponse + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + Alias: (*Alias)(r), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + r.IssueInstant = time.Time(aux.IssueInstant) + return nil +} + +// Response represents the SAML object of the same name. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf +type Response struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Response"` + ID string `xml:",attr"` + InResponseTo string `xml:",attr"` + Version string `xml:",attr"` + IssueInstant time.Time `xml:",attr"` + Destination string `xml:",attr"` + Consent string `xml:",attr"` + Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` + Signature *etree.Element + Status Status `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"` + + // TODO(ross): more than one EncryptedAssertion is allowed + EncryptedAssertion *etree.Element `xml:"urn:oasis:names:tc:SAML:2.0:assertion EncryptedAssertion"` + + // TODO(ross): more than one Assertion is allowed + Assertion *Assertion `xml:"urn:oasis:names:tc:SAML:2.0:assertion Assertion"` +} + +// Element returns an etree.Element representing the object in XML form. +func (r *Response) Element() *etree.Element { + el := etree.NewElement("samlp:Response") + el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") + el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") + + // Note: This namespace is not used by any element or attribute name, but + // is required so that the AttributeValue type element can have a value like + // "xs:string". If we don't declare it here, then it will be stripped by the + // cannonicalizer. This could be avoided by providing a prefix list to the + // cannonicalizer, but prefix lists do not appear to be implemented correctly + // in some libraries, so the safest action is to always produce XML that is + // (a) in canonical form and (b) does not require prefix lists. + el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") + + el.CreateAttr("ID", r.ID) + if r.InResponseTo != "" { + el.CreateAttr("InResponseTo", r.InResponseTo) + } + el.CreateAttr("Version", r.Version) + el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) + if r.Destination != "" { + el.CreateAttr("Destination", r.Destination) + } + if r.Consent != "" { + el.CreateAttr("Consent", r.Consent) + } + if r.Issuer != nil { + el.AddChild(r.Issuer.Element()) + } + if r.Signature != nil { + el.AddChild(r.Signature) + } + el.AddChild(r.Status.Element()) + if r.EncryptedAssertion != nil { + el.AddChild(r.EncryptedAssertion) + } + if r.Assertion != nil { + el.AddChild(r.Assertion.Element()) + } + return el +} + +// MarshalXML implements xml.Marshaler +func (r *Response) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias Response + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + IssueInstant: RelaxedTime(r.IssueInstant), + Alias: (*Alias)(r), + } + return e.Encode(aux) +} + +// UnmarshalXML implements xml.Unmarshaler +func (r *Response) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias Response + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + Alias: (*Alias)(r), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + r.IssueInstant = time.Time(aux.IssueInstant) + return nil +} + +// Status represents the SAML object of the same name. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf +type Status struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"` + StatusCode StatusCode + StatusMessage *StatusMessage + StatusDetail *StatusDetail +} + +// Element returns an etree.Element representing the object in XML form. +func (s *Status) Element() *etree.Element { + el := etree.NewElement("samlp:Status") + el.AddChild(s.StatusCode.Element()) + if s.StatusMessage != nil { + el.AddChild(s.StatusMessage.Element()) + } + if s.StatusDetail != nil { + el.AddChild(s.StatusDetail.Element()) + } + return el +} + +// StatusCode represents the SAML object of the same name. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf +type StatusCode struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol StatusCode"` + Value string `xml:",attr"` + StatusCode *StatusCode +} + +// Element returns an etree.Element representing the object in XML form. +func (s *StatusCode) Element() *etree.Element { + el := etree.NewElement("samlp:StatusCode") + el.CreateAttr("Value", s.Value) + if s.StatusCode != nil { + el.AddChild(s.StatusCode.Element()) + } + return el +} + +// StatusSuccess means the request succeeded. Additional information MAY be returned in the and/or elements. +// +// TODO(ross): this value is mostly constant, but is mutated in tests. Fix the hacky test so this can be const. +var StatusSuccess = "urn:oasis:names:tc:SAML:2.0:status:Success" + +const ( + // The permissible top-level values are as follows: + + // StatusRequester means the request could not be performed due to an error on the part of the requester. + StatusRequester = "urn:oasis:names:tc:SAML:2.0:status:Requester" + + // StatusResponder means the request could not be performed due to an error on the part of the SAML responder or SAML authority. + StatusResponder = "urn:oasis:names:tc:SAML:2.0:status:Responder" + + // StatusVersionMismatch means the SAML responder could not process the request because the version of the request message was incorrect. + StatusVersionMismatch = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch" + + // The following second-level status codes are referenced at various places in this specification. Additional + // second-level status codes MAY be defined in future versions of the SAML specification. System entities + // are free to define more specific status codes by defining appropriate URI references. + + // StatusAuthnFailed means the responding provider was unable to successfully authenticate the principal. + StatusAuthnFailed = "urn:oasis:names:tc:SAML:2.0:status:AuthnFailed" + + // StatusInvalidAttrNameOrValue means Unexpected or invalid content was encountered within a or element. + StatusInvalidAttrNameOrValue = "urn:oasis:names:tc:SAML:2.0:status:InvalidAttrNameOrValue" + + // StatusInvalidNameIDPolicy means the responding provider cannot or will not support the requested name identifier policy. + StatusInvalidNameIDPolicy = "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy" + + // StatusNoAuthnContext means the specified authentication context requirements cannot be met by the responder. + StatusNoAuthnContext = "urn:oasis:names:tc:SAML:2.0:status:NoAuthnContext" + + // StatusNoAvailableIDP is used by an intermediary to indicate that none of the supported identity provider elements in an can be resolved or that none of the supported identity providers are available. + StatusNoAvailableIDP = "urn:oasis:names:tc:SAML:2.0:status:NoAvailableIDP" + + // StatusNoPassive means Indicates the responding provider cannot authenticate the principal passively, as has been requested. + StatusNoPassive = "urn:oasis:names:tc:SAML:2.0:status:NoPassive" //nolint:gosec + + // StatusNoSupportedIDP is used by an intermediary to indicate that none of the identity providers in an are supported by the intermediary. + StatusNoSupportedIDP = "urn:oasis:names:tc:SAML:2.0:status:NoSupportedIDP" + + // StatusPartialLogout is used by a session authority to indicate to a session participant that it was not able to propagate logout to all other session participants. + StatusPartialLogout = "urn:oasis:names:tc:SAML:2.0:status:PartialLogout" + + // StatusProxyCountExceeded means Indicates that a responding provider cannot authenticate the principal directly and is not permitted to proxy the request further. + StatusProxyCountExceeded = "urn:oasis:names:tc:SAML:2.0:status:ProxyCountExceeded" + + // StatusRequestDenied means the SAML responder or SAML authority is able to process the request but has chosen not to respond. This status code MAY be used when there is concern about the security context of the request message or the sequence of request messages received from a particular requester. + StatusRequestDenied = "urn:oasis:names:tc:SAML:2.0:status:RequestDenied" + + // StatusRequestUnsupported means the SAML responder or SAML authority does not support the request. + StatusRequestUnsupported = "urn:oasis:names:tc:SAML:2.0:status:RequestUnsupported" + + // StatusRequestVersionDeprecated means the SAML responder cannot process any requests with the protocol version specified in the request. + StatusRequestVersionDeprecated = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionDeprecated" + + // StatusRequestVersionTooHigh means the SAML responder cannot process the request because the protocol version specified in the request message is a major upgrade from the highest protocol version supported by the responder. + StatusRequestVersionTooHigh = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooHigh" + + // StatusRequestVersionTooLow means the SAML responder cannot process the request because the protocol version specified in the request message is too low. + StatusRequestVersionTooLow = "urn:oasis:names:tc:SAML:2.0:status:RequestVersionTooLow" + + // StatusResourceNotRecognized means the resource value provided in the request message is invalid or unrecognized. + StatusResourceNotRecognized = "urn:oasis:names:tc:SAML:2.0:status:ResourceNotRecognized" + + // StatusTooManyResponses means the response message would contain more elements than the SAML responder is able to return. + StatusTooManyResponses = "urn:oasis:names:tc:SAML:2.0:status:TooManyResponses" + + // StatusUnknownAttrProfile means an entity that has no knowledge of a particular attribute profile has been presented with an attribute means drawn from that profile. + StatusUnknownAttrProfile = "urn:oasis:names:tc:SAML:2.0:status:UnknownAttrProfile" + + // StatusUnknownPrincipal means the responding provider does not recognize the principal specified or implied by the request. + StatusUnknownPrincipal = "urn:oasis:names:tc:SAML:2.0:status:UnknownPrincipal" + + // StatusUnsupportedBinding means the SAML responder cannot properly fulfill the request using the protocol binding specified in the request. + StatusUnsupportedBinding = "urn:oasis:names:tc:SAML:2.0:status:UnsupportedBinding" +) + +// StatusMessage represents the SAML element StatusMessage. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.2.2.3 +type StatusMessage struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol StatusMessage"` + Value string `xml:",chardata"` +} + +// Element returns an etree.Element representing the object in XML form. +func (sm StatusMessage) Element() *etree.Element { + el := etree.NewElement("samlp:StatusMessage") + el.SetText(sm.Value) + return el +} + +// StatusDetail represents the SAML element StatusDetail. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.2.2.4 +type StatusDetail struct { + Children []*etree.Element +} + +// Element returns an etree.Element representing the object in XML form. +func (sm StatusDetail) Element() *etree.Element { + el := etree.NewElement("samlp:StatusDetail") + for _, child := range sm.Children { + el.AddChild(child) + } + return el +} + +// Assertion represents the SAML element Assertion. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.3.3 +type Assertion struct { + XMLName xml.Name `xml:"Assertion"` + ID string `xml:",attr"` + IssueInstant time.Time `xml:",attr"` + Version string `xml:",attr"` + Issuer Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` + Signature *etree.Element + Subject *Subject + Conditions *Conditions + // Advice *Advice + // Statements []Statement + AuthnStatements []AuthnStatement `xml:"AuthnStatement"` + // AuthzDecisionStatements []AuthzDecisionStatement + AttributeStatements []AttributeStatement `xml:"AttributeStatement"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *Assertion) Element() *etree.Element { + el := etree.NewElement("saml:Assertion") + el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") + el.CreateAttr("Version", "2.0") + el.CreateAttr("ID", a.ID) + el.CreateAttr("IssueInstant", a.IssueInstant.Format(timeFormat)) + el.AddChild(a.Issuer.Element()) + if a.Signature != nil { + el.AddChild(a.Signature) + } + if a.Subject != nil { + el.AddChild(a.Subject.Element()) + } + if a.Conditions != nil { + el.AddChild(a.Conditions.Element()) + } + for _, authnStatement := range a.AuthnStatements { + el.AddChild(authnStatement.Element()) + } + for _, attributeStatement := range a.AttributeStatements { + el.AddChild(attributeStatement.Element()) + } + err := etreeutils.TransformExcC14n(el, canonicalizerPrefixList) + if err != nil { + panic(err) + } + return el +} + +// UnmarshalXML implements xml.Unmarshaler +func (a *Assertion) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias Assertion + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + Alias: (*Alias)(a), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + a.IssueInstant = time.Time(aux.IssueInstant) + return nil +} + +// Subject represents the SAML element Subject. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1 +type Subject struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:assertion Subject"` + // BaseID *BaseID ... TODO + NameID *NameID + // EncryptedID *EncryptedID ... TODO + SubjectConfirmations []SubjectConfirmation `xml:"SubjectConfirmation"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *Subject) Element() *etree.Element { + el := etree.NewElement("saml:Subject") + if a.NameID != nil { + el.AddChild(a.NameID.Element()) + } + for _, v := range a.SubjectConfirmations { + el.AddChild(v.Element()) + } + return el +} + +// NameID represents the SAML element NameID. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.2.3 +type NameID struct { + NameQualifier string `xml:",attr"` + SPNameQualifier string `xml:",attr"` + Format string `xml:",attr"` + SPProvidedID string `xml:",attr"` + Value string `xml:",chardata"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *NameID) Element() *etree.Element { + el := etree.NewElement("saml:NameID") + if a.NameQualifier != "" { + el.CreateAttr("NameQualifier", a.NameQualifier) + } + if a.SPNameQualifier != "" { + el.CreateAttr("SPNameQualifier", a.SPNameQualifier) + } + if a.Format != "" { + el.CreateAttr("Format", a.Format) + } + if a.SPProvidedID != "" { + el.CreateAttr("SPProvidedID", a.SPProvidedID) + } + if a.Value != "" { + el.SetText(a.Value) + } + return el +} + +// SessionIndex represents the SAML element SessionIndex. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §3.7.1 +type SessionIndex struct { + Value string `xml:",chardata"` +} + +// Element returns an etree.Element representing the object in XML form. +func (s *SessionIndex) Element() *etree.Element { + el := etree.NewElement("samlp:SessionIndex") + el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") + if s.Value != "" { + el.SetText(s.Value) + } + return el +} + +// SubjectConfirmation represents the SAML element SubjectConfirmation. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1.1 +type SubjectConfirmation struct { + Method string `xml:",attr"` + // BaseID *BaseID ... TODO + NameID *NameID + // EncryptedID *EncryptedID ... TODO + SubjectConfirmationData *SubjectConfirmationData +} + +// Element returns an etree.Element representing the object in XML form. +func (a *SubjectConfirmation) Element() *etree.Element { + el := etree.NewElement("saml:SubjectConfirmation") + el.CreateAttr("Method", a.Method) + if a.NameID != nil { + el.AddChild(a.NameID.Element()) + } + if a.SubjectConfirmationData != nil { + el.AddChild(a.SubjectConfirmationData.Element()) + } + return el +} + +// SubjectConfirmationData represents the SAML element SubjectConfirmationData. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.4.1.2 +type SubjectConfirmationData struct { + NotBefore time.Time `xml:",attr"` + NotOnOrAfter time.Time `xml:",attr"` + Recipient string `xml:",attr"` + InResponseTo string `xml:",attr"` + Address string `xml:",attr"` +} + +// Element returns an etree.Element representing the object in XML form. +func (s *SubjectConfirmationData) Element() *etree.Element { + el := etree.NewElement("saml:SubjectConfirmationData") + if !s.NotBefore.IsZero() { + el.CreateAttr("NotBefore", s.NotBefore.Format(timeFormat)) + } + if !s.NotOnOrAfter.IsZero() { + el.CreateAttr("NotOnOrAfter", s.NotOnOrAfter.Format(timeFormat)) + } + if s.Recipient != "" { + el.CreateAttr("Recipient", s.Recipient) + } + if s.InResponseTo != "" { + el.CreateAttr("InResponseTo", s.InResponseTo) + } + if s.Address != "" { + el.CreateAttr("Address", s.Address) + } + return el +} + +// MarshalXML implements xml.Marshaler +func (s *SubjectConfirmationData) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias SubjectConfirmationData + aux := &struct { + NotOnOrAfter RelaxedTime `xml:",attr"` + *Alias + }{ + NotOnOrAfter: RelaxedTime(s.NotOnOrAfter), + Alias: (*Alias)(s), + } + return e.EncodeElement(aux, start) +} + +// UnmarshalXML implements xml.Unmarshaler +func (s *SubjectConfirmationData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias SubjectConfirmationData + aux := &struct { + NotOnOrAfter RelaxedTime `xml:",attr"` + *Alias + }{ + Alias: (*Alias)(s), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + s.NotOnOrAfter = time.Time(aux.NotOnOrAfter) + return nil +} + +// Conditions represents the SAML element Conditions. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1 +type Conditions struct { + NotBefore time.Time `xml:",attr"` + NotOnOrAfter time.Time `xml:",attr"` + AudienceRestrictions []AudienceRestriction `xml:"AudienceRestriction"` + OneTimeUse *OneTimeUse + ProxyRestriction *ProxyRestriction +} + +// Element returns an etree.Element representing the object in XML form. +func (c *Conditions) Element() *etree.Element { + el := etree.NewElement("saml:Conditions") + if !c.NotBefore.IsZero() { + el.CreateAttr("NotBefore", c.NotBefore.Format(timeFormat)) + } + if !c.NotOnOrAfter.IsZero() { + el.CreateAttr("NotOnOrAfter", c.NotOnOrAfter.Format(timeFormat)) + } + for _, v := range c.AudienceRestrictions { + el.AddChild(v.Element()) + } + if c.OneTimeUse != nil { + el.AddChild(c.OneTimeUse.Element()) + } + if c.ProxyRestriction != nil { + el.AddChild(c.ProxyRestriction.Element()) + } + return el +} + +// MarshalXML implements xml.Marshaler +func (c *Conditions) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias Conditions + aux := &struct { + NotBefore RelaxedTime `xml:",attr"` + NotOnOrAfter RelaxedTime `xml:",attr"` + *Alias + }{ + NotBefore: RelaxedTime(c.NotBefore), + NotOnOrAfter: RelaxedTime(c.NotOnOrAfter), + Alias: (*Alias)(c), + } + return e.EncodeElement(aux, start) +} + +// UnmarshalXML implements xml.Unmarshaler +func (c *Conditions) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias Conditions + aux := &struct { + NotBefore RelaxedTime `xml:",attr"` + NotOnOrAfter RelaxedTime `xml:",attr"` + *Alias + }{ + Alias: (*Alias)(c), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + c.NotBefore = time.Time(aux.NotBefore) + c.NotOnOrAfter = time.Time(aux.NotOnOrAfter) + return nil +} + +// AudienceRestriction represents the SAML element AudienceRestriction. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.4 +type AudienceRestriction struct { + Audience Audience +} + +// Element returns an etree.Element representing the object in XML form. +func (a *AudienceRestriction) Element() *etree.Element { + el := etree.NewElement("saml:AudienceRestriction") + el.AddChild(a.Audience.Element()) + return el +} + +// Audience represents the SAML element Audience. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.4 +type Audience struct { + Value string `xml:",chardata"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *Audience) Element() *etree.Element { + el := etree.NewElement("saml:Audience") + el.SetText(a.Value) + return el +} + +// OneTimeUse represents the SAML element OneTimeUse. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.5 +type OneTimeUse struct{} + +// Element returns an etree.Element representing the object in XML form. +func (a *OneTimeUse) Element() *etree.Element { + return etree.NewElement("saml:OneTimeUse") +} + +// ProxyRestriction represents the SAML element ProxyRestriction. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.5.1.6 +type ProxyRestriction struct { + Count *int + Audiences []Audience +} + +// Element returns an etree.Element representing the object in XML form. +func (a *ProxyRestriction) Element() *etree.Element { + el := etree.NewElement("saml:ProxyRestriction") + if a.Count != nil { + el.CreateAttr("Count", strconv.Itoa(*a.Count)) + } + for _, v := range a.Audiences { + el.AddChild(v.Element()) + } + return el +} + +// AuthnStatement represents the SAML element AuthnStatement. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2 +type AuthnStatement struct { + AuthnInstant time.Time `xml:",attr"` + SessionIndex string `xml:",attr"` + SessionNotOnOrAfter *time.Time `xml:",attr,omitempty"` + SubjectLocality *SubjectLocality + AuthnContext AuthnContext +} + +// Element returns an etree.Element representing the object in XML form. +func (a *AuthnStatement) Element() *etree.Element { + el := etree.NewElement("saml:AuthnStatement") + el.CreateAttr("AuthnInstant", a.AuthnInstant.Format(timeFormat)) + if a.SessionIndex != "" { + el.CreateAttr("SessionIndex", a.SessionIndex) + } + if a.SessionNotOnOrAfter != nil { + el.CreateAttr("SessionNotOnOrAfter", a.SessionNotOnOrAfter.Format(timeFormat)) + } + if a.SubjectLocality != nil { + el.AddChild(a.SubjectLocality.Element()) + } + el.AddChild(a.AuthnContext.Element()) + return el +} + +// MarshalXML implements xml.Marshaler +func (a *AuthnStatement) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias AuthnStatement + aux := &struct { + AuthnInstant RelaxedTime `xml:",attr"` + SessionNotOnOrAfter *RelaxedTime `xml:",attr,omitempty"` + *Alias + }{ + AuthnInstant: RelaxedTime(a.AuthnInstant), + SessionNotOnOrAfter: (*RelaxedTime)(a.SessionNotOnOrAfter), + Alias: (*Alias)(a), + } + return e.EncodeElement(aux, start) +} + +// UnmarshalXML implements xml.Unmarshaler +func (a *AuthnStatement) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias AuthnStatement + aux := &struct { + AuthnInstant RelaxedTime `xml:",attr"` + SessionNotOnOrAfter *RelaxedTime `xml:",attr,omitempty"` + *Alias + }{ + Alias: (*Alias)(a), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + a.AuthnInstant = time.Time(aux.AuthnInstant) + a.SessionNotOnOrAfter = (*time.Time)(aux.SessionNotOnOrAfter) + return nil +} + +// SubjectLocality represents the SAML element SubjectLocality. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.1 +type SubjectLocality struct { + Address string `xml:",attr"` + DNSName string `xml:",attr"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *SubjectLocality) Element() *etree.Element { + el := etree.NewElement("saml:SubjectLocality") + if a.Address != "" { + el.CreateAttr("Address", a.Address) + } + if a.DNSName != "" { + el.CreateAttr("DNSName", a.DNSName) + } + return el +} + +// AuthnContext represents the SAML element AuthnContext. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.2 +type AuthnContext struct { + AuthnContextClassRef *AuthnContextClassRef + //AuthnContextDecl *AuthnContextDecl ... TODO + //AuthnContextDeclRef *AuthnContextDeclRef ... TODO + //AuthenticatingAuthorities []AuthenticatingAuthority... TODO +} + +// Element returns an etree.Element representing the object in XML form. +func (a *AuthnContext) Element() *etree.Element { + el := etree.NewElement("saml:AuthnContext") + if a.AuthnContextClassRef != nil { + el.AddChild(a.AuthnContextClassRef.Element()) + } + return el +} + +// AuthnContextClassRef represents the SAML element AuthnContextClassRef. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.2.2 +type AuthnContextClassRef struct { + Value string `xml:",chardata"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *AuthnContextClassRef) Element() *etree.Element { + el := etree.NewElement("saml:AuthnContextClassRef") + el.SetText(a.Value) + return el +} + +// AttributeStatement represents the SAML element AttributeStatement. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3 +type AttributeStatement struct { + Attributes []Attribute `xml:"Attribute"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *AttributeStatement) Element() *etree.Element { + el := etree.NewElement("saml:AttributeStatement") + for _, v := range a.Attributes { + el.AddChild(v.Element()) + } + return el +} + +// Attribute represents the SAML element Attribute. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3.1 +type Attribute struct { + FriendlyName string `xml:",attr"` + Name string `xml:",attr"` + NameFormat string `xml:",attr"` + Values []AttributeValue `xml:"AttributeValue"` +} + +// Element returns an etree.Element representing the object in XML form. +func (a *Attribute) Element() *etree.Element { + el := etree.NewElement("saml:Attribute") + if a.FriendlyName != "" { + el.CreateAttr("FriendlyName", a.FriendlyName) + } + if a.Name != "" { + el.CreateAttr("Name", a.Name) + } + if a.NameFormat != "" { + el.CreateAttr("NameFormat", a.NameFormat) + } + for _, v := range a.Values { + el.AddChild(v.Element()) + } + return el +} + +// AttributeValue represents the SAML element AttributeValue. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf §2.7.3.1.1 +type AttributeValue struct { + Type string `xml:"http://www.w3.org/2001/XMLSchema-instance type,attr"` + Value string `xml:",chardata"` + NameID *NameID +} + +// Element returns an etree.Element representing the object in XML form. +func (a *AttributeValue) Element() *etree.Element { + el := etree.NewElement("saml:AttributeValue") + el.CreateAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance") + el.CreateAttr("xmlns:xs", "http://www.w3.org/2001/XMLSchema") + el.CreateAttr("xsi:type", a.Type) + if a.NameID != nil { + el.AddChild(a.NameID.Element()) + } + el.SetText(a.Value) + return el +} + +// LogoutResponse represents the SAML object of the same name. +// +// See http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf +type LogoutResponse struct { + XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:protocol LogoutResponse"` + ID string `xml:",attr"` + InResponseTo string `xml:",attr"` + Version string `xml:",attr"` + IssueInstant time.Time `xml:",attr"` + Destination string `xml:",attr"` + Consent string `xml:",attr"` + Issuer *Issuer `xml:"urn:oasis:names:tc:SAML:2.0:assertion Issuer"` + Signature *etree.Element + Status Status `xml:"urn:oasis:names:tc:SAML:2.0:protocol Status"` +} + +// Element returns an etree.Element representing the object in XML form. +func (r *LogoutResponse) Element() *etree.Element { + el := etree.NewElement("samlp:LogoutResponse") + el.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion") + el.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol") + + el.CreateAttr("ID", r.ID) + if r.InResponseTo != "" { + el.CreateAttr("InResponseTo", r.InResponseTo) + } + el.CreateAttr("Version", r.Version) + el.CreateAttr("IssueInstant", r.IssueInstant.Format(timeFormat)) + if r.Destination != "" { + el.CreateAttr("Destination", r.Destination) + } + if r.Consent != "" { + el.CreateAttr("Consent", r.Consent) + } + if r.Issuer != nil { + el.AddChild(r.Issuer.Element()) + } + if r.Signature != nil { + el.AddChild(r.Signature) + } + el.AddChild(r.Status.Element()) + return el +} + +// MarshalXML implements xml.Marshaler +func (r *LogoutResponse) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + type Alias LogoutResponse + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + IssueInstant: RelaxedTime(r.IssueInstant), + Alias: (*Alias)(r), + } + return e.Encode(aux) +} + +// UnmarshalXML implements xml.Unmarshaler +func (r *LogoutResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + type Alias LogoutResponse + aux := &struct { + IssueInstant RelaxedTime `xml:",attr"` + *Alias + }{ + Alias: (*Alias)(r), + } + if err := d.DecodeElement(&aux, &start); err != nil { + return err + } + r.IssueInstant = time.Time(aux.IssueInstant) + return nil +} diff --git a/vendor/github.com/mickael-kerjean/saml/service_provider.go b/vendor/github.com/mickael-kerjean/saml/service_provider.go new file mode 100644 index 00000000..29b415ed --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/service_provider.go @@ -0,0 +1,1676 @@ +package saml + +import ( + "bytes" + "compress/flate" + "context" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "encoding/xml" + "errors" + "fmt" + "html/template" + "io/ioutil" + "net/http" + "net/url" + "regexp" + "time" + + "github.com/beevik/etree" + xrv "github.com/mattermost/xml-roundtrip-validator" + dsig "github.com/russellhaering/goxmldsig" + "github.com/russellhaering/goxmldsig/etreeutils" + + "github.com/mickael-kerjean/saml/xmlenc" +) + +// NameIDFormat is the format of the id +type NameIDFormat string + +// Element returns an XML element representation of n. +func (n NameIDFormat) Element() *etree.Element { + el := etree.NewElement("") + el.SetText(string(n)) + return el +} + +// Name ID formats +const ( + UnspecifiedNameIDFormat NameIDFormat = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" + TransientNameIDFormat NameIDFormat = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient" + EmailAddressNameIDFormat NameIDFormat = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" + PersistentNameIDFormat NameIDFormat = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" +) + +// SignatureVerifier verifies a signature +// +// Can be implemented in order to override ServiceProvider's default +// way of verifying signatures. +type SignatureVerifier interface { + VerifySignature(validationContext *dsig.ValidationContext, el *etree.Element) error +} + +// ServiceProvider implements SAML Service provider. +// +// In SAML, service providers delegate responsibility for identifying +// clients to an identity provider. If you are writing an application +// that uses passwords (or whatever) stored somewhere else, then you +// are service provider. +// +// See the example directory for an example of a web application using +// the service provider interface. +type ServiceProvider struct { + // Entity ID is optional - if not specified then MetadataURL will be used + EntityID string + + // Key is the RSA private key we use to sign requests. + Key *rsa.PrivateKey + + // Certificate is the RSA public part of Key. + Certificate *x509.Certificate + Intermediates []*x509.Certificate + + // HTTPClient to use during SAML artifact resolution + HTTPClient *http.Client + + // MetadataURL is the full URL to the metadata endpoint on this host, + // i.e. https://example.com/saml/metadata + MetadataURL url.URL + + // AcsURL is the full URL to the SAML Assertion Customer Service endpoint + // on this host, i.e. https://example.com/saml/acs + AcsURL url.URL + + // SloURL is the full URL to the SAML Single Logout endpoint on this host. + // i.e. https://example.com/saml/slo + SloURL url.URL + + // IDPMetadata is the metadata from the identity provider. + IDPMetadata *EntityDescriptor + + // AuthnNameIDFormat is the format used in the NameIDPolicy for + // authentication requests + AuthnNameIDFormat NameIDFormat + + // MetadataValidDuration is a duration used to calculate validUntil + // attribute in the metadata endpoint + MetadataValidDuration time.Duration + + // ForceAuthn allows you to force re-authentication of users even if the user + // has a SSO session at the IdP. + ForceAuthn *bool + + // RequestedAuthnContext allow you to specify the requested authentication + // context in authentication requests + RequestedAuthnContext *RequestedAuthnContext + + // AllowIdpInitiated + AllowIDPInitiated bool + + // DefaultRedirectURI where untracked requests (as of IDPInitiated) are redirected to + DefaultRedirectURI string + + // SignatureVerifier, if non-nil, allows you to implement an alternative way + // to verify signatures. + SignatureVerifier SignatureVerifier + + // SignatureMethod, if non-empty, authentication requests will be signed + SignatureMethod string + + // LogoutBindings specify the bindings available for SLO endpoint. If empty, + // HTTP-POST binding is used. + LogoutBindings []string +} + +// MaxIssueDelay is the longest allowed time between when a SAML assertion is +// issued by the IDP and the time it is received by ParseResponse. This is used +// to prevent old responses from being replayed (while allowing for some clock +// drift between the SP and IDP). +var MaxIssueDelay = time.Second * 90 + +// MaxClockSkew allows for leeway for clock skew between the IDP and SP when +// validating assertions. It defaults to 180 seconds (matches shibboleth). +var MaxClockSkew = time.Second * 180 + +// DefaultValidDuration is how long we assert that the SP metadata is valid. +const DefaultValidDuration = time.Hour * 24 * 2 + +// DefaultCacheDuration is how long we ask the IDP to cache the SP metadata. +const DefaultCacheDuration = time.Hour * 24 * 1 + +// Metadata returns the service provider metadata +func (sp *ServiceProvider) Metadata() *EntityDescriptor { + validDuration := DefaultValidDuration + if sp.MetadataValidDuration > 0 { + validDuration = sp.MetadataValidDuration + } + + authnRequestsSigned := len(sp.SignatureMethod) > 0 + wantAssertionsSigned := true + validUntil := TimeNow().Add(validDuration) + + var keyDescriptors []KeyDescriptor + if sp.Certificate != nil { + certBytes := sp.Certificate.Raw + for _, intermediate := range sp.Intermediates { + certBytes = append(certBytes, intermediate.Raw...) + } + keyDescriptors = []KeyDescriptor{ + { + Use: "encryption", + KeyInfo: KeyInfo{ + X509Data: X509Data{ + X509Certificates: []X509Certificate{ + {Data: base64.StdEncoding.EncodeToString(certBytes)}, + }, + }, + }, + EncryptionMethods: []EncryptionMethod{ + {Algorithm: "http://www.w3.org/2001/04/xmlenc#aes128-cbc"}, + {Algorithm: "http://www.w3.org/2001/04/xmlenc#aes192-cbc"}, + {Algorithm: "http://www.w3.org/2001/04/xmlenc#aes256-cbc"}, + {Algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"}, + }, + }, + } + if len(sp.SignatureMethod) > 0 { + keyDescriptors = append(keyDescriptors, KeyDescriptor{ + Use: "signing", + KeyInfo: KeyInfo{ + X509Data: X509Data{ + X509Certificates: []X509Certificate{ + {Data: base64.StdEncoding.EncodeToString(certBytes)}, + }, + }, + }, + }) + } + } + + var sloEndpoints []Endpoint + for _, binding := range sp.LogoutBindings { + sloEndpoints = append(sloEndpoints, Endpoint{ + Binding: binding, + Location: sp.SloURL.String(), + ResponseLocation: sp.SloURL.String(), + }) + } + + return &EntityDescriptor{ + EntityID: firstSet(sp.EntityID, sp.MetadataURL.String()), + ValidUntil: validUntil, + + SPSSODescriptors: []SPSSODescriptor{ + { + SSODescriptor: SSODescriptor{ + RoleDescriptor: RoleDescriptor{ + ProtocolSupportEnumeration: "urn:oasis:names:tc:SAML:2.0:protocol", + KeyDescriptors: keyDescriptors, + ValidUntil: &validUntil, + }, + SingleLogoutServices: sloEndpoints, + NameIDFormats: []NameIDFormat{sp.AuthnNameIDFormat}, + }, + AuthnRequestsSigned: &authnRequestsSigned, + WantAssertionsSigned: &wantAssertionsSigned, + + AssertionConsumerServices: []IndexedEndpoint{ + { + Binding: HTTPPostBinding, + Location: sp.AcsURL.String(), + Index: 1, + }, + { + Binding: HTTPArtifactBinding, + Location: sp.AcsURL.String(), + Index: 2, + }, + }, + }, + }, + } +} + +// MakeRedirectAuthenticationRequest creates a SAML authentication request using +// the HTTP-Redirect binding. It returns a URL that we will redirect the user to +// in order to start the auth process. +func (sp *ServiceProvider) MakeRedirectAuthenticationRequest(relayState string) (*url.URL, error) { + req, err := sp.MakeAuthenticationRequest(sp.GetSSOBindingLocation(HTTPRedirectBinding), HTTPRedirectBinding, HTTPPostBinding) + if err != nil { + return nil, err + } + return req.Redirect(relayState, sp) +} + +// Redirect returns a URL suitable for using the redirect binding with the request +func (req *AuthnRequest) Redirect(relayState string, sp *ServiceProvider) (*url.URL, error) { + w := &bytes.Buffer{} + w1 := base64.NewEncoder(base64.StdEncoding, w) + w2, _ := flate.NewWriter(w1, 9) + doc := etree.NewDocument() + doc.SetRoot(req.Element()) + if _, err := doc.WriteTo(w2); err != nil { + panic(err) + } + w2.Close() + w1.Close() + + rv, _ := url.Parse(req.Destination) + // We can't depend on Query().set() as order matters for signing + query := rv.RawQuery + if len(query) > 0 { + query += "&SAMLRequest=" + url.QueryEscape(string(w.Bytes())) + } else { + query += "SAMLRequest=" + url.QueryEscape(string(w.Bytes())) + } + + if relayState != "" { + query += "&RelayState=" + relayState + } + if len(sp.SignatureMethod) > 0 { + query += "&SigAlg=" + url.QueryEscape(sp.SignatureMethod) + signingContext, err := GetSigningContext(sp) + + if err != nil { + return nil, err + } + + sig, err := signingContext.SignString(query) + if err != nil { + return nil, err + } + query += "&Signature=" + url.QueryEscape(base64.StdEncoding.EncodeToString(sig)) + } + + rv.RawQuery = query + + return rv, nil +} + +// GetSSOBindingLocation returns URL for the IDP's Single Sign On Service binding +// of the specified type (HTTPRedirectBinding or HTTPPostBinding) +func (sp *ServiceProvider) GetSSOBindingLocation(binding string) string { + for _, idpSSODescriptor := range sp.IDPMetadata.IDPSSODescriptors { + for _, singleSignOnService := range idpSSODescriptor.SingleSignOnServices { + if singleSignOnService.Binding == binding { + return singleSignOnService.Location + } + } + } + return "" +} + +// GetArtifactBindingLocation returns URL for the IDP's Artifact binding of the +// specified type +func (sp *ServiceProvider) GetArtifactBindingLocation(binding string) string { + for _, idpSSODescriptor := range sp.IDPMetadata.IDPSSODescriptors { + for _, artifactResolutionService := range idpSSODescriptor.ArtifactResolutionServices { + if artifactResolutionService.Binding == binding { + return artifactResolutionService.Location + } + } + } + return "" +} + +// GetSLOBindingLocation returns URL for the IDP's Single Log Out Service binding +// of the specified type (HTTPRedirectBinding or HTTPPostBinding) +func (sp *ServiceProvider) GetSLOBindingLocation(binding string) string { + for _, idpSSODescriptor := range sp.IDPMetadata.IDPSSODescriptors { + for _, singleLogoutService := range idpSSODescriptor.SingleLogoutServices { + if singleLogoutService.Binding == binding { + return singleLogoutService.Location + } + } + } + return "" +} + +// getIDPSigningCerts returns the certificates which we can use to verify things +// signed by the IDP in PEM format, or nil if no such certificate is found. +func (sp *ServiceProvider) getIDPSigningCerts() ([]*x509.Certificate, error) { + var certStrs []string + + // We need to include non-empty certs where the "use" attribute is + // either set to "signing" or is missing + for _, idpSSODescriptor := range sp.IDPMetadata.IDPSSODescriptors { + for _, keyDescriptor := range idpSSODescriptor.KeyDescriptors { + if len(keyDescriptor.KeyInfo.X509Data.X509Certificates) != 0 { + switch keyDescriptor.Use { + case "", "signing": + for _, certificate := range keyDescriptor.KeyInfo.X509Data.X509Certificates { + certStrs = append(certStrs, certificate.Data) + } + } + } + } + } + + if len(certStrs) == 0 { + return nil, errors.New("cannot find any signing certificate in the IDP SSO descriptor") + } + + var certs []*x509.Certificate + + // cleanup whitespace + regex := regexp.MustCompile(`\s+`) + for _, certStr := range certStrs { + certStr = regex.ReplaceAllString(certStr, "") + certBytes, err := base64.StdEncoding.DecodeString(certStr) + if err != nil { + return nil, fmt.Errorf("cannot parse certificate: %s", err) + } + + parsedCert, err := x509.ParseCertificate(certBytes) + if err != nil { + return nil, err + } + certs = append(certs, parsedCert) + } + + return certs, nil +} + +// MakeArtifactResolveRequest produces a new ArtifactResolve object to send to the idp's Artifact resolver +func (sp *ServiceProvider) MakeArtifactResolveRequest(artifactID string) (*ArtifactResolve, error) { + req := ArtifactResolve{ + ID: fmt.Sprintf("id-%x", randomBytes(20)), + IssueInstant: TimeNow(), + Version: "2.0", + Issuer: &Issuer{ + Format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity", + Value: firstSet(sp.EntityID, sp.MetadataURL.String()), + }, + Artifact: artifactID, + } + + if len(sp.SignatureMethod) > 0 { + if err := sp.SignArtifactResolve(&req); err != nil { + return nil, err + } + } + + return &req, nil +} + +// MakeAuthenticationRequest produces a new AuthnRequest object to send to the idpURL +// that uses the specified binding (HTTPRedirectBinding or HTTPPostBinding) +func (sp *ServiceProvider) MakeAuthenticationRequest(idpURL string, binding string, resultBinding string) (*AuthnRequest, error) { + + allowCreate := true + nameIDFormat := sp.nameIDFormat() + req := AuthnRequest{ + AssertionConsumerServiceURL: sp.AcsURL.String(), + Destination: idpURL, + ProtocolBinding: resultBinding, // default binding for the response + ID: fmt.Sprintf("id-%x", randomBytes(20)), + IssueInstant: TimeNow(), + Version: "2.0", + Issuer: &Issuer{ + Format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity", + Value: firstSet(sp.EntityID, sp.MetadataURL.String()), + }, + NameIDPolicy: &NameIDPolicy{ + AllowCreate: &allowCreate, + // TODO(ross): figure out exactly policy we need + // urn:mace:shibboleth:1.0:nameIdentifier + // urn:oasis:names:tc:SAML:2.0:nameid-format:transient + Format: &nameIDFormat, + }, + ForceAuthn: sp.ForceAuthn, + RequestedAuthnContext: sp.RequestedAuthnContext, + } + // We don't need to sign the XML document if the IDP uses HTTP-Redirect binding + if len(sp.SignatureMethod) > 0 && binding == HTTPPostBinding { + if err := sp.SignAuthnRequest(&req); err != nil { + return nil, err + } + } + return &req, nil +} + +// GetSigningContext returns a dsig.SigningContext initialized based on the Service Provider's configuration +func GetSigningContext(sp *ServiceProvider) (*dsig.SigningContext, error) { + keyPair := tls.Certificate{ + Certificate: [][]byte{sp.Certificate.Raw}, + PrivateKey: sp.Key, + Leaf: sp.Certificate, + } + // TODO: add intermediates for SP + //for _, cert := range sp.Intermediates { + // keyPair.Certificate = append(keyPair.Certificate, cert.Raw) + //} + keyStore := dsig.TLSCertKeyStore(keyPair) + + if sp.SignatureMethod != dsig.RSASHA1SignatureMethod && + sp.SignatureMethod != dsig.RSASHA256SignatureMethod && + sp.SignatureMethod != dsig.RSASHA512SignatureMethod { + return nil, fmt.Errorf("invalid signing method %s", sp.SignatureMethod) + } + signatureMethod := sp.SignatureMethod + signingContext := dsig.NewDefaultSigningContext(keyStore) + signingContext.Canonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList(canonicalizerPrefixList) + if err := signingContext.SetSignatureMethod(signatureMethod); err != nil { + return nil, err + } + + return signingContext, nil +} + +// SignArtifactResolve adds the `Signature` element to the `ArtifactResolve`. +func (sp *ServiceProvider) SignArtifactResolve(req *ArtifactResolve) error { + signingContext, err := GetSigningContext(sp) + if err != nil { + return err + } + assertionEl := req.Element() + + signedRequestEl, err := signingContext.SignEnveloped(assertionEl) + if err != nil { + return err + } + + sigEl := signedRequestEl.Child[len(signedRequestEl.Child)-1] + req.Signature = sigEl.(*etree.Element) + return nil +} + +// SignAuthnRequest adds the `Signature` element to the `AuthnRequest`. +func (sp *ServiceProvider) SignAuthnRequest(req *AuthnRequest) error { + + signingContext, err := GetSigningContext(sp) + if err != nil { + return err + } + assertionEl := req.Element() + + signedRequestEl, err := signingContext.SignEnveloped(assertionEl) + if err != nil { + return err + } + + sigEl := signedRequestEl.Child[len(signedRequestEl.Child)-1] + req.Signature = sigEl.(*etree.Element) + return nil +} + +// MakePostAuthenticationRequest creates a SAML authentication request using +// the HTTP-POST binding. It returns HTML text representing an HTML form that +// can be sent presented to a browser to initiate the login process. +func (sp *ServiceProvider) MakePostAuthenticationRequest(relayState string) ([]byte, error) { + req, err := sp.MakeAuthenticationRequest(sp.GetSSOBindingLocation(HTTPPostBinding), HTTPPostBinding, HTTPPostBinding) + if err != nil { + return nil, err + } + return req.Post(relayState), nil +} + +// Post returns an HTML form suitable for using the HTTP-POST binding with the request +func (req *AuthnRequest) Post(relayState string) []byte { + doc := etree.NewDocument() + doc.SetRoot(req.Element()) + reqBuf, err := doc.WriteToBytes() + if err != nil { + panic(err) + } + encodedReqBuf := base64.StdEncoding.EncodeToString(reqBuf) + + tmpl := template.Must(template.New("saml-post-form").Parse(`` + + `
` + + `` + + `` + + `` + + `
` + + ``)) + data := struct { + URL string + SAMLRequest string + RelayState string + }{ + URL: req.Destination, + SAMLRequest: encodedReqBuf, + RelayState: relayState, + } + + rv := bytes.Buffer{} + if err := tmpl.Execute(&rv, data); err != nil { + panic(err) + } + + return rv.Bytes() +} + +// AssertionAttributes is a list of AssertionAttribute +type AssertionAttributes []AssertionAttribute + +// Get returns the assertion attribute whose Name or FriendlyName +// matches name, or nil if no matching attribute is found. +func (aa AssertionAttributes) Get(name string) *AssertionAttribute { + for _, attr := range aa { + if attr.Name == name { + return &attr + } + if attr.FriendlyName == name { + return &attr + } + } + return nil +} + +// AssertionAttribute represents an attribute of the user extracted from +// a SAML Assertion. +type AssertionAttribute struct { + FriendlyName string + Name string + Value string +} + +// InvalidResponseError is the error produced by ParseResponse when it fails. +// The underlying error is in PrivateErr. Response is the response as it was +// known at the time validation failed. Now is the time that was used to validate +// time-dependent parts of the assertion. +type InvalidResponseError struct { + PrivateErr error + Response string + Now time.Time +} + +func (ivr *InvalidResponseError) Error() string { + return fmt.Sprintf("Authentication failed") +} + +// ErrBadStatus is returned when the assertion provided is valid but the +// status code is not "urn:oasis:names:tc:SAML:2.0:status:Success". +type ErrBadStatus struct { + Status string +} + +func (e ErrBadStatus) Error() string { + return e.Status +} + +// ParseResponse extracts the SAML IDP response received in req, resolves +// artifacts when necessary, validates it, and returns the verified assertion. +func (sp *ServiceProvider) ParseResponse(req *http.Request, possibleRequestIDs []string) (*Assertion, error) { + if artifactID := req.Form.Get("SAMLart"); artifactID != "" { + return sp.handleArtifactRequest(req.Context(), artifactID, possibleRequestIDs) + } + return sp.parseResponseHTTP(req, possibleRequestIDs) +} + +func (sp *ServiceProvider) handleArtifactRequest(ctx context.Context, artifactID string, possibleRequestIDs []string) (*Assertion, error) { + retErr := &InvalidResponseError{Now: TimeNow()} + + artifactResolveRequest, err := sp.MakeArtifactResolveRequest(artifactID) + if err != nil { + retErr.PrivateErr = fmt.Errorf("Cannot generate artifact resolution request: %s", err) + return nil, retErr + } + + requestBody, err := elementToBytes(artifactResolveRequest.SoapRequest()) + if err != nil { + retErr.PrivateErr = err + return nil, retErr + } + + req, err := http.NewRequestWithContext(ctx, "POST", sp.GetArtifactBindingLocation(SOAPBinding), + bytes.NewReader(requestBody)) + if err != nil { + retErr.PrivateErr = err + return nil, retErr + } + req.Header.Set("Content-Type", "text/xml") + + httpClient := sp.HTTPClient + if httpClient == nil { + httpClient = http.DefaultClient + } + response, err := httpClient.Do(req) + if err != nil { + retErr.PrivateErr = fmt.Errorf("cannot resolve artifact: %s", err) + return nil, retErr + } + defer response.Body.Close() + if response.StatusCode != 200 { + retErr.PrivateErr = fmt.Errorf("Error during artifact resolution: HTTP status %d (%s)", response.StatusCode, response.Status) + return nil, retErr + } + responseBody, err := ioutil.ReadAll(response.Body) + if err != nil { + retErr.PrivateErr = fmt.Errorf("Error during artifact resolution: %s", err) + return nil, retErr + } + assertion, err := sp.ParseXMLArtifactResponse(responseBody, possibleRequestIDs, artifactResolveRequest.ID) + if err != nil { + return nil, err + } + return assertion, nil +} + +func (sp *ServiceProvider) parseResponseHTTP(req *http.Request, possibleRequestIDs []string) (*Assertion, error) { + retErr := &InvalidResponseError{ + Now: TimeNow(), + } + + rawResponseBuf, err := base64.StdEncoding.DecodeString(req.PostForm.Get("SAMLResponse")) + if err != nil { + retErr.PrivateErr = fmt.Errorf("cannot parse base64: %s", err) + return nil, retErr + } + + assertion, err := sp.ParseXMLResponse(rawResponseBuf, possibleRequestIDs) + if err != nil { + return nil, err + } + return assertion, nil +} + +// ParseXMLArtifactResponse validates the SAML Artifact resolver response +// and returns the verified assertion. +// +// This function handles verifying the digital signature, and verifying +// that the specified conditions and properties are met. +// +// If the function fails it will return an InvalidResponseError whose +// properties are useful in describing which part of the parsing process +// failed. However, to discourage inadvertent disclosure the diagnostic +// information, the Error() method returns a static string. +func (sp *ServiceProvider) ParseXMLArtifactResponse(soapResponseXML []byte, possibleRequestIDs []string, artifactRequestID string) (*Assertion, error) { + now := TimeNow() + retErr := &InvalidResponseError{ + Response: string(soapResponseXML), + Now: now, + } + + // ensure that the response XML is well-formed before we parse it + if err := xrv.Validate(bytes.NewReader(soapResponseXML)); err != nil { + retErr.PrivateErr = fmt.Errorf("invalid xml: %s", err) + return nil, retErr + } + + doc := etree.NewDocument() + if err := doc.ReadFromBytes(soapResponseXML); err != nil { + retErr.PrivateErr = fmt.Errorf("cannot unmarshal response: %s", err) + return nil, retErr + } + if doc.Root().NamespaceURI() != "http://schemas.xmlsoap.org/soap/envelope/" || + doc.Root().Tag != "Envelope" { + retErr.PrivateErr = fmt.Errorf("expected a SOAP Envelope") + return nil, retErr + } + + soapBodyEl, err := findOneChild(doc.Root(), "http://schemas.xmlsoap.org/soap/envelope/", "Body") + if err != nil { + retErr.PrivateErr = err + return nil, retErr + } + + artifactResponseEl, err := findOneChild(soapBodyEl, "urn:oasis:names:tc:SAML:2.0:protocol", "ArtifactResponse") + if err != nil { + retErr.PrivateErr = err + return nil, retErr + } + + return sp.parseArtifactResponse(artifactResponseEl, possibleRequestIDs, artifactRequestID, now) +} + +func (sp *ServiceProvider) parseArtifactResponse(artifactResponseEl *etree.Element, possibleRequestIDs []string, artifactRequestID string, now time.Time) (*Assertion, error) { + retErr := &InvalidResponseError{ + Now: now, + Response: elementToString(artifactResponseEl), + } + + { + var artifactResponse ArtifactResponse + if err := unmarshalElement(artifactResponseEl, &artifactResponse); err != nil { + retErr.PrivateErr = err + return nil, retErr + } + if artifactResponse.InResponseTo != artifactRequestID { + retErr.PrivateErr = fmt.Errorf("`InResponseTo` does not match the artifact request ID (expected %s)", artifactRequestID) + return nil, retErr + } + if artifactResponse.IssueInstant.Add(MaxIssueDelay).Before(now) { + retErr.PrivateErr = fmt.Errorf("response IssueInstant expired at %s", artifactResponse.IssueInstant.Add(MaxIssueDelay)) + return nil, retErr + } + if artifactResponse.Issuer != nil && artifactResponse.Issuer.Value != sp.IDPMetadata.EntityID { + retErr.PrivateErr = fmt.Errorf("response Issuer does not match the IDP metadata (expected %q)", sp.IDPMetadata.EntityID) + return nil, retErr + } + if artifactResponse.Status.StatusCode.Value != StatusSuccess { + retErr.PrivateErr = ErrBadStatus{Status: artifactResponse.Status.StatusCode.Value} + return nil, retErr + } + } + + var signatureRequirement signatureRequirement + sigErr := sp.validateSignature(artifactResponseEl) + if sigErr == nil { + signatureRequirement = signatureNotRequired + } else if sigErr == errSignatureElementNotPresent { + signatureRequirement = signatureRequired + } else { + retErr.PrivateErr = sigErr + return nil, retErr + } + + responseEl, err := findOneChild(artifactResponseEl, "urn:oasis:names:tc:SAML:2.0:protocol", "Response") + if err != nil { + retErr.PrivateErr = err + return nil, retErr + } + + assertion, err := sp.parseResponse(responseEl, possibleRequestIDs, now, signatureRequirement) + if err != nil { + retErr.PrivateErr = err + return nil, retErr + } + + return assertion, nil +} + +// ParseXMLResponse parses and validates the SAML IDP response and +// returns the verified assertion. +// +// This function handles decrypting the message, verifying the digital +// signature on the assertion, and verifying that the specified conditions +// and properties are met. +// +// If the function fails it will return an InvalidResponseError whose +// properties are useful in describing which part of the parsing process +// failed. However, to discourage inadvertent disclosure the diagnostic +// information, the Error() method returns a static string. +func (sp *ServiceProvider) ParseXMLResponse(decodedResponseXML []byte, possibleRequestIDs []string) (*Assertion, error) { + now := TimeNow() + var err error + retErr := &InvalidResponseError{ + Now: now, + Response: string(decodedResponseXML), + } + + // ensure that the response XML is well-formed before we parse it + if err := xrv.Validate(bytes.NewReader(decodedResponseXML)); err != nil { + retErr.PrivateErr = fmt.Errorf("invalid xml: %s", err) + return nil, retErr + } + + doc := etree.NewDocument() + if err := doc.ReadFromBytes(decodedResponseXML); err != nil { + retErr.PrivateErr = err + return nil, retErr + } + + assertion, err := sp.parseResponse(doc.Root(), possibleRequestIDs, now, signatureRequired) + if err != nil { + retErr.PrivateErr = err + return nil, retErr + } + + return assertion, nil +} + +type signatureRequirement int + +const ( + signatureRequired signatureRequirement = iota + signatureNotRequired +) + +// validateXMLResponse validates the SAML IDP response and returns +// the verified assertion. +// +// This function handles decrypting the message, verifying the digital +// signature on the assertion, and verifying that the specified conditions +// and properties are met. +func (sp *ServiceProvider) parseResponse(responseEl *etree.Element, possibleRequestIDs []string, now time.Time, signatureRequirement signatureRequirement) (*Assertion, error) { + var responseSignatureErr error + var responseHasSignature bool + if signatureRequirement == signatureRequired { + responseSignatureErr = sp.validateSignature(responseEl) + if responseSignatureErr != errSignatureElementNotPresent { + responseHasSignature = true + } + + // Note: we're deferring taking action on the signature validation until after we've + // processed the request attributes, because certain test cases seem to require this mis-feature. + // TODO(ross): adjust the test cases so that we can abort here if the Response signature is invalid. + } + + // validate request attributes + { + var response Response + if err := unmarshalElement(responseEl, &response); err != nil { + return nil, fmt.Errorf("cannot unmarshal response: %v", err) + } + + // If the response is *not* signed, the Destination may be omitted. + if responseHasSignature || response.Destination != "" { + if response.Destination != sp.AcsURL.String() { + return nil, fmt.Errorf("`Destination` does not match AcsURL (expected %q, actual %q)", sp.AcsURL.String(), response.Destination) + } + } + + requestIDvalid := false + if sp.AllowIDPInitiated { + requestIDvalid = true + } else { + for _, possibleRequestID := range possibleRequestIDs { + if response.InResponseTo == possibleRequestID { + requestIDvalid = true + } + } + } + if !requestIDvalid { + return nil, fmt.Errorf("`InResponseTo` does not match any of the possible request IDs (expected %v)", possibleRequestIDs) + } + + if response.IssueInstant.Add(MaxIssueDelay).Before(now) { + return nil, fmt.Errorf("response IssueInstant expired at %s", response.IssueInstant.Add(MaxIssueDelay)) + } + if response.Issuer != nil && response.Issuer.Value != sp.IDPMetadata.EntityID { + return nil, fmt.Errorf("response Issuer does not match the IDP metadata (expected %q)", sp.IDPMetadata.EntityID) + } + if response.Status.StatusCode.Value != StatusSuccess { + return nil, ErrBadStatus{Status: response.Status.StatusCode.Value} + } + } + + if signatureRequirement == signatureRequired { + if responseSignatureErr == nil { + // since the request has a signature, none of the Assertions need one + signatureRequirement = signatureNotRequired + } else if responseSignatureErr == errSignatureElementNotPresent { + // the request has no signature, so assertions must be signed + signatureRequirement = signatureRequired // nop + } else { + return nil, responseSignatureErr + } + } + + var errs []error + var assertions []Assertion + + // look for encrypted assertions + { + encryptedAssertionEls, err := findChildren(responseEl, "urn:oasis:names:tc:SAML:2.0:assertion", "EncryptedAssertion") + if err != nil { + return nil, err + } + for _, encryptedAssertionEl := range encryptedAssertionEls { + assertion, err := sp.parseEncryptedAssertion(encryptedAssertionEl, possibleRequestIDs, now, signatureRequirement) + if err != nil { + errs = append(errs, err) + continue + } + assertions = append(assertions, *assertion) + } + } + + // look for plaintext assertions + { + assertionEls, err := findChildren(responseEl, "urn:oasis:names:tc:SAML:2.0:assertion", "Assertion") + if err != nil { + return nil, err + } + for _, assertionEl := range assertionEls { + assertion, err := sp.parseAssertion(assertionEl, possibleRequestIDs, now, signatureRequirement) + if err != nil { + errs = append(errs, err) + continue + } + assertions = append(assertions, *assertion) + } + } + + if len(assertions) == 0 { + if len(errs) > 0 { + return nil, errs[0] + } + return nil, fmt.Errorf("expected at least one valid Assertion, none found") + } + + // if we have at least one assertion, return the first one. It is almost universally true that valid responses + // contain only one assertion. This is less that fully correct, but we didn't realize that there could be more + // than one assertion at the time of establishing the public interface of ParseXMLResponse(), so for compatibility + // we return the first one. + return &assertions[0], nil +} + +func (sp *ServiceProvider) parseEncryptedAssertion(encryptedAssertionEl *etree.Element, possibleRequestIDs []string, now time.Time, signatureRequirement signatureRequirement) (*Assertion, error) { + assertionEl, err := sp.decryptElement(encryptedAssertionEl) + if err != nil { + return nil, fmt.Errorf("failed to decrypt EncryptedAssertion: %v", err) + } + return sp.parseAssertion(assertionEl, possibleRequestIDs, now, signatureRequirement) +} + +func (sp *ServiceProvider) decryptElement(encryptedEl *etree.Element) (*etree.Element, error) { + encryptedDataEl, err := findOneChild(encryptedEl, "http://www.w3.org/2001/04/xmlenc#", "EncryptedData") + if err != nil { + return nil, err + } + + var key interface{} = sp.Key + keyEl := encryptedEl.FindElement("./EncryptedKey") + if keyEl != nil { + var err error + key, err = xmlenc.Decrypt(sp.Key, keyEl) + if err != nil { + return nil, fmt.Errorf("failed to decrypt key from response: %s", err) + } + } + + plaintextEl, err := xmlenc.Decrypt(key, encryptedDataEl) + if err != nil { + return nil, err + } + + if err := xrv.Validate(bytes.NewReader(plaintextEl)); err != nil { + return nil, fmt.Errorf("plaintext response contains invalid XML: %s", err) + } + + doc := etree.NewDocument() + if err := doc.ReadFromBytes(plaintextEl); err != nil { + return nil, fmt.Errorf("cannot parse plaintext response %v", err) + } + return doc.Root(), nil +} + +func (sp *ServiceProvider) parseAssertion(assertionEl *etree.Element, possibleRequestIDs []string, now time.Time, signatureRequirement signatureRequirement) (*Assertion, error) { + if signatureRequirement == signatureRequired { + sigErr := sp.validateSignature(assertionEl) + if sigErr != nil { + return nil, sigErr + } + } + + // parse the assertion we just validated + var assertion Assertion + if err := unmarshalElement(assertionEl, &assertion); err != nil { + return nil, err + } + + if err := sp.validateAssertion(&assertion, possibleRequestIDs, now); err != nil { + return nil, err + } + + return &assertion, nil +} + +// validateAssertion checks that the conditions specified in assertion match +// the requirements to accept. If validation fails, it returns an error describing +// the failure. (The digital signature on the assertion is not checked -- this +// should be done before calling this function). +func (sp *ServiceProvider) validateAssertion(assertion *Assertion, possibleRequestIDs []string, now time.Time) error { + if assertion.IssueInstant.Add(MaxIssueDelay).Before(now) { + return fmt.Errorf("expired on %s", assertion.IssueInstant.Add(MaxIssueDelay)) + } + // if assertion.Issuer.Value != sp.IDPMetadata.EntityID { + // return fmt.Errorf("issuer is not %q - got %q", sp.IDPMetadata.EntityID, assertion.Issuer.Value) + // } + if assertion.Subject != nil { + for _, subjectConfirmation := range assertion.Subject.SubjectConfirmations { + requestIDvalid := false + + // We *DO NOT* validate InResponseTo when AllowIDPInitiated is set. Here's why: + // + // The SAML specification does not provide clear guidance for handling InResponseTo for IDP-initiated + // requests where there is no request to be in response to. The specification says: + // + // InResponseTo [Optional] + // The ID of a SAML protocol message in response to which an attesting entity can present the + // assertion. For example, this attribute might be used to correlate the assertion to a SAML + // request that resulted in its presentation. + // + // The initial thought was that we should specify a single empty string in possibleRequestIDs for IDP-initiated + // requests so that we would ensure that an InResponseTo was *not* provided in those cases where it wasn't + // expected. Even that turns out to be frustrating for users. And in practice some IDPs (e.g. Rippling) + // set a specific non-empty value for InResponseTo in IDP-initiated requests. + // + // Finally, it is unclear that there is significant security value in checking InResponseTo when we allow + // IDP initiated assertions. + if !sp.AllowIDPInitiated { + for _, possibleRequestID := range possibleRequestIDs { + if subjectConfirmation.SubjectConfirmationData.InResponseTo == possibleRequestID { + requestIDvalid = true + break + } + } + if !requestIDvalid { + return fmt.Errorf("assertion SubjectConfirmation one of the possible request IDs (%v)", possibleRequestIDs) + } + } + if subjectConfirmation.SubjectConfirmationData.Recipient != sp.AcsURL.String() { + return fmt.Errorf("assertion SubjectConfirmation Recipient is not %s", sp.AcsURL.String()) + } + if subjectConfirmation.SubjectConfirmationData.NotOnOrAfter.Add(MaxClockSkew).Before(now) { + return fmt.Errorf("assertion SubjectConfirmationData is expired") + } + } + } + if assertion.Conditions.NotBefore.Add(-MaxClockSkew).After(now) { + return fmt.Errorf("assertion Conditions is not yet valid") + } + if assertion.Conditions.NotOnOrAfter.Add(MaxClockSkew).Before(now) { + return fmt.Errorf("assertion Conditions is expired") + } + + audienceRestrictionsValid := len(assertion.Conditions.AudienceRestrictions) == 0 + audience := firstSet(sp.EntityID, sp.MetadataURL.String()) + for _, audienceRestriction := range assertion.Conditions.AudienceRestrictions { + if audienceRestriction.Audience.Value == audience { + audienceRestrictionsValid = true + } + } + if !audienceRestrictionsValid { + return fmt.Errorf("assertion Conditions AudienceRestriction does not contain %q", audience) + } + return nil +} + +var errSignatureElementNotPresent = errors.New("Signature element not present") + +// validateSignature returns nil iff the Signature embedded in the element is valid +func (sp *ServiceProvider) validateSignature(el *etree.Element) error { + sigEl, err := findChild(el, "http://www.w3.org/2000/09/xmldsig#", "Signature") + if err != nil { + return err + } + if sigEl == nil { + return errSignatureElementNotPresent + } + + certs, err := sp.getIDPSigningCerts() + if err != nil { + return fmt.Errorf("cannot validate signature on %s: %v", el.Tag, err) + } + + certificateStore := dsig.MemoryX509CertificateStore{ + Roots: certs, + } + + validationContext := dsig.NewDefaultValidationContext(&certificateStore) + validationContext.IdAttribute = "ID" + if Clock != nil { + validationContext.Clock = Clock + } + + // Some SAML responses contain a RSAKeyValue element. One of two things is happening here: + // + // (1) We're getting something signed by a key we already know about -- the public key + // of the signing cert provided in the metadata. + // (2) We're getting something signed by a key we *don't* know about, and which we have + // no ability to verify. + // + // The best course of action is to just remove the KeyInfo so that dsig falls back to + // verifying against the public key provided in the metadata. + if el.FindElement("./Signature/KeyInfo/X509Data/X509Certificate") == nil { + if sigEl := el.FindElement("./Signature"); sigEl != nil { + if keyInfo := sigEl.FindElement("KeyInfo"); keyInfo != nil { + sigEl.RemoveChild(keyInfo) + } + } + } + + ctx, err := etreeutils.NSBuildParentContext(el) + if err != nil { + return fmt.Errorf("cannot validate signature on %s: %v", el.Tag, err) + } + ctx, err = ctx.SubContext(el) + if err != nil { + return fmt.Errorf("cannot validate signature on %s: %v", el.Tag, err) + } + el, err = etreeutils.NSDetatch(ctx, el) + if err != nil { + return fmt.Errorf("cannot validate signature on %s: %v", el.Tag, err) + } + + if sp.SignatureVerifier != nil { + return sp.SignatureVerifier.VerifySignature(validationContext, el) + } + + if _, err := validationContext.Validate(el); err != nil { + return fmt.Errorf("cannot validate signature on %s: %v", el.Tag, err) + } + + return nil +} + +// SignLogoutRequest adds the `Signature` element to the `LogoutRequest`. +func (sp *ServiceProvider) SignLogoutRequest(req *LogoutRequest) error { + keyPair := tls.Certificate{ + Certificate: [][]byte{sp.Certificate.Raw}, + PrivateKey: sp.Key, + Leaf: sp.Certificate, + } + // TODO: add intermediates for SP + //for _, cert := range sp.Intermediates { + // keyPair.Certificate = append(keyPair.Certificate, cert.Raw) + //} + keyStore := dsig.TLSCertKeyStore(keyPair) + + if sp.SignatureMethod != dsig.RSASHA1SignatureMethod && + sp.SignatureMethod != dsig.RSASHA256SignatureMethod && + sp.SignatureMethod != dsig.RSASHA512SignatureMethod { + return fmt.Errorf("invalid signing method %s", sp.SignatureMethod) + } + signatureMethod := sp.SignatureMethod + signingContext := dsig.NewDefaultSigningContext(keyStore) + signingContext.Canonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList(canonicalizerPrefixList) + if err := signingContext.SetSignatureMethod(signatureMethod); err != nil { + return err + } + + assertionEl := req.Element() + + signedRequestEl, err := signingContext.SignEnveloped(assertionEl) + if err != nil { + return err + } + + sigEl := signedRequestEl.Child[len(signedRequestEl.Child)-1] + req.Signature = sigEl.(*etree.Element) + return nil +} + +// MakeLogoutRequest produces a new LogoutRequest object for idpURL. +func (sp *ServiceProvider) MakeLogoutRequest(idpURL, nameID string) (*LogoutRequest, error) { + + req := LogoutRequest{ + ID: fmt.Sprintf("id-%x", randomBytes(20)), + IssueInstant: TimeNow(), + Version: "2.0", + Destination: idpURL, + Issuer: &Issuer{ + Format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity", + Value: firstSet(sp.EntityID, sp.MetadataURL.String()), + }, + NameID: &NameID{ + Format: sp.nameIDFormat(), + Value: nameID, + NameQualifier: sp.IDPMetadata.EntityID, + SPNameQualifier: sp.Metadata().EntityID, + }, + } + if len(sp.SignatureMethod) > 0 { + if err := sp.SignLogoutRequest(&req); err != nil { + return nil, err + } + } + return &req, nil +} + +// MakeRedirectLogoutRequest creates a SAML authentication request using +// the HTTP-Redirect binding. It returns a URL that we will redirect the user to +// in order to start the auth process. +func (sp *ServiceProvider) MakeRedirectLogoutRequest(nameID, relayState string) (*url.URL, error) { + req, err := sp.MakeLogoutRequest(sp.GetSLOBindingLocation(HTTPRedirectBinding), nameID) + if err != nil { + return nil, err + } + return req.Redirect(relayState), nil +} + +// Redirect returns a URL suitable for using the redirect binding with the request +func (req *LogoutRequest) Redirect(relayState string) *url.URL { + w := &bytes.Buffer{} + w1 := base64.NewEncoder(base64.StdEncoding, w) + w2, _ := flate.NewWriter(w1, 9) + doc := etree.NewDocument() + doc.SetRoot(req.Element()) + if _, err := doc.WriteTo(w2); err != nil { + panic(err) + } + w2.Close() + w1.Close() + + rv, _ := url.Parse(req.Destination) + + query := rv.Query() + query.Set("SAMLRequest", string(w.Bytes())) + if relayState != "" { + query.Set("RelayState", relayState) + } + rv.RawQuery = query.Encode() + + return rv +} + +// MakePostLogoutRequest creates a SAML authentication request using +// the HTTP-POST binding. It returns HTML text representing an HTML form that +// can be sent presented to a browser to initiate the logout process. +func (sp *ServiceProvider) MakePostLogoutRequest(nameID, relayState string) ([]byte, error) { + req, err := sp.MakeLogoutRequest(sp.GetSLOBindingLocation(HTTPPostBinding), nameID) + if err != nil { + return nil, err + } + return req.Post(relayState), nil +} + +// Post returns an HTML form suitable for using the HTTP-POST binding with the request +func (req *LogoutRequest) Post(relayState string) []byte { + doc := etree.NewDocument() + doc.SetRoot(req.Element()) + reqBuf, err := doc.WriteToBytes() + if err != nil { + panic(err) + } + encodedReqBuf := base64.StdEncoding.EncodeToString(reqBuf) + + tmpl := template.Must(template.New("saml-post-form").Parse(`` + + `
` + + `` + + `` + + `` + + `
` + + ``)) + data := struct { + URL string + SAMLRequest string + RelayState string + }{ + URL: req.Destination, + SAMLRequest: encodedReqBuf, + RelayState: relayState, + } + + rv := bytes.Buffer{} + if err := tmpl.Execute(&rv, data); err != nil { + panic(err) + } + + return rv.Bytes() +} + +// MakeLogoutResponse produces a new LogoutResponse object for idpURL and logoutRequestID. +func (sp *ServiceProvider) MakeLogoutResponse(idpURL, logoutRequestID string) (*LogoutResponse, error) { + response := LogoutResponse{ + ID: fmt.Sprintf("id-%x", randomBytes(20)), + InResponseTo: logoutRequestID, + Version: "2.0", + IssueInstant: TimeNow(), + Destination: idpURL, + Issuer: &Issuer{ + Format: "urn:oasis:names:tc:SAML:2.0:nameid-format:entity", + Value: firstSet(sp.EntityID, sp.MetadataURL.String()), + }, + Status: Status{ + StatusCode: StatusCode{ + Value: StatusSuccess, + }, + }, + } + + if len(sp.SignatureMethod) > 0 { + if err := sp.SignLogoutResponse(&response); err != nil { + return nil, err + } + } + return &response, nil +} + +// MakeRedirectLogoutResponse creates a SAML LogoutResponse using +// the HTTP-Redirect binding. It returns a URL that we will redirect the user to +// for LogoutResponse. +func (sp *ServiceProvider) MakeRedirectLogoutResponse(logoutRequestID, relayState string) (*url.URL, error) { + resp, err := sp.MakeLogoutResponse(sp.GetSLOBindingLocation(HTTPRedirectBinding), logoutRequestID) + if err != nil { + return nil, err + } + return resp.Redirect(relayState), nil +} + +// Redirect returns a URL suitable for using the redirect binding with the LogoutResponse. +func (resp *LogoutResponse) Redirect(relayState string) *url.URL { + w := &bytes.Buffer{} + w1 := base64.NewEncoder(base64.StdEncoding, w) + w2, _ := flate.NewWriter(w1, 9) + doc := etree.NewDocument() + doc.SetRoot(resp.Element()) + if _, err := doc.WriteTo(w2); err != nil { + panic(err) + } + w2.Close() + w1.Close() + + rv, _ := url.Parse(resp.Destination) + + query := rv.Query() + query.Set("SAMLResponse", string(w.Bytes())) + if relayState != "" { + query.Set("RelayState", relayState) + } + rv.RawQuery = query.Encode() + + return rv +} + +// MakePostLogoutResponse creates a SAML LogoutResponse using +// the HTTP-POST binding. It returns HTML text representing an HTML form that +// can be sent presented to a browser for LogoutResponse. +func (sp *ServiceProvider) MakePostLogoutResponse(logoutRequestID, relayState string) ([]byte, error) { + resp, err := sp.MakeLogoutResponse(sp.GetSLOBindingLocation(HTTPPostBinding), logoutRequestID) + if err != nil { + return nil, err + } + return resp.Post(relayState), nil +} + +// Post returns an HTML form suitable for using the HTTP-POST binding with the LogoutResponse. +func (resp *LogoutResponse) Post(relayState string) []byte { + doc := etree.NewDocument() + doc.SetRoot(resp.Element()) + reqBuf, err := doc.WriteToBytes() + if err != nil { + panic(err) + } + encodedReqBuf := base64.StdEncoding.EncodeToString(reqBuf) + + tmpl := template.Must(template.New("saml-post-form").Parse(`` + + `
` + + `` + + `` + + `` + + `
` + + ``)) + data := struct { + URL string + SAMLResponse string + RelayState string + }{ + URL: resp.Destination, + SAMLResponse: encodedReqBuf, + RelayState: relayState, + } + + rv := bytes.Buffer{} + if err := tmpl.Execute(&rv, data); err != nil { + panic(err) + } + + return rv.Bytes() +} + +// SignLogoutResponse adds the `Signature` element to the `LogoutResponse`. +func (sp *ServiceProvider) SignLogoutResponse(resp *LogoutResponse) error { + keyPair := tls.Certificate{ + Certificate: [][]byte{sp.Certificate.Raw}, + PrivateKey: sp.Key, + Leaf: sp.Certificate, + } + // TODO: add intermediates for SP + //for _, cert := range sp.Intermediates { + // keyPair.Certificate = append(keyPair.Certificate, cert.Raw) + //} + keyStore := dsig.TLSCertKeyStore(keyPair) + + if sp.SignatureMethod != dsig.RSASHA1SignatureMethod && + sp.SignatureMethod != dsig.RSASHA256SignatureMethod && + sp.SignatureMethod != dsig.RSASHA512SignatureMethod { + return fmt.Errorf("invalid signing method %s", sp.SignatureMethod) + } + signatureMethod := sp.SignatureMethod + signingContext := dsig.NewDefaultSigningContext(keyStore) + signingContext.Canonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList(canonicalizerPrefixList) + if err := signingContext.SetSignatureMethod(signatureMethod); err != nil { + return err + } + + assertionEl := resp.Element() + + signedRequestEl, err := signingContext.SignEnveloped(assertionEl) + if err != nil { + return err + } + + sigEl := signedRequestEl.Child[len(signedRequestEl.Child)-1] + resp.Signature = sigEl.(*etree.Element) + return nil +} + +func (sp *ServiceProvider) nameIDFormat() string { + var nameIDFormat string + switch sp.AuthnNameIDFormat { + case "": + // To maintain library back-compat, use "transient" if unset. + nameIDFormat = string(TransientNameIDFormat) + case UnspecifiedNameIDFormat: + // Spec defines an empty value as "unspecified" so don't set one. + default: + nameIDFormat = string(sp.AuthnNameIDFormat) + } + return nameIDFormat +} + +// ValidateLogoutResponseRequest validates the LogoutResponse content from the request +func (sp *ServiceProvider) ValidateLogoutResponseRequest(req *http.Request) error { + if data := req.URL.Query().Get("SAMLResponse"); data != "" { + return sp.ValidateLogoutResponseRedirect(data) + } + + err := req.ParseForm() + if err != nil { + return fmt.Errorf("unable to parse form: %v", err) + } + + return sp.ValidateLogoutResponseForm(req.PostForm.Get("SAMLResponse")) +} + +// ValidateLogoutResponseForm returns a nil error if the logout response is valid. +func (sp *ServiceProvider) ValidateLogoutResponseForm(postFormData string) error { + retErr := &InvalidResponseError{ + Now: TimeNow(), + } + + rawResponseBuf, err := base64.StdEncoding.DecodeString(postFormData) + if err != nil { + retErr.PrivateErr = fmt.Errorf("unable to parse base64: %s", err) + return retErr + } + retErr.Response = string(rawResponseBuf) + + // TODO(ross): add test case for this (SLO does not have tests right now) + if err := xrv.Validate(bytes.NewReader(rawResponseBuf)); err != nil { + return fmt.Errorf("response contains invalid XML: %s", err) + } + + doc := etree.NewDocument() + if err := doc.ReadFromBytes(rawResponseBuf); err != nil { + retErr.PrivateErr = err + return retErr + } + + if err := sp.validateSignature(doc.Root()); err != nil { + retErr.PrivateErr = err + return retErr + } + + var resp LogoutResponse + if err := unmarshalElement(doc.Root(), &resp); err != nil { + retErr.PrivateErr = err + return retErr + } + if err := sp.validateLogoutResponse(&resp); err != nil { + return err + } + return nil +} + +// ValidateLogoutResponseRedirect returns a nil error if the logout response is valid. +// +// URL Binding appears to be gzip / flate encoded +// See https://www.oasis-open.org/committees/download.php/20645/sstc-saml-tech-overview-2%200-draft-10.pdf 6.6 +func (sp *ServiceProvider) ValidateLogoutResponseRedirect(queryParameterData string) error { + retErr := &InvalidResponseError{ + Now: TimeNow(), + } + + rawResponseBuf, err := base64.StdEncoding.DecodeString(queryParameterData) + if err != nil { + retErr.PrivateErr = fmt.Errorf("unable to parse base64: %s", err) + return retErr + } + retErr.Response = string(rawResponseBuf) + + gr, err := ioutil.ReadAll(flate.NewReader(bytes.NewBuffer(rawResponseBuf))) + if err != nil { + retErr.PrivateErr = err + return retErr + } + + if err := xrv.Validate(bytes.NewReader(gr)); err != nil { + return err + } + + doc := etree.NewDocument() + if err := doc.ReadFromBytes(rawResponseBuf); err != nil { + retErr.PrivateErr = err + return retErr + } + + if err := sp.validateSignature(doc.Root()); err != nil { + retErr.PrivateErr = err + return retErr + } + + var resp LogoutResponse + if err := unmarshalElement(doc.Root(), &resp); err != nil { + retErr.PrivateErr = err + return retErr + } + if err := sp.validateLogoutResponse(&resp); err != nil { + return err + } + return nil +} + +// validateLogoutResponse validates the LogoutResponse fields. Returns a nil error if the LogoutResponse is valid. +func (sp *ServiceProvider) validateLogoutResponse(resp *LogoutResponse) error { + if resp.Destination != sp.SloURL.String() { + return fmt.Errorf("`Destination` does not match SloURL (expected %q)", sp.SloURL.String()) + } + + now := time.Now() + if resp.IssueInstant.Add(MaxIssueDelay).Before(now) { + return fmt.Errorf("issueInstant expired at %s", resp.IssueInstant.Add(MaxIssueDelay)) + } + if resp.Issuer.Value != sp.IDPMetadata.EntityID { + return fmt.Errorf("issuer does not match the IDP metadata (expected %q)", sp.IDPMetadata.EntityID) + } + if resp.Status.StatusCode.Value != StatusSuccess { + return fmt.Errorf("status code was not %s", StatusSuccess) + } + + return nil +} + +func firstSet(a, b string) string { + if a == "" { + return b + } + return a +} + +// findChildren returns all the elements matching childNS/childTag that are direct children of parentEl. +func findChildren(parentEl *etree.Element, childNS string, childTag string) ([]*etree.Element, error) { + var rv []*etree.Element + for _, childEl := range parentEl.ChildElements() { + if childEl.Tag != childTag { + continue + } + + ctx, err := etreeutils.NSBuildParentContext(childEl) + if err != nil { + return nil, err + } + ctx, err = ctx.SubContext(childEl) + if err != nil { + return nil, err + } + + ns, err := ctx.LookupPrefix(childEl.Space) + if err != nil { + return nil, fmt.Errorf("[%s]:%s cannot find prefix %s: %v", childNS, childTag, childEl.Space, err) + } + if ns != childNS { + continue + } + + rv = append(rv, childEl) + } + + return rv, nil +} + +// findOneChild finds the specified child element. Returns an error if the element doesn't exist. +func findOneChild(parentEl *etree.Element, childNS string, childTag string) (*etree.Element, error) { + children, err := findChildren(parentEl, childNS, childTag) + if err != nil { + return nil, err + } + switch len(children) { + case 0: + return nil, fmt.Errorf("cannot find %s:%s element", childNS, childTag) + case 1: + return children[0], nil + default: + return nil, fmt.Errorf("expected exactly one %s:%s element", childNS, childTag) + } +} + +// findChild finds the specified child element. Returns (nil, nil) of the element doesn't exist. +func findChild(parentEl *etree.Element, childNS string, childTag string) (*etree.Element, error) { + children, err := findChildren(parentEl, childNS, childTag) + if err != nil { + return nil, err + } + switch len(children) { + case 0: + return nil, nil + case 1: + return children[0], nil + default: + return nil, fmt.Errorf("expected at most one %s:%s element", childNS, childTag) + } +} + +func elementToBytes(el *etree.Element) ([]byte, error) { + namespaces := map[string]string{} + for _, childEl := range el.FindElements("//*") { + ns := childEl.NamespaceURI() + if ns != "" { + namespaces[childEl.Space] = ns + } + } + + doc := etree.NewDocument() + doc.SetRoot(el.Copy()) + for space, uri := range namespaces { + doc.Root().CreateAttr("xmlns:"+space, uri) + } + + return doc.WriteToBytes() +} + +// unmarshalElement serializes el into v by serializing el and then parsing it with xml.Unmarshal. +func unmarshalElement(el *etree.Element, v interface{}) error { + buf, err := elementToBytes(el) + if err != nil { + return err + } + return xml.Unmarshal(buf, v) +} + +func elementToString(el *etree.Element) string { + buf, err := elementToBytes(el) + if err != nil { + return "" + } + return string(buf) +} diff --git a/vendor/github.com/mickael-kerjean/saml/time.go b/vendor/github.com/mickael-kerjean/saml/time.go new file mode 100644 index 00000000..3f266f97 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/time.go @@ -0,0 +1,52 @@ +package saml + +import "time" + +// RelaxedTime is a version of time.Time that supports the time format +// found in SAML documents. +type RelaxedTime time.Time + +const timeFormat = "2006-01-02T15:04:05.999Z07:00" + +// MarshalText implements encoding.TextMarshaler +func (m RelaxedTime) MarshalText() ([]byte, error) { + // According to section 1.2.2 of the OASIS SAML 1.1 spec, we can't trust + // other applications to handle time resolution finer than a millisecond. + // + // The time MUST be expressed in UTC. + return []byte(m.String()), nil +} + +func (m RelaxedTime) String() string { + return time.Time(m).Round(time.Millisecond).UTC().Format(timeFormat) +} + +// UnmarshalText implements encoding.TextUnmarshaler +func (m *RelaxedTime) UnmarshalText(text []byte) error { + if len(text) == 0 { + *m = RelaxedTime(time.Time{}) + return nil + } + t, err1 := time.Parse(time.RFC3339, string(text)) + if err1 == nil { + t = t.Round(time.Millisecond) + *m = RelaxedTime(t) + return nil + } + + t, err2 := time.Parse(time.RFC3339Nano, string(text)) + if err2 == nil { + t = t.Round(time.Millisecond) + *m = RelaxedTime(t) + return nil + } + + t, err2 = time.Parse("2006-01-02T15:04:05.999999999", string(text)) + if err2 == nil { + t = t.Round(time.Millisecond) + *m = RelaxedTime(t) + return nil + } + + return err1 +} diff --git a/vendor/github.com/mickael-kerjean/saml/util.go b/vendor/github.com/mickael-kerjean/saml/util.go new file mode 100644 index 00000000..c9731b1b --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/util.go @@ -0,0 +1,31 @@ +package saml + +import ( + "crypto/rand" + "io" + "time" + + dsig "github.com/russellhaering/goxmldsig" +) + +// TimeNow is a function that returns the current time. The default +// value is time.Now, but it can be replaced for testing. +var TimeNow = func() time.Time { return time.Now().UTC() } + +// Clock is assigned to dsig validation and signing contexts if it is +// not nil, otherwise the default clock is used. +var Clock *dsig.Clock + +// RandReader is the io.Reader that produces cryptographically random +// bytes when they are need by the library. The default value is +// rand.Reader, but it can be replaced for testing. +var RandReader = rand.Reader + +func randomBytes(n int) []byte { + rv := make([]byte, n) + + if _, err := io.ReadFull(RandReader, rv); err != nil { + panic(err) + } + return rv +} diff --git a/vendor/github.com/mickael-kerjean/saml/xmlenc/cbc.go b/vendor/github.com/mickael-kerjean/saml/xmlenc/cbc.go new file mode 100644 index 00000000..77ddb3b2 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/xmlenc/cbc.go @@ -0,0 +1,187 @@ +package xmlenc + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/des" // nolint: gas + "encoding/base64" + "errors" + "fmt" + + "github.com/beevik/etree" +) + +// CBC implements Decrypter and Encrypter for block ciphers in CBC mode +type CBC struct { + keySize int + algorithm string + cipher func([]byte) (cipher.Block, error) +} + +// KeySize returns the length of the key required. +func (e CBC) KeySize() int { + return e.keySize +} + +// Algorithm returns the name of the algorithm, as will be found +// in an xenc:EncryptionMethod element. +func (e CBC) Algorithm() string { + return e.algorithm +} + +// Encrypt encrypts plaintext with key, which should be a []byte of length KeySize(). +// It returns an xenc:EncryptedData element. +func (e CBC) Encrypt(key interface{}, plaintext []byte, nonce []byte) (*etree.Element, error) { + keyBuf, ok := key.([]byte) + if !ok { + return nil, ErrIncorrectKeyType("[]byte") + } + if len(keyBuf) != e.keySize { + return nil, ErrIncorrectKeyLength(e.keySize) + } + + block, err := e.cipher(keyBuf) + if err != nil { + return nil, err + } + + encryptedDataEl := etree.NewElement("xenc:EncryptedData") + encryptedDataEl.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#") + { + randBuf := make([]byte, 16) + if _, err := RandReader.Read(randBuf); err != nil { + return nil, err + } + encryptedDataEl.CreateAttr("Id", fmt.Sprintf("_%x", randBuf)) + } + + em := encryptedDataEl.CreateElement("xenc:EncryptionMethod") + em.CreateAttr("Algorithm", e.algorithm) + em.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#") + + plaintext = appendPadding(plaintext, block.BlockSize()) + + iv := make([]byte, block.BlockSize()) + if _, err := RandReader.Read(iv); err != nil { + return nil, err + } + + mode := cipher.NewCBCEncrypter(block, iv) + ciphertext := make([]byte, len(plaintext)) + mode.CryptBlocks(ciphertext, plaintext) + ciphertext = append(iv, ciphertext...) + + cd := encryptedDataEl.CreateElement("xenc:CipherData") + cd.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#") + cd.CreateElement("xenc:CipherValue").SetText(base64.StdEncoding.EncodeToString(ciphertext)) + return encryptedDataEl, nil +} + +// Decrypt decrypts an encrypted element with key. If the ciphertext contains an +// EncryptedKey element, then the type of `key` is determined by the registered +// Decryptor for the EncryptedKey element. Otherwise, `key` must be a []byte of +// length KeySize(). +func (e CBC) Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error) { + // If the key is encrypted, decrypt it. + if encryptedKeyEl := ciphertextEl.FindElement("./KeyInfo/EncryptedKey"); encryptedKeyEl != nil { + var err error + key, err = Decrypt(key, encryptedKeyEl) + if err != nil { + return nil, err + } + } + + keyBuf, ok := key.([]byte) + if !ok { + return nil, ErrIncorrectKeyType("[]byte") + } + if len(keyBuf) != e.KeySize() { + return nil, ErrIncorrectKeyLength(e.KeySize()) + } + + block, err := e.cipher(keyBuf) + if err != nil { + return nil, err + } + + ciphertext, err := getCiphertext(ciphertextEl) + if err != nil { + return nil, err + } + + if len(ciphertext) < block.BlockSize() { + return nil, errors.New("ciphertext too short") + } + + iv := ciphertext[:aes.BlockSize] + ciphertext = ciphertext[aes.BlockSize:] + + mode := cipher.NewCBCDecrypter(block, iv) + plaintext := make([]byte, len(ciphertext)) + mode.CryptBlocks(plaintext, ciphertext) // decrypt in place + + plaintext, err = stripPadding(plaintext) + if err != nil { + return nil, err + } + + return plaintext, nil +} + +var ( + // AES128CBC implements AES128-CBC symetric key mode for encryption and decryption + AES128CBC BlockCipher = CBC{ + keySize: 16, + algorithm: "http://www.w3.org/2001/04/xmlenc#aes128-cbc", + cipher: aes.NewCipher, + } + + // AES192CBC implements AES192-CBC symetric key mode for encryption and decryption + AES192CBC BlockCipher = CBC{ + keySize: 24, + algorithm: "http://www.w3.org/2001/04/xmlenc#aes192-cbc", + cipher: aes.NewCipher, + } + + // AES256CBC implements AES256-CBC symetric key mode for encryption and decryption + AES256CBC BlockCipher = CBC{ + keySize: 32, + algorithm: "http://www.w3.org/2001/04/xmlenc#aes256-cbc", + cipher: aes.NewCipher, + } + + // TripleDES implements 3DES in CBC mode for encryption and decryption + TripleDES BlockCipher = CBC{ + keySize: 8, + algorithm: "http://www.w3.org/2001/04/xmlenc#tripledes-cbc", + cipher: des.NewCipher, + } +) + +func init() { + RegisterDecrypter(AES128CBC) + RegisterDecrypter(AES192CBC) + RegisterDecrypter(AES256CBC) + RegisterDecrypter(TripleDES) +} + +func appendPadding(buf []byte, blockSize int) []byte { + paddingBytes := blockSize - (len(buf) % blockSize) + padding := make([]byte, paddingBytes) + padding[len(padding)-1] = byte(paddingBytes) + return append(buf, padding...) +} + +func stripPadding(buf []byte) ([]byte, error) { + if len(buf) < 1 { + return nil, errors.New("buffer is too short for padding") + } + paddingBytes := int(buf[len(buf)-1]) + if paddingBytes > len(buf)-1 { + return nil, errors.New("buffer is too short for padding") + } + if paddingBytes < 1 { + return nil, errors.New("padding must be at least one byte") + } + return buf[:len(buf)-paddingBytes], nil +} diff --git a/vendor/github.com/mickael-kerjean/saml/xmlenc/decrypt.go b/vendor/github.com/mickael-kerjean/saml/xmlenc/decrypt.go new file mode 100644 index 00000000..93991f9f --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/xmlenc/decrypt.go @@ -0,0 +1,115 @@ +package xmlenc + +import ( + + // nolint: gas + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + + "strings" + + "github.com/beevik/etree" +) + +// ErrAlgorithmNotImplemented is returned when encryption used is not +// supported. +type ErrAlgorithmNotImplemented string + +func (e ErrAlgorithmNotImplemented) Error() string { + return "algorithm is not implemented: " + string(e) +} + +// ErrCannotFindRequiredElement is returned by Decrypt when a required +// element cannot be found. +type ErrCannotFindRequiredElement string + +func (e ErrCannotFindRequiredElement) Error() string { + return "cannot find required element: " + string(e) +} + +// ErrIncorrectTag is returned when Decrypt is passed an element which +// is neither an EncryptedType nor an EncryptedKey +var ErrIncorrectTag = fmt.Errorf("tag must be an EncryptedType or EncryptedKey") + +// ErrIncorrectKeyLength is returned when the fixed length key is not +// of the required length. +type ErrIncorrectKeyLength int + +func (e ErrIncorrectKeyLength) Error() string { + return fmt.Sprintf("expected key to be %d bytes", int(e)) +} + +// ErrIncorrectKeyType is returned when the key is not the correct type +type ErrIncorrectKeyType string + +func (e ErrIncorrectKeyType) Error() string { + return fmt.Sprintf("expected key to be %s", string(e)) +} + +// Decrypt decrypts the encrypted data using the provided key. If the +// data are encrypted using AES or 3DEC, then the key should be a []byte. +// If the data are encrypted with PKCS1v15 or RSA-OAEP-MGF1P then key should +// be a *rsa.PrivateKey. +func Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error) { + encryptionMethodEl := ciphertextEl.FindElement("./EncryptionMethod") + if encryptionMethodEl == nil { + return nil, ErrCannotFindRequiredElement("EncryptionMethod") + } + algorithm := encryptionMethodEl.SelectAttrValue("Algorithm", "") + decrypter, ok := decrypters[algorithm] + if !ok { + return nil, ErrAlgorithmNotImplemented(algorithm) + } + return decrypter.Decrypt(key, ciphertextEl) +} + +func getCiphertext(encryptedKey *etree.Element) ([]byte, error) { + ciphertextEl := encryptedKey.FindElement("./CipherData/CipherValue") + if ciphertextEl == nil { + return nil, fmt.Errorf("cannot find CipherData element containing a CipherValue element") + } + ciphertext, err := base64.StdEncoding.DecodeString(strings.TrimSpace(ciphertextEl.Text())) + if err != nil { + return nil, err + } + return ciphertext, nil +} + +func validateRSAKeyIfPresent(key interface{}, encryptedKey *etree.Element) (*rsa.PrivateKey, error) { + rsaKey, ok := key.(*rsa.PrivateKey) + if !ok { + return nil, errors.New("expected key to be a *rsa.PrivateKey") + } + + // extract and verify that the public key matches the certificate + // this section is included to either let the service know up front + // if the key will work, or let the service provider know which key + // to use to decrypt the message. Either way, verification is not + // security-critical. + if el := encryptedKey.FindElement("./KeyInfo/X509Data/X509Certificate"); el != nil { + certPEMbuf := el.Text() + certPEMbuf = "-----BEGIN CERTIFICATE-----\n" + certPEMbuf + "\n-----END CERTIFICATE-----\n" + certPEM, _ := pem.Decode([]byte(certPEMbuf)) + if certPEM == nil { + return nil, fmt.Errorf("invalid certificate") + } + cert, err := x509.ParseCertificate(certPEM.Bytes) + if err != nil { + return nil, err + } + pubKey, ok := cert.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, fmt.Errorf("expected certificate to be an *rsa.PublicKey") + } + if rsaKey.N.Cmp(pubKey.N) != 0 || rsaKey.E != pubKey.E { + return nil, fmt.Errorf("certificate does not match provided key") + } + } else if el = encryptedKey.FindElement("./KeyInfo/X509Data/X509IssuerSerial"); el != nil { + // TODO: determine how to validate the issuer serial information + } + return rsaKey, nil +} diff --git a/vendor/github.com/mickael-kerjean/saml/xmlenc/digest.go b/vendor/github.com/mickael-kerjean/saml/xmlenc/digest.go new file mode 100644 index 00000000..801347f2 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/xmlenc/digest.go @@ -0,0 +1,56 @@ +package xmlenc + +import ( + "crypto/sha1" //nolint:gosec // required for protocol support + "crypto/sha256" + "crypto/sha512" + "hash" + + "golang.org/x/crypto/ripemd160" +) + +type digestMethod struct { + algorithm string + hash func() hash.Hash +} + +func (dm digestMethod) Algorithm() string { + return dm.algorithm +} + +func (dm digestMethod) Hash() hash.Hash { + return dm.hash() +} + +var ( + // SHA1 implements the SHA-1 digest method (which is considered insecure) + SHA1 = digestMethod{ + algorithm: "http://www.w3.org/2000/09/xmldsig#sha1", + hash: sha1.New, + } + + // SHA256 implements the SHA-256 digest method + SHA256 = digestMethod{ + algorithm: "http://www.w3.org/2000/09/xmldsig#sha256", + hash: sha256.New, + } + + // SHA512 implements the SHA-512 digest method + SHA512 = digestMethod{ + algorithm: "http://www.w3.org/2000/09/xmldsig#sha512", + hash: sha512.New, + } + + // RIPEMD160 implements the RIPEMD160 digest method + RIPEMD160 = digestMethod{ + algorithm: "http://www.w3.org/2000/09/xmldsig#ripemd160", + hash: ripemd160.New, + } +) + +func init() { + RegisterDigestMethod(SHA1) + RegisterDigestMethod(SHA256) + RegisterDigestMethod(SHA512) + RegisterDigestMethod(RIPEMD160) +} diff --git a/vendor/github.com/mickael-kerjean/saml/xmlenc/fuzz.go b/vendor/github.com/mickael-kerjean/saml/xmlenc/fuzz.go new file mode 100644 index 00000000..c035d65f --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/xmlenc/fuzz.go @@ -0,0 +1,49 @@ +package xmlenc + +import ( + "crypto/rsa" + "crypto/x509" + "encoding/pem" + + "github.com/beevik/etree" +) + +var testKey = func() *rsa.PrivateKey { + const keyStr = `-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDkXTUsWzRVpUHjbDpWCfYDfXmQ/q4LkaioZoTpu4ut1Q3eQC5t +gD14agJhgT8yzeY5S/YNlwCyuVkjuFyoyTHFX2IOPpz7jnh4KnQ+B1IH9fY/+kmk +zHJgxSUDJsdUMPgGpKt5hnEn7ziXAWXLc2udFbnHwhi9TXXwRHGi9wZ4YwIDAQAB +AoGBALNTnlXeqRI4W61DZ+v4ln/XIIeD9xiOoWrcVrNU2zL+g41ryQmkEqFkXcpD +vGUg2xFTXTz+v0WZ1y39sIW6uKFRYUfaNsF6iVfGAyx1VWK/jgtPnCWDQy26Eby0 +BqpbZRy1a6MLYVEG/5bvZE01CDV4XttpTrNX91WWcYGduJxBAkEA6ED1ZOqIzBpu +c2KAo+bWmroCH8+cSDk0gVq6bnRB+EEhRCmo/VgvndWLxfexdGmDIOAIisB06N5a +GzBSCaEY/QJBAPu2cNvuuBNLwrlxPCwOEpIHYT4gJq8UMtg6O6N+u++nYCGhK6uo +VCmrKY+UewyNIcsLZF0jsNI2qJjiU1vQxN8CQQDfQJnigMQwlfO3/Ga1po6Buu2R +0IpkroB3G1R8GkrTrR+iGv2zUdKrwHsUOC2fPlFrB4+OeMOomRw6aG9jjDStAkB1 +ztiZhuvuVAoKIv5HnDqC0CNqIUAZtzlozDB3f+xT6SFr+/Plfn4Nlod4JMVGhZNo +ZaeOlBLBAEX+cAcVtOs/AkBicZOAPv84ABmFfyhXhYaAuacaJLq//jg+t+URUOg+ +XZS9naRmawEQxOkZQVoMeKgvu05+V4MniFqdQBINIkr5 +-----END RSA PRIVATE KEY-----` + b, _ := pem.Decode([]byte(keyStr)) + k, err := x509.ParsePKCS1PrivateKey(b.Bytes) + if err != nil { + panic(err) + } + return k +}() + +// Fuzz is the go-fuzz fuzzing function +func Fuzz(data []byte) int { + doc := etree.NewDocument() + if err := doc.ReadFromBytes(data); err != nil { + return 0 + } + if doc.Root() == nil { + return 0 + } + + if _, err := Decrypt(testKey, doc.Root()); err != nil { + return 0 + } + return 1 +} diff --git a/vendor/github.com/mickael-kerjean/saml/xmlenc/gcm.go b/vendor/github.com/mickael-kerjean/saml/xmlenc/gcm.go new file mode 100644 index 00000000..91911319 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/xmlenc/gcm.go @@ -0,0 +1,143 @@ +package xmlenc + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "fmt" + "io" + + "github.com/beevik/etree" +) + +// GCM implements Decrypter and Encrypter for block ciphers in struct mode +type GCM struct { + keySize int + algorithm string + cipher func([]byte) (cipher.Block, error) +} + +// KeySize returns the length of the key required. +func (e GCM) KeySize() int { + return e.keySize +} + +// Algorithm returns the name of the algorithm, as will be found +// in an xenc:EncryptionMethod element. +func (e GCM) Algorithm() string { + return e.algorithm +} + +// Encrypt encrypts plaintext with key and nonce +func (e GCM) Encrypt(key interface{}, plaintext []byte, nonce []byte) (*etree.Element, error) { + keyBuf, ok := key.([]byte) + if !ok { + return nil, ErrIncorrectKeyType("[]byte") + } + if len(keyBuf) != e.keySize { + return nil, ErrIncorrectKeyLength(e.keySize) + } + + block, err := e.cipher(keyBuf) + if err != nil { + return nil, err + } + + encryptedDataEl := etree.NewElement("xenc:EncryptedData") + encryptedDataEl.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#") + { + randBuf := make([]byte, 16) + if _, err := RandReader.Read(randBuf); err != nil { + return nil, err + } + encryptedDataEl.CreateAttr("Id", fmt.Sprintf("_%x", randBuf)) + } + + em := encryptedDataEl.CreateElement("xenc:EncryptionMethod") + em.CreateAttr("Algorithm", e.algorithm) + em.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#") + + plaintext = appendPadding(plaintext, block.BlockSize()) + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + if nonce == nil { + // generate random nonce when it's nil + nonce := make([]byte, aesgcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + panic(err.Error()) + } + } + + ciphertext := make([]byte, len(plaintext)) + text := aesgcm.Seal(nil, nonce, ciphertext, nil) + + cd := encryptedDataEl.CreateElement("xenc:CipherData") + cd.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#") + cd.CreateElement("xenc:CipherValue").SetText(base64.StdEncoding.EncodeToString(text)) + return encryptedDataEl, nil +} + +// Decrypt decrypts an encrypted element with key. If the ciphertext contains an +// EncryptedKey element, then the type of `key` is determined by the registered +// Decryptor for the EncryptedKey element. Otherwise, `key` must be a []byte of +// length KeySize(). +func (e GCM) Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error) { + if encryptedKeyEl := ciphertextEl.FindElement("./KeyInfo/EncryptedKey"); encryptedKeyEl != nil { + var err error + key, err = Decrypt(key, encryptedKeyEl) + if err != nil { + return nil, err + } + } + + keyBuf, ok := key.([]byte) + + if !ok { + return nil, ErrIncorrectKeyType("[]byte") + } + if len(keyBuf) != e.KeySize() { + return nil, ErrIncorrectKeyLength(e.KeySize()) + } + + block, err := e.cipher(keyBuf) + if err != nil { + return nil, err + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + ciphertext, err := getCiphertext(ciphertextEl) + if err != nil { + return nil, err + } + + nonce := ciphertext[:aesgcm.NonceSize()] + text := ciphertext[aesgcm.NonceSize():] + + plainText, err := aesgcm.Open(nil, nonce, text, nil) + if err != nil { + return nil, err + } + return plainText, nil +} + +var ( + // AES128GCM implements AES128-GCM mode for encryption and decryption + AES128GCM BlockCipher = GCM{ + keySize: 16, + algorithm: "http://www.w3.org/2009/xmlenc11#aes128-gcm", + cipher: aes.NewCipher, + } +) + +func init() { + RegisterDecrypter(AES128GCM) +} diff --git a/vendor/github.com/mickael-kerjean/saml/xmlenc/pubkey.go b/vendor/github.com/mickael-kerjean/saml/xmlenc/pubkey.go new file mode 100644 index 00000000..13d4d9e7 --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/xmlenc/pubkey.go @@ -0,0 +1,162 @@ +package xmlenc + +import ( + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "fmt" + + "github.com/beevik/etree" +) + +// RSA implements Encrypter and Decrypter using RSA public key encryption. +// +// Use function like OAEP(), or PKCS1v15() to get an instance of this type ready +// to use. +type RSA struct { + BlockCipher BlockCipher + DigestMethod DigestMethod // only for OAEP + + algorithm string + keyEncrypter func(e RSA, pubKey *rsa.PublicKey, plaintext []byte) ([]byte, error) + keyDecrypter func(e RSA, privKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) +} + +// Algorithm returns the name of the algorithm +func (e RSA) Algorithm() string { + return e.algorithm +} + +// Encrypt implements encrypter. certificate must be a []byte containing the ASN.1 bytes +// of certificate containing an RSA public key. +func (e RSA) Encrypt(certificate interface{}, plaintext []byte, nonce []byte) (*etree.Element, error) { + cert, ok := certificate.(*x509.Certificate) + if !ok { + return nil, ErrIncorrectKeyType("*x.509 certificate") + } + + pubKey, ok := cert.PublicKey.(*rsa.PublicKey) + if !ok { + return nil, ErrIncorrectKeyType("x.509 certificate with an RSA public key") + } + + // generate a key + key := make([]byte, e.BlockCipher.KeySize()) + if _, err := RandReader.Read(key); err != nil { + return nil, err + } + + keyInfoEl := etree.NewElement("ds:KeyInfo") + keyInfoEl.CreateAttr("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") + + encryptedKey := keyInfoEl.CreateElement("xenc:EncryptedKey") + { + randBuf := make([]byte, 16) + if _, err := RandReader.Read(randBuf); err != nil { + return nil, err + } + encryptedKey.CreateAttr("Id", fmt.Sprintf("_%x", randBuf)) + } + encryptedKey.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#") + + encryptionMethodEl := encryptedKey.CreateElement("xenc:EncryptionMethod") + encryptionMethodEl.CreateAttr("Algorithm", e.algorithm) + encryptionMethodEl.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#") + if e.DigestMethod != nil { + dm := encryptionMethodEl.CreateElement("ds:DigestMethod") + dm.CreateAttr("Algorithm", e.DigestMethod.Algorithm()) + dm.CreateAttr("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") + } + { + innerKeyInfoEl := encryptedKey.CreateElement("ds:KeyInfo") + x509data := innerKeyInfoEl.CreateElement("ds:X509Data") + x509data.CreateElement("ds:X509Certificate").SetText( + base64.StdEncoding.EncodeToString(cert.Raw), + ) + } + + buf, err := e.keyEncrypter(e, pubKey, key) + if err != nil { + return nil, err + } + + cd := encryptedKey.CreateElement("xenc:CipherData") + cd.CreateAttr("xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#") + cd.CreateElement("xenc:CipherValue").SetText(base64.StdEncoding.EncodeToString(buf)) + encryptedDataEl, err := e.BlockCipher.Encrypt(key, plaintext, nonce) + if err != nil { + return nil, err + } + encryptedDataEl.InsertChildAt(encryptedDataEl.FindElement("./CipherData").Index(), keyInfoEl) + + return encryptedDataEl, nil +} + +// Decrypt implements Decryptor. `key` must be an *rsa.PrivateKey. +func (e RSA) Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error) { + rsaKey, err := validateRSAKeyIfPresent(key, ciphertextEl) + if err != nil { + return nil, err + } + + ciphertext, err := getCiphertext(ciphertextEl) + if err != nil { + return nil, err + } + + { + digestMethodEl := ciphertextEl.FindElement("./EncryptionMethod/DigestMethod") + if digestMethodEl == nil { + e.DigestMethod = SHA1 + } else { + hashAlgorithmStr := digestMethodEl.SelectAttrValue("Algorithm", "") + digestMethod, ok := digestMethods[hashAlgorithmStr] + if !ok { + return nil, ErrAlgorithmNotImplemented(hashAlgorithmStr) + } + e.DigestMethod = digestMethod + } + } + + return e.keyDecrypter(e, rsaKey, ciphertext) +} + +// OAEP returns a version of RSA that implements RSA in OAEP-MGF1P mode. By default +// the block cipher used is AES-256 CBC and the digest method is SHA-256. You can +// specify other ciphers and digest methods by assigning to BlockCipher or +// DigestMethod. +func OAEP() RSA { + return RSA{ + BlockCipher: AES256CBC, + DigestMethod: SHA256, + algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", + keyEncrypter: func(e RSA, pubKey *rsa.PublicKey, plaintext []byte) ([]byte, error) { + return rsa.EncryptOAEP(e.DigestMethod.Hash(), RandReader, pubKey, plaintext, nil) + }, + keyDecrypter: func(e RSA, privKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) { + return rsa.DecryptOAEP(e.DigestMethod.Hash(), RandReader, privKey, ciphertext, nil) + }, + } +} + +// PKCS1v15 returns a version of RSA that implements RSA in PKCS1v15 mode. By default +// the block cipher used is AES-256 CBC. The DigestMethod field is ignored because PKCS1v15 +// does not use a digest function. +func PKCS1v15() RSA { + return RSA{ + BlockCipher: AES256CBC, + DigestMethod: nil, + algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5", + keyEncrypter: func(e RSA, pubKey *rsa.PublicKey, plaintext []byte) ([]byte, error) { + return rsa.EncryptPKCS1v15(RandReader, pubKey, plaintext) + }, + keyDecrypter: func(e RSA, privKey *rsa.PrivateKey, ciphertext []byte) ([]byte, error) { + return rsa.DecryptPKCS1v15(RandReader, privKey, ciphertext) + }, + } +} + +func init() { + RegisterDecrypter(OAEP()) + RegisterDecrypter(PKCS1v15()) +} diff --git a/vendor/github.com/mickael-kerjean/saml/xmlenc/xmlenc.go b/vendor/github.com/mickael-kerjean/saml/xmlenc/xmlenc.go new file mode 100644 index 00000000..719c523f --- /dev/null +++ b/vendor/github.com/mickael-kerjean/saml/xmlenc/xmlenc.go @@ -0,0 +1,62 @@ +// Package xmlenc is a partial implementation of the xmlenc standard +// as described in https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html. +// The purpose of this implementation is to support encrypted SAML assertions. +package xmlenc + +import ( + "crypto/rand" + "hash" + + "github.com/beevik/etree" +) + +// RandReader is a thunk that allows test to replace the source of randomness used by +// this package. By default it is Reader from crypto/rand. +var RandReader = rand.Reader + +// Encrypter is an interface that encrypts things. Given a plaintext it returns an +// XML EncryptedData or EncryptedKey element. The required type of `key` varies +// depending on the implementation. +type Encrypter interface { + Encrypt(key interface{}, plaintext []byte, nonce []byte) (*etree.Element, error) +} + +// Decrypter is an interface that decrypts things. The Decrypt() method returns the +// plaintext version of the EncryptedData or EncryptedKey element passed. +// +// You probably don't have to use this interface directly, instead you may call +// Decrypt() and it will examine the element to determine which Decrypter to use. +type Decrypter interface { + Algorithm() string + Decrypt(key interface{}, ciphertextEl *etree.Element) ([]byte, error) +} + +// DigestMethod represents a digest method such as SHA1, etc. +type DigestMethod interface { + Algorithm() string + Hash() hash.Hash +} + +var ( + decrypters = map[string]Decrypter{} + digestMethods = map[string]DigestMethod{} +) + +// RegisterDecrypter registers the specified decrypter to that it can be +// used with Decrypt(). +func RegisterDecrypter(d Decrypter) { + decrypters[d.Algorithm()] = d +} + +// RegisterDigestMethod registers the specified digest method to that it can be +// used with Decrypt(). +func RegisterDigestMethod(dm DigestMethod) { + digestMethods[dm.Algorithm()] = dm +} + +// BlockCipher implements a cipher with a fixed size key like AES or 3DES. +type BlockCipher interface { + Encrypter + Decrypter + KeySize() int +} diff --git a/vendor/github.com/pmezard/go-difflib/LICENSE b/vendor/github.com/pmezard/go-difflib/LICENSE new file mode 100644 index 00000000..c67dad61 --- /dev/null +++ b/vendor/github.com/pmezard/go-difflib/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, Patrick Mezard +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + The names of its contributors may not be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/pmezard/go-difflib/difflib/difflib.go b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go new file mode 100644 index 00000000..003e99fa --- /dev/null +++ b/vendor/github.com/pmezard/go-difflib/difflib/difflib.go @@ -0,0 +1,772 @@ +// Package difflib is a partial port of Python difflib module. +// +// It provides tools to compare sequences of strings and generate textual diffs. +// +// The following class and functions have been ported: +// +// - SequenceMatcher +// +// - unified_diff +// +// - context_diff +// +// Getting unified diffs was the main goal of the port. Keep in mind this code +// is mostly suitable to output text differences in a human friendly way, there +// are no guarantees generated diffs are consumable by patch(1). +package difflib + +import ( + "bufio" + "bytes" + "fmt" + "io" + "strings" +) + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func calculateRatio(matches, length int) float64 { + if length > 0 { + return 2.0 * float64(matches) / float64(length) + } + return 1.0 +} + +type Match struct { + A int + B int + Size int +} + +type OpCode struct { + Tag byte + I1 int + I2 int + J1 int + J2 int +} + +// SequenceMatcher compares sequence of strings. The basic +// algorithm predates, and is a little fancier than, an algorithm +// published in the late 1980's by Ratcliff and Obershelp under the +// hyperbolic name "gestalt pattern matching". The basic idea is to find +// the longest contiguous matching subsequence that contains no "junk" +// elements (R-O doesn't address junk). The same idea is then applied +// recursively to the pieces of the sequences to the left and to the right +// of the matching subsequence. This does not yield minimal edit +// sequences, but does tend to yield matches that "look right" to people. +// +// SequenceMatcher tries to compute a "human-friendly diff" between two +// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the +// longest *contiguous* & junk-free matching subsequence. That's what +// catches peoples' eyes. The Windows(tm) windiff has another interesting +// notion, pairing up elements that appear uniquely in each sequence. +// That, and the method here, appear to yield more intuitive difference +// reports than does diff. This method appears to be the least vulnerable +// to synching up on blocks of "junk lines", though (like blank lines in +// ordinary text files, or maybe "

" lines in HTML files). That may be +// because this is the only method of the 3 that has a *concept* of +// "junk" . +// +// Timing: Basic R-O is cubic time worst case and quadratic time expected +// case. SequenceMatcher is quadratic time for the worst case and has +// expected-case behavior dependent in a complicated way on how many +// elements the sequences have in common; best case time is linear. +type SequenceMatcher struct { + a []string + b []string + b2j map[string][]int + IsJunk func(string) bool + autoJunk bool + bJunk map[string]struct{} + matchingBlocks []Match + fullBCount map[string]int + bPopular map[string]struct{} + opCodes []OpCode +} + +func NewMatcher(a, b []string) *SequenceMatcher { + m := SequenceMatcher{autoJunk: true} + m.SetSeqs(a, b) + return &m +} + +func NewMatcherWithJunk(a, b []string, autoJunk bool, + isJunk func(string) bool) *SequenceMatcher { + + m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk} + m.SetSeqs(a, b) + return &m +} + +// Set two sequences to be compared. +func (m *SequenceMatcher) SetSeqs(a, b []string) { + m.SetSeq1(a) + m.SetSeq2(b) +} + +// Set the first sequence to be compared. The second sequence to be compared is +// not changed. +// +// SequenceMatcher computes and caches detailed information about the second +// sequence, so if you want to compare one sequence S against many sequences, +// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other +// sequences. +// +// See also SetSeqs() and SetSeq2(). +func (m *SequenceMatcher) SetSeq1(a []string) { + if &a == &m.a { + return + } + m.a = a + m.matchingBlocks = nil + m.opCodes = nil +} + +// Set the second sequence to be compared. The first sequence to be compared is +// not changed. +func (m *SequenceMatcher) SetSeq2(b []string) { + if &b == &m.b { + return + } + m.b = b + m.matchingBlocks = nil + m.opCodes = nil + m.fullBCount = nil + m.chainB() +} + +func (m *SequenceMatcher) chainB() { + // Populate line -> index mapping + b2j := map[string][]int{} + for i, s := range m.b { + indices := b2j[s] + indices = append(indices, i) + b2j[s] = indices + } + + // Purge junk elements + m.bJunk = map[string]struct{}{} + if m.IsJunk != nil { + junk := m.bJunk + for s, _ := range b2j { + if m.IsJunk(s) { + junk[s] = struct{}{} + } + } + for s, _ := range junk { + delete(b2j, s) + } + } + + // Purge remaining popular elements + popular := map[string]struct{}{} + n := len(m.b) + if m.autoJunk && n >= 200 { + ntest := n/100 + 1 + for s, indices := range b2j { + if len(indices) > ntest { + popular[s] = struct{}{} + } + } + for s, _ := range popular { + delete(b2j, s) + } + } + m.bPopular = popular + m.b2j = b2j +} + +func (m *SequenceMatcher) isBJunk(s string) bool { + _, ok := m.bJunk[s] + return ok +} + +// Find longest matching block in a[alo:ahi] and b[blo:bhi]. +// +// If IsJunk is not defined: +// +// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where +// alo <= i <= i+k <= ahi +// blo <= j <= j+k <= bhi +// and for all (i',j',k') meeting those conditions, +// k >= k' +// i <= i' +// and if i == i', j <= j' +// +// In other words, of all maximal matching blocks, return one that +// starts earliest in a, and of all those maximal matching blocks that +// start earliest in a, return the one that starts earliest in b. +// +// If IsJunk is defined, first the longest matching block is +// determined as above, but with the additional restriction that no +// junk element appears in the block. Then that block is extended as +// far as possible by matching (only) junk elements on both sides. So +// the resulting block never matches on junk except as identical junk +// happens to be adjacent to an "interesting" match. +// +// If no blocks match, return (alo, blo, 0). +func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match { + // CAUTION: stripping common prefix or suffix would be incorrect. + // E.g., + // ab + // acab + // Longest matching block is "ab", but if common prefix is + // stripped, it's "a" (tied with "b"). UNIX(tm) diff does so + // strip, so ends up claiming that ab is changed to acab by + // inserting "ca" in the middle. That's minimal but unintuitive: + // "it's obvious" that someone inserted "ac" at the front. + // Windiff ends up at the same place as diff, but by pairing up + // the unique 'b's and then matching the first two 'a's. + besti, bestj, bestsize := alo, blo, 0 + + // find longest junk-free match + // during an iteration of the loop, j2len[j] = length of longest + // junk-free match ending with a[i-1] and b[j] + j2len := map[int]int{} + for i := alo; i != ahi; i++ { + // look at all instances of a[i] in b; note that because + // b2j has no junk keys, the loop is skipped if a[i] is junk + newj2len := map[int]int{} + for _, j := range m.b2j[m.a[i]] { + // a[i] matches b[j] + if j < blo { + continue + } + if j >= bhi { + break + } + k := j2len[j-1] + 1 + newj2len[j] = k + if k > bestsize { + besti, bestj, bestsize = i-k+1, j-k+1, k + } + } + j2len = newj2len + } + + // Extend the best by non-junk elements on each end. In particular, + // "popular" non-junk elements aren't in b2j, which greatly speeds + // the inner loop above, but also means "the best" match so far + // doesn't contain any junk *or* popular non-junk elements. + for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) && + m.a[besti-1] == m.b[bestj-1] { + besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 + } + for besti+bestsize < ahi && bestj+bestsize < bhi && + !m.isBJunk(m.b[bestj+bestsize]) && + m.a[besti+bestsize] == m.b[bestj+bestsize] { + bestsize += 1 + } + + // Now that we have a wholly interesting match (albeit possibly + // empty!), we may as well suck up the matching junk on each + // side of it too. Can't think of a good reason not to, and it + // saves post-processing the (possibly considerable) expense of + // figuring out what to do with it. In the case of an empty + // interesting match, this is clearly the right thing to do, + // because no other kind of match is possible in the regions. + for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) && + m.a[besti-1] == m.b[bestj-1] { + besti, bestj, bestsize = besti-1, bestj-1, bestsize+1 + } + for besti+bestsize < ahi && bestj+bestsize < bhi && + m.isBJunk(m.b[bestj+bestsize]) && + m.a[besti+bestsize] == m.b[bestj+bestsize] { + bestsize += 1 + } + + return Match{A: besti, B: bestj, Size: bestsize} +} + +// Return list of triples describing matching subsequences. +// +// Each triple is of the form (i, j, n), and means that +// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in +// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are +// adjacent triples in the list, and the second is not the last triple in the +// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe +// adjacent equal blocks. +// +// The last triple is a dummy, (len(a), len(b), 0), and is the only +// triple with n==0. +func (m *SequenceMatcher) GetMatchingBlocks() []Match { + if m.matchingBlocks != nil { + return m.matchingBlocks + } + + var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match + matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match { + match := m.findLongestMatch(alo, ahi, blo, bhi) + i, j, k := match.A, match.B, match.Size + if match.Size > 0 { + if alo < i && blo < j { + matched = matchBlocks(alo, i, blo, j, matched) + } + matched = append(matched, match) + if i+k < ahi && j+k < bhi { + matched = matchBlocks(i+k, ahi, j+k, bhi, matched) + } + } + return matched + } + matched := matchBlocks(0, len(m.a), 0, len(m.b), nil) + + // It's possible that we have adjacent equal blocks in the + // matching_blocks list now. + nonAdjacent := []Match{} + i1, j1, k1 := 0, 0, 0 + for _, b := range matched { + // Is this block adjacent to i1, j1, k1? + i2, j2, k2 := b.A, b.B, b.Size + if i1+k1 == i2 && j1+k1 == j2 { + // Yes, so collapse them -- this just increases the length of + // the first block by the length of the second, and the first + // block so lengthened remains the block to compare against. + k1 += k2 + } else { + // Not adjacent. Remember the first block (k1==0 means it's + // the dummy we started with), and make the second block the + // new block to compare against. + if k1 > 0 { + nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) + } + i1, j1, k1 = i2, j2, k2 + } + } + if k1 > 0 { + nonAdjacent = append(nonAdjacent, Match{i1, j1, k1}) + } + + nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0}) + m.matchingBlocks = nonAdjacent + return m.matchingBlocks +} + +// Return list of 5-tuples describing how to turn a into b. +// +// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple +// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the +// tuple preceding it, and likewise for j1 == the previous j2. +// +// The tags are characters, with these meanings: +// +// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2] +// +// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case. +// +// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case. +// +// 'e' (equal): a[i1:i2] == b[j1:j2] +func (m *SequenceMatcher) GetOpCodes() []OpCode { + if m.opCodes != nil { + return m.opCodes + } + i, j := 0, 0 + matching := m.GetMatchingBlocks() + opCodes := make([]OpCode, 0, len(matching)) + for _, m := range matching { + // invariant: we've pumped out correct diffs to change + // a[:i] into b[:j], and the next matching block is + // a[ai:ai+size] == b[bj:bj+size]. So we need to pump + // out a diff to change a[i:ai] into b[j:bj], pump out + // the matching block, and move (i,j) beyond the match + ai, bj, size := m.A, m.B, m.Size + tag := byte(0) + if i < ai && j < bj { + tag = 'r' + } else if i < ai { + tag = 'd' + } else if j < bj { + tag = 'i' + } + if tag > 0 { + opCodes = append(opCodes, OpCode{tag, i, ai, j, bj}) + } + i, j = ai+size, bj+size + // the list of matching blocks is terminated by a + // sentinel with size 0 + if size > 0 { + opCodes = append(opCodes, OpCode{'e', ai, i, bj, j}) + } + } + m.opCodes = opCodes + return m.opCodes +} + +// Isolate change clusters by eliminating ranges with no changes. +// +// Return a generator of groups with up to n lines of context. +// Each group is in the same format as returned by GetOpCodes(). +func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode { + if n < 0 { + n = 3 + } + codes := m.GetOpCodes() + if len(codes) == 0 { + codes = []OpCode{OpCode{'e', 0, 1, 0, 1}} + } + // Fixup leading and trailing groups if they show no changes. + if codes[0].Tag == 'e' { + c := codes[0] + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2} + } + if codes[len(codes)-1].Tag == 'e' { + c := codes[len(codes)-1] + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)} + } + nn := n + n + groups := [][]OpCode{} + group := []OpCode{} + for _, c := range codes { + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + // End the current group and start a new one whenever + // there is a large range with no changes. + if c.Tag == 'e' && i2-i1 > nn { + group = append(group, OpCode{c.Tag, i1, min(i2, i1+n), + j1, min(j2, j1+n)}) + groups = append(groups, group) + group = []OpCode{} + i1, j1 = max(i1, i2-n), max(j1, j2-n) + } + group = append(group, OpCode{c.Tag, i1, i2, j1, j2}) + } + if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') { + groups = append(groups, group) + } + return groups +} + +// Return a measure of the sequences' similarity (float in [0,1]). +// +// Where T is the total number of elements in both sequences, and +// M is the number of matches, this is 2.0*M / T. +// Note that this is 1 if the sequences are identical, and 0 if +// they have nothing in common. +// +// .Ratio() is expensive to compute if you haven't already computed +// .GetMatchingBlocks() or .GetOpCodes(), in which case you may +// want to try .QuickRatio() or .RealQuickRation() first to get an +// upper bound. +func (m *SequenceMatcher) Ratio() float64 { + matches := 0 + for _, m := range m.GetMatchingBlocks() { + matches += m.Size + } + return calculateRatio(matches, len(m.a)+len(m.b)) +} + +// Return an upper bound on ratio() relatively quickly. +// +// This isn't defined beyond that it is an upper bound on .Ratio(), and +// is faster to compute. +func (m *SequenceMatcher) QuickRatio() float64 { + // viewing a and b as multisets, set matches to the cardinality + // of their intersection; this counts the number of matches + // without regard to order, so is clearly an upper bound + if m.fullBCount == nil { + m.fullBCount = map[string]int{} + for _, s := range m.b { + m.fullBCount[s] = m.fullBCount[s] + 1 + } + } + + // avail[x] is the number of times x appears in 'b' less the + // number of times we've seen it in 'a' so far ... kinda + avail := map[string]int{} + matches := 0 + for _, s := range m.a { + n, ok := avail[s] + if !ok { + n = m.fullBCount[s] + } + avail[s] = n - 1 + if n > 0 { + matches += 1 + } + } + return calculateRatio(matches, len(m.a)+len(m.b)) +} + +// Return an upper bound on ratio() very quickly. +// +// This isn't defined beyond that it is an upper bound on .Ratio(), and +// is faster to compute than either .Ratio() or .QuickRatio(). +func (m *SequenceMatcher) RealQuickRatio() float64 { + la, lb := len(m.a), len(m.b) + return calculateRatio(min(la, lb), la+lb) +} + +// Convert range to the "ed" format +func formatRangeUnified(start, stop int) string { + // Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning := start + 1 // lines start numbering with one + length := stop - start + if length == 1 { + return fmt.Sprintf("%d", beginning) + } + if length == 0 { + beginning -= 1 // empty ranges begin at line just before the range + } + return fmt.Sprintf("%d,%d", beginning, length) +} + +// Unified diff parameters +type UnifiedDiff struct { + A []string // First sequence lines + FromFile string // First file name + FromDate string // First file time + B []string // Second sequence lines + ToFile string // Second file name + ToDate string // Second file time + Eol string // Headers end of line, defaults to LF + Context int // Number of context lines +} + +// Compare two sequences of lines; generate the delta as a unified diff. +// +// Unified diffs are a compact way of showing line changes and a few +// lines of context. The number of context lines is set by 'n' which +// defaults to three. +// +// By default, the diff control lines (those with ---, +++, or @@) are +// created with a trailing newline. This is helpful so that inputs +// created from file.readlines() result in diffs that are suitable for +// file.writelines() since both the inputs and outputs have trailing +// newlines. +// +// For inputs that do not have trailing newlines, set the lineterm +// argument to "" so that the output will be uniformly newline free. +// +// The unidiff format normally has a header for filenames and modification +// times. Any or all of these may be specified using strings for +// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'. +// The modification times are normally expressed in the ISO 8601 format. +func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error { + buf := bufio.NewWriter(writer) + defer buf.Flush() + wf := func(format string, args ...interface{}) error { + _, err := buf.WriteString(fmt.Sprintf(format, args...)) + return err + } + ws := func(s string) error { + _, err := buf.WriteString(s) + return err + } + + if len(diff.Eol) == 0 { + diff.Eol = "\n" + } + + started := false + m := NewMatcher(diff.A, diff.B) + for _, g := range m.GetGroupedOpCodes(diff.Context) { + if !started { + started = true + fromDate := "" + if len(diff.FromDate) > 0 { + fromDate = "\t" + diff.FromDate + } + toDate := "" + if len(diff.ToDate) > 0 { + toDate = "\t" + diff.ToDate + } + if diff.FromFile != "" || diff.ToFile != "" { + err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol) + if err != nil { + return err + } + err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol) + if err != nil { + return err + } + } + } + first, last := g[0], g[len(g)-1] + range1 := formatRangeUnified(first.I1, last.I2) + range2 := formatRangeUnified(first.J1, last.J2) + if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil { + return err + } + for _, c := range g { + i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2 + if c.Tag == 'e' { + for _, line := range diff.A[i1:i2] { + if err := ws(" " + line); err != nil { + return err + } + } + continue + } + if c.Tag == 'r' || c.Tag == 'd' { + for _, line := range diff.A[i1:i2] { + if err := ws("-" + line); err != nil { + return err + } + } + } + if c.Tag == 'r' || c.Tag == 'i' { + for _, line := range diff.B[j1:j2] { + if err := ws("+" + line); err != nil { + return err + } + } + } + } + } + return nil +} + +// Like WriteUnifiedDiff but returns the diff a string. +func GetUnifiedDiffString(diff UnifiedDiff) (string, error) { + w := &bytes.Buffer{} + err := WriteUnifiedDiff(w, diff) + return string(w.Bytes()), err +} + +// Convert range to the "ed" format. +func formatRangeContext(start, stop int) string { + // Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning := start + 1 // lines start numbering with one + length := stop - start + if length == 0 { + beginning -= 1 // empty ranges begin at line just before the range + } + if length <= 1 { + return fmt.Sprintf("%d", beginning) + } + return fmt.Sprintf("%d,%d", beginning, beginning+length-1) +} + +type ContextDiff UnifiedDiff + +// Compare two sequences of lines; generate the delta as a context diff. +// +// Context diffs are a compact way of showing line changes and a few +// lines of context. The number of context lines is set by diff.Context +// which defaults to three. +// +// By default, the diff control lines (those with *** or ---) are +// created with a trailing newline. +// +// For inputs that do not have trailing newlines, set the diff.Eol +// argument to "" so that the output will be uniformly newline free. +// +// The context diff format normally has a header for filenames and +// modification times. Any or all of these may be specified using +// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate. +// The modification times are normally expressed in the ISO 8601 format. +// If not specified, the strings default to blanks. +func WriteContextDiff(writer io.Writer, diff ContextDiff) error { + buf := bufio.NewWriter(writer) + defer buf.Flush() + var diffErr error + wf := func(format string, args ...interface{}) { + _, err := buf.WriteString(fmt.Sprintf(format, args...)) + if diffErr == nil && err != nil { + diffErr = err + } + } + ws := func(s string) { + _, err := buf.WriteString(s) + if diffErr == nil && err != nil { + diffErr = err + } + } + + if len(diff.Eol) == 0 { + diff.Eol = "\n" + } + + prefix := map[byte]string{ + 'i': "+ ", + 'd': "- ", + 'r': "! ", + 'e': " ", + } + + started := false + m := NewMatcher(diff.A, diff.B) + for _, g := range m.GetGroupedOpCodes(diff.Context) { + if !started { + started = true + fromDate := "" + if len(diff.FromDate) > 0 { + fromDate = "\t" + diff.FromDate + } + toDate := "" + if len(diff.ToDate) > 0 { + toDate = "\t" + diff.ToDate + } + if diff.FromFile != "" || diff.ToFile != "" { + wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol) + wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol) + } + } + + first, last := g[0], g[len(g)-1] + ws("***************" + diff.Eol) + + range1 := formatRangeContext(first.I1, last.I2) + wf("*** %s ****%s", range1, diff.Eol) + for _, c := range g { + if c.Tag == 'r' || c.Tag == 'd' { + for _, cc := range g { + if cc.Tag == 'i' { + continue + } + for _, line := range diff.A[cc.I1:cc.I2] { + ws(prefix[cc.Tag] + line) + } + } + break + } + } + + range2 := formatRangeContext(first.J1, last.J2) + wf("--- %s ----%s", range2, diff.Eol) + for _, c := range g { + if c.Tag == 'r' || c.Tag == 'i' { + for _, cc := range g { + if cc.Tag == 'd' { + continue + } + for _, line := range diff.B[cc.J1:cc.J2] { + ws(prefix[cc.Tag] + line) + } + } + break + } + } + } + return diffErr +} + +// Like WriteContextDiff but returns the diff a string. +func GetContextDiffString(diff ContextDiff) (string, error) { + w := &bytes.Buffer{} + err := WriteContextDiff(w, diff) + return string(w.Bytes()), err +} + +// Split a string on "\n" while preserving them. The output can be used +// as input for UnifiedDiff and ContextDiff structures. +func SplitLines(s string) []string { + lines := strings.SplitAfter(s, "\n") + lines[len(lines)-1] += "\n" + return lines +} diff --git a/vendor/github.com/russellhaering/goxmldsig/.gitignore b/vendor/github.com/russellhaering/goxmldsig/.gitignore new file mode 100644 index 00000000..9ed3b07c --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/.gitignore @@ -0,0 +1 @@ +*.test diff --git a/vendor/github.com/russellhaering/goxmldsig/.travis.yml b/vendor/github.com/russellhaering/goxmldsig/.travis.yml new file mode 100644 index 00000000..8ad33f7d --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/.travis.yml @@ -0,0 +1,11 @@ +arch: + - amd64 + - ppc64le + +language: go + +go: + - "1.14.x" + - "1.15.x" + - "1.17.x" + - master diff --git a/vendor/github.com/russellhaering/goxmldsig/LICENSE b/vendor/github.com/russellhaering/goxmldsig/LICENSE new file mode 100644 index 00000000..67db8588 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/LICENSE @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/vendor/github.com/russellhaering/goxmldsig/README.md b/vendor/github.com/russellhaering/goxmldsig/README.md new file mode 100644 index 00000000..9464e61e --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/README.md @@ -0,0 +1,90 @@ +# goxmldsig + +[![Build Status](https://travis-ci.org/russellhaering/goxmldsig.svg?branch=master)](https://travis-ci.org/russellhaering/goxmldsig) +[![GoDoc](https://godoc.org/github.com/russellhaering/goxmldsig?status.svg)](https://godoc.org/github.com/russellhaering/goxmldsig) + +XML Digital Signatures implemented in pure Go. + +## Installation + +Install `goxmldsig` using `go get`: + +``` +$ go get github.com/russellhaering/goxmldsig +``` + +## Usage + +### Signing + +```go +package main + +import ( + "github.com/beevik/etree" + "github.com/russellhaering/goxmldsig" +) + +func main() { + // Generate a key and self-signed certificate for signing + randomKeyStore := dsig.RandomKeyStoreForTest() + ctx := dsig.NewDefaultSigningContext(randomKeyStore) + elementToSign := &etree.Element{ + Tag: "ExampleElement", + } + elementToSign.CreateAttr("ID", "id1234") + + // Sign the element + signedElement, err := ctx.SignEnveloped(elementToSign) + if err != nil { + panic(err) + } + + // Serialize the signed element. It is important not to modify the element + // after it has been signed - even pretty-printing the XML will invalidate + // the signature. + doc := etree.NewDocument() + doc.SetRoot(signedElement) + str, err := doc.WriteToString() + if err != nil { + panic(err) + } + + println(str) +} +``` + +### Signature Validation + +```go +// Validate an element against a root certificate +func validate(root *x509.Certificate, el *etree.Element) { + // Construct a signing context with one or more roots of trust. + ctx := dsig.NewDefaultValidationContext(&dsig.MemoryX509CertificateStore{ + Roots: []*x509.Certificate{root}, + }) + + // It is important to only use the returned validated element. + // See: https://www.w3.org/TR/xmldsig-bestpractices/#check-what-is-signed + validated, err := ctx.Validate(el) + if err != nil { + panic(err) + } + + doc := etree.NewDocument() + doc.SetRoot(validated) + str, err := doc.WriteToString() + if err != nil { + panic(err) + } + + println(str) +} +``` + +## Limitations + +This library was created in order to [implement SAML 2.0](https://github.com/russellhaering/gosaml2) +without needing to execute a command line tool to create and validate signatures. It currently +only implements the subset of relevant standards needed to support that implementation, but +I hope to make it more complete over time. Contributions are welcome. diff --git a/vendor/github.com/russellhaering/goxmldsig/canonicalize.go b/vendor/github.com/russellhaering/goxmldsig/canonicalize.go new file mode 100644 index 00000000..05655ebc --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/canonicalize.go @@ -0,0 +1,178 @@ +package dsig + +import ( + "sort" + + "github.com/beevik/etree" + "github.com/russellhaering/goxmldsig/etreeutils" +) + +// Canonicalizer is an implementation of a canonicalization algorithm. +type Canonicalizer interface { + Canonicalize(el *etree.Element) ([]byte, error) + Algorithm() AlgorithmID +} + +type NullCanonicalizer struct { +} + +func MakeNullCanonicalizer() Canonicalizer { + return &NullCanonicalizer{} +} + +func (c *NullCanonicalizer) Algorithm() AlgorithmID { + return AlgorithmID("NULL") +} + +func (c *NullCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) { + scope := make(map[string]struct{}) + return canonicalSerialize(canonicalPrep(el, scope, false)) +} + +type c14N10ExclusiveCanonicalizer struct { + prefixList string +} + +// MakeC14N10ExclusiveCanonicalizerWithPrefixList constructs an exclusive Canonicalizer +// from a PrefixList in NMTOKENS format (a white space separated list). +func MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList string) Canonicalizer { + return &c14N10ExclusiveCanonicalizer{ + prefixList: prefixList, + } +} + +// Canonicalize transforms the input Element into a serialized XML document in canonical form. +func (c *c14N10ExclusiveCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) { + err := etreeutils.TransformExcC14n(el, c.prefixList) + if err != nil { + return nil, err + } + + return canonicalSerialize(el) +} + +func (c *c14N10ExclusiveCanonicalizer) Algorithm() AlgorithmID { + return CanonicalXML10ExclusiveAlgorithmId +} + +type c14N11Canonicalizer struct{} + +// MakeC14N11Canonicalizer constructs an inclusive canonicalizer. +func MakeC14N11Canonicalizer() Canonicalizer { + return &c14N11Canonicalizer{} +} + +// Canonicalize transforms the input Element into a serialized XML document in canonical form. +func (c *c14N11Canonicalizer) Canonicalize(el *etree.Element) ([]byte, error) { + scope := make(map[string]struct{}) + return canonicalSerialize(canonicalPrep(el, scope, true)) +} + +func (c *c14N11Canonicalizer) Algorithm() AlgorithmID { + return CanonicalXML11AlgorithmId +} + +type c14N10RecCanonicalizer struct{} + +// MakeC14N10RecCanonicalizer constructs an inclusive canonicalizer. +func MakeC14N10RecCanonicalizer() Canonicalizer { + return &c14N10RecCanonicalizer{} +} + +// Canonicalize transforms the input Element into a serialized XML document in canonical form. +func (c *c14N10RecCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) { + scope := make(map[string]struct{}) + return canonicalSerialize(canonicalPrep(el, scope, true)) +} + +func (c *c14N10RecCanonicalizer) Algorithm() AlgorithmID { + return CanonicalXML10RecAlgorithmId +} + +type c14N10CommentCanonicalizer struct{} + +// MakeC14N10CommentCanonicalizer constructs an inclusive canonicalizer. +func MakeC14N10CommentCanonicalizer() Canonicalizer { + return &c14N10CommentCanonicalizer{} +} + +// Canonicalize transforms the input Element into a serialized XML document in canonical form. +func (c *c14N10CommentCanonicalizer) Canonicalize(el *etree.Element) ([]byte, error) { + scope := make(map[string]struct{}) + return canonicalSerialize(canonicalPrep(el, scope, true)) +} + +func (c *c14N10CommentCanonicalizer) Algorithm() AlgorithmID { + return CanonicalXML10CommentAlgorithmId +} + +func composeAttr(space, key string) string { + if space != "" { + return space + ":" + key + } + + return key +} + +type c14nSpace struct { + a etree.Attr + used bool +} + +const nsSpace = "xmlns" + +// canonicalPrep accepts an *etree.Element and transforms it into one which is ready +// for serialization into inclusive canonical form. Specifically this +// entails: +// +// 1. Stripping re-declarations of namespaces +// 2. Sorting attributes into canonical order +// +// Inclusive canonicalization does not strip unused namespaces. +// +// TODO(russell_h): This is very similar to excCanonicalPrep - perhaps they should +// be unified into one parameterized function? +func canonicalPrep(el *etree.Element, seenSoFar map[string]struct{}, strip bool) *etree.Element { + _seenSoFar := make(map[string]struct{}) + for k, v := range seenSoFar { + _seenSoFar[k] = v + } + + ne := el.Copy() + sort.Sort(etreeutils.SortedAttrs(ne.Attr)) + if len(ne.Attr) != 0 { + for _, attr := range ne.Attr { + if attr.Space != nsSpace { + continue + } + key := attr.Space + ":" + attr.Key + if _, seen := _seenSoFar[key]; seen { + ne.RemoveAttr(attr.Space + ":" + attr.Key) + } else { + _seenSoFar[key] = struct{}{} + } + } + } + + for i, token := range ne.Child { + childElement, ok := token.(*etree.Element) + if ok { + ne.Child[i] = canonicalPrep(childElement, _seenSoFar, strip) + } + } + + return ne +} + +func canonicalSerialize(el *etree.Element) ([]byte, error) { + doc := etree.NewDocument() + doc.SetRoot(el.Copy()) + + doc.WriteSettings = etree.WriteSettings{ + CanonicalAttrVal: true, + CanonicalEndTags: true, + CanonicalText: true, + } + + return doc.WriteToBytes() +} diff --git a/vendor/github.com/russellhaering/goxmldsig/clock.go b/vendor/github.com/russellhaering/goxmldsig/clock.go new file mode 100644 index 00000000..cceaaa54 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/clock.go @@ -0,0 +1,55 @@ +package dsig + +import ( + "time" + + "github.com/jonboulle/clockwork" +) + +// Clock wraps a clockwork.Clock (which could be real or fake) in order +// to default to a real clock when a nil *Clock is used. In other words, +// if you attempt to use a nil *Clock it will defer to the real system +// clock. This allows Clock to be easily added to structs with methods +// that currently reference the time package, without requiring every +// instantiation of that struct to be updated. +type Clock struct { + wrapped clockwork.Clock +} + +func (c *Clock) getWrapped() clockwork.Clock { + if c == nil { + return clockwork.NewRealClock() + } + + return c.wrapped +} + +func (c *Clock) After(d time.Duration) <-chan time.Time { + return c.getWrapped().After(d) +} + +func (c *Clock) Sleep(d time.Duration) { + c.getWrapped().Sleep(d) +} + +func (c *Clock) Now() time.Time { + return c.getWrapped().Now() +} + +func NewRealClock() *Clock { + return &Clock{ + wrapped: clockwork.NewRealClock(), + } +} + +func NewFakeClock(wrapped clockwork.Clock) *Clock { + return &Clock{ + wrapped: wrapped, + } +} + +func NewFakeClockAt(t time.Time) *Clock { + return &Clock{ + wrapped: clockwork.NewFakeClockAt(t), + } +} diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go new file mode 100644 index 00000000..e9f8deb1 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/canonicalize.go @@ -0,0 +1,98 @@ +package etreeutils + +import ( + "sort" + "strings" + + "github.com/beevik/etree" +) + +// TransformExcC14n transforms the passed element into xml-exc-c14n form. +func TransformExcC14n(el *etree.Element, inclusiveNamespacesPrefixList string) error { + prefixes := strings.Fields(inclusiveNamespacesPrefixList) + prefixSet := make(map[string]struct{}, len(prefixes)) + + for _, prefix := range prefixes { + prefixSet[prefix] = struct{}{} + } + + err := transformExcC14n(DefaultNSContext, DefaultNSContext, el, prefixSet) + if err != nil { + return err + } + + return nil +} + +func transformExcC14n(ctx, declared NSContext, el *etree.Element, inclusiveNamespaces map[string]struct{}) error { + scope, err := ctx.SubContext(el) + if err != nil { + return err + } + + visiblyUtilizedPrefixes := map[string]struct{}{ + el.Space: struct{}{}, + } + + filteredAttrs := []etree.Attr{} + + // Filter out all namespace declarations + for _, attr := range el.Attr { + switch { + case attr.Space == xmlnsPrefix: + if _, ok := inclusiveNamespaces[attr.Key]; ok { + visiblyUtilizedPrefixes[attr.Key] = struct{}{} + } + + case attr.Space == defaultPrefix && attr.Key == xmlnsPrefix: + if _, ok := inclusiveNamespaces[defaultPrefix]; ok { + visiblyUtilizedPrefixes[defaultPrefix] = struct{}{} + } + + default: + if attr.Space != defaultPrefix { + visiblyUtilizedPrefixes[attr.Space] = struct{}{} + } + + filteredAttrs = append(filteredAttrs, attr) + } + } + + el.Attr = filteredAttrs + + declared = declared.Copy() + + // Declare all visibly utilized prefixes that are in-scope but haven't + // been declared in the canonicalized form yet. These might have been + // declared on this element but then filtered out above, or they might + // have been declared on an ancestor (before canonicalization) which + // didn't visibly utilize and thus had them removed. + for prefix := range visiblyUtilizedPrefixes { + // Skip redundant declarations - they have to already have the same + // value. + if declaredNamespace, ok := declared.prefixes[prefix]; ok { + if value, ok := scope.prefixes[prefix]; ok && declaredNamespace == value { + continue + } + } + + namespace, err := scope.LookupPrefix(prefix) + if err != nil { + return err + } + + el.Attr = append(el.Attr, declared.declare(prefix, namespace)) + } + + sort.Sort(SortedAttrs(el.Attr)) + + // Transform child elements + for _, child := range el.ChildElements() { + err := transformExcC14n(scope, declared, child, inclusiveNamespaces) + if err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go new file mode 100644 index 00000000..baf1124f --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/namespace.go @@ -0,0 +1,407 @@ +package etreeutils + +import ( + "errors" + + "fmt" + + "sort" + + "github.com/beevik/etree" +) + +const ( + defaultPrefix = "" + xmlnsPrefix = "xmlns" + xmlPrefix = "xml" + + XMLNamespace = "http://www.w3.org/XML/1998/namespace" + XMLNSNamespace = "http://www.w3.org/2000/xmlns/" +) + +var ( + DefaultNSContext = NSContext{ + prefixes: map[string]string{ + defaultPrefix: XMLNamespace, + xmlPrefix: XMLNamespace, + xmlnsPrefix: XMLNSNamespace, + }, + } + + EmptyNSContext = NSContext{} + + ErrReservedNamespace = errors.New("disallowed declaration of reserved namespace") + ErrInvalidDefaultNamespace = errors.New("invalid default namespace declaration") + ErrTraversalHalted = errors.New("traversal halted") +) + +type ErrUndeclaredNSPrefix struct { + Prefix string +} + +func (e ErrUndeclaredNSPrefix) Error() string { + return fmt.Sprintf("undeclared namespace prefix: '%s'", e.Prefix) +} + +type NSContext struct { + prefixes map[string]string +} + +func (ctx NSContext) Copy() NSContext { + prefixes := make(map[string]string, len(ctx.prefixes)+4) + for k, v := range ctx.prefixes { + prefixes[k] = v + } + + return NSContext{prefixes: prefixes} +} + +func (ctx NSContext) declare(prefix, namespace string) etree.Attr { + ctx.prefixes[prefix] = namespace + + switch prefix { + case defaultPrefix: + return etree.Attr{ + Key: xmlnsPrefix, + Value: namespace, + } + + default: + return etree.Attr{ + Space: xmlnsPrefix, + Key: prefix, + Value: namespace, + } + } +} + +func (ctx NSContext) SubContext(el *etree.Element) (NSContext, error) { + // The subcontext should inherit existing declared prefixes + newCtx := ctx.Copy() + + // Merge new namespace declarations on top of existing ones. + for _, attr := range el.Attr { + if attr.Space == xmlnsPrefix { + // This attribute is a namespace declaration of the form "xmlns:" + + // The 'xml' namespace may only be re-declared with the name 'http://www.w3.org/XML/1998/namespace' + if attr.Key == xmlPrefix && attr.Value != XMLNamespace { + return ctx, ErrReservedNamespace + } + + // The 'xmlns' namespace may not be re-declared + if attr.Key == xmlnsPrefix { + return ctx, ErrReservedNamespace + } + + newCtx.declare(attr.Key, attr.Value) + } else if attr.Space == defaultPrefix && attr.Key == xmlnsPrefix { + // This attribute is a default namespace declaration + + // The xmlns namespace value may not be declared as the default namespace + if attr.Value == XMLNSNamespace { + return ctx, ErrInvalidDefaultNamespace + } + + newCtx.declare(defaultPrefix, attr.Value) + } + } + + return newCtx, nil +} + +// Prefixes returns a copy of this context's prefix map. +func (ctx NSContext) Prefixes() map[string]string { + prefixes := make(map[string]string, len(ctx.prefixes)) + for k, v := range ctx.prefixes { + prefixes[k] = v + } + + return prefixes +} + +// LookupPrefix attempts to find a declared namespace for the specified prefix. If the prefix +// is an empty string this will be the default namespace for this context. If the prefix is +// undeclared in this context an ErrUndeclaredNSPrefix will be returned. +func (ctx NSContext) LookupPrefix(prefix string) (string, error) { + if namespace, ok := ctx.prefixes[prefix]; ok { + return namespace, nil + } + + return "", ErrUndeclaredNSPrefix{ + Prefix: prefix, + } +} + +// NSIterHandler is a function which is invoked with a element and its surrounding +// NSContext during traversals. +type NSIterHandler func(NSContext, *etree.Element) error + +// NSTraverse traverses an element tree, invoking the passed handler for each element +// in the tree. +func NSTraverse(ctx NSContext, el *etree.Element, handle NSIterHandler) error { + ctx, err := ctx.SubContext(el) + if err != nil { + return err + } + + err = handle(ctx, el) + if err != nil { + return err + } + + // Recursively traverse child elements. + for _, child := range el.ChildElements() { + err := NSTraverse(ctx, child, handle) + if err != nil { + return err + } + } + + return nil +} + +// NSDetatch makes a copy of the passed element, and declares any namespaces in +// the passed context onto the new element before returning it. +func NSDetatch(ctx NSContext, el *etree.Element) (*etree.Element, error) { + ctx, err := ctx.SubContext(el) + if err != nil { + return nil, err + } + + el = el.Copy() + + // Build a new attribute list + attrs := make([]etree.Attr, 0, len(el.Attr)) + + // First copy over anything that isn't a namespace declaration + for _, attr := range el.Attr { + if attr.Space == xmlnsPrefix { + continue + } + + if attr.Space == defaultPrefix && attr.Key == xmlnsPrefix { + continue + } + + attrs = append(attrs, attr) + } + + // Append all in-context namespace declarations + for prefix, namespace := range ctx.prefixes { + // Skip the implicit "xml" and "xmlns" prefix declarations + if prefix == xmlnsPrefix || prefix == xmlPrefix { + continue + } + + // Also skip declararing the default namespace as XMLNamespace + if prefix == defaultPrefix && namespace == XMLNamespace { + continue + } + + if prefix != defaultPrefix { + attrs = append(attrs, etree.Attr{ + Space: xmlnsPrefix, + Key: prefix, + Value: namespace, + }) + } else { + attrs = append(attrs, etree.Attr{ + Key: xmlnsPrefix, + Value: namespace, + }) + } + } + + sort.Sort(SortedAttrs(attrs)) + + el.Attr = attrs + + return el, nil +} + +// NSSelectOne behaves identically to NSSelectOneCtx, but uses DefaultNSContext as the +// surrounding context. +func NSSelectOne(el *etree.Element, namespace, tag string) (*etree.Element, error) { + return NSSelectOneCtx(DefaultNSContext, el, namespace, tag) +} + +// NSSelectOneCtx conducts a depth-first search for an element with the specified namespace +// and tag. If such an element is found, a new *etree.Element is returned which is a +// copy of the found element, but with all in-context namespace declarations attached +// to the element as attributes. +func NSSelectOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etree.Element, error) { + var found *etree.Element + + err := NSFindIterateCtx(ctx, el, namespace, tag, func(ctx NSContext, el *etree.Element) error { + var err error + + found, err = NSDetatch(ctx, el) + if err != nil { + return err + } + + return ErrTraversalHalted + }) + + if err != nil { + return nil, err + } + + return found, nil +} + +// NSFindIterate behaves identically to NSFindIterateCtx, but uses DefaultNSContext +// as the surrounding context. +func NSFindIterate(el *etree.Element, namespace, tag string, handle NSIterHandler) error { + return NSFindIterateCtx(DefaultNSContext, el, namespace, tag, handle) +} + +// NSFindIterateCtx conducts a depth-first traversal searching for elements with the +// specified tag in the specified namespace. It uses the passed NSContext for prefix +// lookups. For each such element, the passed handler function is invoked. If the +// handler function returns an error traversal is immediately halted. If the error +// returned by the handler is ErrTraversalHalted then nil will be returned by +// NSFindIterate. If any other error is returned by the handler, that error will be +// returned by NSFindIterate. +func NSFindIterateCtx(ctx NSContext, el *etree.Element, namespace, tag string, handle NSIterHandler) error { + err := NSTraverse(ctx, el, func(ctx NSContext, el *etree.Element) error { + _ctx, err := ctx.SubContext(el) + if err != nil { + return err + } + + currentNS, err := _ctx.LookupPrefix(el.Space) + if err != nil { + return err + } + + // Base case, el is the sought after element. + if currentNS == namespace && el.Tag == tag { + return handle(ctx, el) + } + + return nil + }) + + if err != nil && err != ErrTraversalHalted { + return err + } + + return nil +} + +// NSFindOne behaves identically to NSFindOneCtx, but uses DefaultNSContext for +// context. +func NSFindOne(el *etree.Element, namespace, tag string) (*etree.Element, error) { + return NSFindOneCtx(DefaultNSContext, el, namespace, tag) +} + +// NSFindOneCtx conducts a depth-first search for the specified element. If such an element +// is found a reference to it is returned. +func NSFindOneCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etree.Element, error) { + var found *etree.Element + + err := NSFindIterateCtx(ctx, el, namespace, tag, func(ctx NSContext, el *etree.Element) error { + found = el + return ErrTraversalHalted + }) + + if err != nil { + return nil, err + } + + return found, nil +} + +// NSIterateChildren iterates the children of an element, invoking the passed +// handler with each direct child of the element, and the context surrounding +// that child. +func NSIterateChildren(ctx NSContext, el *etree.Element, handle NSIterHandler) error { + ctx, err := ctx.SubContext(el) + if err != nil { + return err + } + + // Iterate the child elements. + for _, child := range el.ChildElements() { + err = handle(ctx, child) + if err != nil { + return err + } + } + + return nil +} + +// NSFindIterateChildrenCtx takes an element and its surrounding context, and iterates +// the children of that element searching for an element matching the passed namespace +// and tag. For each such element that is found, handle is invoked with the matched +// element and its own surrounding context. +func NSFindChildrenIterateCtx(ctx NSContext, el *etree.Element, namespace, tag string, handle NSIterHandler) error { + err := NSIterateChildren(ctx, el, func(ctx NSContext, el *etree.Element) error { + _ctx, err := ctx.SubContext(el) + if err != nil { + return err + } + + currentNS, err := _ctx.LookupPrefix(el.Space) + if err != nil { + return err + } + + // Base case, el is the sought after element. + if currentNS == namespace && el.Tag == tag { + return handle(ctx, el) + } + + return nil + }) + + if err != nil && err != ErrTraversalHalted { + return err + } + + return nil +} + +// NSFindOneChild behaves identically to NSFindOneChildCtx, but uses +// DefaultNSContext for context. +func NSFindOneChild(el *etree.Element, namespace, tag string) (*etree.Element, error) { + return NSFindOneChildCtx(DefaultNSContext, el, namespace, tag) +} + +// NSFindOneCtx conducts a depth-first search for the specified element. If such an +// element is found a reference to it is returned. +func NSFindOneChildCtx(ctx NSContext, el *etree.Element, namespace, tag string) (*etree.Element, error) { + var found *etree.Element + + err := NSFindChildrenIterateCtx(ctx, el, namespace, tag, func(ctx NSContext, el *etree.Element) error { + found = el + return ErrTraversalHalted + }) + + if err != nil && err != ErrTraversalHalted { + return nil, err + } + + return found, nil +} + +// NSBuildParentContext recurses upward from an element in order to build an NSContext +// for its immediate parent. If the element has no parent DefaultNSContext +// is returned. +func NSBuildParentContext(el *etree.Element) (NSContext, error) { + parent := el.Parent() + if parent == nil { + return DefaultNSContext, nil + } + + ctx, err := NSBuildParentContext(parent) + + if err != nil { + return ctx, err + } + + return ctx.SubContext(parent) +} diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go new file mode 100644 index 00000000..5871a391 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/sort.go @@ -0,0 +1,66 @@ +package etreeutils + +import "github.com/beevik/etree" + +// SortedAttrs provides sorting capabilities, compatible with XML C14N, on top +// of an []etree.Attr +type SortedAttrs []etree.Attr + +func (a SortedAttrs) Len() int { + return len(a) +} + +func (a SortedAttrs) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +func (a SortedAttrs) Less(i, j int) bool { + // This is the best reference I've found on sort order: + // http://dst.lbl.gov/~ksb/Scratch/XMLC14N.html + + // If attr j is a default namespace declaration, attr i may + // not be strictly "less" than it. + if a[j].Space == defaultPrefix && a[j].Key == xmlnsPrefix { + return false + } + + // Otherwise, if attr i is a default namespace declaration, it + // must be less than anything else. + if a[i].Space == defaultPrefix && a[i].Key == xmlnsPrefix { + return true + } + + // Next, namespace prefix declarations, sorted by prefix, come before + // anythign else. + if a[i].Space == xmlnsPrefix { + if a[j].Space == xmlnsPrefix { + return a[i].Key < a[j].Key + } + return true + } + + if a[j].Space == xmlnsPrefix { + return false + } + + // Then come unprefixed attributes, sorted by key. + if a[i].Space == defaultPrefix { + if a[j].Space == defaultPrefix { + return a[i].Key < a[j].Key + } + return true + } + + if a[j].Space == defaultPrefix { + return false + } + + // Wow. We're still going. Finally, attributes in the same namespace should be + // sorted by key. Attributes in different namespaces should be sorted by the + // actual namespace (_not_ the prefix). For now just use the prefix. + if a[i].Space == a[j].Space { + return a[i].Key < a[j].Key + } + + return a[i].Space < a[j].Space +} diff --git a/vendor/github.com/russellhaering/goxmldsig/etreeutils/unmarshal.go b/vendor/github.com/russellhaering/goxmldsig/etreeutils/unmarshal.go new file mode 100644 index 00000000..b1fecf85 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/etreeutils/unmarshal.go @@ -0,0 +1,43 @@ +package etreeutils + +import ( + "encoding/xml" + + "github.com/beevik/etree" +) + +// NSUnmarshalElement unmarshals the passed etree Element into the value pointed to by +// v using encoding/xml in the context of the passed NSContext. If v implements +// ElementKeeper, SetUnderlyingElement will be called on v with a reference to el. +func NSUnmarshalElement(ctx NSContext, el *etree.Element, v interface{}) error { + detatched, err := NSDetatch(ctx, el) + if err != nil { + return err + } + + doc := etree.NewDocument() + doc.AddChild(detatched) + data, err := doc.WriteToBytes() + if err != nil { + return err + } + + err = xml.Unmarshal(data, v) + if err != nil { + return err + } + + switch v := v.(type) { + case ElementKeeper: + v.SetUnderlyingElement(el) + } + + return nil +} + +// ElementKeeper should be implemented by types which will be passed to +// UnmarshalElement, but wish to keep a reference +type ElementKeeper interface { + SetUnderlyingElement(*etree.Element) + UnderlyingElement() *etree.Element +} diff --git a/vendor/github.com/russellhaering/goxmldsig/go.mod b/vendor/github.com/russellhaering/goxmldsig/go.mod new file mode 100644 index 00000000..0203efdc --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/go.mod @@ -0,0 +1,13 @@ +module github.com/russellhaering/goxmldsig + +go 1.15 + +require ( + github.com/beevik/etree v1.1.0 + github.com/jonboulle/clockwork v0.2.2 + github.com/kr/pretty v0.3.0 // indirect + github.com/rogpeppe/go-internal v1.8.0 // indirect + github.com/stretchr/testify v1.6.1 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect +) diff --git a/vendor/github.com/russellhaering/goxmldsig/go.sum b/vendor/github.com/russellhaering/goxmldsig/go.sum new file mode 100644 index 00000000..d806ab87 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/go.sum @@ -0,0 +1,34 @@ +github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= +github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jonboulle/clockwork v0.2.0 h1:J2SLSdy7HgElq8ekSl2Mxh6vrRNFxqbXGenYH2I02Vs= +github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/russellhaering/goxmldsig/keystore.go b/vendor/github.com/russellhaering/goxmldsig/keystore.go new file mode 100644 index 00000000..313d9b6a --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/keystore.go @@ -0,0 +1,67 @@ +package dsig + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "math/big" + "time" +) + +type X509KeyStore interface { + GetKeyPair() (privateKey *rsa.PrivateKey, cert []byte, err error) +} + +type X509ChainStore interface { + GetChain() (certs [][]byte, err error) +} + +type X509CertificateStore interface { + Certificates() (roots []*x509.Certificate, err error) +} + +type MemoryX509CertificateStore struct { + Roots []*x509.Certificate +} + +func (mX509cs *MemoryX509CertificateStore) Certificates() ([]*x509.Certificate, error) { + return mX509cs.Roots, nil +} + +type MemoryX509KeyStore struct { + privateKey *rsa.PrivateKey + cert []byte +} + +func (ks *MemoryX509KeyStore) GetKeyPair() (*rsa.PrivateKey, []byte, error) { + return ks.privateKey, ks.cert, nil +} + +func RandomKeyStoreForTest() X509KeyStore { + key, err := rsa.GenerateKey(rand.Reader, 1024) + if err != nil { + panic(err) + } + + now := time.Now() + + template := &x509.Certificate{ + SerialNumber: big.NewInt(0), + NotBefore: now.Add(-5 * time.Minute), + NotAfter: now.Add(365 * 24 * time.Hour), + + KeyUsage: x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{}, + BasicConstraintsValid: true, + } + + cert, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key) + if err != nil { + panic(err) + } + + return &MemoryX509KeyStore{ + privateKey: key, + cert: cert, + } +} diff --git a/vendor/github.com/russellhaering/goxmldsig/run_test.sh b/vendor/github.com/russellhaering/goxmldsig/run_test.sh new file mode 100644 index 00000000..cfe5b2ea --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/run_test.sh @@ -0,0 +1,12 @@ +#!/bin/bash +cd `dirname $0` +DIRS=`git grep -l 'func Test' | xargs dirname | sort -u` +for DIR in $DIRS +do + echo + echo "dir: $DIR" + echo "======================================" + pushd $DIR >/dev/null + go test -v || exit 1 + popd >/dev/null +done diff --git a/vendor/github.com/russellhaering/goxmldsig/sign.go b/vendor/github.com/russellhaering/goxmldsig/sign.go new file mode 100644 index 00000000..2be34b7f --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/sign.go @@ -0,0 +1,257 @@ +package dsig + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" + _ "crypto/sha1" + _ "crypto/sha256" + "encoding/base64" + "errors" + "fmt" + + "github.com/beevik/etree" + "github.com/russellhaering/goxmldsig/etreeutils" +) + +type SigningContext struct { + Hash crypto.Hash + KeyStore X509KeyStore + IdAttribute string + Prefix string + Canonicalizer Canonicalizer +} + +func NewDefaultSigningContext(ks X509KeyStore) *SigningContext { + return &SigningContext{ + Hash: crypto.SHA256, + KeyStore: ks, + IdAttribute: DefaultIdAttr, + Prefix: DefaultPrefix, + Canonicalizer: MakeC14N11Canonicalizer(), + } +} + +func (ctx *SigningContext) SetSignatureMethod(algorithmID string) error { + hash, ok := signatureMethodsByIdentifier[algorithmID] + if !ok { + return fmt.Errorf("Unknown SignatureMethod: %s", algorithmID) + } + + ctx.Hash = hash + + return nil +} + +func (ctx *SigningContext) digest(el *etree.Element) ([]byte, error) { + canonical, err := ctx.Canonicalizer.Canonicalize(el) + if err != nil { + return nil, err + } + + hash := ctx.Hash.New() + _, err = hash.Write(canonical) + if err != nil { + return nil, err + } + + return hash.Sum(nil), nil +} + +func (ctx *SigningContext) constructSignedInfo(el *etree.Element, enveloped bool) (*etree.Element, error) { + digestAlgorithmIdentifier := ctx.GetDigestAlgorithmIdentifier() + if digestAlgorithmIdentifier == "" { + return nil, errors.New("unsupported hash mechanism") + } + + signatureMethodIdentifier := ctx.GetSignatureMethodIdentifier() + if signatureMethodIdentifier == "" { + return nil, errors.New("unsupported signature method") + } + + digest, err := ctx.digest(el) + if err != nil { + return nil, err + } + + signedInfo := &etree.Element{ + Tag: SignedInfoTag, + Space: ctx.Prefix, + } + + // /SignedInfo/CanonicalizationMethod + canonicalizationMethod := ctx.createNamespacedElement(signedInfo, CanonicalizationMethodTag) + canonicalizationMethod.CreateAttr(AlgorithmAttr, string(ctx.Canonicalizer.Algorithm())) + + // /SignedInfo/SignatureMethod + signatureMethod := ctx.createNamespacedElement(signedInfo, SignatureMethodTag) + signatureMethod.CreateAttr(AlgorithmAttr, signatureMethodIdentifier) + + // /SignedInfo/Reference + reference := ctx.createNamespacedElement(signedInfo, ReferenceTag) + + dataId := el.SelectAttrValue(ctx.IdAttribute, "") + if dataId == "" { + reference.CreateAttr(URIAttr, "") + } else { + reference.CreateAttr(URIAttr, "#"+dataId) + } + + + // /SignedInfo/Reference/Transforms + transforms := ctx.createNamespacedElement(reference, TransformsTag) + if enveloped { + envelopedTransform := ctx.createNamespacedElement(transforms, TransformTag) + envelopedTransform.CreateAttr(AlgorithmAttr, EnvelopedSignatureAltorithmId.String()) + } + canonicalizationAlgorithm := ctx.createNamespacedElement(transforms, TransformTag) + canonicalizationAlgorithm.CreateAttr(AlgorithmAttr, string(ctx.Canonicalizer.Algorithm())) + + // /SignedInfo/Reference/DigestMethod + digestMethod := ctx.createNamespacedElement(reference, DigestMethodTag) + digestMethod.CreateAttr(AlgorithmAttr, digestAlgorithmIdentifier) + + // /SignedInfo/Reference/DigestValue + digestValue := ctx.createNamespacedElement(reference, DigestValueTag) + digestValue.SetText(base64.StdEncoding.EncodeToString(digest)) + + return signedInfo, nil +} + +func (ctx *SigningContext) ConstructSignature(el *etree.Element, enveloped bool) (*etree.Element, error) { + signedInfo, err := ctx.constructSignedInfo(el, enveloped) + if err != nil { + return nil, err + } + + sig := &etree.Element{ + Tag: SignatureTag, + Space: ctx.Prefix, + } + + xmlns := "xmlns" + if ctx.Prefix != "" { + xmlns += ":" + ctx.Prefix + } + + sig.CreateAttr(xmlns, Namespace) + sig.AddChild(signedInfo) + + // When using xml-c14n11 (ie, non-exclusive canonicalization) the canonical form + // of the SignedInfo must declare all namespaces that are in scope at it's final + // enveloped location in the document. In order to do that, we're going to construct + // a series of cascading NSContexts to capture namespace declarations: + + // First get the context surrounding the element we are signing. + rootNSCtx, err := etreeutils.NSBuildParentContext(el) + if err != nil { + return nil, err + } + + // Then capture any declarations on the element itself. + elNSCtx, err := rootNSCtx.SubContext(el) + if err != nil { + return nil, err + } + + // Followed by declarations on the Signature (which we just added above) + sigNSCtx, err := elNSCtx.SubContext(sig) + if err != nil { + return nil, err + } + + // Finally detatch the SignedInfo in order to capture all of the namespace + // declarations in the scope we've constructed. + detatchedSignedInfo, err := etreeutils.NSDetatch(sigNSCtx, signedInfo) + if err != nil { + return nil, err + } + + digest, err := ctx.digest(detatchedSignedInfo) + if err != nil { + return nil, err + } + + key, cert, err := ctx.KeyStore.GetKeyPair() + if err != nil { + return nil, err + } + + certs := [][]byte{cert} + if cs, ok := ctx.KeyStore.(X509ChainStore); ok { + certs, err = cs.GetChain() + if err != nil { + return nil, err + } + } + + rawSignature, err := rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest) + if err != nil { + return nil, err + } + + signatureValue := ctx.createNamespacedElement(sig, SignatureValueTag) + signatureValue.SetText(base64.StdEncoding.EncodeToString(rawSignature)) + + keyInfo := ctx.createNamespacedElement(sig, KeyInfoTag) + x509Data := ctx.createNamespacedElement(keyInfo, X509DataTag) + for _, cert := range certs { + x509Certificate := ctx.createNamespacedElement(x509Data, X509CertificateTag) + x509Certificate.SetText(base64.StdEncoding.EncodeToString(cert)) + } + + return sig, nil +} + +func (ctx *SigningContext) createNamespacedElement(el *etree.Element, tag string) *etree.Element { + child := el.CreateElement(tag) + child.Space = ctx.Prefix + return child +} + +func (ctx *SigningContext) SignEnveloped(el *etree.Element) (*etree.Element, error) { + sig, err := ctx.ConstructSignature(el, true) + if err != nil { + return nil, err + } + + ret := el.Copy() + ret.Child = append(ret.Child, sig) + + return ret, nil +} + +func (ctx *SigningContext) GetSignatureMethodIdentifier() string { + if ident, ok := signatureMethodIdentifiers[ctx.Hash]; ok { + return ident + } + return "" +} + +func (ctx *SigningContext) GetDigestAlgorithmIdentifier() string { + if ident, ok := digestAlgorithmIdentifiers[ctx.Hash]; ok { + return ident + } + return "" +} + +// Useful for signing query string (including DEFLATED AuthnRequest) when +// using HTTP-Redirect to make a signed request. +// See 3.4.4.1 DEFLATE Encoding of https://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf +func (ctx *SigningContext) SignString(content string) ([]byte, error) { + hash := ctx.Hash.New() + if ln, err := hash.Write([]byte(content)); err != nil { + return nil, fmt.Errorf("error calculating hash: %v", err) + } else if ln < 1 { + return nil, fmt.Errorf("zero length hash") + } + digest := hash.Sum(nil) + + var signature []byte + if key, _, err := ctx.KeyStore.GetKeyPair(); err != nil { + return nil, fmt.Errorf("unable to fetch key for signing: %v", err) + } else if signature, err = rsa.SignPKCS1v15(rand.Reader, key, ctx.Hash, digest); err != nil { + return nil, fmt.Errorf("error signing: %v", err) + } + return signature, nil +} diff --git a/vendor/github.com/russellhaering/goxmldsig/tls_keystore.go b/vendor/github.com/russellhaering/goxmldsig/tls_keystore.go new file mode 100644 index 00000000..79a1a4d8 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/tls_keystore.go @@ -0,0 +1,39 @@ +package dsig + +import ( + "crypto/rsa" + "crypto/tls" + "fmt" +) + +//Well-known errors +var ( + ErrNonRSAKey = fmt.Errorf("Private key was not RSA") + ErrMissingCertificates = fmt.Errorf("No public certificates provided") +) + +//TLSCertKeyStore wraps the stdlib tls.Certificate to return its contained key +//and certs. +type TLSCertKeyStore tls.Certificate + +//GetKeyPair implements X509KeyStore using the underlying tls.Certificate +func (d TLSCertKeyStore) GetKeyPair() (*rsa.PrivateKey, []byte, error) { + pk, ok := d.PrivateKey.(*rsa.PrivateKey) + + if !ok { + return nil, nil, ErrNonRSAKey + } + + if len(d.Certificate) < 1 { + return nil, nil, ErrMissingCertificates + } + + crt := d.Certificate[0] + + return pk, crt, nil +} + +//GetChain impliments X509ChainStore using the underlying tls.Certificate +func (d TLSCertKeyStore) GetChain() ([][]byte, error) { + return d.Certificate, nil +} diff --git a/vendor/github.com/russellhaering/goxmldsig/types/signature.go b/vendor/github.com/russellhaering/goxmldsig/types/signature.go new file mode 100644 index 00000000..17fd3d72 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/types/signature.go @@ -0,0 +1,93 @@ +package types + +import ( + "encoding/xml" + + "github.com/beevik/etree" +) + +type InclusiveNamespaces struct { + XMLName xml.Name `xml:"http://www.w3.org/2001/10/xml-exc-c14n# InclusiveNamespaces"` + PrefixList string `xml:"PrefixList,attr"` +} + +type Transform struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Transform"` + Algorithm string `xml:"Algorithm,attr"` + InclusiveNamespaces *InclusiveNamespaces `xml:"InclusiveNamespaces"` +} + +type Transforms struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Transforms"` + Transforms []Transform `xml:"Transform"` +} + +type DigestMethod struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# DigestMethod"` + Algorithm string `xml:"Algorithm,attr"` +} + +type Reference struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Reference"` + URI string `xml:"URI,attr"` + DigestValue string `xml:"DigestValue"` + DigestAlgo DigestMethod `xml:"DigestMethod"` + Transforms Transforms `xml:"Transforms"` +} + +type CanonicalizationMethod struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# CanonicalizationMethod"` + Algorithm string `xml:"Algorithm,attr"` +} + +type SignatureMethod struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# SignatureMethod"` + Algorithm string `xml:"Algorithm,attr"` +} + +type SignedInfo struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# SignedInfo"` + CanonicalizationMethod CanonicalizationMethod `xml:"CanonicalizationMethod"` + SignatureMethod SignatureMethod `xml:"SignatureMethod"` + References []Reference `xml:"Reference"` +} + +type SignatureValue struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# SignatureValue"` + Data string `xml:",chardata"` +} + +type KeyInfo struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"` + X509Data X509Data `xml:"X509Data"` +} + +type X509Data struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"` + X509Certificates []X509Certificate `xml:"X509Certificate"` +} + +type X509Certificate struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# X509Certificate"` + Data string `xml:",chardata"` +} + +type Signature struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Signature"` + SignedInfo *SignedInfo `xml:"SignedInfo"` + SignatureValue *SignatureValue `xml:"SignatureValue"` + KeyInfo *KeyInfo `xml:"KeyInfo"` + el *etree.Element +} + +// SetUnderlyingElement will be called with a reference to the Element this Signature +// was unmarshaled from. +func (s *Signature) SetUnderlyingElement(el *etree.Element) { + s.el = el +} + +// UnderlyingElement returns a reference to the Element this signature was unmarshaled +// from, where applicable. +func (s *Signature) UnderlyingElement() *etree.Element { + return s.el +} diff --git a/vendor/github.com/russellhaering/goxmldsig/validate.go b/vendor/github.com/russellhaering/goxmldsig/validate.go new file mode 100644 index 00000000..84045858 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/validate.go @@ -0,0 +1,491 @@ +package dsig + +import ( + "bytes" + "crypto/rsa" + "crypto/x509" + "encoding/base64" + "errors" + "fmt" + "regexp" + + "github.com/beevik/etree" + "github.com/russellhaering/goxmldsig/etreeutils" + "github.com/russellhaering/goxmldsig/types" +) + +var uriRegexp = regexp.MustCompile("^#[a-zA-Z_][\\w.-]*$") +var whiteSpace = regexp.MustCompile("\\s+") + +var ( + // ErrMissingSignature indicates that no enveloped signature was found referencing + // the top level element passed for signature verification. + ErrMissingSignature = errors.New("Missing signature referencing the top-level element") + ErrInvalidSignature = errors.New( "Invalid Signature") +) + +type ValidationContext struct { + CertificateStore X509CertificateStore + IdAttribute string + Clock *Clock +} + +func NewDefaultValidationContext(certificateStore X509CertificateStore) *ValidationContext { + return &ValidationContext{ + CertificateStore: certificateStore, + IdAttribute: DefaultIdAttr, + } +} + +// TODO(russell_h): More flexible namespace support. This might barely work. +func inNamespace(el *etree.Element, ns string) bool { + for _, attr := range el.Attr { + if attr.Value == ns { + if attr.Space == "" && attr.Key == "xmlns" { + return el.Space == "" + } else if attr.Space == "xmlns" { + return el.Space == attr.Key + } + } + } + + return false +} + +func childPath(space, tag string) string { + if space == "" { + return "./" + tag + } else { + return "./" + space + ":" + tag + } +} + +func mapPathToElement(tree, el *etree.Element) []int { + for i, child := range tree.Child { + if child == el { + return []int{i} + } + } + + for i, child := range tree.Child { + if childElement, ok := child.(*etree.Element); ok { + childPath := mapPathToElement(childElement, el) + if childElement != nil { + return append([]int{i}, childPath...) + } + } + } + + return nil +} + +func removeElementAtPath(el *etree.Element, path []int) bool { + if len(path) == 0 { + return false + } + + if len(el.Child) <= path[0] { + return false + } + + childElement, ok := el.Child[path[0]].(*etree.Element) + if !ok { + return false + } + + if len(path) == 1 { + el.RemoveChild(childElement) + return true + } + + return removeElementAtPath(childElement, path[1:]) +} + +// Transform returns a new element equivalent to the passed root el, but with +// the set of transformations described by the ref applied. +// +// The functionality of transform is currently very limited and purpose-specific. +func (ctx *ValidationContext) transform( + el *etree.Element, + sig *types.Signature, + ref *types.Reference) (*etree.Element, Canonicalizer, error) { + transforms := ref.Transforms.Transforms + + // map the path to the passed signature relative to the passed root, in + // order to enable removal of the signature by an enveloped signature + // transform + signaturePath := mapPathToElement(el, sig.UnderlyingElement()) + + // make a copy of the passed root + el = el.Copy() + + var canonicalizer Canonicalizer + + for _, transform := range transforms { + algo := transform.Algorithm + + switch AlgorithmID(algo) { + case EnvelopedSignatureAltorithmId: + if !removeElementAtPath(el, signaturePath) { + return nil, nil, errors.New("Error applying canonicalization transform: Signature not found") + } + + case CanonicalXML10ExclusiveAlgorithmId: + var prefixList string + if transform.InclusiveNamespaces != nil { + prefixList = transform.InclusiveNamespaces.PrefixList + } + + canonicalizer = MakeC14N10ExclusiveCanonicalizerWithPrefixList(prefixList) + + case CanonicalXML11AlgorithmId: + canonicalizer = MakeC14N11Canonicalizer() + + case CanonicalXML10RecAlgorithmId: + canonicalizer = MakeC14N10RecCanonicalizer() + + case CanonicalXML10CommentAlgorithmId: + canonicalizer = MakeC14N10CommentCanonicalizer() + + default: + return nil, nil, errors.New("Unknown Transform Algorithm: " + algo) + } + } + + if canonicalizer == nil { + canonicalizer = MakeNullCanonicalizer() + } + + return el, canonicalizer, nil +} + +func (ctx *ValidationContext) digest(el *etree.Element, digestAlgorithmId string, canonicalizer Canonicalizer) ([]byte, error) { + data, err := canonicalizer.Canonicalize(el) + if err != nil { + return nil, err + } + + digestAlgorithm, ok := digestAlgorithmsByIdentifier[digestAlgorithmId] + if !ok { + return nil, errors.New("Unknown digest algorithm: " + digestAlgorithmId) + } + + hash := digestAlgorithm.New() + _, err = hash.Write(data) + if err != nil { + return nil, err + } + + return hash.Sum(nil), nil +} + +func (ctx *ValidationContext) verifySignedInfo(sig *types.Signature, canonicalizer Canonicalizer, signatureMethodId string, cert *x509.Certificate, decodedSignature []byte) error { + signatureElement := sig.UnderlyingElement() + + nsCtx, err := etreeutils.NSBuildParentContext(signatureElement) + if err != nil { + return err + } + + signedInfo, err := etreeutils.NSFindOneChildCtx(nsCtx, signatureElement, Namespace, SignedInfoTag) + if err != nil { + return err + } + + if signedInfo == nil { + return errors.New("Missing SignedInfo") + } + + // Canonicalize the xml + canonical, err := canonicalSerialize(signedInfo) + if err != nil { + return err + } + + signatureAlgorithm, ok := signatureMethodsByIdentifier[signatureMethodId] + if !ok { + return errors.New("Unknown signature method: " + signatureMethodId) + } + + hash := signatureAlgorithm.New() + _, err = hash.Write(canonical) + if err != nil { + return err + } + + hashed := hash.Sum(nil) + + pubKey, ok := cert.PublicKey.(*rsa.PublicKey) + if !ok { + return errors.New("Invalid public key") + } + + // Verify that the private key matching the public key from the cert was what was used to sign the 'SignedInfo' and produce the 'SignatureValue' + err = rsa.VerifyPKCS1v15(pubKey, signatureAlgorithm, hashed[:], decodedSignature) + if err != nil { + return err + } + + return nil +} + +func (ctx *ValidationContext) validateSignature(el *etree.Element, sig *types.Signature, cert *x509.Certificate) (*etree.Element, error) { + idAttrEl := el.SelectAttr(ctx.IdAttribute) + idAttr := "" + if idAttrEl != nil { + idAttr = idAttrEl.Value + } + + var ref *types.Reference + + // Find the first reference which references the top-level element + for _, _ref := range sig.SignedInfo.References { + if _ref.URI == "" || _ref.URI[1:] == idAttr { + ref = &_ref + } + } + + // Perform all transformations listed in the 'SignedInfo' + // Basically, this means removing the 'SignedInfo' + transformed, canonicalizer, err := ctx.transform(el, sig, ref) + if err != nil { + return nil, err + } + + digestAlgorithm := ref.DigestAlgo.Algorithm + + // Digest the transformed XML and compare it to the 'DigestValue' from the 'SignedInfo' + digest, err := ctx.digest(transformed, digestAlgorithm, canonicalizer) + if err != nil { + return nil, err + } + + decodedDigestValue, err := base64.StdEncoding.DecodeString(ref.DigestValue) + if err != nil { + return nil, err + } + + if !bytes.Equal(digest, decodedDigestValue) { + return nil, errors.New("Signature could not be verified") + } + if sig.SignatureValue == nil { + return nil, errors.New("Signature could not be verified") + } + + // Decode the 'SignatureValue' so we can compare against it + decodedSignature, err := base64.StdEncoding.DecodeString(sig.SignatureValue.Data) + if err != nil { + return nil, errors.New("Could not decode signature") + } + + // Actually verify the 'SignedInfo' was signed by a trusted source + signatureMethod := sig.SignedInfo.SignatureMethod.Algorithm + err = ctx.verifySignedInfo(sig, canonicalizer, signatureMethod, cert, decodedSignature) + if err != nil { + return nil, err + } + + return transformed, nil +} + +func contains(roots []*x509.Certificate, cert *x509.Certificate) bool { + for _, root := range roots { + if root.Equal(cert) { + return true + } + } + return false +} + +// In most places, we use etree Elements, but while deserializing the Signature, we use +// encoding/xml unmarshal directly to convert to a convenient go struct. This presents a problem in some cases because +// when an xml element repeats under the parent, the last element will win and/or be appended. We need to assert that +// the Signature object matches the expected shape of a Signature object. +func validateShape(signatureEl *etree.Element) error { + children := signatureEl.ChildElements() + + childCounts := map[string]int{} + for _, child := range children { + childCounts[child.Tag]++ + } + + validateCount := childCounts[SignedInfoTag] == 1 && childCounts[KeyInfoTag] <= 1 && childCounts[SignatureValueTag] == 1 + if !validateCount { + return ErrInvalidSignature + } + return nil +} + +// findSignature searches for a Signature element referencing the passed root element. +func (ctx *ValidationContext) findSignature(root *etree.Element) (*types.Signature, error) { + idAttrEl := root.SelectAttr(ctx.IdAttribute) + idAttr := "" + if idAttrEl != nil { + idAttr = idAttrEl.Value + } + + var sig *types.Signature + + // Traverse the tree looking for a Signature element + err := etreeutils.NSFindIterate(root, Namespace, SignatureTag, func(ctx etreeutils.NSContext, signatureEl *etree.Element) error { + err := validateShape(signatureEl) + if err != nil { + return err + } + found := false + err = etreeutils.NSFindChildrenIterateCtx(ctx, signatureEl, Namespace, SignedInfoTag, + func(ctx etreeutils.NSContext, signedInfo *etree.Element) error { + detachedSignedInfo, err := etreeutils.NSDetatch(ctx, signedInfo) + if err != nil { + return err + } + + c14NMethod, err := etreeutils.NSFindOneChildCtx(ctx, detachedSignedInfo, Namespace, CanonicalizationMethodTag) + if err != nil { + return err + } + + if c14NMethod == nil { + return errors.New("missing CanonicalizationMethod on Signature") + } + + c14NAlgorithm := c14NMethod.SelectAttrValue(AlgorithmAttr, "") + + var canonicalSignedInfo *etree.Element + + switch AlgorithmID(c14NAlgorithm) { + case CanonicalXML10ExclusiveAlgorithmId: + err := etreeutils.TransformExcC14n(detachedSignedInfo, "") + if err != nil { + return err + } + + // NOTE: TransformExcC14n transforms the element in-place, + // while canonicalPrep isn't meant to. Once we standardize + // this behavior we can drop this, as well as the adding and + // removing of elements below. + canonicalSignedInfo = detachedSignedInfo + + case CanonicalXML11AlgorithmId: + canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true) + + case CanonicalXML10RecAlgorithmId: + canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true) + + case CanonicalXML10CommentAlgorithmId: + canonicalSignedInfo = canonicalPrep(detachedSignedInfo, map[string]struct{}{}, true) + + default: + return fmt.Errorf("invalid CanonicalizationMethod on Signature: %s", c14NAlgorithm) + } + + signatureEl.RemoveChild(signedInfo) + signatureEl.AddChild(canonicalSignedInfo) + + found = true + + return etreeutils.ErrTraversalHalted + }) + if err != nil { + return err + } + + if !found { + return errors.New("Missing SignedInfo") + } + + // Unmarshal the signature into a structured Signature type + _sig := &types.Signature{} + err = etreeutils.NSUnmarshalElement(ctx, signatureEl, _sig) + if err != nil { + return err + } + + // Traverse references in the signature to determine whether it has at least + // one reference to the top level element. If so, conclude the search. + for _, ref := range _sig.SignedInfo.References { + if ref.URI == "" || ref.URI[1:] == idAttr { + sig = _sig + return etreeutils.ErrTraversalHalted + } + } + + return nil + }) + + if err != nil { + return nil, err + } + + if sig == nil { + return nil, ErrMissingSignature + } + + return sig, nil +} + +func (ctx *ValidationContext) verifyCertificate(sig *types.Signature) (*x509.Certificate, error) { + now := ctx.Clock.Now() + + roots, err := ctx.CertificateStore.Certificates() + if err != nil { + return nil, err + } + + var cert *x509.Certificate + + if sig.KeyInfo != nil { + // If the Signature includes KeyInfo, extract the certificate from there + if len(sig.KeyInfo.X509Data.X509Certificates) == 0 || sig.KeyInfo.X509Data.X509Certificates[0].Data == "" { + return nil, errors.New("missing X509Certificate within KeyInfo") + } + + certData, err := base64.StdEncoding.DecodeString( + whiteSpace.ReplaceAllString(sig.KeyInfo.X509Data.X509Certificates[0].Data, "")) + if err != nil { + return nil, errors.New("Failed to parse certificate") + } + + cert, err = x509.ParseCertificate(certData) + if err != nil { + return nil, err + } + } else { + // If the Signature doesn't have KeyInfo, Use the root certificate if there is only one + if len(roots) == 1 { + cert = roots[0] + } else { + return nil, errors.New("Missing x509 Element") + } + } + + // Verify that the certificate is one we trust + if !contains(roots, cert) { + return nil, errors.New("Could not verify certificate against trusted certs") + } + + if now.Before(cert.NotBefore) || now.After(cert.NotAfter) { + return nil, errors.New("Cert is not valid at this time") + } + + return cert, nil +} + +// Validate verifies that the passed element contains a valid enveloped signature +// matching a currently-valid certificate in the context's CertificateStore. +func (ctx *ValidationContext) Validate(el *etree.Element) (*etree.Element, error) { + // Make a copy of the element to avoid mutating the one we were passed. + el = el.Copy() + + sig, err := ctx.findSignature(el) + if err != nil { + return nil, err + } + + cert, err := ctx.verifyCertificate(sig) + if err != nil { + return nil, err + } + + return ctx.validateSignature(el, sig, cert) +} diff --git a/vendor/github.com/russellhaering/goxmldsig/xml_constants.go b/vendor/github.com/russellhaering/goxmldsig/xml_constants.go new file mode 100644 index 00000000..c4b815b2 --- /dev/null +++ b/vendor/github.com/russellhaering/goxmldsig/xml_constants.go @@ -0,0 +1,81 @@ +package dsig + +import "crypto" + +const ( + DefaultPrefix = "ds" + Namespace = "http://www.w3.org/2000/09/xmldsig#" +) + +// Tags +const ( + SignatureTag = "Signature" + SignedInfoTag = "SignedInfo" + CanonicalizationMethodTag = "CanonicalizationMethod" + SignatureMethodTag = "SignatureMethod" + ReferenceTag = "Reference" + TransformsTag = "Transforms" + TransformTag = "Transform" + DigestMethodTag = "DigestMethod" + DigestValueTag = "DigestValue" + SignatureValueTag = "SignatureValue" + KeyInfoTag = "KeyInfo" + X509DataTag = "X509Data" + X509CertificateTag = "X509Certificate" + InclusiveNamespacesTag = "InclusiveNamespaces" +) + +const ( + AlgorithmAttr = "Algorithm" + URIAttr = "URI" + DefaultIdAttr = "ID" + PrefixListAttr = "PrefixList" +) + +type AlgorithmID string + +func (id AlgorithmID) String() string { + return string(id) +} + +const ( + RSASHA1SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1" + RSASHA256SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" + RSASHA512SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512" +) + +//Well-known signature algorithms +const ( + // Supported canonicalization algorithms + CanonicalXML10ExclusiveAlgorithmId AlgorithmID = "http://www.w3.org/2001/10/xml-exc-c14n#" + CanonicalXML11AlgorithmId AlgorithmID = "http://www.w3.org/2006/12/xml-c14n11" + + CanonicalXML10RecAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" + CanonicalXML10CommentAlgorithmId AlgorithmID = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments" + + EnvelopedSignatureAltorithmId AlgorithmID = "http://www.w3.org/2000/09/xmldsig#enveloped-signature" +) + +var digestAlgorithmIdentifiers = map[crypto.Hash]string{ + crypto.SHA1: "http://www.w3.org/2000/09/xmldsig#sha1", + crypto.SHA256: "http://www.w3.org/2001/04/xmlenc#sha256", + crypto.SHA512: "http://www.w3.org/2001/04/xmlenc#sha512", +} + +var digestAlgorithmsByIdentifier = map[string]crypto.Hash{} +var signatureMethodsByIdentifier = map[string]crypto.Hash{} + +func init() { + for hash, id := range digestAlgorithmIdentifiers { + digestAlgorithmsByIdentifier[id] = hash + } + for hash, id := range signatureMethodIdentifiers { + signatureMethodsByIdentifier[id] = hash + } +} + +var signatureMethodIdentifiers = map[crypto.Hash]string{ + crypto.SHA1: RSASHA1SignatureMethod, + crypto.SHA256: RSASHA256SignatureMethod, + crypto.SHA512: RSASHA512SignatureMethod, +} diff --git a/vendor/github.com/stretchr/testify/LICENSE b/vendor/github.com/stretchr/testify/LICENSE new file mode 100644 index 00000000..4b0421cf --- /dev/null +++ b/vendor/github.com/stretchr/testify/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/stretchr/testify/assert/assertion_compare.go b/vendor/github.com/stretchr/testify/assert/assertion_compare.go new file mode 100644 index 00000000..41649d26 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_compare.go @@ -0,0 +1,394 @@ +package assert + +import ( + "fmt" + "reflect" +) + +type CompareType int + +const ( + compareLess CompareType = iota - 1 + compareEqual + compareGreater +) + +var ( + intType = reflect.TypeOf(int(1)) + int8Type = reflect.TypeOf(int8(1)) + int16Type = reflect.TypeOf(int16(1)) + int32Type = reflect.TypeOf(int32(1)) + int64Type = reflect.TypeOf(int64(1)) + + uintType = reflect.TypeOf(uint(1)) + uint8Type = reflect.TypeOf(uint8(1)) + uint16Type = reflect.TypeOf(uint16(1)) + uint32Type = reflect.TypeOf(uint32(1)) + uint64Type = reflect.TypeOf(uint64(1)) + + float32Type = reflect.TypeOf(float32(1)) + float64Type = reflect.TypeOf(float64(1)) + + stringType = reflect.TypeOf("") +) + +func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { + obj1Value := reflect.ValueOf(obj1) + obj2Value := reflect.ValueOf(obj2) + + // throughout this switch we try and avoid calling .Convert() if possible, + // as this has a pretty big performance impact + switch kind { + case reflect.Int: + { + intobj1, ok := obj1.(int) + if !ok { + intobj1 = obj1Value.Convert(intType).Interface().(int) + } + intobj2, ok := obj2.(int) + if !ok { + intobj2 = obj2Value.Convert(intType).Interface().(int) + } + if intobj1 > intobj2 { + return compareGreater, true + } + if intobj1 == intobj2 { + return compareEqual, true + } + if intobj1 < intobj2 { + return compareLess, true + } + } + case reflect.Int8: + { + int8obj1, ok := obj1.(int8) + if !ok { + int8obj1 = obj1Value.Convert(int8Type).Interface().(int8) + } + int8obj2, ok := obj2.(int8) + if !ok { + int8obj2 = obj2Value.Convert(int8Type).Interface().(int8) + } + if int8obj1 > int8obj2 { + return compareGreater, true + } + if int8obj1 == int8obj2 { + return compareEqual, true + } + if int8obj1 < int8obj2 { + return compareLess, true + } + } + case reflect.Int16: + { + int16obj1, ok := obj1.(int16) + if !ok { + int16obj1 = obj1Value.Convert(int16Type).Interface().(int16) + } + int16obj2, ok := obj2.(int16) + if !ok { + int16obj2 = obj2Value.Convert(int16Type).Interface().(int16) + } + if int16obj1 > int16obj2 { + return compareGreater, true + } + if int16obj1 == int16obj2 { + return compareEqual, true + } + if int16obj1 < int16obj2 { + return compareLess, true + } + } + case reflect.Int32: + { + int32obj1, ok := obj1.(int32) + if !ok { + int32obj1 = obj1Value.Convert(int32Type).Interface().(int32) + } + int32obj2, ok := obj2.(int32) + if !ok { + int32obj2 = obj2Value.Convert(int32Type).Interface().(int32) + } + if int32obj1 > int32obj2 { + return compareGreater, true + } + if int32obj1 == int32obj2 { + return compareEqual, true + } + if int32obj1 < int32obj2 { + return compareLess, true + } + } + case reflect.Int64: + { + int64obj1, ok := obj1.(int64) + if !ok { + int64obj1 = obj1Value.Convert(int64Type).Interface().(int64) + } + int64obj2, ok := obj2.(int64) + if !ok { + int64obj2 = obj2Value.Convert(int64Type).Interface().(int64) + } + if int64obj1 > int64obj2 { + return compareGreater, true + } + if int64obj1 == int64obj2 { + return compareEqual, true + } + if int64obj1 < int64obj2 { + return compareLess, true + } + } + case reflect.Uint: + { + uintobj1, ok := obj1.(uint) + if !ok { + uintobj1 = obj1Value.Convert(uintType).Interface().(uint) + } + uintobj2, ok := obj2.(uint) + if !ok { + uintobj2 = obj2Value.Convert(uintType).Interface().(uint) + } + if uintobj1 > uintobj2 { + return compareGreater, true + } + if uintobj1 == uintobj2 { + return compareEqual, true + } + if uintobj1 < uintobj2 { + return compareLess, true + } + } + case reflect.Uint8: + { + uint8obj1, ok := obj1.(uint8) + if !ok { + uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8) + } + uint8obj2, ok := obj2.(uint8) + if !ok { + uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8) + } + if uint8obj1 > uint8obj2 { + return compareGreater, true + } + if uint8obj1 == uint8obj2 { + return compareEqual, true + } + if uint8obj1 < uint8obj2 { + return compareLess, true + } + } + case reflect.Uint16: + { + uint16obj1, ok := obj1.(uint16) + if !ok { + uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16) + } + uint16obj2, ok := obj2.(uint16) + if !ok { + uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16) + } + if uint16obj1 > uint16obj2 { + return compareGreater, true + } + if uint16obj1 == uint16obj2 { + return compareEqual, true + } + if uint16obj1 < uint16obj2 { + return compareLess, true + } + } + case reflect.Uint32: + { + uint32obj1, ok := obj1.(uint32) + if !ok { + uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32) + } + uint32obj2, ok := obj2.(uint32) + if !ok { + uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32) + } + if uint32obj1 > uint32obj2 { + return compareGreater, true + } + if uint32obj1 == uint32obj2 { + return compareEqual, true + } + if uint32obj1 < uint32obj2 { + return compareLess, true + } + } + case reflect.Uint64: + { + uint64obj1, ok := obj1.(uint64) + if !ok { + uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64) + } + uint64obj2, ok := obj2.(uint64) + if !ok { + uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64) + } + if uint64obj1 > uint64obj2 { + return compareGreater, true + } + if uint64obj1 == uint64obj2 { + return compareEqual, true + } + if uint64obj1 < uint64obj2 { + return compareLess, true + } + } + case reflect.Float32: + { + float32obj1, ok := obj1.(float32) + if !ok { + float32obj1 = obj1Value.Convert(float32Type).Interface().(float32) + } + float32obj2, ok := obj2.(float32) + if !ok { + float32obj2 = obj2Value.Convert(float32Type).Interface().(float32) + } + if float32obj1 > float32obj2 { + return compareGreater, true + } + if float32obj1 == float32obj2 { + return compareEqual, true + } + if float32obj1 < float32obj2 { + return compareLess, true + } + } + case reflect.Float64: + { + float64obj1, ok := obj1.(float64) + if !ok { + float64obj1 = obj1Value.Convert(float64Type).Interface().(float64) + } + float64obj2, ok := obj2.(float64) + if !ok { + float64obj2 = obj2Value.Convert(float64Type).Interface().(float64) + } + if float64obj1 > float64obj2 { + return compareGreater, true + } + if float64obj1 == float64obj2 { + return compareEqual, true + } + if float64obj1 < float64obj2 { + return compareLess, true + } + } + case reflect.String: + { + stringobj1, ok := obj1.(string) + if !ok { + stringobj1 = obj1Value.Convert(stringType).Interface().(string) + } + stringobj2, ok := obj2.(string) + if !ok { + stringobj2 = obj2Value.Convert(stringType).Interface().(string) + } + if stringobj1 > stringobj2 { + return compareGreater, true + } + if stringobj1 == stringobj2 { + return compareEqual, true + } + if stringobj1 < stringobj2 { + return compareLess, true + } + } + } + + return compareEqual, false +} + +// Greater asserts that the first element is greater than the second +// +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") +func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") +func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) +} + +// Less asserts that the first element is less than the second +// +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") +func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") +func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) +} + +// Positive asserts that the specified element is positive +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + zero := reflect.Zero(reflect.TypeOf(e)) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs) +} + +// Negative asserts that the specified element is negative +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { + zero := reflect.Zero(reflect.TypeOf(e)) + return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs) +} + +func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + e1Kind := reflect.ValueOf(e1).Kind() + e2Kind := reflect.ValueOf(e2).Kind() + if e1Kind != e2Kind { + return Fail(t, "Elements should be the same type", msgAndArgs...) + } + + compareResult, isComparable := compare(e1, e2, e1Kind) + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\"", reflect.TypeOf(e1)), msgAndArgs...) + } + + if !containsValue(allowedComparesResults, compareResult) { + return Fail(t, fmt.Sprintf(failMessage, e1, e2), msgAndArgs...) + } + + return true +} + +func containsValue(values []CompareType, value CompareType) bool { + for _, v := range values { + if v == value { + return true + } + } + + return false +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go b/vendor/github.com/stretchr/testify/assert/assertion_format.go new file mode 100644 index 00000000..4dfd1229 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go @@ -0,0 +1,741 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package assert + +import ( + http "net/http" + url "net/url" + time "time" +) + +// Conditionf uses a Comparison to assert a complex condition. +func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Condition(t, comp, append([]interface{}{msg}, args...)...) +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") +// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") +// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") +func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Contains(t, s, contains, append([]interface{}{msg}, args...)...) +} + +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return DirExists(t, path, append([]interface{}{msg}, args...)...) +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...) +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Emptyf(t, obj, "error message %s", "formatted") +func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Empty(t, object, append([]interface{}{msg}, args...)...) +} + +// Equalf asserts that two objects are equal. +// +// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Equal(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...) +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") +func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Error(t, err, append([]interface{}{msg}, args...)...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return ErrorIs(t, err, target, append([]interface{}{msg}, args...)...) +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") +func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Failf reports a failure through +func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, failureMessage, append([]interface{}{msg}, args...)...) +} + +// FailNowf fails test +func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...) +} + +// Falsef asserts that the specified value is false. +// +// assert.Falsef(t, myBool, "error message %s", "formatted") +func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return False(t, value, append([]interface{}{msg}, args...)...) +} + +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return FileExists(t, path, append([]interface{}{msg}, args...)...) +} + +// Greaterf asserts that the first element is greater than the second +// +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Greater(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...) +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...) +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...) +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...) +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPStatusCode(t, handler, method, url, values, statuscode, append([]interface{}{msg}, args...)...) +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...) +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...) +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...) +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...) +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...) +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsDecreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsIncreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasing(t, object, append([]interface{}{msg}, args...)...) +} + +// IsTypef asserts that the specified objects are of the same type. +func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...) +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Len(t, object, length, append([]interface{}{msg}, args...)...) +} + +// Lessf asserts that the first element is less than the second +// +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") +// assert.Lessf(t, "a", "b", "error message %s", "formatted") +func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Less(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...) +} + +// Negativef asserts that the specified element is negative +// +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") +func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Negative(t, e, append([]interface{}{msg}, args...)...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...) +} + +// Nilf asserts that the specified object is nil. +// +// assert.Nilf(t, err, "error message %s", "formatted") +func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Nil(t, object, append([]interface{}{msg}, args...)...) +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NoDirExists(t, path, append([]interface{}{msg}, args...)...) +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NoError(t, err, append([]interface{}{msg}, args...)...) +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NoFileExists(t, path, append([]interface{}{msg}, args...)...) +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") +// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") +func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotContains(t, s, contains, append([]interface{}{msg}, args...)...) +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotEmpty(t, object, append([]interface{}{msg}, args...)...) +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...) +} + +// NotNilf asserts that the specified object is not nil. +// +// assert.NotNilf(t, err, "error message %s", "formatted") +func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotNil(t, object, append([]interface{}{msg}, args...)...) +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotPanics(t, f, append([]interface{}{msg}, args...)...) +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...) +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...) +} + +// NotZerof asserts that i is not the zero value for its type. +func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return NotZero(t, i, append([]interface{}{msg}, args...)...) +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Panics(t, f, append([]interface{}{msg}, args...)...) +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...) +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...) +} + +// Positivef asserts that the specified element is positive +// +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") +func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Positive(t, e, append([]interface{}{msg}, args...)...) +} + +// Regexpf asserts that a specified regexp matches a string. +// +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Regexp(t, rx, str, append([]interface{}{msg}, args...)...) +} + +// Samef asserts that two pointers reference the same object. +// +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Same(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Subset(t, list, subset, append([]interface{}{msg}, args...)...) +} + +// Truef asserts that the specified value is true. +// +// assert.Truef(t, myBool, "error message %s", "formatted") +func Truef(t TestingT, value bool, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return True(t, value, append([]interface{}{msg}, args...)...) +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...) +} + +// Zerof asserts that i is the zero value for its type. +func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Zero(t, i, append([]interface{}{msg}, args...)...) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl new file mode 100644 index 00000000..d2bb0b81 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl @@ -0,0 +1,5 @@ +{{.CommentFormat}} +func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { + if h, ok := t.(tHelper); ok { h.Helper() } + return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go b/vendor/github.com/stretchr/testify/assert/assertion_forward.go new file mode 100644 index 00000000..25337a6f --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go @@ -0,0 +1,1470 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package assert + +import ( + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Condition(a.t, comp, msgAndArgs...) +} + +// Conditionf uses a Comparison to assert a complex condition. +func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Conditionf(a.t, comp, msg, args...) +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") +func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Contains(a.t, s, contains, msgAndArgs...) +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Containsf("Hello World", "World", "error message %s", "formatted") +// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") +// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") +func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Containsf(a.t, s, contains, msg, args...) +} + +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return DirExists(a.t, path, msgAndArgs...) +} + +// DirExistsf checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return DirExistsf(a.t, path, msg, args...) +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) +func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ElementsMatch(a.t, listA, listB, msgAndArgs...) +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ElementsMatchf(a.t, listA, listB, msg, args...) +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Empty(obj) +func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Empty(a.t, object, msgAndArgs...) +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Emptyf(obj, "error message %s", "formatted") +func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Emptyf(a.t, object, msg, args...) +} + +// Equal asserts that two objects are equal. +// +// a.Equal(123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Equal(a.t, expected, actual, msgAndArgs...) +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) +func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualError(a.t, theError, errString, msgAndArgs...) +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualErrorf(a.t, theError, errString, msg, args...) +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValues(uint32(123), int32(123)) +func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualValues(a.t, expected, actual, msgAndArgs...) +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return EqualValuesf(a.t, expected, actual, msg, args...) +} + +// Equalf asserts that two objects are equal. +// +// a.Equalf(123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Equalf(a.t, expected, actual, msg, args...) +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } +func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Error(a.t, err, msgAndArgs...) +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorAsf(a.t, err, target, msg, args...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return ErrorIsf(a.t, err, target, msg, args...) +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Errorf(a.t, err, msg, args...) +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Eventually(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Eventuallyf(a.t, condition, waitFor, tick, msg, args...) +} + +// Exactly asserts that two objects are equal in value and type. +// +// a.Exactly(int32(123), int64(123)) +func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Exactly(a.t, expected, actual, msgAndArgs...) +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Exactlyf(a.t, expected, actual, msg, args...) +} + +// Fail reports a failure through +func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Fail(a.t, failureMessage, msgAndArgs...) +} + +// FailNow fails test +func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return FailNow(a.t, failureMessage, msgAndArgs...) +} + +// FailNowf fails test +func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return FailNowf(a.t, failureMessage, msg, args...) +} + +// Failf reports a failure through +func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Failf(a.t, failureMessage, msg, args...) +} + +// False asserts that the specified value is false. +// +// a.False(myBool) +func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return False(a.t, value, msgAndArgs...) +} + +// Falsef asserts that the specified value is false. +// +// a.Falsef(myBool, "error message %s", "formatted") +func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Falsef(a.t, value, msg, args...) +} + +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return FileExists(a.t, path, msgAndArgs...) +} + +// FileExistsf checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return FileExistsf(a.t, path, msg, args...) +} + +// Greater asserts that the first element is greater than the second +// +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") +func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Greater(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") +func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return GreaterOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return GreaterOrEqualf(a.t, e1, e2, msg, args...) +} + +// Greaterf asserts that the first element is greater than the second +// +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") +// a.Greaterf("b", "a", "error message %s", "formatted") +func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Greaterf(a.t, e1, e2, msg, args...) +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPError(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPErrorf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPRedirectf(a.t, handler, method, url, values, msg, args...) +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return HTTPSuccessf(a.t, handler, method, url, values, msg, args...) +} + +// Implements asserts that an object is implemented by the specified interface. +// +// a.Implements((*MyInterface)(nil), new(MyObject)) +func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Implements(a.t, interfaceObject, object, msgAndArgs...) +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Implementsf(a.t, interfaceObject, object, msg, args...) +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// a.InDelta(math.Pi, 22/7.0, 0.01) +func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDelta(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) +} + +// InDeltaSlicef is the same as InDelta, except it compares two slices. +func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaSlicef(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InDeltaf(a.t, expected, actual, delta, msg, args...) +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. +func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return InEpsilonf(a.t, expected, actual, epsilon, msg, args...) +} + +// IsDecreasing asserts that the collection is decreasing +// +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) +func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsDecreasingf(a.t, object, msg, args...) +} + +// IsIncreasing asserts that the collection is increasing +// +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) +func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsIncreasingf(a.t, object, msg, args...) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) +func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonDecreasingf(a.t, object, msg, args...) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) +func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsNonIncreasingf(a.t, object, msg, args...) +} + +// IsType asserts that the specified objects are of the same type. +func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsType(a.t, expectedType, object, msgAndArgs...) +} + +// IsTypef asserts that the specified objects are of the same type. +func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return IsTypef(a.t, expectedType, object, msg, args...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return JSONEq(a.t, expected, actual, msgAndArgs...) +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return JSONEqf(a.t, expected, actual, msg, args...) +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// a.Len(mySlice, 3) +func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Len(a.t, object, length, msgAndArgs...) +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// a.Lenf(mySlice, 3, "error message %s", "formatted") +func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Lenf(a.t, object, length, msg, args...) +} + +// Less asserts that the first element is less than the second +// +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") +func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Less(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") +func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return LessOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return LessOrEqualf(a.t, e1, e2, msg, args...) +} + +// Lessf asserts that the first element is less than the second +// +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") +// a.Lessf("a", "b", "error message %s", "formatted") +func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Lessf(a.t, e1, e2, msg, args...) +} + +// Negative asserts that the specified element is negative +// +// a.Negative(-1) +// a.Negative(-1.23) +func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Negative(a.t, e, msgAndArgs...) +} + +// Negativef asserts that the specified element is negative +// +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") +func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Negativef(a.t, e, msg, args...) +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Never(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Neverf(a.t, condition, waitFor, tick, msg, args...) +} + +// Nil asserts that the specified object is nil. +// +// a.Nil(err) +func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Nil(a.t, object, msgAndArgs...) +} + +// Nilf asserts that the specified object is nil. +// +// a.Nilf(err, "error message %s", "formatted") +func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Nilf(a.t, object, msg, args...) +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoDirExists(a.t, path, msgAndArgs...) +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoDirExistsf(a.t, path, msg, args...) +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoError(a.t, err, msgAndArgs...) +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoErrorf(a.t, err, msg, args...) +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoFileExists(a.t, path, msgAndArgs...) +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NoFileExistsf(a.t, path, msg, args...) +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") +func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotContains(a.t, s, contains, msgAndArgs...) +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") +// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") +// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") +func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotContainsf(a.t, s, contains, msg, args...) +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEmpty(a.t, object, msgAndArgs...) +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEmptyf(a.t, object, msg, args...) +} + +// NotEqual asserts that the specified values are NOT equal. +// +// a.NotEqual(obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqual(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValues(obj1, obj2) +func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqualValues(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqualValuesf(a.t, expected, actual, msg, args...) +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotEqualf(a.t, expected, actual, msg, args...) +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotErrorIsf(a.t, err, target, msg, args...) +} + +// NotNil asserts that the specified object is not nil. +// +// a.NotNil(err) +func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotNil(a.t, object, msgAndArgs...) +} + +// NotNilf asserts that the specified object is not nil. +// +// a.NotNilf(err, "error message %s", "formatted") +func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotNilf(a.t, object, msg, args...) +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanics(func(){ RemainCalm() }) +func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotPanics(a.t, f, msgAndArgs...) +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotPanicsf(a.t, f, msg, args...) +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") +func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotRegexp(a.t, rx, str, msgAndArgs...) +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotRegexpf(a.t, rx, str, msg, args...) +} + +// NotSame asserts that two pointers do not reference the same object. +// +// a.NotSame(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSame(a.t, expected, actual, msgAndArgs...) +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSamef(a.t, expected, actual, msg, args...) +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSubset(a.t, list, subset, msgAndArgs...) +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotSubsetf(a.t, list, subset, msg, args...) +} + +// NotZero asserts that i is not the zero value for its type. +func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotZero(a.t, i, msgAndArgs...) +} + +// NotZerof asserts that i is not the zero value for its type. +func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return NotZerof(a.t, i, msg, args...) +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panics(func(){ GoCrazy() }) +func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Panics(a.t, f, msgAndArgs...) +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithError(a.t, errString, f, msgAndArgs...) +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithErrorf(a.t, errString, f, msg, args...) +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithValue(a.t, expected, f, msgAndArgs...) +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return PanicsWithValuef(a.t, expected, f, msg, args...) +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Panicsf(a.t, f, msg, args...) +} + +// Positive asserts that the specified element is positive +// +// a.Positive(1) +// a.Positive(1.23) +func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Positive(a.t, e, msgAndArgs...) +} + +// Positivef asserts that the specified element is positive +// +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") +func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Positivef(a.t, e, msg, args...) +} + +// Regexp asserts that a specified regexp matches a string. +// +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") +func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Regexp(a.t, rx, str, msgAndArgs...) +} + +// Regexpf asserts that a specified regexp matches a string. +// +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Regexpf(a.t, rx, str, msg, args...) +} + +// Same asserts that two pointers reference the same object. +// +// a.Same(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Same(a.t, expected, actual, msgAndArgs...) +} + +// Samef asserts that two pointers reference the same object. +// +// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Samef(a.t, expected, actual, msg, args...) +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Subset(a.t, list, subset, msgAndArgs...) +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") +func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Subsetf(a.t, list, subset, msg, args...) +} + +// True asserts that the specified value is true. +// +// a.True(myBool) +func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return True(a.t, value, msgAndArgs...) +} + +// Truef asserts that the specified value is true. +// +// a.Truef(myBool, "error message %s", "formatted") +func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Truef(a.t, value, msg, args...) +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return WithinDuration(a.t, expected, actual, delta, msgAndArgs...) +} + +// WithinDurationf asserts that the two times are within duration delta of each other. +// +// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") +func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return WithinDurationf(a.t, expected, actual, delta, msg, args...) +} + +// YAMLEq asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return YAMLEq(a.t, expected, actual, msgAndArgs...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return YAMLEqf(a.t, expected, actual, msg, args...) +} + +// Zero asserts that i is the zero value for its type. +func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Zero(a.t, i, msgAndArgs...) +} + +// Zerof asserts that i is the zero value for its type. +func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + return Zerof(a.t, i, msg, args...) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl new file mode 100644 index 00000000..188bb9e1 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl @@ -0,0 +1,5 @@ +{{.CommentWithoutT "a"}} +func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { + if h, ok := a.t.(tHelper); ok { h.Helper() } + return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertion_order.go b/vendor/github.com/stretchr/testify/assert/assertion_order.go new file mode 100644 index 00000000..1c3b4718 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertion_order.go @@ -0,0 +1,81 @@ +package assert + +import ( + "fmt" + "reflect" +) + +// isOrdered checks that collection contains orderable elements. +func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { + objKind := reflect.TypeOf(object).Kind() + if objKind != reflect.Slice && objKind != reflect.Array { + return false + } + + objValue := reflect.ValueOf(object) + objLen := objValue.Len() + + if objLen <= 1 { + return true + } + + value := objValue.Index(0) + valueInterface := value.Interface() + firstValueKind := value.Kind() + + for i := 1; i < objLen; i++ { + prevValue := value + prevValueInterface := valueInterface + + value = objValue.Index(i) + valueInterface = value.Interface() + + compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind) + + if !isComparable { + return Fail(t, fmt.Sprintf("Can not compare type \"%s\" and \"%s\"", reflect.TypeOf(value), reflect.TypeOf(prevValue)), msgAndArgs...) + } + + if !containsValue(allowedComparesResults, compareResult) { + return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...) + } + } + + return true +} + +// IsIncreasing asserts that the collection is increasing +// +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) +func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) +func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) +} + +// IsDecreasing asserts that the collection is decreasing +// +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) +func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) +func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) +} diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go new file mode 100644 index 00000000..bcac4401 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -0,0 +1,1774 @@ +package assert + +import ( + "bufio" + "bytes" + "encoding/json" + "errors" + "fmt" + "math" + "os" + "reflect" + "regexp" + "runtime" + "runtime/debug" + "strings" + "time" + "unicode" + "unicode/utf8" + + "github.com/davecgh/go-spew/spew" + "github.com/pmezard/go-difflib/difflib" + yaml "gopkg.in/yaml.v3" +) + +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl" + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + Errorf(format string, args ...interface{}) +} + +// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful +// for table driven tests. +type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool + +// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful +// for table driven tests. +type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool + +// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful +// for table driven tests. +type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool + +// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful +// for table driven tests. +type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool + +// Comparison is a custom function that returns true on success and false on failure +type Comparison func() (success bool) + +/* + Helper functions +*/ + +// ObjectsAreEqual determines if two objects are considered equal. +// +// This function does no assertion of any kind. +func ObjectsAreEqual(expected, actual interface{}) bool { + if expected == nil || actual == nil { + return expected == actual + } + + exp, ok := expected.([]byte) + if !ok { + return reflect.DeepEqual(expected, actual) + } + + act, ok := actual.([]byte) + if !ok { + return false + } + if exp == nil || act == nil { + return exp == nil && act == nil + } + return bytes.Equal(exp, act) +} + +// ObjectsAreEqualValues gets whether two objects are equal, or if their +// values are equal. +func ObjectsAreEqualValues(expected, actual interface{}) bool { + if ObjectsAreEqual(expected, actual) { + return true + } + + actualType := reflect.TypeOf(actual) + if actualType == nil { + return false + } + expectedValue := reflect.ValueOf(expected) + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + // Attempt comparison after type conversion + return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) + } + + return false +} + +/* CallerInfo is necessary because the assert functions use the testing object +internally, causing it to print the file:line of the assert method, rather than where +the problem actually occurred in calling code.*/ + +// CallerInfo returns an array of strings containing the file and line number +// of each stack frame leading from the current test to the assert call that +// failed. +func CallerInfo() []string { + + var pc uintptr + var ok bool + var file string + var line int + var name string + + callers := []string{} + for i := 0; ; i++ { + pc, file, line, ok = runtime.Caller(i) + if !ok { + // The breaks below failed to terminate the loop, and we ran off the + // end of the call stack. + break + } + + // This is a huge edge case, but it will panic if this is the case, see #180 + if file == "" { + break + } + + f := runtime.FuncForPC(pc) + if f == nil { + break + } + name = f.Name() + + // testing.tRunner is the standard library function that calls + // tests. Subtests are called directly by tRunner, without going through + // the Test/Benchmark/Example function that contains the t.Run calls, so + // with subtests we should break when we hit tRunner, without adding it + // to the list of callers. + if name == "testing.tRunner" { + break + } + + parts := strings.Split(file, "/") + file = parts[len(parts)-1] + if len(parts) > 1 { + dir := parts[len(parts)-2] + if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { + callers = append(callers, fmt.Sprintf("%s:%d", file, line)) + } + } + + // Drop the package + segments := strings.Split(name, ".") + name = segments[len(segments)-1] + if isTest(name, "Test") || + isTest(name, "Benchmark") || + isTest(name, "Example") { + break + } + } + + return callers +} + +// Stolen from the `go test` tool. +// isTest tells whether name looks like a test (or benchmark, according to prefix). +// It is a Test (say) if there is a character after Test that is not a lower-case letter. +// We don't want TesticularCancer. +func isTest(name, prefix string) bool { + if !strings.HasPrefix(name, prefix) { + return false + } + if len(name) == len(prefix) { // "Test" is ok + return true + } + r, _ := utf8.DecodeRuneInString(name[len(prefix):]) + return !unicode.IsLower(r) +} + +func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { + if len(msgAndArgs) == 0 || msgAndArgs == nil { + return "" + } + if len(msgAndArgs) == 1 { + msg := msgAndArgs[0] + if msgAsStr, ok := msg.(string); ok { + return msgAsStr + } + return fmt.Sprintf("%+v", msg) + } + if len(msgAndArgs) > 1 { + return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) + } + return "" +} + +// Aligns the provided message so that all lines after the first line start at the same location as the first line. +// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). +// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the +// basis on which the alignment occurs). +func indentMessageLines(message string, longestLabelLen int) string { + outBuf := new(bytes.Buffer) + + for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ { + // no need to align first line because it starts at the correct location (after the label) + if i != 0 { + // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab + outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t") + } + outBuf.WriteString(scanner.Text()) + } + + return outBuf.String() +} + +type failNower interface { + FailNow() +} + +// FailNow fails test +func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + Fail(t, failureMessage, msgAndArgs...) + + // We cannot extend TestingT with FailNow() and + // maintain backwards compatibility, so we fallback + // to panicking when FailNow is not available in + // TestingT. + // See issue #263 + + if t, ok := t.(failNower); ok { + t.FailNow() + } else { + panic("test failed and t is missing `FailNow()`") + } + return false +} + +// Fail reports a failure through +func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + content := []labeledContent{ + {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")}, + {"Error", failureMessage}, + } + + // Add test name if the Go version supports it + if n, ok := t.(interface { + Name() string + }); ok { + content = append(content, labeledContent{"Test", n.Name()}) + } + + message := messageFromMsgAndArgs(msgAndArgs...) + if len(message) > 0 { + content = append(content, labeledContent{"Messages", message}) + } + + t.Errorf("\n%s", ""+labeledOutput(content...)) + + return false +} + +type labeledContent struct { + label string + content string +} + +// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: +// +// \t{{label}}:{{align_spaces}}\t{{content}}\n +// +// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. +// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this +// alignment is achieved, "\t{{content}}\n" is added for the output. +// +// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line. +func labeledOutput(content ...labeledContent) string { + longestLabel := 0 + for _, v := range content { + if len(v.label) > longestLabel { + longestLabel = len(v.label) + } + } + var output string + for _, v := range content { + output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n" + } + return output +} + +// Implements asserts that an object is implemented by the specified interface. +// +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + interfaceType := reflect.TypeOf(interfaceObject).Elem() + + if object == nil { + return Fail(t, fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...) + } + if !reflect.TypeOf(object).Implements(interfaceType) { + return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...) + } + + return true +} + +// IsType asserts that the specified objects are of the same type. +func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) { + return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...) + } + + return true +} + +// Equal asserts that two objects are equal. +// +// assert.Equal(t, 123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if err := validateEqualArgs(expected, actual); err != nil { + return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)", + expected, actual, err), msgAndArgs...) + } + + if !ObjectsAreEqual(expected, actual) { + diff := diff(expected, actual) + expected, actual = formatUnequalValues(expected, actual) + return Fail(t, fmt.Sprintf("Not equal: \n"+ + "expected: %s\n"+ + "actual : %s%s", expected, actual, diff), msgAndArgs...) + } + + return true + +} + +// validateEqualArgs checks whether provided arguments can be safely used in the +// Equal/NotEqual functions. +func validateEqualArgs(expected, actual interface{}) error { + if expected == nil && actual == nil { + return nil + } + + if isFunction(expected) || isFunction(actual) { + return errors.New("cannot take func type as argument") + } + return nil +} + +// Same asserts that two pointers reference the same object. +// +// assert.Same(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if !samePointers(expected, actual) { + return Fail(t, fmt.Sprintf("Not same: \n"+ + "expected: %p %#v\n"+ + "actual : %p %#v", expected, expected, actual, actual), msgAndArgs...) + } + + return true +} + +// NotSame asserts that two pointers do not reference the same object. +// +// assert.NotSame(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if samePointers(expected, actual) { + return Fail(t, fmt.Sprintf( + "Expected and actual point to the same object: %p %#v", + expected, expected), msgAndArgs...) + } + return true +} + +// samePointers compares two generic interface objects and returns whether +// they point to the same object +func samePointers(first, second interface{}) bool { + firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second) + if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr { + return false + } + + firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second) + if firstType != secondType { + return false + } + + // compare pointer addresses + return first == second +} + +// formatUnequalValues takes two values of arbitrary types and returns string +// representations appropriate to be presented to the user. +// +// If the values are not of like type, the returned strings will be prefixed +// with the type name, and the value will be enclosed in parenthesis similar +// to a type conversion in the Go grammar. +func formatUnequalValues(expected, actual interface{}) (e string, a string) { + if reflect.TypeOf(expected) != reflect.TypeOf(actual) { + return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)), + fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual)) + } + switch expected.(type) { + case time.Duration: + return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual) + } + return truncatingFormat(expected), truncatingFormat(actual) +} + +// truncatingFormat formats the data and truncates it if it's too long. +// +// This helps keep formatted error messages lines from exceeding the +// bufio.MaxScanTokenSize max line length that the go testing framework imposes. +func truncatingFormat(data interface{}) string { + value := fmt.Sprintf("%#v", data) + max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed. + if len(value) > max { + value = value[0:max] + "<... truncated>" + } + return value +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValues(t, uint32(123), int32(123)) +func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if !ObjectsAreEqualValues(expected, actual) { + diff := diff(expected, actual) + expected, actual = formatUnequalValues(expected, actual) + return Fail(t, fmt.Sprintf("Not equal: \n"+ + "expected: %s\n"+ + "actual : %s%s", expected, actual, diff), msgAndArgs...) + } + + return true + +} + +// Exactly asserts that two objects are equal in value and type. +// +// assert.Exactly(t, int32(123), int64(123)) +func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + aType := reflect.TypeOf(expected) + bType := reflect.TypeOf(actual) + + if aType != bType { + return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...) + } + + return Equal(t, expected, actual, msgAndArgs...) + +} + +// NotNil asserts that the specified object is not nil. +// +// assert.NotNil(t, err) +func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if !isNil(object) { + return true + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, "Expected value not to be nil.", msgAndArgs...) +} + +// containsKind checks if a specified kind in the slice of kinds. +func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool { + for i := 0; i < len(kinds); i++ { + if kind == kinds[i] { + return true + } + } + + return false +} + +// isNil checks if a specified object is nil or not, without Failing. +func isNil(object interface{}) bool { + if object == nil { + return true + } + + value := reflect.ValueOf(object) + kind := value.Kind() + isNilableKind := containsKind( + []reflect.Kind{ + reflect.Chan, reflect.Func, + reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice}, + kind) + + if isNilableKind && value.IsNil() { + return true + } + + return false +} + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + if isNil(object) { + return true + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) +} + +// isEmpty gets whether the specified object is considered empty or not. +func isEmpty(object interface{}) bool { + + // get nil case out of the way + if object == nil { + return true + } + + objValue := reflect.ValueOf(object) + + switch objValue.Kind() { + // collection types are empty when they have no element + case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: + return objValue.Len() == 0 + // pointers are empty if nil or if the value they point to is empty + case reflect.Ptr: + if objValue.IsNil() { + return true + } + deref := objValue.Elem().Interface() + return isEmpty(deref) + // for all other types, compare against the zero value + default: + zero := reflect.Zero(objValue.Type()) + return reflect.DeepEqual(object, zero.Interface()) + } +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Empty(t, obj) +func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + pass := isEmpty(object) + if !pass { + if h, ok := t.(tHelper); ok { + h.Helper() + } + Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...) + } + + return pass + +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { + pass := !isEmpty(object) + if !pass { + if h, ok := t.(tHelper); ok { + h.Helper() + } + Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...) + } + + return pass + +} + +// getLen try to get length of object. +// return (false, 0) if impossible. +func getLen(x interface{}) (ok bool, length int) { + v := reflect.ValueOf(x) + defer func() { + if e := recover(); e != nil { + ok = false + } + }() + return true, v.Len() +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// assert.Len(t, mySlice, 3) +func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + ok, l := getLen(object) + if !ok { + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...) + } + + if l != length { + return Fail(t, fmt.Sprintf("\"%s\" should have %d item(s), but has %d", object, length, l), msgAndArgs...) + } + return true +} + +// True asserts that the specified value is true. +// +// assert.True(t, myBool) +func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { + if !value { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, "Should be true", msgAndArgs...) + } + + return true + +} + +// False asserts that the specified value is false. +// +// assert.False(t, myBool) +func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { + if value { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, "Should be false", msgAndArgs...) + } + + return true + +} + +// NotEqual asserts that the specified values are NOT equal. +// +// assert.NotEqual(t, obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if err := validateEqualArgs(expected, actual); err != nil { + return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)", + expected, actual, err), msgAndArgs...) + } + + if ObjectsAreEqual(expected, actual) { + return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) + } + + return true + +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValues(t, obj1, obj2) +func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if ObjectsAreEqualValues(expected, actual) { + return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...) + } + + return true +} + +// containsElement try loop over the list check if the list includes the element. +// return (false, false) if impossible. +// return (true, false) if element was not found. +// return (true, true) if element was found. +func includeElement(list interface{}, element interface{}) (ok, found bool) { + + listValue := reflect.ValueOf(list) + listKind := reflect.TypeOf(list).Kind() + defer func() { + if e := recover(); e != nil { + ok = false + found = false + } + }() + + if listKind == reflect.String { + elementValue := reflect.ValueOf(element) + return true, strings.Contains(listValue.String(), elementValue.String()) + } + + if listKind == reflect.Map { + mapKeys := listValue.MapKeys() + for i := 0; i < len(mapKeys); i++ { + if ObjectsAreEqual(mapKeys[i].Interface(), element) { + return true, true + } + } + return true, false + } + + for i := 0; i < listValue.Len(); i++ { + if ObjectsAreEqual(listValue.Index(i).Interface(), element) { + return true, true + } + } + return true, false + +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") +func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + ok, found := includeElement(s, contains) + if !ok { + return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) + } + if !found { + return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...) + } + + return true + +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") +func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + ok, found := includeElement(s, contains) + if !ok { + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) + } + if found { + return Fail(t, fmt.Sprintf("\"%s\" should not contain \"%s\"", s, contains), msgAndArgs...) + } + + return true + +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if subset == nil { + return true // we consider nil to be equal to the nil set + } + + subsetValue := reflect.ValueOf(subset) + defer func() { + if e := recover(); e != nil { + ok = false + } + }() + + listKind := reflect.TypeOf(list).Kind() + subsetKind := reflect.TypeOf(subset).Kind() + + if listKind != reflect.Array && listKind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) + } + + if subsetKind != reflect.Array && subsetKind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) + } + + for i := 0; i < subsetValue.Len(); i++ { + element := subsetValue.Index(i).Interface() + ok, found := includeElement(list, element) + if !ok { + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) + } + if !found { + return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, element), msgAndArgs...) + } + } + + return true +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if subset == nil { + return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...) + } + + subsetValue := reflect.ValueOf(subset) + defer func() { + if e := recover(); e != nil { + ok = false + } + }() + + listKind := reflect.TypeOf(list).Kind() + subsetKind := reflect.TypeOf(subset).Kind() + + if listKind != reflect.Array && listKind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) + } + + if subsetKind != reflect.Array && subsetKind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) + } + + for i := 0; i < subsetValue.Len(); i++ { + element := subsetValue.Index(i).Interface() + ok, found := includeElement(list, element) + if !ok { + return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) + } + if !found { + return true + } + } + + return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, +// the number of appearances of each of them in both lists should match. +// +// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) +func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if isEmpty(listA) && isEmpty(listB) { + return true + } + + if !isList(t, listA, msgAndArgs...) || !isList(t, listB, msgAndArgs...) { + return false + } + + extraA, extraB := diffLists(listA, listB) + + if len(extraA) == 0 && len(extraB) == 0 { + return true + } + + return Fail(t, formatListDiff(listA, listB, extraA, extraB), msgAndArgs...) +} + +// isList checks that the provided value is array or slice. +func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok bool) { + kind := reflect.TypeOf(list).Kind() + if kind != reflect.Array && kind != reflect.Slice { + return Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind), + msgAndArgs...) + } + return true +} + +// diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B. +// If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and +// 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored. +func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) { + aValue := reflect.ValueOf(listA) + bValue := reflect.ValueOf(listB) + + aLen := aValue.Len() + bLen := bValue.Len() + + // Mark indexes in bValue that we already used + visited := make([]bool, bLen) + for i := 0; i < aLen; i++ { + element := aValue.Index(i).Interface() + found := false + for j := 0; j < bLen; j++ { + if visited[j] { + continue + } + if ObjectsAreEqual(bValue.Index(j).Interface(), element) { + visited[j] = true + found = true + break + } + } + if !found { + extraA = append(extraA, element) + } + } + + for j := 0; j < bLen; j++ { + if visited[j] { + continue + } + extraB = append(extraB, bValue.Index(j).Interface()) + } + + return +} + +func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) string { + var msg bytes.Buffer + + msg.WriteString("elements differ") + if len(extraA) > 0 { + msg.WriteString("\n\nextra elements in list A:\n") + msg.WriteString(spewConfig.Sdump(extraA)) + } + if len(extraB) > 0 { + msg.WriteString("\n\nextra elements in list B:\n") + msg.WriteString(spewConfig.Sdump(extraB)) + } + msg.WriteString("\n\nlistA:\n") + msg.WriteString(spewConfig.Sdump(listA)) + msg.WriteString("\n\nlistB:\n") + msg.WriteString(spewConfig.Sdump(listB)) + + return msg.String() +} + +// Condition uses a Comparison to assert a complex condition. +func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + result := comp() + if !result { + Fail(t, "Condition failed!", msgAndArgs...) + } + return result +} + +// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics +// methods, and represents a simple func that takes no arguments, and returns nothing. +type PanicTestFunc func() + +// didPanic returns true if the function passed to it panics. Otherwise, it returns false. +func didPanic(f PanicTestFunc) (bool, interface{}, string) { + + didPanic := false + var message interface{} + var stack string + func() { + + defer func() { + if message = recover(); message != nil { + didPanic = true + stack = string(debug.Stack()) + } + }() + + // call the target function + f() + + }() + + return didPanic, message, stack + +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panics(t, func(){ GoCrazy() }) +func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) + } + + return true +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + funcDidPanic, panicValue, panickedStack := didPanic(f) + if !funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) + } + if panicValue != expected { + return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expected, panicValue, panickedStack), msgAndArgs...) + } + + return true +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + funcDidPanic, panicValue, panickedStack := didPanic(f) + if !funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...) + } + panicErr, ok := panicValue.(error) + if !ok || panicErr.Error() != errString { + return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...) + } + + return true +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanics(t, func(){ RemainCalm() }) +func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic { + return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...) + } + + return true +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + dt := expected.Sub(actual) + if dt < -delta || dt > delta { + return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) + } + + return true +} + +func toFloat(x interface{}) (float64, bool) { + var xf float64 + xok := true + + switch xn := x.(type) { + case uint: + xf = float64(xn) + case uint8: + xf = float64(xn) + case uint16: + xf = float64(xn) + case uint32: + xf = float64(xn) + case uint64: + xf = float64(xn) + case int: + xf = float64(xn) + case int8: + xf = float64(xn) + case int16: + xf = float64(xn) + case int32: + xf = float64(xn) + case int64: + xf = float64(xn) + case float32: + xf = float64(xn) + case float64: + xf = xn + case time.Duration: + xf = float64(xn) + default: + xok = false + } + + return xf, xok +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + af, aok := toFloat(expected) + bf, bok := toFloat(actual) + + if !aok || !bok { + return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...) + } + + if math.IsNaN(af) { + return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...) + } + + if math.IsNaN(bf) { + return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...) + } + + dt := af - bf + if dt < -delta || dt > delta { + return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...) + } + + return true +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if expected == nil || actual == nil || + reflect.TypeOf(actual).Kind() != reflect.Slice || + reflect.TypeOf(expected).Kind() != reflect.Slice { + return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + } + + actualSlice := reflect.ValueOf(actual) + expectedSlice := reflect.ValueOf(expected) + + for i := 0; i < actualSlice.Len(); i++ { + result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...) + if !result { + return result + } + } + + return true +} + +// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. +func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if expected == nil || actual == nil || + reflect.TypeOf(actual).Kind() != reflect.Map || + reflect.TypeOf(expected).Kind() != reflect.Map { + return Fail(t, "Arguments must be maps", msgAndArgs...) + } + + expectedMap := reflect.ValueOf(expected) + actualMap := reflect.ValueOf(actual) + + if expectedMap.Len() != actualMap.Len() { + return Fail(t, "Arguments must have the same number of keys", msgAndArgs...) + } + + for _, k := range expectedMap.MapKeys() { + ev := expectedMap.MapIndex(k) + av := actualMap.MapIndex(k) + + if !ev.IsValid() { + return Fail(t, fmt.Sprintf("missing key %q in expected map", k), msgAndArgs...) + } + + if !av.IsValid() { + return Fail(t, fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...) + } + + if !InDelta( + t, + ev.Interface(), + av.Interface(), + delta, + msgAndArgs..., + ) { + return false + } + } + + return true +} + +func calcRelativeError(expected, actual interface{}) (float64, error) { + af, aok := toFloat(expected) + if !aok { + return 0, fmt.Errorf("expected value %q cannot be converted to float", expected) + } + if math.IsNaN(af) { + return 0, errors.New("expected value must not be NaN") + } + if af == 0 { + return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") + } + bf, bok := toFloat(actual) + if !bok { + return 0, fmt.Errorf("actual value %q cannot be converted to float", actual) + } + if math.IsNaN(bf) { + return 0, errors.New("actual value must not be NaN") + } + + return math.Abs(af-bf) / math.Abs(af), nil +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if math.IsNaN(epsilon) { + return Fail(t, "epsilon must not be NaN") + } + actualEpsilon, err := calcRelativeError(expected, actual) + if err != nil { + return Fail(t, err.Error(), msgAndArgs...) + } + if actualEpsilon > epsilon { + return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+ + " < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...) + } + + return true +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if expected == nil || actual == nil || + reflect.TypeOf(actual).Kind() != reflect.Slice || + reflect.TypeOf(expected).Kind() != reflect.Slice { + return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) + } + + actualSlice := reflect.ValueOf(actual) + expectedSlice := reflect.ValueOf(expected) + + for i := 0; i < actualSlice.Len(); i++ { + result := InEpsilon(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), epsilon) + if !result { + return result + } + } + + return true +} + +/* + Errors +*/ + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { + if err != nil { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) + } + + return true +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } +func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { + if err == nil { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, "An error is expected but got nil.", msgAndArgs...) + } + + return true +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) +func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !Error(t, theError, msgAndArgs...) { + return false + } + expected := errString + actual := theError.Error() + // don't need to use deep equals here, we know they are both strings + if expected != actual { + return Fail(t, fmt.Sprintf("Error message not equal:\n"+ + "expected: %q\n"+ + "actual : %q", expected, actual), msgAndArgs...) + } + return true +} + +// matchRegexp return true if a specified regexp matches a string. +func matchRegexp(rx interface{}, str interface{}) bool { + + var r *regexp.Regexp + if rr, ok := rx.(*regexp.Regexp); ok { + r = rr + } else { + r = regexp.MustCompile(fmt.Sprint(rx)) + } + + return (r.FindStringIndex(fmt.Sprint(str)) != nil) + +} + +// Regexp asserts that a specified regexp matches a string. +// +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") +func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + match := matchRegexp(rx, str) + + if !match { + Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...) + } + + return match +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") +func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + match := matchRegexp(rx, str) + + if match { + Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...) + } + + return !match + +} + +// Zero asserts that i is the zero value for its type. +func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { + return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...) + } + return true +} + +// NotZero asserts that i is not the zero value for its type. +func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { + return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...) + } + return true +} + +// FileExists checks whether a file exists in the given path. It also fails if +// the path points to a directory or there is an error when trying to check the file. +func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + if os.IsNotExist(err) { + return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...) + } + return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...) + } + if info.IsDir() { + return Fail(t, fmt.Sprintf("%q is a directory", path), msgAndArgs...) + } + return true +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + return true + } + if info.IsDir() { + return true + } + return Fail(t, fmt.Sprintf("file %q exists", path), msgAndArgs...) +} + +// DirExists checks whether a directory exists in the given path. It also fails +// if the path is a file rather a directory or there is an error checking whether it exists. +func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + if os.IsNotExist(err) { + return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...) + } + return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...) + } + if !info.IsDir() { + return Fail(t, fmt.Sprintf("%q is a file", path), msgAndArgs...) + } + return true +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + info, err := os.Lstat(path) + if err != nil { + if os.IsNotExist(err) { + return true + } + return true + } + if !info.IsDir() { + return true + } + return Fail(t, fmt.Sprintf("directory %q exists", path), msgAndArgs...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + var expectedJSONAsInterface, actualJSONAsInterface interface{} + + if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...) + } + + if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...) + } + + return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...) +} + +// YAMLEq asserts that two YAML strings are equivalent. +func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + var expectedYAMLAsInterface, actualYAMLAsInterface interface{} + + if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...) + } + + if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil { + return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...) + } + + return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...) +} + +func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { + t := reflect.TypeOf(v) + k := t.Kind() + + if k == reflect.Ptr { + t = t.Elem() + k = t.Kind() + } + return t, k +} + +// diff returns a diff of both values as long as both are of the same type and +// are a struct, map, slice, array or string. Otherwise it returns an empty string. +func diff(expected interface{}, actual interface{}) string { + if expected == nil || actual == nil { + return "" + } + + et, ek := typeAndKind(expected) + at, _ := typeAndKind(actual) + + if et != at { + return "" + } + + if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String { + return "" + } + + var e, a string + if et != reflect.TypeOf("") { + e = spewConfig.Sdump(expected) + a = spewConfig.Sdump(actual) + } else { + e = reflect.ValueOf(expected).String() + a = reflect.ValueOf(actual).String() + } + + diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ + A: difflib.SplitLines(e), + B: difflib.SplitLines(a), + FromFile: "Expected", + FromDate: "", + ToFile: "Actual", + ToDate: "", + Context: 1, + }) + + return "\n\nDiff:\n" + diff +} + +func isFunction(arg interface{}) bool { + if arg == nil { + return false + } + return reflect.TypeOf(arg).Kind() == reflect.Func +} + +var spewConfig = spew.ConfigState{ + Indent: " ", + DisablePointerAddresses: true, + DisableCapacities: true, + SortKeys: true, + DisableMethods: true, + MaxDepth: 10, +} + +type tHelper interface { + Helper() +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + ch := make(chan bool, 1) + + timer := time.NewTimer(waitFor) + defer timer.Stop() + + ticker := time.NewTicker(tick) + defer ticker.Stop() + + for tick := ticker.C; ; { + select { + case <-timer.C: + return Fail(t, "Condition never satisfied", msgAndArgs...) + case <-tick: + tick = nil + go func() { ch <- condition() }() + case v := <-ch: + if v { + return true + } + tick = ticker.C + } + } +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + ch := make(chan bool, 1) + + timer := time.NewTimer(waitFor) + defer timer.Stop() + + ticker := time.NewTicker(tick) + defer ticker.Stop() + + for tick := ticker.C; ; { + select { + case <-timer.C: + return true + case <-tick: + tick = nil + go func() { ch <- condition() }() + case v := <-ch: + if v { + return Fail(t, "Condition satisfied", msgAndArgs...) + } + tick = ticker.C + } + } +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if errors.Is(err, target) { + return true + } + + var expectedText string + if target != nil { + expectedText = target.Error() + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+ + "expected: %q\n"+ + "in chain: %s", expectedText, chain, + ), msgAndArgs...) +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if !errors.Is(err, target) { + return true + } + + var expectedText string + if target != nil { + expectedText = target.Error() + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+ + "found: %q\n"+ + "in chain: %s", expectedText, chain, + ), msgAndArgs...) +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if errors.As(err, target) { + return true + } + + chain := buildErrorChainString(err) + + return Fail(t, fmt.Sprintf("Should be in error chain:\n"+ + "expected: %q\n"+ + "in chain: %s", target, chain, + ), msgAndArgs...) +} + +func buildErrorChainString(err error) string { + if err == nil { + return "" + } + + e := errors.Unwrap(err) + chain := fmt.Sprintf("%q", err.Error()) + for e != nil { + chain += fmt.Sprintf("\n\t%q", e.Error()) + e = errors.Unwrap(e) + } + return chain +} diff --git a/vendor/github.com/stretchr/testify/assert/doc.go b/vendor/github.com/stretchr/testify/assert/doc.go new file mode 100644 index 00000000..c9dccc4d --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/doc.go @@ -0,0 +1,45 @@ +// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. +// +// Example Usage +// +// The following is a complete example using assert in a standard test function: +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// ) +// +// func TestSomething(t *testing.T) { +// +// var a string = "Hello" +// var b string = "Hello" +// +// assert.Equal(t, a, b, "The two words should be the same.") +// +// } +// +// if you assert many times, use the format below: +// +// import ( +// "testing" +// "github.com/stretchr/testify/assert" +// ) +// +// func TestSomething(t *testing.T) { +// assert := assert.New(t) +// +// var a string = "Hello" +// var b string = "Hello" +// +// assert.Equal(a, b, "The two words should be the same.") +// } +// +// Assertions +// +// Assertions allow you to easily write test code, and are global funcs in the `assert` package. +// All assertion functions take, as the first argument, the `*testing.T` object provided by the +// testing framework. This allows the assertion funcs to write the failings and other details to +// the correct place. +// +// Every assertion function also takes an optional string message as the final argument, +// allowing custom error messages to be appended to the message the assertion method outputs. +package assert diff --git a/vendor/github.com/stretchr/testify/assert/errors.go b/vendor/github.com/stretchr/testify/assert/errors.go new file mode 100644 index 00000000..ac9dc9d1 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/errors.go @@ -0,0 +1,10 @@ +package assert + +import ( + "errors" +) + +// AnError is an error instance useful for testing. If the code does not care +// about error specifics, and only needs to return the error for example, this +// error should be used to make the test code more readable. +var AnError = errors.New("assert.AnError general error for testing") diff --git a/vendor/github.com/stretchr/testify/assert/forward_assertions.go b/vendor/github.com/stretchr/testify/assert/forward_assertions.go new file mode 100644 index 00000000..df189d23 --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/forward_assertions.go @@ -0,0 +1,16 @@ +package assert + +// Assertions provides assertion methods around the +// TestingT interface. +type Assertions struct { + t TestingT +} + +// New makes a new Assertions object for the specified TestingT. +func New(t TestingT) *Assertions { + return &Assertions{ + t: t, + } +} + +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs" diff --git a/vendor/github.com/stretchr/testify/assert/http_assertions.go b/vendor/github.com/stretchr/testify/assert/http_assertions.go new file mode 100644 index 00000000..4ed341dd --- /dev/null +++ b/vendor/github.com/stretchr/testify/assert/http_assertions.go @@ -0,0 +1,162 @@ +package assert + +import ( + "fmt" + "net/http" + "net/http/httptest" + "net/url" + "strings" +) + +// httpCode is a helper that returns HTTP code of the response. It returns -1 and +// an error if building a new request fails. +func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { + w := httptest.NewRecorder() + req, err := http.NewRequest(method, url, nil) + if err != nil { + return -1, err + } + req.URL.RawQuery = values.Encode() + handler(w, req) + return w.Code, nil +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + code, err := httpCode(handler, method, url, values) + if err != nil { + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + } + + isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent + if !isSuccessCode { + Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code)) + } + + return isSuccessCode +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + code, err := httpCode(handler, method, url, values) + if err != nil { + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + } + + isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect + if !isRedirectCode { + Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code)) + } + + return isRedirectCode +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + code, err := httpCode(handler, method, url, values) + if err != nil { + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + } + + isErrorCode := code >= http.StatusBadRequest + if !isErrorCode { + Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code)) + } + + return isErrorCode +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + code, err := httpCode(handler, method, url, values) + if err != nil { + Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) + } + + successful := code == statuscode + if !successful { + Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code)) + } + + return successful +} + +// HTTPBody is a helper that returns HTTP body of the response. It returns +// empty string if building a new request fails. +func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { + w := httptest.NewRecorder() + req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) + if err != nil { + return "" + } + handler(w, req) + return w.Body.String() +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + body := HTTPBody(handler, method, url, values) + + contains := strings.Contains(body, fmt.Sprint(str)) + if !contains { + Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) + } + + return contains +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + body := HTTPBody(handler, method, url, values) + + contains := strings.Contains(body, fmt.Sprint(str)) + if contains { + Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body)) + } + + return !contains +} diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go new file mode 100644 index 00000000..904b57e0 --- /dev/null +++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go @@ -0,0 +1,77 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC +2898 / PKCS #5 v2.0. + +A key derivation function is useful when encrypting data based on a password +or any other not-fully-random data. It uses a pseudorandom function to derive +a secure encryption key based on the password. + +While v2.0 of the standard defines only one pseudorandom function to use, +HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved +Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To +choose, you can pass the `New` functions from the different SHA packages to +pbkdf2.Key. +*/ +package pbkdf2 // import "golang.org/x/crypto/pbkdf2" + +import ( + "crypto/hmac" + "hash" +) + +// Key derives a key from the password, salt and iteration count, returning a +// []byte of length keylen that can be used as cryptographic key. The key is +// derived based on the method described as PBKDF2 with the HMAC variant using +// the supplied hash function. +// +// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you +// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by +// doing: +// +// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New) +// +// Remember to get a good random salt. At least 8 bytes is recommended by the +// RFC. +// +// Using a higher iteration count will increase the cost of an exhaustive +// search but will also make derivation proportionally slower. +func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte { + prf := hmac.New(h, password) + hashLen := prf.Size() + numBlocks := (keyLen + hashLen - 1) / hashLen + + var buf [4]byte + dk := make([]byte, 0, numBlocks*hashLen) + U := make([]byte, hashLen) + for block := 1; block <= numBlocks; block++ { + // N.B.: || means concatenation, ^ means XOR + // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter + // U_1 = PRF(password, salt || uint(i)) + prf.Reset() + prf.Write(salt) + buf[0] = byte(block >> 24) + buf[1] = byte(block >> 16) + buf[2] = byte(block >> 8) + buf[3] = byte(block) + prf.Write(buf[:4]) + dk = prf.Sum(dk) + T := dk[len(dk)-hashLen:] + copy(U, T) + + // U_n = PRF(password, U_(n-1)) + for n := 2; n <= iter; n++ { + prf.Reset() + prf.Write(U) + U = U[:0] + U = prf.Sum(U) + for x := range U { + T[x] ^= U[x] + } + } + } + return dk[:keyLen] +} diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go new file mode 100644 index 00000000..cf3eeb15 --- /dev/null +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go @@ -0,0 +1,124 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package ripemd160 implements the RIPEMD-160 hash algorithm. +// +// Deprecated: RIPEMD-160 is a legacy hash and should not be used for new +// applications. Also, this package does not and will not provide an optimized +// implementation. Instead, use a modern hash like SHA-256 (from crypto/sha256). +package ripemd160 // import "golang.org/x/crypto/ripemd160" + +// RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart +// Preneel with specifications available at: +// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf. + +import ( + "crypto" + "hash" +) + +func init() { + crypto.RegisterHash(crypto.RIPEMD160, New) +} + +// The size of the checksum in bytes. +const Size = 20 + +// The block size of the hash algorithm in bytes. +const BlockSize = 64 + +const ( + _s0 = 0x67452301 + _s1 = 0xefcdab89 + _s2 = 0x98badcfe + _s3 = 0x10325476 + _s4 = 0xc3d2e1f0 +) + +// digest represents the partial evaluation of a checksum. +type digest struct { + s [5]uint32 // running context + x [BlockSize]byte // temporary buffer + nx int // index into x + tc uint64 // total count of bytes processed +} + +func (d *digest) Reset() { + d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4 + d.nx = 0 + d.tc = 0 +} + +// New returns a new hash.Hash computing the checksum. +func New() hash.Hash { + result := new(digest) + result.Reset() + return result +} + +func (d *digest) Size() int { return Size } + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Write(p []byte) (nn int, err error) { + nn = len(p) + d.tc += uint64(nn) + if d.nx > 0 { + n := len(p) + if n > BlockSize-d.nx { + n = BlockSize - d.nx + } + for i := 0; i < n; i++ { + d.x[d.nx+i] = p[i] + } + d.nx += n + if d.nx == BlockSize { + _Block(d, d.x[0:]) + d.nx = 0 + } + p = p[n:] + } + n := _Block(d, p) + p = p[n:] + if len(p) > 0 { + d.nx = copy(d.x[:], p) + } + return +} + +func (d0 *digest) Sum(in []byte) []byte { + // Make a copy of d0 so that caller can keep writing and summing. + d := *d0 + + // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. + tc := d.tc + var tmp [64]byte + tmp[0] = 0x80 + if tc%64 < 56 { + d.Write(tmp[0 : 56-tc%64]) + } else { + d.Write(tmp[0 : 64+56-tc%64]) + } + + // Length in bits. + tc <<= 3 + for i := uint(0); i < 8; i++ { + tmp[i] = byte(tc >> (8 * i)) + } + d.Write(tmp[0:8]) + + if d.nx != 0 { + panic("d.nx != 0") + } + + var digest [Size]byte + for i, s := range d.s { + digest[i*4] = byte(s) + digest[i*4+1] = byte(s >> 8) + digest[i*4+2] = byte(s >> 16) + digest[i*4+3] = byte(s >> 24) + } + + return append(in, digest[:]...) +} diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go new file mode 100644 index 00000000..e0edc02f --- /dev/null +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go @@ -0,0 +1,165 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// RIPEMD-160 block step. +// In its own file so that a faster assembly or C version +// can be substituted easily. + +package ripemd160 + +import ( + "math/bits" +) + +// work buffer indices and roll amounts for one line +var _n = [80]uint{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13, +} + +var _r = [80]uint{ + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6, +} + +// same for the other parallel one +var n_ = [80]uint{ + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11, +} + +var r_ = [80]uint{ + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11, +} + +func _Block(md *digest, p []byte) int { + n := 0 + var x [16]uint32 + var alpha, beta uint32 + for len(p) >= BlockSize { + a, b, c, d, e := md.s[0], md.s[1], md.s[2], md.s[3], md.s[4] + aa, bb, cc, dd, ee := a, b, c, d, e + j := 0 + for i := 0; i < 16; i++ { + x[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24 + j += 4 + } + + // round 1 + i := 0 + for i < 16 { + alpha = a + (b ^ c ^ d) + x[_n[i]] + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // round 2 + for i < 32 { + alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // round 3 + for i < 48 { + alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // round 4 + for i < 64 { + alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // round 5 + for i < 80 { + alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) + a, b, c, d, e = e, alpha, b, beta, d + + // parallel line + alpha = aa + (bb ^ cc ^ dd) + x[n_[i]] + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) + aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd + + i++ + } + + // combine results + dd += c + md.s[1] + md.s[1] = md.s[2] + d + ee + md.s[2] = md.s[3] + e + aa + md.s[3] = md.s[4] + a + bb + md.s[4] = md.s[0] + b + cc + md.s[0] = dd + + p = p[BlockSize:] + n += BlockSize + } + return n +} diff --git a/vendor/gopkg.in/ldap.v2/.gitignore b/vendor/gopkg.in/ldap.v2/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/vendor/gopkg.in/ldap.v2/.travis.yml b/vendor/gopkg.in/ldap.v2/.travis.yml new file mode 100644 index 00000000..9782c9ba --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/.travis.yml @@ -0,0 +1,31 @@ +language: go +env: + global: + - VET_VERSIONS="1.6 1.7 1.8 1.9 tip" + - LINT_VERSIONS="1.6 1.7 1.8 1.9 tip" +go: + - 1.2 + - 1.3 + - 1.4 + - 1.5 + - 1.6 + - 1.7 + - 1.8 + - 1.9 + - tip +matrix: + fast_finish: true + allow_failures: + - go: tip +go_import_path: gopkg.in/ldap.v2 +install: + - go get gopkg.in/asn1-ber.v1 + - go get gopkg.in/ldap.v2 + - go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover + - go get github.com/golang/lint/golint || true + - go build -v ./... +script: + - make test + - make fmt + - if [[ "$VET_VERSIONS" == *"$TRAVIS_GO_VERSION"* ]]; then make vet; fi + - if [[ "$LINT_VERSIONS" == *"$TRAVIS_GO_VERSION"* ]]; then make lint; fi diff --git a/vendor/gopkg.in/ldap.v2/LICENSE b/vendor/gopkg.in/ldap.v2/LICENSE new file mode 100644 index 00000000..6c0ed4b3 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2011-2015 Michael Mitton (mmitton@gmail.com) +Portions copyright (c) 2015-2016 go-ldap Authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/gopkg.in/ldap.v2/Makefile b/vendor/gopkg.in/ldap.v2/Makefile new file mode 100644 index 00000000..a9d351c7 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/Makefile @@ -0,0 +1,52 @@ +.PHONY: default install build test quicktest fmt vet lint + +GO_VERSION := $(shell go version | cut -d' ' -f3 | cut -d. -f2) + +# Only use the `-race` flag on newer versions of Go +IS_OLD_GO := $(shell test $(GO_VERSION) -le 2 && echo true) +ifeq ($(IS_OLD_GO),true) + RACE_FLAG := +else + RACE_FLAG := -race -cpu 1,2,4 +endif + +default: fmt vet lint build quicktest + +install: + go get -t -v ./... + +build: + go build -v ./... + +test: + go test -v $(RACE_FLAG) -cover ./... + +quicktest: + go test ./... + +# Capture output and force failure when there is non-empty output +fmt: + @echo gofmt -l . + @OUTPUT=`gofmt -l . 2>&1`; \ + if [ "$$OUTPUT" ]; then \ + echo "gofmt must be run on the following files:"; \ + echo "$$OUTPUT"; \ + exit 1; \ + fi + +# Only run on go1.5+ +vet: + go tool vet -atomic -bool -copylocks -nilfunc -printf -shadow -rangeloops -unreachable -unsafeptr -unusedresult . + +# https://github.com/golang/lint +# go get github.com/golang/lint/golint +# Capture output and force failure when there is non-empty output +# Only run on go1.5+ +lint: + @echo golint ./... + @OUTPUT=`golint ./... 2>&1`; \ + if [ "$$OUTPUT" ]; then \ + echo "golint errors:"; \ + echo "$$OUTPUT"; \ + exit 1; \ + fi diff --git a/vendor/gopkg.in/ldap.v2/README.md b/vendor/gopkg.in/ldap.v2/README.md new file mode 100644 index 00000000..a26ed2d8 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/README.md @@ -0,0 +1,53 @@ +[![GoDoc](https://godoc.org/gopkg.in/ldap.v2?status.svg)](https://godoc.org/gopkg.in/ldap.v2) +[![Build Status](https://travis-ci.org/go-ldap/ldap.svg)](https://travis-ci.org/go-ldap/ldap) + +# Basic LDAP v3 functionality for the GO programming language. + +## Install + +For the latest version use: + + go get gopkg.in/ldap.v2 + +Import the latest version with: + + import "gopkg.in/ldap.v2" + +## Required Libraries: + + - gopkg.in/asn1-ber.v1 + +## Features: + + - Connecting to LDAP server (non-TLS, TLS, STARTTLS) + - Binding to LDAP server + - Searching for entries + - Filter Compile / Decompile + - Paging Search Results + - Modify Requests / Responses + - Add Requests / Responses + - Delete Requests / Responses + +## Examples: + + - search + - modify + +## Contributing: + +Bug reports and pull requests are welcome! + +Before submitting a pull request, please make sure tests and verification scripts pass: +``` +make all +``` + +To set up a pre-push hook to run the tests and verify scripts before pushing: +``` +ln -s ../../.githooks/pre-push .git/hooks/pre-push +``` + +--- +The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) +The design is licensed under the Creative Commons 3.0 Attributions license. +Read this article for more details: http://blog.golang.org/gopher diff --git a/vendor/gopkg.in/ldap.v2/add.go b/vendor/gopkg.in/ldap.v2/add.go new file mode 100644 index 00000000..0e5f6cdb --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/add.go @@ -0,0 +1,113 @@ +// +// https://tools.ietf.org/html/rfc4511 +// +// AddRequest ::= [APPLICATION 8] SEQUENCE { +// entry LDAPDN, +// attributes AttributeList } +// +// AttributeList ::= SEQUENCE OF attribute Attribute + +package ldap + +import ( + "errors" + "log" + + "gopkg.in/asn1-ber.v1" +) + +// Attribute represents an LDAP attribute +type Attribute struct { + // Type is the name of the LDAP attribute + Type string + // Vals are the LDAP attribute values + Vals []string +} + +func (a *Attribute) encode() *ber.Packet { + seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attribute") + seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.Type, "Type")) + set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue") + for _, value := range a.Vals { + set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals")) + } + seq.AppendChild(set) + return seq +} + +// AddRequest represents an LDAP AddRequest operation +type AddRequest struct { + // DN identifies the entry being added + DN string + // Attributes list the attributes of the new entry + Attributes []Attribute +} + +func (a AddRequest) encode() *ber.Packet { + request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request") + request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.DN, "DN")) + attributes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes") + for _, attribute := range a.Attributes { + attributes.AppendChild(attribute.encode()) + } + request.AppendChild(attributes) + return request +} + +// Attribute adds an attribute with the given type and values +func (a *AddRequest) Attribute(attrType string, attrVals []string) { + a.Attributes = append(a.Attributes, Attribute{Type: attrType, Vals: attrVals}) +} + +// NewAddRequest returns an AddRequest for the given DN, with no attributes +func NewAddRequest(dn string) *AddRequest { + return &AddRequest{ + DN: dn, + } + +} + +// Add performs the given AddRequest +func (l *Conn) Add(addRequest *AddRequest) error { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + packet.AppendChild(addRequest.encode()) + + l.Debug.PrintPacket(packet) + + msgCtx, err := l.sendMessage(packet) + if err != nil { + return err + } + defer l.finishMessage(msgCtx) + + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + return err + } + ber.PrintPacket(packet) + } + + if packet.Children[1].Tag == ApplicationAddResponse { + resultCode, resultDescription := getLDAPResultCode(packet) + if resultCode != 0 { + return NewError(resultCode, errors.New(resultDescription)) + } + } else { + log.Printf("Unexpected Response: %d", packet.Children[1].Tag) + } + + l.Debug.Printf("%d: returning", msgCtx.id) + return nil +} diff --git a/vendor/gopkg.in/ldap.v2/atomic_value.go b/vendor/gopkg.in/ldap.v2/atomic_value.go new file mode 100644 index 00000000..bccf7573 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/atomic_value.go @@ -0,0 +1,13 @@ +// +build go1.4 + +package ldap + +import ( + "sync/atomic" +) + +// For compilers that support it, we just use the underlying sync/atomic.Value +// type. +type atomicValue struct { + atomic.Value +} diff --git a/vendor/gopkg.in/ldap.v2/atomic_value_go13.go b/vendor/gopkg.in/ldap.v2/atomic_value_go13.go new file mode 100644 index 00000000..04920bb2 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/atomic_value_go13.go @@ -0,0 +1,28 @@ +// +build !go1.4 + +package ldap + +import ( + "sync" +) + +// This is a helper type that emulates the use of the "sync/atomic.Value" +// struct that's available in Go 1.4 and up. +type atomicValue struct { + value interface{} + lock sync.RWMutex +} + +func (av *atomicValue) Store(val interface{}) { + av.lock.Lock() + av.value = val + av.lock.Unlock() +} + +func (av *atomicValue) Load() interface{} { + av.lock.RLock() + ret := av.value + av.lock.RUnlock() + + return ret +} diff --git a/vendor/gopkg.in/ldap.v2/bind.go b/vendor/gopkg.in/ldap.v2/bind.go new file mode 100644 index 00000000..26b3cc72 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/bind.go @@ -0,0 +1,143 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ldap + +import ( + "errors" + + "gopkg.in/asn1-ber.v1" +) + +// SimpleBindRequest represents a username/password bind operation +type SimpleBindRequest struct { + // Username is the name of the Directory object that the client wishes to bind as + Username string + // Password is the credentials to bind with + Password string + // Controls are optional controls to send with the bind request + Controls []Control +} + +// SimpleBindResult contains the response from the server +type SimpleBindResult struct { + Controls []Control +} + +// NewSimpleBindRequest returns a bind request +func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest { + return &SimpleBindRequest{ + Username: username, + Password: password, + Controls: controls, + } +} + +func (bindRequest *SimpleBindRequest) encode() *ber.Packet { + request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request") + request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version")) + request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name")) + request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password")) + + request.AppendChild(encodeControls(bindRequest.Controls)) + + return request +} + +// SimpleBind performs the simple bind operation defined in the given request +func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + encodedBindRequest := simpleBindRequest.encode() + packet.AppendChild(encodedBindRequest) + + if l.Debug { + ber.PrintPacket(packet) + } + + msgCtx, err := l.sendMessage(packet) + if err != nil { + return nil, err + } + defer l.finishMessage(msgCtx) + + packetResponse, ok := <-msgCtx.responses + if !ok { + return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return nil, err + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + return nil, err + } + ber.PrintPacket(packet) + } + + result := &SimpleBindResult{ + Controls: make([]Control, 0), + } + + if len(packet.Children) == 3 { + for _, child := range packet.Children[2].Children { + result.Controls = append(result.Controls, DecodeControl(child)) + } + } + + resultCode, resultDescription := getLDAPResultCode(packet) + if resultCode != 0 { + return result, NewError(resultCode, errors.New(resultDescription)) + } + + return result, nil +} + +// Bind performs a bind with the given username and password +func (l *Conn) Bind(username, password string) error { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request") + bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version")) + bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, username, "User Name")) + bindRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, password, "Password")) + packet.AppendChild(bindRequest) + + if l.Debug { + ber.PrintPacket(packet) + } + + msgCtx, err := l.sendMessage(packet) + if err != nil { + return err + } + defer l.finishMessage(msgCtx) + + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + return err + } + ber.PrintPacket(packet) + } + + resultCode, resultDescription := getLDAPResultCode(packet) + if resultCode != 0 { + return NewError(resultCode, errors.New(resultDescription)) + } + + return nil +} diff --git a/vendor/gopkg.in/ldap.v2/client.go b/vendor/gopkg.in/ldap.v2/client.go new file mode 100644 index 00000000..055b27b5 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/client.go @@ -0,0 +1,27 @@ +package ldap + +import ( + "crypto/tls" + "time" +) + +// Client knows how to interact with an LDAP server +type Client interface { + Start() + StartTLS(config *tls.Config) error + Close() + SetTimeout(time.Duration) + + Bind(username, password string) error + SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) + + Add(addRequest *AddRequest) error + Del(delRequest *DelRequest) error + Modify(modifyRequest *ModifyRequest) error + + Compare(dn, attribute, value string) (bool, error) + PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) + + Search(searchRequest *SearchRequest) (*SearchResult, error) + SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) +} diff --git a/vendor/gopkg.in/ldap.v2/compare.go b/vendor/gopkg.in/ldap.v2/compare.go new file mode 100644 index 00000000..cc6d2af5 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/compare.go @@ -0,0 +1,85 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// File contains Compare functionality +// +// https://tools.ietf.org/html/rfc4511 +// +// CompareRequest ::= [APPLICATION 14] SEQUENCE { +// entry LDAPDN, +// ava AttributeValueAssertion } +// +// AttributeValueAssertion ::= SEQUENCE { +// attributeDesc AttributeDescription, +// assertionValue AssertionValue } +// +// AttributeDescription ::= LDAPString +// -- Constrained to +// -- [RFC4512] +// +// AttributeValue ::= OCTET STRING +// + +package ldap + +import ( + "errors" + "fmt" + + "gopkg.in/asn1-ber.v1" +) + +// Compare checks to see if the attribute of the dn matches value. Returns true if it does otherwise +// false with any error that occurs if any. +func (l *Conn) Compare(dn, attribute, value string) (bool, error) { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + + request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationCompareRequest, nil, "Compare Request") + request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, dn, "DN")) + + ava := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeValueAssertion") + ava.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "AttributeDesc")) + ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagOctetString, value, "AssertionValue")) + request.AppendChild(ava) + packet.AppendChild(request) + + l.Debug.PrintPacket(packet) + + msgCtx, err := l.sendMessage(packet) + if err != nil { + return false, err + } + defer l.finishMessage(msgCtx) + + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return false, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return false, err + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + return false, err + } + ber.PrintPacket(packet) + } + + if packet.Children[1].Tag == ApplicationCompareResponse { + resultCode, resultDescription := getLDAPResultCode(packet) + if resultCode == LDAPResultCompareTrue { + return true, nil + } else if resultCode == LDAPResultCompareFalse { + return false, nil + } else { + return false, NewError(resultCode, errors.New(resultDescription)) + } + } + return false, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag) +} diff --git a/vendor/gopkg.in/ldap.v2/conn.go b/vendor/gopkg.in/ldap.v2/conn.go new file mode 100644 index 00000000..eb28eb47 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/conn.go @@ -0,0 +1,470 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ldap + +import ( + "crypto/tls" + "errors" + "fmt" + "log" + "net" + "sync" + "sync/atomic" + "time" + + "gopkg.in/asn1-ber.v1" +) + +const ( + // MessageQuit causes the processMessages loop to exit + MessageQuit = 0 + // MessageRequest sends a request to the server + MessageRequest = 1 + // MessageResponse receives a response from the server + MessageResponse = 2 + // MessageFinish indicates the client considers a particular message ID to be finished + MessageFinish = 3 + // MessageTimeout indicates the client-specified timeout for a particular message ID has been reached + MessageTimeout = 4 +) + +// PacketResponse contains the packet or error encountered reading a response +type PacketResponse struct { + // Packet is the packet read from the server + Packet *ber.Packet + // Error is an error encountered while reading + Error error +} + +// ReadPacket returns the packet or an error +func (pr *PacketResponse) ReadPacket() (*ber.Packet, error) { + if (pr == nil) || (pr.Packet == nil && pr.Error == nil) { + return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve response")) + } + return pr.Packet, pr.Error +} + +type messageContext struct { + id int64 + // close(done) should only be called from finishMessage() + done chan struct{} + // close(responses) should only be called from processMessages(), and only sent to from sendResponse() + responses chan *PacketResponse +} + +// sendResponse should only be called within the processMessages() loop which +// is also responsible for closing the responses channel. +func (msgCtx *messageContext) sendResponse(packet *PacketResponse) { + select { + case msgCtx.responses <- packet: + // Successfully sent packet to message handler. + case <-msgCtx.done: + // The request handler is done and will not receive more + // packets. + } +} + +type messagePacket struct { + Op int + MessageID int64 + Packet *ber.Packet + Context *messageContext +} + +type sendMessageFlags uint + +const ( + startTLS sendMessageFlags = 1 << iota +) + +// Conn represents an LDAP Connection +type Conn struct { + conn net.Conn + isTLS bool + closing uint32 + closeErr atomicValue + isStartingTLS bool + Debug debugging + chanConfirm chan struct{} + messageContexts map[int64]*messageContext + chanMessage chan *messagePacket + chanMessageID chan int64 + wgClose sync.WaitGroup + outstandingRequests uint + messageMutex sync.Mutex + requestTimeout int64 +} + +var _ Client = &Conn{} + +// DefaultTimeout is a package-level variable that sets the timeout value +// used for the Dial and DialTLS methods. +// +// WARNING: since this is a package-level variable, setting this value from +// multiple places will probably result in undesired behaviour. +var DefaultTimeout = 60 * time.Second + +// Dial connects to the given address on the given network using net.Dial +// and then returns a new Conn for the connection. +func Dial(network, addr string) (*Conn, error) { + c, err := net.DialTimeout(network, addr, DefaultTimeout) + if err != nil { + return nil, NewError(ErrorNetwork, err) + } + conn := NewConn(c, false) + conn.Start() + return conn, nil +} + +// DialTLS connects to the given address on the given network using tls.Dial +// and then returns a new Conn for the connection. +func DialTLS(network, addr string, config *tls.Config) (*Conn, error) { + dc, err := net.DialTimeout(network, addr, DefaultTimeout) + if err != nil { + return nil, NewError(ErrorNetwork, err) + } + c := tls.Client(dc, config) + err = c.Handshake() + if err != nil { + // Handshake error, close the established connection before we return an error + dc.Close() + return nil, NewError(ErrorNetwork, err) + } + conn := NewConn(c, true) + conn.Start() + return conn, nil +} + +// NewConn returns a new Conn using conn for network I/O. +func NewConn(conn net.Conn, isTLS bool) *Conn { + return &Conn{ + conn: conn, + chanConfirm: make(chan struct{}), + chanMessageID: make(chan int64), + chanMessage: make(chan *messagePacket, 10), + messageContexts: map[int64]*messageContext{}, + requestTimeout: 0, + isTLS: isTLS, + } +} + +// Start initializes goroutines to read responses and process messages +func (l *Conn) Start() { + go l.reader() + go l.processMessages() + l.wgClose.Add(1) +} + +// isClosing returns whether or not we're currently closing. +func (l *Conn) isClosing() bool { + return atomic.LoadUint32(&l.closing) == 1 +} + +// setClosing sets the closing value to true +func (l *Conn) setClosing() bool { + return atomic.CompareAndSwapUint32(&l.closing, 0, 1) +} + +// Close closes the connection. +func (l *Conn) Close() { + l.messageMutex.Lock() + defer l.messageMutex.Unlock() + + if l.setClosing() { + l.Debug.Printf("Sending quit message and waiting for confirmation") + l.chanMessage <- &messagePacket{Op: MessageQuit} + <-l.chanConfirm + close(l.chanMessage) + + l.Debug.Printf("Closing network connection") + if err := l.conn.Close(); err != nil { + log.Println(err) + } + + l.wgClose.Done() + } + l.wgClose.Wait() +} + +// SetTimeout sets the time after a request is sent that a MessageTimeout triggers +func (l *Conn) SetTimeout(timeout time.Duration) { + if timeout > 0 { + atomic.StoreInt64(&l.requestTimeout, int64(timeout)) + } +} + +// Returns the next available messageID +func (l *Conn) nextMessageID() int64 { + if messageID, ok := <-l.chanMessageID; ok { + return messageID + } + return 0 +} + +// StartTLS sends the command to start a TLS session and then creates a new TLS Client +func (l *Conn) StartTLS(config *tls.Config) error { + if l.isTLS { + return NewError(ErrorNetwork, errors.New("ldap: already encrypted")) + } + + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Start TLS") + request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, "1.3.6.1.4.1.1466.20037", "TLS Extended Command")) + packet.AppendChild(request) + l.Debug.PrintPacket(packet) + + msgCtx, err := l.sendMessageWithFlags(packet, startTLS) + if err != nil { + return err + } + defer l.finishMessage(msgCtx) + + l.Debug.Printf("%d: waiting for response", msgCtx.id) + + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + l.Close() + return err + } + ber.PrintPacket(packet) + } + + if resultCode, message := getLDAPResultCode(packet); resultCode == LDAPResultSuccess { + conn := tls.Client(l.conn, config) + + if err := conn.Handshake(); err != nil { + l.Close() + return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", err)) + } + + l.isTLS = true + l.conn = conn + } else { + return NewError(resultCode, fmt.Errorf("ldap: cannot StartTLS (%s)", message)) + } + go l.reader() + + return nil +} + +func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) { + return l.sendMessageWithFlags(packet, 0) +} + +func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) { + if l.isClosing() { + return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed")) + } + l.messageMutex.Lock() + l.Debug.Printf("flags&startTLS = %d", flags&startTLS) + if l.isStartingTLS { + l.messageMutex.Unlock() + return nil, NewError(ErrorNetwork, errors.New("ldap: connection is in startls phase")) + } + if flags&startTLS != 0 { + if l.outstandingRequests != 0 { + l.messageMutex.Unlock() + return nil, NewError(ErrorNetwork, errors.New("ldap: cannot StartTLS with outstanding requests")) + } + l.isStartingTLS = true + } + l.outstandingRequests++ + + l.messageMutex.Unlock() + + responses := make(chan *PacketResponse) + messageID := packet.Children[0].Value.(int64) + message := &messagePacket{ + Op: MessageRequest, + MessageID: messageID, + Packet: packet, + Context: &messageContext{ + id: messageID, + done: make(chan struct{}), + responses: responses, + }, + } + l.sendProcessMessage(message) + return message.Context, nil +} + +func (l *Conn) finishMessage(msgCtx *messageContext) { + close(msgCtx.done) + + if l.isClosing() { + return + } + + l.messageMutex.Lock() + l.outstandingRequests-- + if l.isStartingTLS { + l.isStartingTLS = false + } + l.messageMutex.Unlock() + + message := &messagePacket{ + Op: MessageFinish, + MessageID: msgCtx.id, + } + l.sendProcessMessage(message) +} + +func (l *Conn) sendProcessMessage(message *messagePacket) bool { + l.messageMutex.Lock() + defer l.messageMutex.Unlock() + if l.isClosing() { + return false + } + l.chanMessage <- message + return true +} + +func (l *Conn) processMessages() { + defer func() { + if err := recover(); err != nil { + log.Printf("ldap: recovered panic in processMessages: %v", err) + } + for messageID, msgCtx := range l.messageContexts { + // If we are closing due to an error, inform anyone who + // is waiting about the error. + if l.isClosing() && l.closeErr.Load() != nil { + msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)}) + } + l.Debug.Printf("Closing channel for MessageID %d", messageID) + close(msgCtx.responses) + delete(l.messageContexts, messageID) + } + close(l.chanMessageID) + close(l.chanConfirm) + }() + + var messageID int64 = 1 + for { + select { + case l.chanMessageID <- messageID: + messageID++ + case message := <-l.chanMessage: + switch message.Op { + case MessageQuit: + l.Debug.Printf("Shutting down - quit message received") + return + case MessageRequest: + // Add to message list and write to network + l.Debug.Printf("Sending message %d", message.MessageID) + + buf := message.Packet.Bytes() + _, err := l.conn.Write(buf) + if err != nil { + l.Debug.Printf("Error Sending Message: %s", err.Error()) + message.Context.sendResponse(&PacketResponse{Error: fmt.Errorf("unable to send request: %s", err)}) + close(message.Context.responses) + break + } + + // Only add to messageContexts if we were able to + // successfully write the message. + l.messageContexts[message.MessageID] = message.Context + + // Add timeout if defined + requestTimeout := time.Duration(atomic.LoadInt64(&l.requestTimeout)) + if requestTimeout > 0 { + go func() { + defer func() { + if err := recover(); err != nil { + log.Printf("ldap: recovered panic in RequestTimeout: %v", err) + } + }() + time.Sleep(requestTimeout) + timeoutMessage := &messagePacket{ + Op: MessageTimeout, + MessageID: message.MessageID, + } + l.sendProcessMessage(timeoutMessage) + }() + } + case MessageResponse: + l.Debug.Printf("Receiving message %d", message.MessageID) + if msgCtx, ok := l.messageContexts[message.MessageID]; ok { + msgCtx.sendResponse(&PacketResponse{message.Packet, nil}) + } else { + log.Printf("Received unexpected message %d, %v", message.MessageID, l.isClosing()) + ber.PrintPacket(message.Packet) + } + case MessageTimeout: + // Handle the timeout by closing the channel + // All reads will return immediately + if msgCtx, ok := l.messageContexts[message.MessageID]; ok { + l.Debug.Printf("Receiving message timeout for %d", message.MessageID) + msgCtx.sendResponse(&PacketResponse{message.Packet, errors.New("ldap: connection timed out")}) + delete(l.messageContexts, message.MessageID) + close(msgCtx.responses) + } + case MessageFinish: + l.Debug.Printf("Finished message %d", message.MessageID) + if msgCtx, ok := l.messageContexts[message.MessageID]; ok { + delete(l.messageContexts, message.MessageID) + close(msgCtx.responses) + } + } + } + } +} + +func (l *Conn) reader() { + cleanstop := false + defer func() { + if err := recover(); err != nil { + log.Printf("ldap: recovered panic in reader: %v", err) + } + if !cleanstop { + l.Close() + } + }() + + for { + if cleanstop { + l.Debug.Printf("reader clean stopping (without closing the connection)") + return + } + packet, err := ber.ReadPacket(l.conn) + if err != nil { + // A read error is expected here if we are closing the connection... + if !l.isClosing() { + l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err)) + l.Debug.Printf("reader error: %s", err.Error()) + } + return + } + addLDAPDescriptions(packet) + if len(packet.Children) == 0 { + l.Debug.Printf("Received bad ldap packet") + continue + } + l.messageMutex.Lock() + if l.isStartingTLS { + cleanstop = true + } + l.messageMutex.Unlock() + message := &messagePacket{ + Op: MessageResponse, + MessageID: packet.Children[0].Value.(int64), + Packet: packet, + } + if !l.sendProcessMessage(message) { + return + } + } +} diff --git a/vendor/gopkg.in/ldap.v2/control.go b/vendor/gopkg.in/ldap.v2/control.go new file mode 100644 index 00000000..342f325c --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/control.go @@ -0,0 +1,420 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ldap + +import ( + "fmt" + "strconv" + + "gopkg.in/asn1-ber.v1" +) + +const ( + // ControlTypePaging - https://www.ietf.org/rfc/rfc2696.txt + ControlTypePaging = "1.2.840.113556.1.4.319" + // ControlTypeBeheraPasswordPolicy - https://tools.ietf.org/html/draft-behera-ldap-password-policy-10 + ControlTypeBeheraPasswordPolicy = "1.3.6.1.4.1.42.2.27.8.5.1" + // ControlTypeVChuPasswordMustChange - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 + ControlTypeVChuPasswordMustChange = "2.16.840.1.113730.3.4.4" + // ControlTypeVChuPasswordWarning - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 + ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5" + // ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296 + ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2" +) + +// ControlTypeMap maps controls to text descriptions +var ControlTypeMap = map[string]string{ + ControlTypePaging: "Paging", + ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft", + ControlTypeManageDsaIT: "Manage DSA IT", +} + +// Control defines an interface controls provide to encode and describe themselves +type Control interface { + // GetControlType returns the OID + GetControlType() string + // Encode returns the ber packet representation + Encode() *ber.Packet + // String returns a human-readable description + String() string +} + +// ControlString implements the Control interface for simple controls +type ControlString struct { + ControlType string + Criticality bool + ControlValue string +} + +// GetControlType returns the OID +func (c *ControlString) GetControlType() string { + return c.ControlType +} + +// Encode returns the ber packet representation +func (c *ControlString) Encode() *ber.Packet { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")")) + if c.Criticality { + packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) + } + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, string(c.ControlValue), "Control Value")) + return packet +} + +// String returns a human-readable description +func (c *ControlString) String() string { + return fmt.Sprintf("Control Type: %s (%q) Criticality: %t Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue) +} + +// ControlPaging implements the paging control described in https://www.ietf.org/rfc/rfc2696.txt +type ControlPaging struct { + // PagingSize indicates the page size + PagingSize uint32 + // Cookie is an opaque value returned by the server to track a paging cursor + Cookie []byte +} + +// GetControlType returns the OID +func (c *ControlPaging) GetControlType() string { + return ControlTypePaging +} + +// Encode returns the ber packet representation +func (c *ControlPaging) Encode() *ber.Packet { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")")) + + p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)") + seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value") + seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.PagingSize), "Paging Size")) + cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie") + cookie.Value = c.Cookie + cookie.Data.Write(c.Cookie) + seq.AppendChild(cookie) + p2.AppendChild(seq) + + packet.AppendChild(p2) + return packet +} + +// String returns a human-readable description +func (c *ControlPaging) String() string { + return fmt.Sprintf( + "Control Type: %s (%q) Criticality: %t PagingSize: %d Cookie: %q", + ControlTypeMap[ControlTypePaging], + ControlTypePaging, + false, + c.PagingSize, + c.Cookie) +} + +// SetCookie stores the given cookie in the paging control +func (c *ControlPaging) SetCookie(cookie []byte) { + c.Cookie = cookie +} + +// ControlBeheraPasswordPolicy implements the control described in https://tools.ietf.org/html/draft-behera-ldap-password-policy-10 +type ControlBeheraPasswordPolicy struct { + // Expire contains the number of seconds before a password will expire + Expire int64 + // Grace indicates the remaining number of times a user will be allowed to authenticate with an expired password + Grace int64 + // Error indicates the error code + Error int8 + // ErrorString is a human readable error + ErrorString string +} + +// GetControlType returns the OID +func (c *ControlBeheraPasswordPolicy) GetControlType() string { + return ControlTypeBeheraPasswordPolicy +} + +// Encode returns the ber packet representation +func (c *ControlBeheraPasswordPolicy) Encode() *ber.Packet { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeBeheraPasswordPolicy, "Control Type ("+ControlTypeMap[ControlTypeBeheraPasswordPolicy]+")")) + + return packet +} + +// String returns a human-readable description +func (c *ControlBeheraPasswordPolicy) String() string { + return fmt.Sprintf( + "Control Type: %s (%q) Criticality: %t Expire: %d Grace: %d Error: %d, ErrorString: %s", + ControlTypeMap[ControlTypeBeheraPasswordPolicy], + ControlTypeBeheraPasswordPolicy, + false, + c.Expire, + c.Grace, + c.Error, + c.ErrorString) +} + +// ControlVChuPasswordMustChange implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 +type ControlVChuPasswordMustChange struct { + // MustChange indicates if the password is required to be changed + MustChange bool +} + +// GetControlType returns the OID +func (c *ControlVChuPasswordMustChange) GetControlType() string { + return ControlTypeVChuPasswordMustChange +} + +// Encode returns the ber packet representation +func (c *ControlVChuPasswordMustChange) Encode() *ber.Packet { + return nil +} + +// String returns a human-readable description +func (c *ControlVChuPasswordMustChange) String() string { + return fmt.Sprintf( + "Control Type: %s (%q) Criticality: %t MustChange: %v", + ControlTypeMap[ControlTypeVChuPasswordMustChange], + ControlTypeVChuPasswordMustChange, + false, + c.MustChange) +} + +// ControlVChuPasswordWarning implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00 +type ControlVChuPasswordWarning struct { + // Expire indicates the time in seconds until the password expires + Expire int64 +} + +// GetControlType returns the OID +func (c *ControlVChuPasswordWarning) GetControlType() string { + return ControlTypeVChuPasswordWarning +} + +// Encode returns the ber packet representation +func (c *ControlVChuPasswordWarning) Encode() *ber.Packet { + return nil +} + +// String returns a human-readable description +func (c *ControlVChuPasswordWarning) String() string { + return fmt.Sprintf( + "Control Type: %s (%q) Criticality: %t Expire: %b", + ControlTypeMap[ControlTypeVChuPasswordWarning], + ControlTypeVChuPasswordWarning, + false, + c.Expire) +} + +// ControlManageDsaIT implements the control described in https://tools.ietf.org/html/rfc3296 +type ControlManageDsaIT struct { + // Criticality indicates if this control is required + Criticality bool +} + +// GetControlType returns the OID +func (c *ControlManageDsaIT) GetControlType() string { + return ControlTypeManageDsaIT +} + +// Encode returns the ber packet representation +func (c *ControlManageDsaIT) Encode() *ber.Packet { + //FIXME + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeManageDsaIT, "Control Type ("+ControlTypeMap[ControlTypeManageDsaIT]+")")) + if c.Criticality { + packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality")) + } + return packet +} + +// String returns a human-readable description +func (c *ControlManageDsaIT) String() string { + return fmt.Sprintf( + "Control Type: %s (%q) Criticality: %t", + ControlTypeMap[ControlTypeManageDsaIT], + ControlTypeManageDsaIT, + c.Criticality) +} + +// NewControlManageDsaIT returns a ControlManageDsaIT control +func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT { + return &ControlManageDsaIT{Criticality: Criticality} +} + +// FindControl returns the first control of the given type in the list, or nil +func FindControl(controls []Control, controlType string) Control { + for _, c := range controls { + if c.GetControlType() == controlType { + return c + } + } + return nil +} + +// DecodeControl returns a control read from the given packet, or nil if no recognized control can be made +func DecodeControl(packet *ber.Packet) Control { + var ( + ControlType = "" + Criticality = false + value *ber.Packet + ) + + switch len(packet.Children) { + case 0: + // at least one child is required for control type + return nil + + case 1: + // just type, no criticality or value + packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" + ControlType = packet.Children[0].Value.(string) + + case 2: + packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" + ControlType = packet.Children[0].Value.(string) + + // Children[1] could be criticality or value (both are optional) + // duck-type on whether this is a boolean + if _, ok := packet.Children[1].Value.(bool); ok { + packet.Children[1].Description = "Criticality" + Criticality = packet.Children[1].Value.(bool) + } else { + packet.Children[1].Description = "Control Value" + value = packet.Children[1] + } + + case 3: + packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")" + ControlType = packet.Children[0].Value.(string) + + packet.Children[1].Description = "Criticality" + Criticality = packet.Children[1].Value.(bool) + + packet.Children[2].Description = "Control Value" + value = packet.Children[2] + + default: + // more than 3 children is invalid + return nil + } + + switch ControlType { + case ControlTypeManageDsaIT: + return NewControlManageDsaIT(Criticality) + case ControlTypePaging: + value.Description += " (Paging)" + c := new(ControlPaging) + if value.Value != nil { + valueChildren := ber.DecodePacket(value.Data.Bytes()) + value.Data.Truncate(0) + value.Value = nil + value.AppendChild(valueChildren) + } + value = value.Children[0] + value.Description = "Search Control Value" + value.Children[0].Description = "Paging Size" + value.Children[1].Description = "Cookie" + c.PagingSize = uint32(value.Children[0].Value.(int64)) + c.Cookie = value.Children[1].Data.Bytes() + value.Children[1].Value = c.Cookie + return c + case ControlTypeBeheraPasswordPolicy: + value.Description += " (Password Policy - Behera)" + c := NewControlBeheraPasswordPolicy() + if value.Value != nil { + valueChildren := ber.DecodePacket(value.Data.Bytes()) + value.Data.Truncate(0) + value.Value = nil + value.AppendChild(valueChildren) + } + + sequence := value.Children[0] + + for _, child := range sequence.Children { + if child.Tag == 0 { + //Warning + warningPacket := child.Children[0] + packet := ber.DecodePacket(warningPacket.Data.Bytes()) + val, ok := packet.Value.(int64) + if ok { + if warningPacket.Tag == 0 { + //timeBeforeExpiration + c.Expire = val + warningPacket.Value = c.Expire + } else if warningPacket.Tag == 1 { + //graceAuthNsRemaining + c.Grace = val + warningPacket.Value = c.Grace + } + } + } else if child.Tag == 1 { + // Error + packet := ber.DecodePacket(child.Data.Bytes()) + val, ok := packet.Value.(int8) + if !ok { + // what to do? + val = -1 + } + c.Error = val + child.Value = c.Error + c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error] + } + } + return c + case ControlTypeVChuPasswordMustChange: + c := &ControlVChuPasswordMustChange{MustChange: true} + return c + case ControlTypeVChuPasswordWarning: + c := &ControlVChuPasswordWarning{Expire: -1} + expireStr := ber.DecodeString(value.Data.Bytes()) + + expire, err := strconv.ParseInt(expireStr, 10, 64) + if err != nil { + return nil + } + c.Expire = expire + value.Value = c.Expire + + return c + default: + c := new(ControlString) + c.ControlType = ControlType + c.Criticality = Criticality + if value != nil { + c.ControlValue = value.Value.(string) + } + return c + } +} + +// NewControlString returns a generic control +func NewControlString(controlType string, criticality bool, controlValue string) *ControlString { + return &ControlString{ + ControlType: controlType, + Criticality: criticality, + ControlValue: controlValue, + } +} + +// NewControlPaging returns a paging control +func NewControlPaging(pagingSize uint32) *ControlPaging { + return &ControlPaging{PagingSize: pagingSize} +} + +// NewControlBeheraPasswordPolicy returns a ControlBeheraPasswordPolicy +func NewControlBeheraPasswordPolicy() *ControlBeheraPasswordPolicy { + return &ControlBeheraPasswordPolicy{ + Expire: -1, + Grace: -1, + Error: -1, + } +} + +func encodeControls(controls []Control) *ber.Packet { + packet := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls") + for _, control := range controls { + packet.AppendChild(control.Encode()) + } + return packet +} diff --git a/vendor/gopkg.in/ldap.v2/debug.go b/vendor/gopkg.in/ldap.v2/debug.go new file mode 100644 index 00000000..7279fc25 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/debug.go @@ -0,0 +1,24 @@ +package ldap + +import ( + "log" + + "gopkg.in/asn1-ber.v1" +) + +// debugging type +// - has a Printf method to write the debug output +type debugging bool + +// write debug output +func (debug debugging) Printf(format string, args ...interface{}) { + if debug { + log.Printf(format, args...) + } +} + +func (debug debugging) PrintPacket(packet *ber.Packet) { + if debug { + ber.PrintPacket(packet) + } +} diff --git a/vendor/gopkg.in/ldap.v2/del.go b/vendor/gopkg.in/ldap.v2/del.go new file mode 100644 index 00000000..4fd63dc3 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/del.go @@ -0,0 +1,84 @@ +// +// https://tools.ietf.org/html/rfc4511 +// +// DelRequest ::= [APPLICATION 10] LDAPDN + +package ldap + +import ( + "errors" + "log" + + "gopkg.in/asn1-ber.v1" +) + +// DelRequest implements an LDAP deletion request +type DelRequest struct { + // DN is the name of the directory entry to delete + DN string + // Controls hold optional controls to send with the request + Controls []Control +} + +func (d DelRequest) encode() *ber.Packet { + request := ber.Encode(ber.ClassApplication, ber.TypePrimitive, ApplicationDelRequest, d.DN, "Del Request") + request.Data.Write([]byte(d.DN)) + return request +} + +// NewDelRequest creates a delete request for the given DN and controls +func NewDelRequest(DN string, + Controls []Control) *DelRequest { + return &DelRequest{ + DN: DN, + Controls: Controls, + } +} + +// Del executes the given delete request +func (l *Conn) Del(delRequest *DelRequest) error { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + packet.AppendChild(delRequest.encode()) + if delRequest.Controls != nil { + packet.AppendChild(encodeControls(delRequest.Controls)) + } + + l.Debug.PrintPacket(packet) + + msgCtx, err := l.sendMessage(packet) + if err != nil { + return err + } + defer l.finishMessage(msgCtx) + + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + return err + } + ber.PrintPacket(packet) + } + + if packet.Children[1].Tag == ApplicationDelResponse { + resultCode, resultDescription := getLDAPResultCode(packet) + if resultCode != 0 { + return NewError(resultCode, errors.New(resultDescription)) + } + } else { + log.Printf("Unexpected Response: %d", packet.Children[1].Tag) + } + + l.Debug.Printf("%d: returning", msgCtx.id) + return nil +} diff --git a/vendor/gopkg.in/ldap.v2/dn.go b/vendor/gopkg.in/ldap.v2/dn.go new file mode 100644 index 00000000..34e9023a --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/dn.go @@ -0,0 +1,247 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// File contains DN parsing functionality +// +// https://tools.ietf.org/html/rfc4514 +// +// distinguishedName = [ relativeDistinguishedName +// *( COMMA relativeDistinguishedName ) ] +// relativeDistinguishedName = attributeTypeAndValue +// *( PLUS attributeTypeAndValue ) +// attributeTypeAndValue = attributeType EQUALS attributeValue +// attributeType = descr / numericoid +// attributeValue = string / hexstring +// +// ; The following characters are to be escaped when they appear +// ; in the value to be encoded: ESC, one of , leading +// ; SHARP or SPACE, trailing SPACE, and NULL. +// string = [ ( leadchar / pair ) [ *( stringchar / pair ) +// ( trailchar / pair ) ] ] +// +// leadchar = LUTF1 / UTFMB +// LUTF1 = %x01-1F / %x21 / %x24-2A / %x2D-3A / +// %x3D / %x3F-5B / %x5D-7F +// +// trailchar = TUTF1 / UTFMB +// TUTF1 = %x01-1F / %x21 / %x23-2A / %x2D-3A / +// %x3D / %x3F-5B / %x5D-7F +// +// stringchar = SUTF1 / UTFMB +// SUTF1 = %x01-21 / %x23-2A / %x2D-3A / +// %x3D / %x3F-5B / %x5D-7F +// +// pair = ESC ( ESC / special / hexpair ) +// special = escaped / SPACE / SHARP / EQUALS +// escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE +// hexstring = SHARP 1*hexpair +// hexpair = HEX HEX +// +// where the productions , , , , +// , , , , , , , , +// , , and are defined in [RFC4512]. +// + +package ldap + +import ( + "bytes" + enchex "encoding/hex" + "errors" + "fmt" + "strings" + + "gopkg.in/asn1-ber.v1" +) + +// AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514 +type AttributeTypeAndValue struct { + // Type is the attribute type + Type string + // Value is the attribute value + Value string +} + +// RelativeDN represents a relativeDistinguishedName from https://tools.ietf.org/html/rfc4514 +type RelativeDN struct { + Attributes []*AttributeTypeAndValue +} + +// DN represents a distinguishedName from https://tools.ietf.org/html/rfc4514 +type DN struct { + RDNs []*RelativeDN +} + +// ParseDN returns a distinguishedName or an error +func ParseDN(str string) (*DN, error) { + dn := new(DN) + dn.RDNs = make([]*RelativeDN, 0) + rdn := new(RelativeDN) + rdn.Attributes = make([]*AttributeTypeAndValue, 0) + buffer := bytes.Buffer{} + attribute := new(AttributeTypeAndValue) + escaping := false + + unescapedTrailingSpaces := 0 + stringFromBuffer := func() string { + s := buffer.String() + s = s[0 : len(s)-unescapedTrailingSpaces] + buffer.Reset() + unescapedTrailingSpaces = 0 + return s + } + + for i := 0; i < len(str); i++ { + char := str[i] + if escaping { + unescapedTrailingSpaces = 0 + escaping = false + switch char { + case ' ', '"', '#', '+', ',', ';', '<', '=', '>', '\\': + buffer.WriteByte(char) + continue + } + // Not a special character, assume hex encoded octet + if len(str) == i+1 { + return nil, errors.New("Got corrupted escaped character") + } + + dst := []byte{0} + n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2])) + if err != nil { + return nil, fmt.Errorf("Failed to decode escaped character: %s", err) + } else if n != 1 { + return nil, fmt.Errorf("Expected 1 byte when un-escaping, got %d", n) + } + buffer.WriteByte(dst[0]) + i++ + } else if char == '\\' { + unescapedTrailingSpaces = 0 + escaping = true + } else if char == '=' { + attribute.Type = stringFromBuffer() + // Special case: If the first character in the value is # the + // following data is BER encoded so we can just fast forward + // and decode. + if len(str) > i+1 && str[i+1] == '#' { + i += 2 + index := strings.IndexAny(str[i:], ",+") + data := str + if index > 0 { + data = str[i : i+index] + } else { + data = str[i:] + } + rawBER, err := enchex.DecodeString(data) + if err != nil { + return nil, fmt.Errorf("Failed to decode BER encoding: %s", err) + } + packet := ber.DecodePacket(rawBER) + buffer.WriteString(packet.Data.String()) + i += len(data) - 1 + } + } else if char == ',' || char == '+' { + // We're done with this RDN or value, push it + if len(attribute.Type) == 0 { + return nil, errors.New("incomplete type, value pair") + } + attribute.Value = stringFromBuffer() + rdn.Attributes = append(rdn.Attributes, attribute) + attribute = new(AttributeTypeAndValue) + if char == ',' { + dn.RDNs = append(dn.RDNs, rdn) + rdn = new(RelativeDN) + rdn.Attributes = make([]*AttributeTypeAndValue, 0) + } + } else if char == ' ' && buffer.Len() == 0 { + // ignore unescaped leading spaces + continue + } else { + if char == ' ' { + // Track unescaped spaces in case they are trailing and we need to remove them + unescapedTrailingSpaces++ + } else { + // Reset if we see a non-space char + unescapedTrailingSpaces = 0 + } + buffer.WriteByte(char) + } + } + if buffer.Len() > 0 { + if len(attribute.Type) == 0 { + return nil, errors.New("DN ended with incomplete type, value pair") + } + attribute.Value = stringFromBuffer() + rdn.Attributes = append(rdn.Attributes, attribute) + dn.RDNs = append(dn.RDNs, rdn) + } + return dn, nil +} + +// Equal returns true if the DNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch). +// Returns true if they have the same number of relative distinguished names +// and corresponding relative distinguished names (by position) are the same. +func (d *DN) Equal(other *DN) bool { + if len(d.RDNs) != len(other.RDNs) { + return false + } + for i := range d.RDNs { + if !d.RDNs[i].Equal(other.RDNs[i]) { + return false + } + } + return true +} + +// AncestorOf returns true if the other DN consists of at least one RDN followed by all the RDNs of the current DN. +// "ou=widgets,o=acme.com" is an ancestor of "ou=sprockets,ou=widgets,o=acme.com" +// "ou=widgets,o=acme.com" is not an ancestor of "ou=sprockets,ou=widgets,o=foo.com" +// "ou=widgets,o=acme.com" is not an ancestor of "ou=widgets,o=acme.com" +func (d *DN) AncestorOf(other *DN) bool { + if len(d.RDNs) >= len(other.RDNs) { + return false + } + // Take the last `len(d.RDNs)` RDNs from the other DN to compare against + otherRDNs := other.RDNs[len(other.RDNs)-len(d.RDNs):] + for i := range d.RDNs { + if !d.RDNs[i].Equal(otherRDNs[i]) { + return false + } + } + return true +} + +// Equal returns true if the RelativeDNs are equal as defined by rfc4517 4.2.15 (distinguishedNameMatch). +// Relative distinguished names are the same if and only if they have the same number of AttributeTypeAndValues +// and each attribute of the first RDN is the same as the attribute of the second RDN with the same attribute type. +// The order of attributes is not significant. +// Case of attribute types is not significant. +func (r *RelativeDN) Equal(other *RelativeDN) bool { + if len(r.Attributes) != len(other.Attributes) { + return false + } + return r.hasAllAttributes(other.Attributes) && other.hasAllAttributes(r.Attributes) +} + +func (r *RelativeDN) hasAllAttributes(attrs []*AttributeTypeAndValue) bool { + for _, attr := range attrs { + found := false + for _, myattr := range r.Attributes { + if myattr.Equal(attr) { + found = true + break + } + } + if !found { + return false + } + } + return true +} + +// Equal returns true if the AttributeTypeAndValue is equivalent to the specified AttributeTypeAndValue +// Case of the attribute type is not significant +func (a *AttributeTypeAndValue) Equal(other *AttributeTypeAndValue) bool { + return strings.EqualFold(a.Type, other.Type) && a.Value == other.Value +} diff --git a/vendor/gopkg.in/ldap.v2/doc.go b/vendor/gopkg.in/ldap.v2/doc.go new file mode 100644 index 00000000..f20d39bc --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/doc.go @@ -0,0 +1,4 @@ +/* +Package ldap provides basic LDAP v3 functionality. +*/ +package ldap diff --git a/vendor/gopkg.in/ldap.v2/error.go b/vendor/gopkg.in/ldap.v2/error.go new file mode 100644 index 00000000..4cccb537 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/error.go @@ -0,0 +1,155 @@ +package ldap + +import ( + "fmt" + + "gopkg.in/asn1-ber.v1" +) + +// LDAP Result Codes +const ( + LDAPResultSuccess = 0 + LDAPResultOperationsError = 1 + LDAPResultProtocolError = 2 + LDAPResultTimeLimitExceeded = 3 + LDAPResultSizeLimitExceeded = 4 + LDAPResultCompareFalse = 5 + LDAPResultCompareTrue = 6 + LDAPResultAuthMethodNotSupported = 7 + LDAPResultStrongAuthRequired = 8 + LDAPResultReferral = 10 + LDAPResultAdminLimitExceeded = 11 + LDAPResultUnavailableCriticalExtension = 12 + LDAPResultConfidentialityRequired = 13 + LDAPResultSaslBindInProgress = 14 + LDAPResultNoSuchAttribute = 16 + LDAPResultUndefinedAttributeType = 17 + LDAPResultInappropriateMatching = 18 + LDAPResultConstraintViolation = 19 + LDAPResultAttributeOrValueExists = 20 + LDAPResultInvalidAttributeSyntax = 21 + LDAPResultNoSuchObject = 32 + LDAPResultAliasProblem = 33 + LDAPResultInvalidDNSyntax = 34 + LDAPResultAliasDereferencingProblem = 36 + LDAPResultInappropriateAuthentication = 48 + LDAPResultInvalidCredentials = 49 + LDAPResultInsufficientAccessRights = 50 + LDAPResultBusy = 51 + LDAPResultUnavailable = 52 + LDAPResultUnwillingToPerform = 53 + LDAPResultLoopDetect = 54 + LDAPResultNamingViolation = 64 + LDAPResultObjectClassViolation = 65 + LDAPResultNotAllowedOnNonLeaf = 66 + LDAPResultNotAllowedOnRDN = 67 + LDAPResultEntryAlreadyExists = 68 + LDAPResultObjectClassModsProhibited = 69 + LDAPResultAffectsMultipleDSAs = 71 + LDAPResultOther = 80 + + ErrorNetwork = 200 + ErrorFilterCompile = 201 + ErrorFilterDecompile = 202 + ErrorDebugging = 203 + ErrorUnexpectedMessage = 204 + ErrorUnexpectedResponse = 205 +) + +// LDAPResultCodeMap contains string descriptions for LDAP error codes +var LDAPResultCodeMap = map[uint8]string{ + LDAPResultSuccess: "Success", + LDAPResultOperationsError: "Operations Error", + LDAPResultProtocolError: "Protocol Error", + LDAPResultTimeLimitExceeded: "Time Limit Exceeded", + LDAPResultSizeLimitExceeded: "Size Limit Exceeded", + LDAPResultCompareFalse: "Compare False", + LDAPResultCompareTrue: "Compare True", + LDAPResultAuthMethodNotSupported: "Auth Method Not Supported", + LDAPResultStrongAuthRequired: "Strong Auth Required", + LDAPResultReferral: "Referral", + LDAPResultAdminLimitExceeded: "Admin Limit Exceeded", + LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension", + LDAPResultConfidentialityRequired: "Confidentiality Required", + LDAPResultSaslBindInProgress: "Sasl Bind In Progress", + LDAPResultNoSuchAttribute: "No Such Attribute", + LDAPResultUndefinedAttributeType: "Undefined Attribute Type", + LDAPResultInappropriateMatching: "Inappropriate Matching", + LDAPResultConstraintViolation: "Constraint Violation", + LDAPResultAttributeOrValueExists: "Attribute Or Value Exists", + LDAPResultInvalidAttributeSyntax: "Invalid Attribute Syntax", + LDAPResultNoSuchObject: "No Such Object", + LDAPResultAliasProblem: "Alias Problem", + LDAPResultInvalidDNSyntax: "Invalid DN Syntax", + LDAPResultAliasDereferencingProblem: "Alias Dereferencing Problem", + LDAPResultInappropriateAuthentication: "Inappropriate Authentication", + LDAPResultInvalidCredentials: "Invalid Credentials", + LDAPResultInsufficientAccessRights: "Insufficient Access Rights", + LDAPResultBusy: "Busy", + LDAPResultUnavailable: "Unavailable", + LDAPResultUnwillingToPerform: "Unwilling To Perform", + LDAPResultLoopDetect: "Loop Detect", + LDAPResultNamingViolation: "Naming Violation", + LDAPResultObjectClassViolation: "Object Class Violation", + LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf", + LDAPResultNotAllowedOnRDN: "Not Allowed On RDN", + LDAPResultEntryAlreadyExists: "Entry Already Exists", + LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited", + LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs", + LDAPResultOther: "Other", + + ErrorNetwork: "Network Error", + ErrorFilterCompile: "Filter Compile Error", + ErrorFilterDecompile: "Filter Decompile Error", + ErrorDebugging: "Debugging Error", + ErrorUnexpectedMessage: "Unexpected Message", + ErrorUnexpectedResponse: "Unexpected Response", +} + +func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) { + if packet == nil { + return ErrorUnexpectedResponse, "Empty packet" + } else if len(packet.Children) >= 2 { + response := packet.Children[1] + if response == nil { + return ErrorUnexpectedResponse, "Empty response in packet" + } + if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 { + // Children[1].Children[2] is the diagnosticMessage which is guaranteed to exist as seen here: https://tools.ietf.org/html/rfc4511#section-4.1.9 + return uint8(response.Children[0].Value.(int64)), response.Children[2].Value.(string) + } + } + + return ErrorNetwork, "Invalid packet format" +} + +// Error holds LDAP error information +type Error struct { + // Err is the underlying error + Err error + // ResultCode is the LDAP error code + ResultCode uint8 +} + +func (e *Error) Error() string { + return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error()) +} + +// NewError creates an LDAP error with the given code and underlying error +func NewError(resultCode uint8, err error) error { + return &Error{ResultCode: resultCode, Err: err} +} + +// IsErrorWithCode returns true if the given error is an LDAP error with the given result code +func IsErrorWithCode(err error, desiredResultCode uint8) bool { + if err == nil { + return false + } + + serverError, ok := err.(*Error) + if !ok { + return false + } + + return serverError.ResultCode == desiredResultCode +} diff --git a/vendor/gopkg.in/ldap.v2/filter.go b/vendor/gopkg.in/ldap.v2/filter.go new file mode 100644 index 00000000..3858a286 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/filter.go @@ -0,0 +1,469 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ldap + +import ( + "bytes" + hexpac "encoding/hex" + "errors" + "fmt" + "strings" + "unicode/utf8" + + "gopkg.in/asn1-ber.v1" +) + +// Filter choices +const ( + FilterAnd = 0 + FilterOr = 1 + FilterNot = 2 + FilterEqualityMatch = 3 + FilterSubstrings = 4 + FilterGreaterOrEqual = 5 + FilterLessOrEqual = 6 + FilterPresent = 7 + FilterApproxMatch = 8 + FilterExtensibleMatch = 9 +) + +// FilterMap contains human readable descriptions of Filter choices +var FilterMap = map[uint64]string{ + FilterAnd: "And", + FilterOr: "Or", + FilterNot: "Not", + FilterEqualityMatch: "Equality Match", + FilterSubstrings: "Substrings", + FilterGreaterOrEqual: "Greater Or Equal", + FilterLessOrEqual: "Less Or Equal", + FilterPresent: "Present", + FilterApproxMatch: "Approx Match", + FilterExtensibleMatch: "Extensible Match", +} + +// SubstringFilter options +const ( + FilterSubstringsInitial = 0 + FilterSubstringsAny = 1 + FilterSubstringsFinal = 2 +) + +// FilterSubstringsMap contains human readable descriptions of SubstringFilter choices +var FilterSubstringsMap = map[uint64]string{ + FilterSubstringsInitial: "Substrings Initial", + FilterSubstringsAny: "Substrings Any", + FilterSubstringsFinal: "Substrings Final", +} + +// MatchingRuleAssertion choices +const ( + MatchingRuleAssertionMatchingRule = 1 + MatchingRuleAssertionType = 2 + MatchingRuleAssertionMatchValue = 3 + MatchingRuleAssertionDNAttributes = 4 +) + +// MatchingRuleAssertionMap contains human readable descriptions of MatchingRuleAssertion choices +var MatchingRuleAssertionMap = map[uint64]string{ + MatchingRuleAssertionMatchingRule: "Matching Rule Assertion Matching Rule", + MatchingRuleAssertionType: "Matching Rule Assertion Type", + MatchingRuleAssertionMatchValue: "Matching Rule Assertion Match Value", + MatchingRuleAssertionDNAttributes: "Matching Rule Assertion DN Attributes", +} + +// CompileFilter converts a string representation of a filter into a BER-encoded packet +func CompileFilter(filter string) (*ber.Packet, error) { + if len(filter) == 0 || filter[0] != '(' { + return nil, NewError(ErrorFilterCompile, errors.New("ldap: filter does not start with an '('")) + } + packet, pos, err := compileFilter(filter, 1) + if err != nil { + return nil, err + } + switch { + case pos > len(filter): + return nil, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter")) + case pos < len(filter): + return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:]))) + } + return packet, nil +} + +// DecompileFilter converts a packet representation of a filter into a string representation +func DecompileFilter(packet *ber.Packet) (ret string, err error) { + defer func() { + if r := recover(); r != nil { + err = NewError(ErrorFilterDecompile, errors.New("ldap: error decompiling filter")) + } + }() + ret = "(" + err = nil + childStr := "" + + switch packet.Tag { + case FilterAnd: + ret += "&" + for _, child := range packet.Children { + childStr, err = DecompileFilter(child) + if err != nil { + return + } + ret += childStr + } + case FilterOr: + ret += "|" + for _, child := range packet.Children { + childStr, err = DecompileFilter(child) + if err != nil { + return + } + ret += childStr + } + case FilterNot: + ret += "!" + childStr, err = DecompileFilter(packet.Children[0]) + if err != nil { + return + } + ret += childStr + + case FilterSubstrings: + ret += ber.DecodeString(packet.Children[0].Data.Bytes()) + ret += "=" + for i, child := range packet.Children[1].Children { + if i == 0 && child.Tag != FilterSubstringsInitial { + ret += "*" + } + ret += EscapeFilter(ber.DecodeString(child.Data.Bytes())) + if child.Tag != FilterSubstringsFinal { + ret += "*" + } + } + case FilterEqualityMatch: + ret += ber.DecodeString(packet.Children[0].Data.Bytes()) + ret += "=" + ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) + case FilterGreaterOrEqual: + ret += ber.DecodeString(packet.Children[0].Data.Bytes()) + ret += ">=" + ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) + case FilterLessOrEqual: + ret += ber.DecodeString(packet.Children[0].Data.Bytes()) + ret += "<=" + ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) + case FilterPresent: + ret += ber.DecodeString(packet.Data.Bytes()) + ret += "=*" + case FilterApproxMatch: + ret += ber.DecodeString(packet.Children[0].Data.Bytes()) + ret += "~=" + ret += EscapeFilter(ber.DecodeString(packet.Children[1].Data.Bytes())) + case FilterExtensibleMatch: + attr := "" + dnAttributes := false + matchingRule := "" + value := "" + + for _, child := range packet.Children { + switch child.Tag { + case MatchingRuleAssertionMatchingRule: + matchingRule = ber.DecodeString(child.Data.Bytes()) + case MatchingRuleAssertionType: + attr = ber.DecodeString(child.Data.Bytes()) + case MatchingRuleAssertionMatchValue: + value = ber.DecodeString(child.Data.Bytes()) + case MatchingRuleAssertionDNAttributes: + dnAttributes = child.Value.(bool) + } + } + + if len(attr) > 0 { + ret += attr + } + if dnAttributes { + ret += ":dn" + } + if len(matchingRule) > 0 { + ret += ":" + ret += matchingRule + } + ret += ":=" + ret += EscapeFilter(value) + } + + ret += ")" + return +} + +func compileFilterSet(filter string, pos int, parent *ber.Packet) (int, error) { + for pos < len(filter) && filter[pos] == '(' { + child, newPos, err := compileFilter(filter, pos+1) + if err != nil { + return pos, err + } + pos = newPos + parent.AppendChild(child) + } + if pos == len(filter) { + return pos, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter")) + } + + return pos + 1, nil +} + +func compileFilter(filter string, pos int) (*ber.Packet, int, error) { + var ( + packet *ber.Packet + err error + ) + + defer func() { + if r := recover(); r != nil { + err = NewError(ErrorFilterCompile, errors.New("ldap: error compiling filter")) + } + }() + newPos := pos + + currentRune, currentWidth := utf8.DecodeRuneInString(filter[newPos:]) + + switch currentRune { + case utf8.RuneError: + return nil, 0, NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", newPos)) + case '(': + packet, newPos, err = compileFilter(filter, pos+currentWidth) + newPos++ + return packet, newPos, err + case '&': + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterAnd, nil, FilterMap[FilterAnd]) + newPos, err = compileFilterSet(filter, pos+currentWidth, packet) + return packet, newPos, err + case '|': + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterOr, nil, FilterMap[FilterOr]) + newPos, err = compileFilterSet(filter, pos+currentWidth, packet) + return packet, newPos, err + case '!': + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterNot, nil, FilterMap[FilterNot]) + var child *ber.Packet + child, newPos, err = compileFilter(filter, pos+currentWidth) + packet.AppendChild(child) + return packet, newPos, err + default: + const ( + stateReadingAttr = 0 + stateReadingExtensibleMatchingRule = 1 + stateReadingCondition = 2 + ) + + state := stateReadingAttr + + attribute := "" + extensibleDNAttributes := false + extensibleMatchingRule := "" + condition := "" + + for newPos < len(filter) { + remainingFilter := filter[newPos:] + currentRune, currentWidth = utf8.DecodeRuneInString(remainingFilter) + if currentRune == ')' { + break + } + if currentRune == utf8.RuneError { + return packet, newPos, NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", newPos)) + } + + switch state { + case stateReadingAttr: + switch { + // Extensible rule, with only DN-matching + case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:="): + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch]) + extensibleDNAttributes = true + state = stateReadingCondition + newPos += 5 + + // Extensible rule, with DN-matching and a matching OID + case currentRune == ':' && strings.HasPrefix(remainingFilter, ":dn:"): + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch]) + extensibleDNAttributes = true + state = stateReadingExtensibleMatchingRule + newPos += 4 + + // Extensible rule, with attr only + case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="): + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch]) + state = stateReadingCondition + newPos += 2 + + // Extensible rule, with no DN attribute matching + case currentRune == ':': + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterExtensibleMatch, nil, FilterMap[FilterExtensibleMatch]) + state = stateReadingExtensibleMatchingRule + newPos++ + + // Equality condition + case currentRune == '=': + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterEqualityMatch, nil, FilterMap[FilterEqualityMatch]) + state = stateReadingCondition + newPos++ + + // Greater-than or equal + case currentRune == '>' && strings.HasPrefix(remainingFilter, ">="): + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterGreaterOrEqual, nil, FilterMap[FilterGreaterOrEqual]) + state = stateReadingCondition + newPos += 2 + + // Less-than or equal + case currentRune == '<' && strings.HasPrefix(remainingFilter, "<="): + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterLessOrEqual, nil, FilterMap[FilterLessOrEqual]) + state = stateReadingCondition + newPos += 2 + + // Approx + case currentRune == '~' && strings.HasPrefix(remainingFilter, "~="): + packet = ber.Encode(ber.ClassContext, ber.TypeConstructed, FilterApproxMatch, nil, FilterMap[FilterApproxMatch]) + state = stateReadingCondition + newPos += 2 + + // Still reading the attribute name + default: + attribute += fmt.Sprintf("%c", currentRune) + newPos += currentWidth + } + + case stateReadingExtensibleMatchingRule: + switch { + + // Matching rule OID is done + case currentRune == ':' && strings.HasPrefix(remainingFilter, ":="): + state = stateReadingCondition + newPos += 2 + + // Still reading the matching rule oid + default: + extensibleMatchingRule += fmt.Sprintf("%c", currentRune) + newPos += currentWidth + } + + case stateReadingCondition: + // append to the condition + condition += fmt.Sprintf("%c", currentRune) + newPos += currentWidth + } + } + + if newPos == len(filter) { + err = NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter")) + return packet, newPos, err + } + if packet == nil { + err = NewError(ErrorFilterCompile, errors.New("ldap: error parsing filter")) + return packet, newPos, err + } + + switch { + case packet.Tag == FilterExtensibleMatch: + // MatchingRuleAssertion ::= SEQUENCE { + // matchingRule [1] MatchingRuleID OPTIONAL, + // type [2] AttributeDescription OPTIONAL, + // matchValue [3] AssertionValue, + // dnAttributes [4] BOOLEAN DEFAULT FALSE + // } + + // Include the matching rule oid, if specified + if len(extensibleMatchingRule) > 0 { + packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchingRule, extensibleMatchingRule, MatchingRuleAssertionMap[MatchingRuleAssertionMatchingRule])) + } + + // Include the attribute, if specified + if len(attribute) > 0 { + packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionType, attribute, MatchingRuleAssertionMap[MatchingRuleAssertionType])) + } + + // Add the value (only required child) + encodedString, encodeErr := escapedStringToEncodedBytes(condition) + if encodeErr != nil { + return packet, newPos, encodeErr + } + packet.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionMatchValue, encodedString, MatchingRuleAssertionMap[MatchingRuleAssertionMatchValue])) + + // Defaults to false, so only include in the sequence if true + if extensibleDNAttributes { + packet.AppendChild(ber.NewBoolean(ber.ClassContext, ber.TypePrimitive, MatchingRuleAssertionDNAttributes, extensibleDNAttributes, MatchingRuleAssertionMap[MatchingRuleAssertionDNAttributes])) + } + + case packet.Tag == FilterEqualityMatch && condition == "*": + packet = ber.NewString(ber.ClassContext, ber.TypePrimitive, FilterPresent, attribute, FilterMap[FilterPresent]) + case packet.Tag == FilterEqualityMatch && strings.Contains(condition, "*"): + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute")) + packet.Tag = FilterSubstrings + packet.Description = FilterMap[uint64(packet.Tag)] + seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Substrings") + parts := strings.Split(condition, "*") + for i, part := range parts { + if part == "" { + continue + } + var tag ber.Tag + switch i { + case 0: + tag = FilterSubstringsInitial + case len(parts) - 1: + tag = FilterSubstringsFinal + default: + tag = FilterSubstringsAny + } + encodedString, encodeErr := escapedStringToEncodedBytes(part) + if encodeErr != nil { + return packet, newPos, encodeErr + } + seq.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, tag, encodedString, FilterSubstringsMap[uint64(tag)])) + } + packet.AppendChild(seq) + default: + encodedString, encodeErr := escapedStringToEncodedBytes(condition) + if encodeErr != nil { + return packet, newPos, encodeErr + } + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute")) + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, encodedString, "Condition")) + } + + newPos += currentWidth + return packet, newPos, err + } +} + +// Convert from "ABC\xx\xx\xx" form to literal bytes for transport +func escapedStringToEncodedBytes(escapedString string) (string, error) { + var buffer bytes.Buffer + i := 0 + for i < len(escapedString) { + currentRune, currentWidth := utf8.DecodeRuneInString(escapedString[i:]) + if currentRune == utf8.RuneError { + return "", NewError(ErrorFilterCompile, fmt.Errorf("ldap: error reading rune at position %d", i)) + } + + // Check for escaped hex characters and convert them to their literal value for transport. + if currentRune == '\\' { + // http://tools.ietf.org/search/rfc4515 + // \ (%x5C) is not a valid character unless it is followed by two HEX characters due to not + // being a member of UTF1SUBSET. + if i+2 > len(escapedString) { + return "", NewError(ErrorFilterCompile, errors.New("ldap: missing characters for escape in filter")) + } + escByte, decodeErr := hexpac.DecodeString(escapedString[i+1 : i+3]) + if decodeErr != nil { + return "", NewError(ErrorFilterCompile, errors.New("ldap: invalid characters for escape in filter")) + } + buffer.WriteByte(escByte[0]) + i += 2 // +1 from end of loop, so 3 total for \xx. + } else { + buffer.WriteRune(currentRune) + } + + i += currentWidth + } + return buffer.String(), nil +} diff --git a/vendor/gopkg.in/ldap.v2/ldap.go b/vendor/gopkg.in/ldap.v2/ldap.go new file mode 100644 index 00000000..49692475 --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/ldap.go @@ -0,0 +1,320 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ldap + +import ( + "errors" + "io/ioutil" + "os" + + "gopkg.in/asn1-ber.v1" +) + +// LDAP Application Codes +const ( + ApplicationBindRequest = 0 + ApplicationBindResponse = 1 + ApplicationUnbindRequest = 2 + ApplicationSearchRequest = 3 + ApplicationSearchResultEntry = 4 + ApplicationSearchResultDone = 5 + ApplicationModifyRequest = 6 + ApplicationModifyResponse = 7 + ApplicationAddRequest = 8 + ApplicationAddResponse = 9 + ApplicationDelRequest = 10 + ApplicationDelResponse = 11 + ApplicationModifyDNRequest = 12 + ApplicationModifyDNResponse = 13 + ApplicationCompareRequest = 14 + ApplicationCompareResponse = 15 + ApplicationAbandonRequest = 16 + ApplicationSearchResultReference = 19 + ApplicationExtendedRequest = 23 + ApplicationExtendedResponse = 24 +) + +// ApplicationMap contains human readable descriptions of LDAP Application Codes +var ApplicationMap = map[uint8]string{ + ApplicationBindRequest: "Bind Request", + ApplicationBindResponse: "Bind Response", + ApplicationUnbindRequest: "Unbind Request", + ApplicationSearchRequest: "Search Request", + ApplicationSearchResultEntry: "Search Result Entry", + ApplicationSearchResultDone: "Search Result Done", + ApplicationModifyRequest: "Modify Request", + ApplicationModifyResponse: "Modify Response", + ApplicationAddRequest: "Add Request", + ApplicationAddResponse: "Add Response", + ApplicationDelRequest: "Del Request", + ApplicationDelResponse: "Del Response", + ApplicationModifyDNRequest: "Modify DN Request", + ApplicationModifyDNResponse: "Modify DN Response", + ApplicationCompareRequest: "Compare Request", + ApplicationCompareResponse: "Compare Response", + ApplicationAbandonRequest: "Abandon Request", + ApplicationSearchResultReference: "Search Result Reference", + ApplicationExtendedRequest: "Extended Request", + ApplicationExtendedResponse: "Extended Response", +} + +// Ldap Behera Password Policy Draft 10 (https://tools.ietf.org/html/draft-behera-ldap-password-policy-10) +const ( + BeheraPasswordExpired = 0 + BeheraAccountLocked = 1 + BeheraChangeAfterReset = 2 + BeheraPasswordModNotAllowed = 3 + BeheraMustSupplyOldPassword = 4 + BeheraInsufficientPasswordQuality = 5 + BeheraPasswordTooShort = 6 + BeheraPasswordTooYoung = 7 + BeheraPasswordInHistory = 8 +) + +// BeheraPasswordPolicyErrorMap contains human readable descriptions of Behera Password Policy error codes +var BeheraPasswordPolicyErrorMap = map[int8]string{ + BeheraPasswordExpired: "Password expired", + BeheraAccountLocked: "Account locked", + BeheraChangeAfterReset: "Password must be changed", + BeheraPasswordModNotAllowed: "Policy prevents password modification", + BeheraMustSupplyOldPassword: "Policy requires old password in order to change password", + BeheraInsufficientPasswordQuality: "Password fails quality checks", + BeheraPasswordTooShort: "Password is too short for policy", + BeheraPasswordTooYoung: "Password has been changed too recently", + BeheraPasswordInHistory: "New password is in list of old passwords", +} + +// Adds descriptions to an LDAP Response packet for debugging +func addLDAPDescriptions(packet *ber.Packet) (err error) { + defer func() { + if r := recover(); r != nil { + err = NewError(ErrorDebugging, errors.New("ldap: cannot process packet to add descriptions")) + } + }() + packet.Description = "LDAP Response" + packet.Children[0].Description = "Message ID" + + application := uint8(packet.Children[1].Tag) + packet.Children[1].Description = ApplicationMap[application] + + switch application { + case ApplicationBindRequest: + addRequestDescriptions(packet) + case ApplicationBindResponse: + addDefaultLDAPResponseDescriptions(packet) + case ApplicationUnbindRequest: + addRequestDescriptions(packet) + case ApplicationSearchRequest: + addRequestDescriptions(packet) + case ApplicationSearchResultEntry: + packet.Children[1].Children[0].Description = "Object Name" + packet.Children[1].Children[1].Description = "Attributes" + for _, child := range packet.Children[1].Children[1].Children { + child.Description = "Attribute" + child.Children[0].Description = "Attribute Name" + child.Children[1].Description = "Attribute Values" + for _, grandchild := range child.Children[1].Children { + grandchild.Description = "Attribute Value" + } + } + if len(packet.Children) == 3 { + addControlDescriptions(packet.Children[2]) + } + case ApplicationSearchResultDone: + addDefaultLDAPResponseDescriptions(packet) + case ApplicationModifyRequest: + addRequestDescriptions(packet) + case ApplicationModifyResponse: + case ApplicationAddRequest: + addRequestDescriptions(packet) + case ApplicationAddResponse: + case ApplicationDelRequest: + addRequestDescriptions(packet) + case ApplicationDelResponse: + case ApplicationModifyDNRequest: + addRequestDescriptions(packet) + case ApplicationModifyDNResponse: + case ApplicationCompareRequest: + addRequestDescriptions(packet) + case ApplicationCompareResponse: + case ApplicationAbandonRequest: + addRequestDescriptions(packet) + case ApplicationSearchResultReference: + case ApplicationExtendedRequest: + addRequestDescriptions(packet) + case ApplicationExtendedResponse: + } + + return nil +} + +func addControlDescriptions(packet *ber.Packet) { + packet.Description = "Controls" + for _, child := range packet.Children { + var value *ber.Packet + controlType := "" + child.Description = "Control" + switch len(child.Children) { + case 0: + // at least one child is required for control type + continue + + case 1: + // just type, no criticality or value + controlType = child.Children[0].Value.(string) + child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")" + + case 2: + controlType = child.Children[0].Value.(string) + child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")" + // Children[1] could be criticality or value (both are optional) + // duck-type on whether this is a boolean + if _, ok := child.Children[1].Value.(bool); ok { + child.Children[1].Description = "Criticality" + } else { + child.Children[1].Description = "Control Value" + value = child.Children[1] + } + + case 3: + // criticality and value present + controlType = child.Children[0].Value.(string) + child.Children[0].Description = "Control Type (" + ControlTypeMap[controlType] + ")" + child.Children[1].Description = "Criticality" + child.Children[2].Description = "Control Value" + value = child.Children[2] + + default: + // more than 3 children is invalid + continue + } + if value == nil { + continue + } + switch controlType { + case ControlTypePaging: + value.Description += " (Paging)" + if value.Value != nil { + valueChildren := ber.DecodePacket(value.Data.Bytes()) + value.Data.Truncate(0) + value.Value = nil + valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes() + value.AppendChild(valueChildren) + } + value.Children[0].Description = "Real Search Control Value" + value.Children[0].Children[0].Description = "Paging Size" + value.Children[0].Children[1].Description = "Cookie" + + case ControlTypeBeheraPasswordPolicy: + value.Description += " (Password Policy - Behera Draft)" + if value.Value != nil { + valueChildren := ber.DecodePacket(value.Data.Bytes()) + value.Data.Truncate(0) + value.Value = nil + value.AppendChild(valueChildren) + } + sequence := value.Children[0] + for _, child := range sequence.Children { + if child.Tag == 0 { + //Warning + warningPacket := child.Children[0] + packet := ber.DecodePacket(warningPacket.Data.Bytes()) + val, ok := packet.Value.(int64) + if ok { + if warningPacket.Tag == 0 { + //timeBeforeExpiration + value.Description += " (TimeBeforeExpiration)" + warningPacket.Value = val + } else if warningPacket.Tag == 1 { + //graceAuthNsRemaining + value.Description += " (GraceAuthNsRemaining)" + warningPacket.Value = val + } + } + } else if child.Tag == 1 { + // Error + packet := ber.DecodePacket(child.Data.Bytes()) + val, ok := packet.Value.(int8) + if !ok { + val = -1 + } + child.Description = "Error" + child.Value = val + } + } + } + } +} + +func addRequestDescriptions(packet *ber.Packet) { + packet.Description = "LDAP Request" + packet.Children[0].Description = "Message ID" + packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)] + if len(packet.Children) == 3 { + addControlDescriptions(packet.Children[2]) + } +} + +func addDefaultLDAPResponseDescriptions(packet *ber.Packet) { + resultCode, _ := getLDAPResultCode(packet) + packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[resultCode] + ")" + packet.Children[1].Children[1].Description = "Matched DN" + packet.Children[1].Children[2].Description = "Error Message" + if len(packet.Children[1].Children) > 3 { + packet.Children[1].Children[3].Description = "Referral" + } + if len(packet.Children) == 3 { + addControlDescriptions(packet.Children[2]) + } +} + +// DebugBinaryFile reads and prints packets from the given filename +func DebugBinaryFile(fileName string) error { + file, err := ioutil.ReadFile(fileName) + if err != nil { + return NewError(ErrorDebugging, err) + } + ber.PrintBytes(os.Stdout, file, "") + packet := ber.DecodePacket(file) + addLDAPDescriptions(packet) + ber.PrintPacket(packet) + + return nil +} + +var hex = "0123456789abcdef" + +func mustEscape(c byte) bool { + return c > 0x7f || c == '(' || c == ')' || c == '\\' || c == '*' || c == 0 +} + +// EscapeFilter escapes from the provided LDAP filter string the special +// characters in the set `()*\` and those out of the range 0 < c < 0x80, +// as defined in RFC4515. +func EscapeFilter(filter string) string { + escape := 0 + for i := 0; i < len(filter); i++ { + if mustEscape(filter[i]) { + escape++ + } + } + if escape == 0 { + return filter + } + buf := make([]byte, len(filter)+escape*2) + for i, j := 0, 0; i < len(filter); i++ { + c := filter[i] + if mustEscape(c) { + buf[j+0] = '\\' + buf[j+1] = hex[c>>4] + buf[j+2] = hex[c&0xf] + j += 3 + } else { + buf[j] = c + j++ + } + } + return string(buf) +} diff --git a/vendor/gopkg.in/ldap.v2/modify.go b/vendor/gopkg.in/ldap.v2/modify.go new file mode 100644 index 00000000..e4ab6cef --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/modify.go @@ -0,0 +1,170 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// File contains Modify functionality +// +// https://tools.ietf.org/html/rfc4511 +// +// ModifyRequest ::= [APPLICATION 6] SEQUENCE { +// object LDAPDN, +// changes SEQUENCE OF change SEQUENCE { +// operation ENUMERATED { +// add (0), +// delete (1), +// replace (2), +// ... }, +// modification PartialAttribute } } +// +// PartialAttribute ::= SEQUENCE { +// type AttributeDescription, +// vals SET OF value AttributeValue } +// +// AttributeDescription ::= LDAPString +// -- Constrained to +// -- [RFC4512] +// +// AttributeValue ::= OCTET STRING +// + +package ldap + +import ( + "errors" + "log" + + "gopkg.in/asn1-ber.v1" +) + +// Change operation choices +const ( + AddAttribute = 0 + DeleteAttribute = 1 + ReplaceAttribute = 2 +) + +// PartialAttribute for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 +type PartialAttribute struct { + // Type is the type of the partial attribute + Type string + // Vals are the values of the partial attribute + Vals []string +} + +func (p *PartialAttribute) encode() *ber.Packet { + seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "PartialAttribute") + seq.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, p.Type, "Type")) + set := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSet, nil, "AttributeValue") + for _, value := range p.Vals { + set.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "Vals")) + } + seq.AppendChild(set) + return seq +} + +// ModifyRequest as defined in https://tools.ietf.org/html/rfc4511 +type ModifyRequest struct { + // DN is the distinguishedName of the directory entry to modify + DN string + // AddAttributes contain the attributes to add + AddAttributes []PartialAttribute + // DeleteAttributes contain the attributes to delete + DeleteAttributes []PartialAttribute + // ReplaceAttributes contain the attributes to replace + ReplaceAttributes []PartialAttribute +} + +// Add inserts the given attribute to the list of attributes to add +func (m *ModifyRequest) Add(attrType string, attrVals []string) { + m.AddAttributes = append(m.AddAttributes, PartialAttribute{Type: attrType, Vals: attrVals}) +} + +// Delete inserts the given attribute to the list of attributes to delete +func (m *ModifyRequest) Delete(attrType string, attrVals []string) { + m.DeleteAttributes = append(m.DeleteAttributes, PartialAttribute{Type: attrType, Vals: attrVals}) +} + +// Replace inserts the given attribute to the list of attributes to replace +func (m *ModifyRequest) Replace(attrType string, attrVals []string) { + m.ReplaceAttributes = append(m.ReplaceAttributes, PartialAttribute{Type: attrType, Vals: attrVals}) +} + +func (m ModifyRequest) encode() *ber.Packet { + request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request") + request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN")) + changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes") + for _, attribute := range m.AddAttributes { + change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") + change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation")) + change.AppendChild(attribute.encode()) + changes.AppendChild(change) + } + for _, attribute := range m.DeleteAttributes { + change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") + change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation")) + change.AppendChild(attribute.encode()) + changes.AppendChild(change) + } + for _, attribute := range m.ReplaceAttributes { + change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change") + change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation")) + change.AppendChild(attribute.encode()) + changes.AppendChild(change) + } + request.AppendChild(changes) + return request +} + +// NewModifyRequest creates a modify request for the given DN +func NewModifyRequest( + dn string, +) *ModifyRequest { + return &ModifyRequest{ + DN: dn, + } +} + +// Modify performs the ModifyRequest +func (l *Conn) Modify(modifyRequest *ModifyRequest) error { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + packet.AppendChild(modifyRequest.encode()) + + l.Debug.PrintPacket(packet) + + msgCtx, err := l.sendMessage(packet) + if err != nil { + return err + } + defer l.finishMessage(msgCtx) + + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + return err + } + ber.PrintPacket(packet) + } + + if packet.Children[1].Tag == ApplicationModifyResponse { + resultCode, resultDescription := getLDAPResultCode(packet) + if resultCode != 0 { + return NewError(resultCode, errors.New(resultDescription)) + } + } else { + log.Printf("Unexpected Response: %d", packet.Children[1].Tag) + } + + l.Debug.Printf("%d: returning", msgCtx.id) + return nil +} diff --git a/vendor/gopkg.in/ldap.v2/passwdmodify.go b/vendor/gopkg.in/ldap.v2/passwdmodify.go new file mode 100644 index 00000000..7d8246fd --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/passwdmodify.go @@ -0,0 +1,148 @@ +// This file contains the password modify extended operation as specified in rfc 3062 +// +// https://tools.ietf.org/html/rfc3062 +// + +package ldap + +import ( + "errors" + "fmt" + + "gopkg.in/asn1-ber.v1" +) + +const ( + passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1" +) + +// PasswordModifyRequest implements the Password Modify Extended Operation as defined in https://www.ietf.org/rfc/rfc3062.txt +type PasswordModifyRequest struct { + // UserIdentity is an optional string representation of the user associated with the request. + // This string may or may not be an LDAPDN [RFC2253]. + // If no UserIdentity field is present, the request acts up upon the password of the user currently associated with the LDAP session + UserIdentity string + // OldPassword, if present, contains the user's current password + OldPassword string + // NewPassword, if present, contains the desired password for this user + NewPassword string +} + +// PasswordModifyResult holds the server response to a PasswordModifyRequest +type PasswordModifyResult struct { + // GeneratedPassword holds a password generated by the server, if present + GeneratedPassword string +} + +func (r *PasswordModifyRequest) encode() (*ber.Packet, error) { + request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation") + request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID")) + extendedRequestValue := ber.Encode(ber.ClassContext, ber.TypePrimitive, 1, nil, "Extended Request Value: Password Modify Request") + passwordModifyRequestValue := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Password Modify Request") + if r.UserIdentity != "" { + passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, r.UserIdentity, "User Identity")) + } + if r.OldPassword != "" { + passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, r.OldPassword, "Old Password")) + } + if r.NewPassword != "" { + passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, r.NewPassword, "New Password")) + } + + extendedRequestValue.AppendChild(passwordModifyRequestValue) + request.AppendChild(extendedRequestValue) + + return request, nil +} + +// NewPasswordModifyRequest creates a new PasswordModifyRequest +// +// According to the RFC 3602: +// userIdentity is a string representing the user associated with the request. +// This string may or may not be an LDAPDN (RFC 2253). +// If userIdentity is empty then the operation will act on the user associated +// with the session. +// +// oldPassword is the current user's password, it can be empty or it can be +// needed depending on the session user access rights (usually an administrator +// can change a user's password without knowing the current one) and the +// password policy (see pwdSafeModify password policy's attribute) +// +// newPassword is the desired user's password. If empty the server can return +// an error or generate a new password that will be available in the +// PasswordModifyResult.GeneratedPassword +// +func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest { + return &PasswordModifyRequest{ + UserIdentity: userIdentity, + OldPassword: oldPassword, + NewPassword: newPassword, + } +} + +// PasswordModify performs the modification request +func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + + encodedPasswordModifyRequest, err := passwordModifyRequest.encode() + if err != nil { + return nil, err + } + packet.AppendChild(encodedPasswordModifyRequest) + + l.Debug.PrintPacket(packet) + + msgCtx, err := l.sendMessage(packet) + if err != nil { + return nil, err + } + defer l.finishMessage(msgCtx) + + result := &PasswordModifyResult{} + + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return nil, err + } + + if packet == nil { + return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + return nil, err + } + ber.PrintPacket(packet) + } + + if packet.Children[1].Tag == ApplicationExtendedResponse { + resultCode, resultDescription := getLDAPResultCode(packet) + if resultCode != 0 { + return nil, NewError(resultCode, errors.New(resultDescription)) + } + } else { + return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag)) + } + + extendedResponse := packet.Children[1] + for _, child := range extendedResponse.Children { + if child.Tag == 11 { + passwordModifyResponseValue := ber.DecodePacket(child.Data.Bytes()) + if len(passwordModifyResponseValue.Children) == 1 { + if passwordModifyResponseValue.Children[0].Tag == 0 { + result.GeneratedPassword = ber.DecodeString(passwordModifyResponseValue.Children[0].Data.Bytes()) + } + } + } + } + + return result, nil +} diff --git a/vendor/gopkg.in/ldap.v2/search.go b/vendor/gopkg.in/ldap.v2/search.go new file mode 100644 index 00000000..2a99894c --- /dev/null +++ b/vendor/gopkg.in/ldap.v2/search.go @@ -0,0 +1,450 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// File contains Search functionality +// +// https://tools.ietf.org/html/rfc4511 +// +// SearchRequest ::= [APPLICATION 3] SEQUENCE { +// baseObject LDAPDN, +// scope ENUMERATED { +// baseObject (0), +// singleLevel (1), +// wholeSubtree (2), +// ... }, +// derefAliases ENUMERATED { +// neverDerefAliases (0), +// derefInSearching (1), +// derefFindingBaseObj (2), +// derefAlways (3) }, +// sizeLimit INTEGER (0 .. maxInt), +// timeLimit INTEGER (0 .. maxInt), +// typesOnly BOOLEAN, +// filter Filter, +// attributes AttributeSelection } +// +// AttributeSelection ::= SEQUENCE OF selector LDAPString +// -- The LDAPString is constrained to +// -- in Section 4.5.1.8 +// +// Filter ::= CHOICE { +// and [0] SET SIZE (1..MAX) OF filter Filter, +// or [1] SET SIZE (1..MAX) OF filter Filter, +// not [2] Filter, +// equalityMatch [3] AttributeValueAssertion, +// substrings [4] SubstringFilter, +// greaterOrEqual [5] AttributeValueAssertion, +// lessOrEqual [6] AttributeValueAssertion, +// present [7] AttributeDescription, +// approxMatch [8] AttributeValueAssertion, +// extensibleMatch [9] MatchingRuleAssertion, +// ... } +// +// SubstringFilter ::= SEQUENCE { +// type AttributeDescription, +// substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE { +// initial [0] AssertionValue, -- can occur at most once +// any [1] AssertionValue, +// final [2] AssertionValue } -- can occur at most once +// } +// +// MatchingRuleAssertion ::= SEQUENCE { +// matchingRule [1] MatchingRuleId OPTIONAL, +// type [2] AttributeDescription OPTIONAL, +// matchValue [3] AssertionValue, +// dnAttributes [4] BOOLEAN DEFAULT FALSE } +// +// + +package ldap + +import ( + "errors" + "fmt" + "sort" + "strings" + + "gopkg.in/asn1-ber.v1" +) + +// scope choices +const ( + ScopeBaseObject = 0 + ScopeSingleLevel = 1 + ScopeWholeSubtree = 2 +) + +// ScopeMap contains human readable descriptions of scope choices +var ScopeMap = map[int]string{ + ScopeBaseObject: "Base Object", + ScopeSingleLevel: "Single Level", + ScopeWholeSubtree: "Whole Subtree", +} + +// derefAliases +const ( + NeverDerefAliases = 0 + DerefInSearching = 1 + DerefFindingBaseObj = 2 + DerefAlways = 3 +) + +// DerefMap contains human readable descriptions of derefAliases choices +var DerefMap = map[int]string{ + NeverDerefAliases: "NeverDerefAliases", + DerefInSearching: "DerefInSearching", + DerefFindingBaseObj: "DerefFindingBaseObj", + DerefAlways: "DerefAlways", +} + +// NewEntry returns an Entry object with the specified distinguished name and attribute key-value pairs. +// The map of attributes is accessed in alphabetical order of the keys in order to ensure that, for the +// same input map of attributes, the output entry will contain the same order of attributes +func NewEntry(dn string, attributes map[string][]string) *Entry { + var attributeNames []string + for attributeName := range attributes { + attributeNames = append(attributeNames, attributeName) + } + sort.Strings(attributeNames) + + var encodedAttributes []*EntryAttribute + for _, attributeName := range attributeNames { + encodedAttributes = append(encodedAttributes, NewEntryAttribute(attributeName, attributes[attributeName])) + } + return &Entry{ + DN: dn, + Attributes: encodedAttributes, + } +} + +// Entry represents a single search result entry +type Entry struct { + // DN is the distinguished name of the entry + DN string + // Attributes are the returned attributes for the entry + Attributes []*EntryAttribute +} + +// GetAttributeValues returns the values for the named attribute, or an empty list +func (e *Entry) GetAttributeValues(attribute string) []string { + for _, attr := range e.Attributes { + if attr.Name == attribute { + return attr.Values + } + } + return []string{} +} + +// GetRawAttributeValues returns the byte values for the named attribute, or an empty list +func (e *Entry) GetRawAttributeValues(attribute string) [][]byte { + for _, attr := range e.Attributes { + if attr.Name == attribute { + return attr.ByteValues + } + } + return [][]byte{} +} + +// GetAttributeValue returns the first value for the named attribute, or "" +func (e *Entry) GetAttributeValue(attribute string) string { + values := e.GetAttributeValues(attribute) + if len(values) == 0 { + return "" + } + return values[0] +} + +// GetRawAttributeValue returns the first value for the named attribute, or an empty slice +func (e *Entry) GetRawAttributeValue(attribute string) []byte { + values := e.GetRawAttributeValues(attribute) + if len(values) == 0 { + return []byte{} + } + return values[0] +} + +// Print outputs a human-readable description +func (e *Entry) Print() { + fmt.Printf("DN: %s\n", e.DN) + for _, attr := range e.Attributes { + attr.Print() + } +} + +// PrettyPrint outputs a human-readable description indenting +func (e *Entry) PrettyPrint(indent int) { + fmt.Printf("%sDN: %s\n", strings.Repeat(" ", indent), e.DN) + for _, attr := range e.Attributes { + attr.PrettyPrint(indent + 2) + } +} + +// NewEntryAttribute returns a new EntryAttribute with the desired key-value pair +func NewEntryAttribute(name string, values []string) *EntryAttribute { + var bytes [][]byte + for _, value := range values { + bytes = append(bytes, []byte(value)) + } + return &EntryAttribute{ + Name: name, + Values: values, + ByteValues: bytes, + } +} + +// EntryAttribute holds a single attribute +type EntryAttribute struct { + // Name is the name of the attribute + Name string + // Values contain the string values of the attribute + Values []string + // ByteValues contain the raw values of the attribute + ByteValues [][]byte +} + +// Print outputs a human-readable description +func (e *EntryAttribute) Print() { + fmt.Printf("%s: %s\n", e.Name, e.Values) +} + +// PrettyPrint outputs a human-readable description with indenting +func (e *EntryAttribute) PrettyPrint(indent int) { + fmt.Printf("%s%s: %s\n", strings.Repeat(" ", indent), e.Name, e.Values) +} + +// SearchResult holds the server's response to a search request +type SearchResult struct { + // Entries are the returned entries + Entries []*Entry + // Referrals are the returned referrals + Referrals []string + // Controls are the returned controls + Controls []Control +} + +// Print outputs a human-readable description +func (s *SearchResult) Print() { + for _, entry := range s.Entries { + entry.Print() + } +} + +// PrettyPrint outputs a human-readable description with indenting +func (s *SearchResult) PrettyPrint(indent int) { + for _, entry := range s.Entries { + entry.PrettyPrint(indent) + } +} + +// SearchRequest represents a search request to send to the server +type SearchRequest struct { + BaseDN string + Scope int + DerefAliases int + SizeLimit int + TimeLimit int + TypesOnly bool + Filter string + Attributes []string + Controls []Control +} + +func (s *SearchRequest) encode() (*ber.Packet, error) { + request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationSearchRequest, nil, "Search Request") + request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, s.BaseDN, "Base DN")) + request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.Scope), "Scope")) + request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(s.DerefAliases), "Deref Aliases")) + request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.SizeLimit), "Size Limit")) + request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, uint64(s.TimeLimit), "Time Limit")) + request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, s.TypesOnly, "Types Only")) + // compile and encode filter + filterPacket, err := CompileFilter(s.Filter) + if err != nil { + return nil, err + } + request.AppendChild(filterPacket) + // encode attributes + attributesPacket := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes") + for _, attribute := range s.Attributes { + attributesPacket.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "Attribute")) + } + request.AppendChild(attributesPacket) + return request, nil +} + +// NewSearchRequest creates a new search request +func NewSearchRequest( + BaseDN string, + Scope, DerefAliases, SizeLimit, TimeLimit int, + TypesOnly bool, + Filter string, + Attributes []string, + Controls []Control, +) *SearchRequest { + return &SearchRequest{ + BaseDN: BaseDN, + Scope: Scope, + DerefAliases: DerefAliases, + SizeLimit: SizeLimit, + TimeLimit: TimeLimit, + TypesOnly: TypesOnly, + Filter: Filter, + Attributes: Attributes, + Controls: Controls, + } +} + +// SearchWithPaging accepts a search request and desired page size in order to execute LDAP queries to fulfill the +// search request. All paged LDAP query responses will be buffered and the final result will be returned atomically. +// The following four cases are possible given the arguments: +// - given SearchRequest missing a control of type ControlTypePaging: we will add one with the desired paging size +// - given SearchRequest contains a control of type ControlTypePaging that isn't actually a ControlPaging: fail without issuing any queries +// - given SearchRequest contains a control of type ControlTypePaging with pagingSize equal to the size requested: no change to the search request +// - given SearchRequest contains a control of type ControlTypePaging with pagingSize not equal to the size requested: fail without issuing any queries +// A requested pagingSize of 0 is interpreted as no limit by LDAP servers. +func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) { + var pagingControl *ControlPaging + + control := FindControl(searchRequest.Controls, ControlTypePaging) + if control == nil { + pagingControl = NewControlPaging(pagingSize) + searchRequest.Controls = append(searchRequest.Controls, pagingControl) + } else { + castControl, ok := control.(*ControlPaging) + if !ok { + return nil, fmt.Errorf("Expected paging control to be of type *ControlPaging, got %v", control) + } + if castControl.PagingSize != pagingSize { + return nil, fmt.Errorf("Paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize) + } + pagingControl = castControl + } + + searchResult := new(SearchResult) + for { + result, err := l.Search(searchRequest) + l.Debug.Printf("Looking for Paging Control...") + if err != nil { + return searchResult, err + } + if result == nil { + return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received")) + } + + for _, entry := range result.Entries { + searchResult.Entries = append(searchResult.Entries, entry) + } + for _, referral := range result.Referrals { + searchResult.Referrals = append(searchResult.Referrals, referral) + } + for _, control := range result.Controls { + searchResult.Controls = append(searchResult.Controls, control) + } + + l.Debug.Printf("Looking for Paging Control...") + pagingResult := FindControl(result.Controls, ControlTypePaging) + if pagingResult == nil { + pagingControl = nil + l.Debug.Printf("Could not find paging control. Breaking...") + break + } + + cookie := pagingResult.(*ControlPaging).Cookie + if len(cookie) == 0 { + pagingControl = nil + l.Debug.Printf("Could not find cookie. Breaking...") + break + } + pagingControl.SetCookie(cookie) + } + + if pagingControl != nil { + l.Debug.Printf("Abandoning Paging...") + pagingControl.PagingSize = 0 + l.Search(searchRequest) + } + + return searchResult, nil +} + +// Search performs the given search request +func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) + // encode search request + encodedSearchRequest, err := searchRequest.encode() + if err != nil { + return nil, err + } + packet.AppendChild(encodedSearchRequest) + // encode search controls + if searchRequest.Controls != nil { + packet.AppendChild(encodeControls(searchRequest.Controls)) + } + + l.Debug.PrintPacket(packet) + + msgCtx, err := l.sendMessage(packet) + if err != nil { + return nil, err + } + defer l.finishMessage(msgCtx) + + result := &SearchResult{ + Entries: make([]*Entry, 0), + Referrals: make([]string, 0), + Controls: make([]Control, 0)} + + foundSearchResultDone := false + for !foundSearchResultDone { + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses + if !ok { + return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed")) + } + packet, err = packetResponse.ReadPacket() + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return nil, err + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + return nil, err + } + ber.PrintPacket(packet) + } + + switch packet.Children[1].Tag { + case 4: + entry := new(Entry) + entry.DN = packet.Children[1].Children[0].Value.(string) + for _, child := range packet.Children[1].Children[1].Children { + attr := new(EntryAttribute) + attr.Name = child.Children[0].Value.(string) + for _, value := range child.Children[1].Children { + attr.Values = append(attr.Values, value.Value.(string)) + attr.ByteValues = append(attr.ByteValues, value.ByteValue) + } + entry.Attributes = append(entry.Attributes, attr) + } + result.Entries = append(result.Entries, entry) + case 5: + resultCode, resultDescription := getLDAPResultCode(packet) + if resultCode != 0 { + return result, NewError(resultCode, errors.New(resultDescription)) + } + if len(packet.Children) == 3 { + for _, child := range packet.Children[2].Children { + result.Controls = append(result.Controls, DecodeControl(child)) + } + } + foundSearchResultDone = true + case 19: + result.Referrals = append(result.Referrals, packet.Children[1].Children[0].Value.(string)) + } + } + l.Debug.Printf("%d: returning", msgCtx.id) + return result, nil +} diff --git a/vendor/gopkg.in/yaml.v3/LICENSE b/vendor/gopkg.in/yaml.v3/LICENSE new file mode 100644 index 00000000..2683e4bb --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/LICENSE @@ -0,0 +1,50 @@ + +This project is covered by two different licenses: MIT and Apache. + +#### MIT License #### + +The following files were ported to Go from C files of libyaml, and thus +are still covered by their original MIT license, with the additional +copyright staring in 2011 when the project was ported over: + + apic.go emitterc.go parserc.go readerc.go scannerc.go + writerc.go yamlh.go yamlprivateh.go + +Copyright (c) 2006-2010 Kirill Simonov +Copyright (c) 2006-2011 Kirill Simonov + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +### Apache License ### + +All the remaining project files are covered by the Apache license: + +Copyright (c) 2011-2019 Canonical Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/gopkg.in/yaml.v3/NOTICE b/vendor/gopkg.in/yaml.v3/NOTICE new file mode 100644 index 00000000..866d74a7 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/NOTICE @@ -0,0 +1,13 @@ +Copyright 2011-2016 Canonical Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/gopkg.in/yaml.v3/README.md b/vendor/gopkg.in/yaml.v3/README.md new file mode 100644 index 00000000..08eb1bab --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/README.md @@ -0,0 +1,150 @@ +# YAML support for the Go language + +Introduction +------------ + +The yaml package enables Go programs to comfortably encode and decode YAML +values. It was developed within [Canonical](https://www.canonical.com) as +part of the [juju](https://juju.ubuntu.com) project, and is based on a +pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) +C library to parse and generate YAML data quickly and reliably. + +Compatibility +------------- + +The yaml package supports most of YAML 1.2, but preserves some behavior +from 1.1 for backwards compatibility. + +Specifically, as of v3 of the yaml package: + + - YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being + decoded into a typed bool value. Otherwise they behave as a string. Booleans + in YAML 1.2 are _true/false_ only. + - Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_ + as specified in YAML 1.2, because most parsers still use the old format. + Octals in the _0o777_ format are supported though, so new files work. + - Does not support base-60 floats. These are gone from YAML 1.2, and were + actually never supported by this package as it's clearly a poor choice. + +and offers backwards +compatibility with YAML 1.1 in some cases. +1.2, including support for +anchors, tags, map merging, etc. Multi-document unmarshalling is not yet +implemented, and base-60 floats from YAML 1.1 are purposefully not +supported since they're a poor design and are gone in YAML 1.2. + +Installation and usage +---------------------- + +The import path for the package is *gopkg.in/yaml.v3*. + +To install it, run: + + go get gopkg.in/yaml.v3 + +API documentation +----------------- + +If opened in a browser, the import path itself leads to the API documentation: + + - [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3) + +API stability +------------- + +The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in). + + +License +------- + +The yaml package is licensed under the MIT and Apache License 2.0 licenses. +Please see the LICENSE file for details. + + +Example +------- + +```Go +package main + +import ( + "fmt" + "log" + + "gopkg.in/yaml.v3" +) + +var data = ` +a: Easy! +b: + c: 2 + d: [3, 4] +` + +// Note: struct fields must be public in order for unmarshal to +// correctly populate the data. +type T struct { + A string + B struct { + RenamedC int `yaml:"c"` + D []int `yaml:",flow"` + } +} + +func main() { + t := T{} + + err := yaml.Unmarshal([]byte(data), &t) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- t:\n%v\n\n", t) + + d, err := yaml.Marshal(&t) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- t dump:\n%s\n\n", string(d)) + + m := make(map[interface{}]interface{}) + + err = yaml.Unmarshal([]byte(data), &m) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- m:\n%v\n\n", m) + + d, err = yaml.Marshal(&m) + if err != nil { + log.Fatalf("error: %v", err) + } + fmt.Printf("--- m dump:\n%s\n\n", string(d)) +} +``` + +This example will generate the following output: + +``` +--- t: +{Easy! {2 [3 4]}} + +--- t dump: +a: Easy! +b: + c: 2 + d: [3, 4] + + +--- m: +map[a:Easy! b:map[c:2 d:[3 4]]] + +--- m dump: +a: Easy! +b: + c: 2 + d: + - 3 + - 4 +``` + diff --git a/vendor/gopkg.in/yaml.v3/apic.go b/vendor/gopkg.in/yaml.v3/apic.go new file mode 100644 index 00000000..ae7d049f --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/apic.go @@ -0,0 +1,747 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package yaml + +import ( + "io" +) + +func yaml_insert_token(parser *yaml_parser_t, pos int, token *yaml_token_t) { + //fmt.Println("yaml_insert_token", "pos:", pos, "typ:", token.typ, "head:", parser.tokens_head, "len:", len(parser.tokens)) + + // Check if we can move the queue at the beginning of the buffer. + if parser.tokens_head > 0 && len(parser.tokens) == cap(parser.tokens) { + if parser.tokens_head != len(parser.tokens) { + copy(parser.tokens, parser.tokens[parser.tokens_head:]) + } + parser.tokens = parser.tokens[:len(parser.tokens)-parser.tokens_head] + parser.tokens_head = 0 + } + parser.tokens = append(parser.tokens, *token) + if pos < 0 { + return + } + copy(parser.tokens[parser.tokens_head+pos+1:], parser.tokens[parser.tokens_head+pos:]) + parser.tokens[parser.tokens_head+pos] = *token +} + +// Create a new parser object. +func yaml_parser_initialize(parser *yaml_parser_t) bool { + *parser = yaml_parser_t{ + raw_buffer: make([]byte, 0, input_raw_buffer_size), + buffer: make([]byte, 0, input_buffer_size), + } + return true +} + +// Destroy a parser object. +func yaml_parser_delete(parser *yaml_parser_t) { + *parser = yaml_parser_t{} +} + +// String read handler. +func yaml_string_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { + if parser.input_pos == len(parser.input) { + return 0, io.EOF + } + n = copy(buffer, parser.input[parser.input_pos:]) + parser.input_pos += n + return n, nil +} + +// Reader read handler. +func yaml_reader_read_handler(parser *yaml_parser_t, buffer []byte) (n int, err error) { + return parser.input_reader.Read(buffer) +} + +// Set a string input. +func yaml_parser_set_input_string(parser *yaml_parser_t, input []byte) { + if parser.read_handler != nil { + panic("must set the input source only once") + } + parser.read_handler = yaml_string_read_handler + parser.input = input + parser.input_pos = 0 +} + +// Set a file input. +func yaml_parser_set_input_reader(parser *yaml_parser_t, r io.Reader) { + if parser.read_handler != nil { + panic("must set the input source only once") + } + parser.read_handler = yaml_reader_read_handler + parser.input_reader = r +} + +// Set the source encoding. +func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) { + if parser.encoding != yaml_ANY_ENCODING { + panic("must set the encoding only once") + } + parser.encoding = encoding +} + +// Create a new emitter object. +func yaml_emitter_initialize(emitter *yaml_emitter_t) { + *emitter = yaml_emitter_t{ + buffer: make([]byte, output_buffer_size), + raw_buffer: make([]byte, 0, output_raw_buffer_size), + states: make([]yaml_emitter_state_t, 0, initial_stack_size), + events: make([]yaml_event_t, 0, initial_queue_size), + best_width: -1, + } +} + +// Destroy an emitter object. +func yaml_emitter_delete(emitter *yaml_emitter_t) { + *emitter = yaml_emitter_t{} +} + +// String write handler. +func yaml_string_write_handler(emitter *yaml_emitter_t, buffer []byte) error { + *emitter.output_buffer = append(*emitter.output_buffer, buffer...) + return nil +} + +// yaml_writer_write_handler uses emitter.output_writer to write the +// emitted text. +func yaml_writer_write_handler(emitter *yaml_emitter_t, buffer []byte) error { + _, err := emitter.output_writer.Write(buffer) + return err +} + +// Set a string output. +func yaml_emitter_set_output_string(emitter *yaml_emitter_t, output_buffer *[]byte) { + if emitter.write_handler != nil { + panic("must set the output target only once") + } + emitter.write_handler = yaml_string_write_handler + emitter.output_buffer = output_buffer +} + +// Set a file output. +func yaml_emitter_set_output_writer(emitter *yaml_emitter_t, w io.Writer) { + if emitter.write_handler != nil { + panic("must set the output target only once") + } + emitter.write_handler = yaml_writer_write_handler + emitter.output_writer = w +} + +// Set the output encoding. +func yaml_emitter_set_encoding(emitter *yaml_emitter_t, encoding yaml_encoding_t) { + if emitter.encoding != yaml_ANY_ENCODING { + panic("must set the output encoding only once") + } + emitter.encoding = encoding +} + +// Set the canonical output style. +func yaml_emitter_set_canonical(emitter *yaml_emitter_t, canonical bool) { + emitter.canonical = canonical +} + +// Set the indentation increment. +func yaml_emitter_set_indent(emitter *yaml_emitter_t, indent int) { + if indent < 2 || indent > 9 { + indent = 2 + } + emitter.best_indent = indent +} + +// Set the preferred line width. +func yaml_emitter_set_width(emitter *yaml_emitter_t, width int) { + if width < 0 { + width = -1 + } + emitter.best_width = width +} + +// Set if unescaped non-ASCII characters are allowed. +func yaml_emitter_set_unicode(emitter *yaml_emitter_t, unicode bool) { + emitter.unicode = unicode +} + +// Set the preferred line break character. +func yaml_emitter_set_break(emitter *yaml_emitter_t, line_break yaml_break_t) { + emitter.line_break = line_break +} + +///* +// * Destroy a token object. +// */ +// +//YAML_DECLARE(void) +//yaml_token_delete(yaml_token_t *token) +//{ +// assert(token); // Non-NULL token object expected. +// +// switch (token.type) +// { +// case YAML_TAG_DIRECTIVE_TOKEN: +// yaml_free(token.data.tag_directive.handle); +// yaml_free(token.data.tag_directive.prefix); +// break; +// +// case YAML_ALIAS_TOKEN: +// yaml_free(token.data.alias.value); +// break; +// +// case YAML_ANCHOR_TOKEN: +// yaml_free(token.data.anchor.value); +// break; +// +// case YAML_TAG_TOKEN: +// yaml_free(token.data.tag.handle); +// yaml_free(token.data.tag.suffix); +// break; +// +// case YAML_SCALAR_TOKEN: +// yaml_free(token.data.scalar.value); +// break; +// +// default: +// break; +// } +// +// memset(token, 0, sizeof(yaml_token_t)); +//} +// +///* +// * Check if a string is a valid UTF-8 sequence. +// * +// * Check 'reader.c' for more details on UTF-8 encoding. +// */ +// +//static int +//yaml_check_utf8(yaml_char_t *start, size_t length) +//{ +// yaml_char_t *end = start+length; +// yaml_char_t *pointer = start; +// +// while (pointer < end) { +// unsigned char octet; +// unsigned int width; +// unsigned int value; +// size_t k; +// +// octet = pointer[0]; +// width = (octet & 0x80) == 0x00 ? 1 : +// (octet & 0xE0) == 0xC0 ? 2 : +// (octet & 0xF0) == 0xE0 ? 3 : +// (octet & 0xF8) == 0xF0 ? 4 : 0; +// value = (octet & 0x80) == 0x00 ? octet & 0x7F : +// (octet & 0xE0) == 0xC0 ? octet & 0x1F : +// (octet & 0xF0) == 0xE0 ? octet & 0x0F : +// (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; +// if (!width) return 0; +// if (pointer+width > end) return 0; +// for (k = 1; k < width; k ++) { +// octet = pointer[k]; +// if ((octet & 0xC0) != 0x80) return 0; +// value = (value << 6) + (octet & 0x3F); +// } +// if (!((width == 1) || +// (width == 2 && value >= 0x80) || +// (width == 3 && value >= 0x800) || +// (width == 4 && value >= 0x10000))) return 0; +// +// pointer += width; +// } +// +// return 1; +//} +// + +// Create STREAM-START. +func yaml_stream_start_event_initialize(event *yaml_event_t, encoding yaml_encoding_t) { + *event = yaml_event_t{ + typ: yaml_STREAM_START_EVENT, + encoding: encoding, + } +} + +// Create STREAM-END. +func yaml_stream_end_event_initialize(event *yaml_event_t) { + *event = yaml_event_t{ + typ: yaml_STREAM_END_EVENT, + } +} + +// Create DOCUMENT-START. +func yaml_document_start_event_initialize( + event *yaml_event_t, + version_directive *yaml_version_directive_t, + tag_directives []yaml_tag_directive_t, + implicit bool, +) { + *event = yaml_event_t{ + typ: yaml_DOCUMENT_START_EVENT, + version_directive: version_directive, + tag_directives: tag_directives, + implicit: implicit, + } +} + +// Create DOCUMENT-END. +func yaml_document_end_event_initialize(event *yaml_event_t, implicit bool) { + *event = yaml_event_t{ + typ: yaml_DOCUMENT_END_EVENT, + implicit: implicit, + } +} + +// Create ALIAS. +func yaml_alias_event_initialize(event *yaml_event_t, anchor []byte) bool { + *event = yaml_event_t{ + typ: yaml_ALIAS_EVENT, + anchor: anchor, + } + return true +} + +// Create SCALAR. +func yaml_scalar_event_initialize(event *yaml_event_t, anchor, tag, value []byte, plain_implicit, quoted_implicit bool, style yaml_scalar_style_t) bool { + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + anchor: anchor, + tag: tag, + value: value, + implicit: plain_implicit, + quoted_implicit: quoted_implicit, + style: yaml_style_t(style), + } + return true +} + +// Create SEQUENCE-START. +func yaml_sequence_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_sequence_style_t) bool { + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(style), + } + return true +} + +// Create SEQUENCE-END. +func yaml_sequence_end_event_initialize(event *yaml_event_t) bool { + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + } + return true +} + +// Create MAPPING-START. +func yaml_mapping_start_event_initialize(event *yaml_event_t, anchor, tag []byte, implicit bool, style yaml_mapping_style_t) { + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(style), + } +} + +// Create MAPPING-END. +func yaml_mapping_end_event_initialize(event *yaml_event_t) { + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + } +} + +// Destroy an event object. +func yaml_event_delete(event *yaml_event_t) { + *event = yaml_event_t{} +} + +///* +// * Create a document object. +// */ +// +//YAML_DECLARE(int) +//yaml_document_initialize(document *yaml_document_t, +// version_directive *yaml_version_directive_t, +// tag_directives_start *yaml_tag_directive_t, +// tag_directives_end *yaml_tag_directive_t, +// start_implicit int, end_implicit int) +//{ +// struct { +// error yaml_error_type_t +// } context +// struct { +// start *yaml_node_t +// end *yaml_node_t +// top *yaml_node_t +// } nodes = { NULL, NULL, NULL } +// version_directive_copy *yaml_version_directive_t = NULL +// struct { +// start *yaml_tag_directive_t +// end *yaml_tag_directive_t +// top *yaml_tag_directive_t +// } tag_directives_copy = { NULL, NULL, NULL } +// value yaml_tag_directive_t = { NULL, NULL } +// mark yaml_mark_t = { 0, 0, 0 } +// +// assert(document) // Non-NULL document object is expected. +// assert((tag_directives_start && tag_directives_end) || +// (tag_directives_start == tag_directives_end)) +// // Valid tag directives are expected. +// +// if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error +// +// if (version_directive) { +// version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)) +// if (!version_directive_copy) goto error +// version_directive_copy.major = version_directive.major +// version_directive_copy.minor = version_directive.minor +// } +// +// if (tag_directives_start != tag_directives_end) { +// tag_directive *yaml_tag_directive_t +// if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) +// goto error +// for (tag_directive = tag_directives_start +// tag_directive != tag_directives_end; tag_directive ++) { +// assert(tag_directive.handle) +// assert(tag_directive.prefix) +// if (!yaml_check_utf8(tag_directive.handle, +// strlen((char *)tag_directive.handle))) +// goto error +// if (!yaml_check_utf8(tag_directive.prefix, +// strlen((char *)tag_directive.prefix))) +// goto error +// value.handle = yaml_strdup(tag_directive.handle) +// value.prefix = yaml_strdup(tag_directive.prefix) +// if (!value.handle || !value.prefix) goto error +// if (!PUSH(&context, tag_directives_copy, value)) +// goto error +// value.handle = NULL +// value.prefix = NULL +// } +// } +// +// DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, +// tag_directives_copy.start, tag_directives_copy.top, +// start_implicit, end_implicit, mark, mark) +// +// return 1 +// +//error: +// STACK_DEL(&context, nodes) +// yaml_free(version_directive_copy) +// while (!STACK_EMPTY(&context, tag_directives_copy)) { +// value yaml_tag_directive_t = POP(&context, tag_directives_copy) +// yaml_free(value.handle) +// yaml_free(value.prefix) +// } +// STACK_DEL(&context, tag_directives_copy) +// yaml_free(value.handle) +// yaml_free(value.prefix) +// +// return 0 +//} +// +///* +// * Destroy a document object. +// */ +// +//YAML_DECLARE(void) +//yaml_document_delete(document *yaml_document_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// tag_directive *yaml_tag_directive_t +// +// context.error = YAML_NO_ERROR // Eliminate a compiler warning. +// +// assert(document) // Non-NULL document object is expected. +// +// while (!STACK_EMPTY(&context, document.nodes)) { +// node yaml_node_t = POP(&context, document.nodes) +// yaml_free(node.tag) +// switch (node.type) { +// case YAML_SCALAR_NODE: +// yaml_free(node.data.scalar.value) +// break +// case YAML_SEQUENCE_NODE: +// STACK_DEL(&context, node.data.sequence.items) +// break +// case YAML_MAPPING_NODE: +// STACK_DEL(&context, node.data.mapping.pairs) +// break +// default: +// assert(0) // Should not happen. +// } +// } +// STACK_DEL(&context, document.nodes) +// +// yaml_free(document.version_directive) +// for (tag_directive = document.tag_directives.start +// tag_directive != document.tag_directives.end +// tag_directive++) { +// yaml_free(tag_directive.handle) +// yaml_free(tag_directive.prefix) +// } +// yaml_free(document.tag_directives.start) +// +// memset(document, 0, sizeof(yaml_document_t)) +//} +// +///** +// * Get a document node. +// */ +// +//YAML_DECLARE(yaml_node_t *) +//yaml_document_get_node(document *yaml_document_t, index int) +//{ +// assert(document) // Non-NULL document object is expected. +// +// if (index > 0 && document.nodes.start + index <= document.nodes.top) { +// return document.nodes.start + index - 1 +// } +// return NULL +//} +// +///** +// * Get the root object. +// */ +// +//YAML_DECLARE(yaml_node_t *) +//yaml_document_get_root_node(document *yaml_document_t) +//{ +// assert(document) // Non-NULL document object is expected. +// +// if (document.nodes.top != document.nodes.start) { +// return document.nodes.start +// } +// return NULL +//} +// +///* +// * Add a scalar node to a document. +// */ +// +//YAML_DECLARE(int) +//yaml_document_add_scalar(document *yaml_document_t, +// tag *yaml_char_t, value *yaml_char_t, length int, +// style yaml_scalar_style_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// mark yaml_mark_t = { 0, 0, 0 } +// tag_copy *yaml_char_t = NULL +// value_copy *yaml_char_t = NULL +// node yaml_node_t +// +// assert(document) // Non-NULL document object is expected. +// assert(value) // Non-NULL value is expected. +// +// if (!tag) { +// tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG +// } +// +// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error +// tag_copy = yaml_strdup(tag) +// if (!tag_copy) goto error +// +// if (length < 0) { +// length = strlen((char *)value) +// } +// +// if (!yaml_check_utf8(value, length)) goto error +// value_copy = yaml_malloc(length+1) +// if (!value_copy) goto error +// memcpy(value_copy, value, length) +// value_copy[length] = '\0' +// +// SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark) +// if (!PUSH(&context, document.nodes, node)) goto error +// +// return document.nodes.top - document.nodes.start +// +//error: +// yaml_free(tag_copy) +// yaml_free(value_copy) +// +// return 0 +//} +// +///* +// * Add a sequence node to a document. +// */ +// +//YAML_DECLARE(int) +//yaml_document_add_sequence(document *yaml_document_t, +// tag *yaml_char_t, style yaml_sequence_style_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// mark yaml_mark_t = { 0, 0, 0 } +// tag_copy *yaml_char_t = NULL +// struct { +// start *yaml_node_item_t +// end *yaml_node_item_t +// top *yaml_node_item_t +// } items = { NULL, NULL, NULL } +// node yaml_node_t +// +// assert(document) // Non-NULL document object is expected. +// +// if (!tag) { +// tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG +// } +// +// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error +// tag_copy = yaml_strdup(tag) +// if (!tag_copy) goto error +// +// if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error +// +// SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, +// style, mark, mark) +// if (!PUSH(&context, document.nodes, node)) goto error +// +// return document.nodes.top - document.nodes.start +// +//error: +// STACK_DEL(&context, items) +// yaml_free(tag_copy) +// +// return 0 +//} +// +///* +// * Add a mapping node to a document. +// */ +// +//YAML_DECLARE(int) +//yaml_document_add_mapping(document *yaml_document_t, +// tag *yaml_char_t, style yaml_mapping_style_t) +//{ +// struct { +// error yaml_error_type_t +// } context +// mark yaml_mark_t = { 0, 0, 0 } +// tag_copy *yaml_char_t = NULL +// struct { +// start *yaml_node_pair_t +// end *yaml_node_pair_t +// top *yaml_node_pair_t +// } pairs = { NULL, NULL, NULL } +// node yaml_node_t +// +// assert(document) // Non-NULL document object is expected. +// +// if (!tag) { +// tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG +// } +// +// if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error +// tag_copy = yaml_strdup(tag) +// if (!tag_copy) goto error +// +// if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error +// +// MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, +// style, mark, mark) +// if (!PUSH(&context, document.nodes, node)) goto error +// +// return document.nodes.top - document.nodes.start +// +//error: +// STACK_DEL(&context, pairs) +// yaml_free(tag_copy) +// +// return 0 +//} +// +///* +// * Append an item to a sequence node. +// */ +// +//YAML_DECLARE(int) +//yaml_document_append_sequence_item(document *yaml_document_t, +// sequence int, item int) +//{ +// struct { +// error yaml_error_type_t +// } context +// +// assert(document) // Non-NULL document is required. +// assert(sequence > 0 +// && document.nodes.start + sequence <= document.nodes.top) +// // Valid sequence id is required. +// assert(document.nodes.start[sequence-1].type == YAML_SEQUENCE_NODE) +// // A sequence node is required. +// assert(item > 0 && document.nodes.start + item <= document.nodes.top) +// // Valid item id is required. +// +// if (!PUSH(&context, +// document.nodes.start[sequence-1].data.sequence.items, item)) +// return 0 +// +// return 1 +//} +// +///* +// * Append a pair of a key and a value to a mapping node. +// */ +// +//YAML_DECLARE(int) +//yaml_document_append_mapping_pair(document *yaml_document_t, +// mapping int, key int, value int) +//{ +// struct { +// error yaml_error_type_t +// } context +// +// pair yaml_node_pair_t +// +// assert(document) // Non-NULL document is required. +// assert(mapping > 0 +// && document.nodes.start + mapping <= document.nodes.top) +// // Valid mapping id is required. +// assert(document.nodes.start[mapping-1].type == YAML_MAPPING_NODE) +// // A mapping node is required. +// assert(key > 0 && document.nodes.start + key <= document.nodes.top) +// // Valid key id is required. +// assert(value > 0 && document.nodes.start + value <= document.nodes.top) +// // Valid value id is required. +// +// pair.key = key +// pair.value = value +// +// if (!PUSH(&context, +// document.nodes.start[mapping-1].data.mapping.pairs, pair)) +// return 0 +// +// return 1 +//} +// +// diff --git a/vendor/gopkg.in/yaml.v3/decode.go b/vendor/gopkg.in/yaml.v3/decode.go new file mode 100644 index 00000000..df36e3a3 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/decode.go @@ -0,0 +1,950 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package yaml + +import ( + "encoding" + "encoding/base64" + "fmt" + "io" + "math" + "reflect" + "strconv" + "time" +) + +// ---------------------------------------------------------------------------- +// Parser, produces a node tree out of a libyaml event stream. + +type parser struct { + parser yaml_parser_t + event yaml_event_t + doc *Node + anchors map[string]*Node + doneInit bool + textless bool +} + +func newParser(b []byte) *parser { + p := parser{} + if !yaml_parser_initialize(&p.parser) { + panic("failed to initialize YAML emitter") + } + if len(b) == 0 { + b = []byte{'\n'} + } + yaml_parser_set_input_string(&p.parser, b) + return &p +} + +func newParserFromReader(r io.Reader) *parser { + p := parser{} + if !yaml_parser_initialize(&p.parser) { + panic("failed to initialize YAML emitter") + } + yaml_parser_set_input_reader(&p.parser, r) + return &p +} + +func (p *parser) init() { + if p.doneInit { + return + } + p.anchors = make(map[string]*Node) + p.expect(yaml_STREAM_START_EVENT) + p.doneInit = true +} + +func (p *parser) destroy() { + if p.event.typ != yaml_NO_EVENT { + yaml_event_delete(&p.event) + } + yaml_parser_delete(&p.parser) +} + +// expect consumes an event from the event stream and +// checks that it's of the expected type. +func (p *parser) expect(e yaml_event_type_t) { + if p.event.typ == yaml_NO_EVENT { + if !yaml_parser_parse(&p.parser, &p.event) { + p.fail() + } + } + if p.event.typ == yaml_STREAM_END_EVENT { + failf("attempted to go past the end of stream; corrupted value?") + } + if p.event.typ != e { + p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ) + p.fail() + } + yaml_event_delete(&p.event) + p.event.typ = yaml_NO_EVENT +} + +// peek peeks at the next event in the event stream, +// puts the results into p.event and returns the event type. +func (p *parser) peek() yaml_event_type_t { + if p.event.typ != yaml_NO_EVENT { + return p.event.typ + } + if !yaml_parser_parse(&p.parser, &p.event) { + p.fail() + } + return p.event.typ +} + +func (p *parser) fail() { + var where string + var line int + if p.parser.context_mark.line != 0 { + line = p.parser.context_mark.line + // Scanner errors don't iterate line before returning error + if p.parser.error == yaml_SCANNER_ERROR { + line++ + } + } else if p.parser.problem_mark.line != 0 { + line = p.parser.problem_mark.line + // Scanner errors don't iterate line before returning error + if p.parser.error == yaml_SCANNER_ERROR { + line++ + } + } + if line != 0 { + where = "line " + strconv.Itoa(line) + ": " + } + var msg string + if len(p.parser.problem) > 0 { + msg = p.parser.problem + } else { + msg = "unknown problem parsing YAML content" + } + failf("%s%s", where, msg) +} + +func (p *parser) anchor(n *Node, anchor []byte) { + if anchor != nil { + n.Anchor = string(anchor) + p.anchors[n.Anchor] = n + } +} + +func (p *parser) parse() *Node { + p.init() + switch p.peek() { + case yaml_SCALAR_EVENT: + return p.scalar() + case yaml_ALIAS_EVENT: + return p.alias() + case yaml_MAPPING_START_EVENT: + return p.mapping() + case yaml_SEQUENCE_START_EVENT: + return p.sequence() + case yaml_DOCUMENT_START_EVENT: + return p.document() + case yaml_STREAM_END_EVENT: + // Happens when attempting to decode an empty buffer. + return nil + case yaml_TAIL_COMMENT_EVENT: + panic("internal error: unexpected tail comment event (please report)") + default: + panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String()) + } +} + +func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node { + var style Style + if tag != "" && tag != "!" { + tag = shortTag(tag) + style = TaggedStyle + } else if defaultTag != "" { + tag = defaultTag + } else if kind == ScalarNode { + tag, _ = resolve("", value) + } + n := &Node{ + Kind: kind, + Tag: tag, + Value: value, + Style: style, + } + if !p.textless { + n.Line = p.event.start_mark.line + 1 + n.Column = p.event.start_mark.column + 1 + n.HeadComment = string(p.event.head_comment) + n.LineComment = string(p.event.line_comment) + n.FootComment = string(p.event.foot_comment) + } + return n +} + +func (p *parser) parseChild(parent *Node) *Node { + child := p.parse() + parent.Content = append(parent.Content, child) + return child +} + +func (p *parser) document() *Node { + n := p.node(DocumentNode, "", "", "") + p.doc = n + p.expect(yaml_DOCUMENT_START_EVENT) + p.parseChild(n) + if p.peek() == yaml_DOCUMENT_END_EVENT { + n.FootComment = string(p.event.foot_comment) + } + p.expect(yaml_DOCUMENT_END_EVENT) + return n +} + +func (p *parser) alias() *Node { + n := p.node(AliasNode, "", "", string(p.event.anchor)) + n.Alias = p.anchors[n.Value] + if n.Alias == nil { + failf("unknown anchor '%s' referenced", n.Value) + } + p.expect(yaml_ALIAS_EVENT) + return n +} + +func (p *parser) scalar() *Node { + var parsedStyle = p.event.scalar_style() + var nodeStyle Style + switch { + case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0: + nodeStyle = DoubleQuotedStyle + case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0: + nodeStyle = SingleQuotedStyle + case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0: + nodeStyle = LiteralStyle + case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0: + nodeStyle = FoldedStyle + } + var nodeValue = string(p.event.value) + var nodeTag = string(p.event.tag) + var defaultTag string + if nodeStyle == 0 { + if nodeValue == "<<" { + defaultTag = mergeTag + } + } else { + defaultTag = strTag + } + n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue) + n.Style |= nodeStyle + p.anchor(n, p.event.anchor) + p.expect(yaml_SCALAR_EVENT) + return n +} + +func (p *parser) sequence() *Node { + n := p.node(SequenceNode, seqTag, string(p.event.tag), "") + if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 { + n.Style |= FlowStyle + } + p.anchor(n, p.event.anchor) + p.expect(yaml_SEQUENCE_START_EVENT) + for p.peek() != yaml_SEQUENCE_END_EVENT { + p.parseChild(n) + } + n.LineComment = string(p.event.line_comment) + n.FootComment = string(p.event.foot_comment) + p.expect(yaml_SEQUENCE_END_EVENT) + return n +} + +func (p *parser) mapping() *Node { + n := p.node(MappingNode, mapTag, string(p.event.tag), "") + block := true + if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 { + block = false + n.Style |= FlowStyle + } + p.anchor(n, p.event.anchor) + p.expect(yaml_MAPPING_START_EVENT) + for p.peek() != yaml_MAPPING_END_EVENT { + k := p.parseChild(n) + if block && k.FootComment != "" { + // Must be a foot comment for the prior value when being dedented. + if len(n.Content) > 2 { + n.Content[len(n.Content)-3].FootComment = k.FootComment + k.FootComment = "" + } + } + v := p.parseChild(n) + if k.FootComment == "" && v.FootComment != "" { + k.FootComment = v.FootComment + v.FootComment = "" + } + if p.peek() == yaml_TAIL_COMMENT_EVENT { + if k.FootComment == "" { + k.FootComment = string(p.event.foot_comment) + } + p.expect(yaml_TAIL_COMMENT_EVENT) + } + } + n.LineComment = string(p.event.line_comment) + n.FootComment = string(p.event.foot_comment) + if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 { + n.Content[len(n.Content)-2].FootComment = n.FootComment + n.FootComment = "" + } + p.expect(yaml_MAPPING_END_EVENT) + return n +} + +// ---------------------------------------------------------------------------- +// Decoder, unmarshals a node into a provided value. + +type decoder struct { + doc *Node + aliases map[*Node]bool + terrors []string + + stringMapType reflect.Type + generalMapType reflect.Type + + knownFields bool + uniqueKeys bool + decodeCount int + aliasCount int + aliasDepth int +} + +var ( + nodeType = reflect.TypeOf(Node{}) + durationType = reflect.TypeOf(time.Duration(0)) + stringMapType = reflect.TypeOf(map[string]interface{}{}) + generalMapType = reflect.TypeOf(map[interface{}]interface{}{}) + ifaceType = generalMapType.Elem() + timeType = reflect.TypeOf(time.Time{}) + ptrTimeType = reflect.TypeOf(&time.Time{}) +) + +func newDecoder() *decoder { + d := &decoder{ + stringMapType: stringMapType, + generalMapType: generalMapType, + uniqueKeys: true, + } + d.aliases = make(map[*Node]bool) + return d +} + +func (d *decoder) terror(n *Node, tag string, out reflect.Value) { + if n.Tag != "" { + tag = n.Tag + } + value := n.Value + if tag != seqTag && tag != mapTag { + if len(value) > 10 { + value = " `" + value[:7] + "...`" + } else { + value = " `" + value + "`" + } + } + d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type())) +} + +func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) { + err := u.UnmarshalYAML(n) + if e, ok := err.(*TypeError); ok { + d.terrors = append(d.terrors, e.Errors...) + return false + } + if err != nil { + fail(err) + } + return true +} + +func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) { + terrlen := len(d.terrors) + err := u.UnmarshalYAML(func(v interface{}) (err error) { + defer handleErr(&err) + d.unmarshal(n, reflect.ValueOf(v)) + if len(d.terrors) > terrlen { + issues := d.terrors[terrlen:] + d.terrors = d.terrors[:terrlen] + return &TypeError{issues} + } + return nil + }) + if e, ok := err.(*TypeError); ok { + d.terrors = append(d.terrors, e.Errors...) + return false + } + if err != nil { + fail(err) + } + return true +} + +// d.prepare initializes and dereferences pointers and calls UnmarshalYAML +// if a value is found to implement it. +// It returns the initialized and dereferenced out value, whether +// unmarshalling was already done by UnmarshalYAML, and if so whether +// its types unmarshalled appropriately. +// +// If n holds a null value, prepare returns before doing anything. +func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) { + if n.ShortTag() == nullTag { + return out, false, false + } + again := true + for again { + again = false + if out.Kind() == reflect.Ptr { + if out.IsNil() { + out.Set(reflect.New(out.Type().Elem())) + } + out = out.Elem() + again = true + } + if out.CanAddr() { + outi := out.Addr().Interface() + if u, ok := outi.(Unmarshaler); ok { + good = d.callUnmarshaler(n, u) + return out, true, good + } + if u, ok := outi.(obsoleteUnmarshaler); ok { + good = d.callObsoleteUnmarshaler(n, u) + return out, true, good + } + } + } + return out, false, false +} + +func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) { + if n.ShortTag() == nullTag { + return reflect.Value{} + } + for _, num := range index { + for { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) + } + v = v.Elem() + continue + } + break + } + v = v.Field(num) + } + return v +} + +const ( + // 400,000 decode operations is ~500kb of dense object declarations, or + // ~5kb of dense object declarations with 10000% alias expansion + alias_ratio_range_low = 400000 + + // 4,000,000 decode operations is ~5MB of dense object declarations, or + // ~4.5MB of dense object declarations with 10% alias expansion + alias_ratio_range_high = 4000000 + + // alias_ratio_range is the range over which we scale allowed alias ratios + alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low) +) + +func allowedAliasRatio(decodeCount int) float64 { + switch { + case decodeCount <= alias_ratio_range_low: + // allow 99% to come from alias expansion for small-to-medium documents + return 0.99 + case decodeCount >= alias_ratio_range_high: + // allow 10% to come from alias expansion for very large documents + return 0.10 + default: + // scale smoothly from 99% down to 10% over the range. + // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range. + // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps). + return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range) + } +} + +func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) { + d.decodeCount++ + if d.aliasDepth > 0 { + d.aliasCount++ + } + if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) { + failf("document contains excessive aliasing") + } + if out.Type() == nodeType { + out.Set(reflect.ValueOf(n).Elem()) + return true + } + switch n.Kind { + case DocumentNode: + return d.document(n, out) + case AliasNode: + return d.alias(n, out) + } + out, unmarshaled, good := d.prepare(n, out) + if unmarshaled { + return good + } + switch n.Kind { + case ScalarNode: + good = d.scalar(n, out) + case MappingNode: + good = d.mapping(n, out) + case SequenceNode: + good = d.sequence(n, out) + case 0: + if n.IsZero() { + return d.null(out) + } + fallthrough + default: + failf("cannot decode node with unknown kind %d", n.Kind) + } + return good +} + +func (d *decoder) document(n *Node, out reflect.Value) (good bool) { + if len(n.Content) == 1 { + d.doc = n + d.unmarshal(n.Content[0], out) + return true + } + return false +} + +func (d *decoder) alias(n *Node, out reflect.Value) (good bool) { + if d.aliases[n] { + // TODO this could actually be allowed in some circumstances. + failf("anchor '%s' value contains itself", n.Value) + } + d.aliases[n] = true + d.aliasDepth++ + good = d.unmarshal(n.Alias, out) + d.aliasDepth-- + delete(d.aliases, n) + return good +} + +var zeroValue reflect.Value + +func resetMap(out reflect.Value) { + for _, k := range out.MapKeys() { + out.SetMapIndex(k, zeroValue) + } +} + +func (d *decoder) null(out reflect.Value) bool { + if out.CanAddr() { + switch out.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + out.Set(reflect.Zero(out.Type())) + return true + } + } + return false +} + +func (d *decoder) scalar(n *Node, out reflect.Value) bool { + var tag string + var resolved interface{} + if n.indicatedString() { + tag = strTag + resolved = n.Value + } else { + tag, resolved = resolve(n.Tag, n.Value) + if tag == binaryTag { + data, err := base64.StdEncoding.DecodeString(resolved.(string)) + if err != nil { + failf("!!binary value contains invalid base64 data") + } + resolved = string(data) + } + } + if resolved == nil { + return d.null(out) + } + if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { + // We've resolved to exactly the type we want, so use that. + out.Set(resolvedv) + return true + } + // Perhaps we can use the value as a TextUnmarshaler to + // set its value. + if out.CanAddr() { + u, ok := out.Addr().Interface().(encoding.TextUnmarshaler) + if ok { + var text []byte + if tag == binaryTag { + text = []byte(resolved.(string)) + } else { + // We let any value be unmarshaled into TextUnmarshaler. + // That might be more lax than we'd like, but the + // TextUnmarshaler itself should bowl out any dubious values. + text = []byte(n.Value) + } + err := u.UnmarshalText(text) + if err != nil { + fail(err) + } + return true + } + } + switch out.Kind() { + case reflect.String: + if tag == binaryTag { + out.SetString(resolved.(string)) + return true + } + out.SetString(n.Value) + return true + case reflect.Interface: + out.Set(reflect.ValueOf(resolved)) + return true + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + // This used to work in v2, but it's very unfriendly. + isDuration := out.Type() == durationType + + switch resolved := resolved.(type) { + case int: + if !isDuration && !out.OverflowInt(int64(resolved)) { + out.SetInt(int64(resolved)) + return true + } + case int64: + if !isDuration && !out.OverflowInt(resolved) { + out.SetInt(resolved) + return true + } + case uint64: + if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { + out.SetInt(int64(resolved)) + return true + } + case float64: + if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) { + out.SetInt(int64(resolved)) + return true + } + case string: + if out.Type() == durationType { + d, err := time.ParseDuration(resolved) + if err == nil { + out.SetInt(int64(d)) + return true + } + } + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + switch resolved := resolved.(type) { + case int: + if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + case int64: + if resolved >= 0 && !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + case uint64: + if !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + case float64: + if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) { + out.SetUint(uint64(resolved)) + return true + } + } + case reflect.Bool: + switch resolved := resolved.(type) { + case bool: + out.SetBool(resolved) + return true + case string: + // This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html). + // It only works if explicitly attempting to unmarshal into a typed bool value. + switch resolved { + case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON": + out.SetBool(true) + return true + case "n", "N", "no", "No", "NO", "off", "Off", "OFF": + out.SetBool(false) + return true + } + } + case reflect.Float32, reflect.Float64: + switch resolved := resolved.(type) { + case int: + out.SetFloat(float64(resolved)) + return true + case int64: + out.SetFloat(float64(resolved)) + return true + case uint64: + out.SetFloat(float64(resolved)) + return true + case float64: + out.SetFloat(resolved) + return true + } + case reflect.Struct: + if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() { + out.Set(resolvedv) + return true + } + case reflect.Ptr: + panic("yaml internal error: please report the issue") + } + d.terror(n, tag, out) + return false +} + +func settableValueOf(i interface{}) reflect.Value { + v := reflect.ValueOf(i) + sv := reflect.New(v.Type()).Elem() + sv.Set(v) + return sv +} + +func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) { + l := len(n.Content) + + var iface reflect.Value + switch out.Kind() { + case reflect.Slice: + out.Set(reflect.MakeSlice(out.Type(), l, l)) + case reflect.Array: + if l != out.Len() { + failf("invalid array: want %d elements but got %d", out.Len(), l) + } + case reflect.Interface: + // No type hints. Will have to use a generic sequence. + iface = out + out = settableValueOf(make([]interface{}, l)) + default: + d.terror(n, seqTag, out) + return false + } + et := out.Type().Elem() + + j := 0 + for i := 0; i < l; i++ { + e := reflect.New(et).Elem() + if ok := d.unmarshal(n.Content[i], e); ok { + out.Index(j).Set(e) + j++ + } + } + if out.Kind() != reflect.Array { + out.Set(out.Slice(0, j)) + } + if iface.IsValid() { + iface.Set(out) + } + return true +} + +func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { + l := len(n.Content) + if d.uniqueKeys { + nerrs := len(d.terrors) + for i := 0; i < l; i += 2 { + ni := n.Content[i] + for j := i + 2; j < l; j += 2 { + nj := n.Content[j] + if ni.Kind == nj.Kind && ni.Value == nj.Value { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line)) + } + } + } + if len(d.terrors) > nerrs { + return false + } + } + switch out.Kind() { + case reflect.Struct: + return d.mappingStruct(n, out) + case reflect.Map: + // okay + case reflect.Interface: + iface := out + if isStringMap(n) { + out = reflect.MakeMap(d.stringMapType) + } else { + out = reflect.MakeMap(d.generalMapType) + } + iface.Set(out) + default: + d.terror(n, mapTag, out) + return false + } + + outt := out.Type() + kt := outt.Key() + et := outt.Elem() + + stringMapType := d.stringMapType + generalMapType := d.generalMapType + if outt.Elem() == ifaceType { + if outt.Key().Kind() == reflect.String { + d.stringMapType = outt + } else if outt.Key() == ifaceType { + d.generalMapType = outt + } + } + + mapIsNew := false + if out.IsNil() { + out.Set(reflect.MakeMap(outt)) + mapIsNew = true + } + for i := 0; i < l; i += 2 { + if isMerge(n.Content[i]) { + d.merge(n.Content[i+1], out) + continue + } + k := reflect.New(kt).Elem() + if d.unmarshal(n.Content[i], k) { + kkind := k.Kind() + if kkind == reflect.Interface { + kkind = k.Elem().Kind() + } + if kkind == reflect.Map || kkind == reflect.Slice { + failf("invalid map key: %#v", k.Interface()) + } + e := reflect.New(et).Elem() + if d.unmarshal(n.Content[i+1], e) || n.Content[i+1].ShortTag() == nullTag && (mapIsNew || !out.MapIndex(k).IsValid()) { + out.SetMapIndex(k, e) + } + } + } + d.stringMapType = stringMapType + d.generalMapType = generalMapType + return true +} + +func isStringMap(n *Node) bool { + if n.Kind != MappingNode { + return false + } + l := len(n.Content) + for i := 0; i < l; i += 2 { + if n.Content[i].ShortTag() != strTag { + return false + } + } + return true +} + +func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { + sinfo, err := getStructInfo(out.Type()) + if err != nil { + panic(err) + } + + var inlineMap reflect.Value + var elemType reflect.Type + if sinfo.InlineMap != -1 { + inlineMap = out.Field(sinfo.InlineMap) + inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) + elemType = inlineMap.Type().Elem() + } + + for _, index := range sinfo.InlineUnmarshalers { + field := d.fieldByIndex(n, out, index) + d.prepare(n, field) + } + + var doneFields []bool + if d.uniqueKeys { + doneFields = make([]bool, len(sinfo.FieldsList)) + } + name := settableValueOf("") + l := len(n.Content) + for i := 0; i < l; i += 2 { + ni := n.Content[i] + if isMerge(ni) { + d.merge(n.Content[i+1], out) + continue + } + if !d.unmarshal(ni, name) { + continue + } + if info, ok := sinfo.FieldsMap[name.String()]; ok { + if d.uniqueKeys { + if doneFields[info.Id] { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type())) + continue + } + doneFields[info.Id] = true + } + var field reflect.Value + if info.Inline == nil { + field = out.Field(info.Num) + } else { + field = d.fieldByIndex(n, out, info.Inline) + } + d.unmarshal(n.Content[i+1], field) + } else if sinfo.InlineMap != -1 { + if inlineMap.IsNil() { + inlineMap.Set(reflect.MakeMap(inlineMap.Type())) + } + value := reflect.New(elemType).Elem() + d.unmarshal(n.Content[i+1], value) + inlineMap.SetMapIndex(name, value) + } else if d.knownFields { + d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type())) + } + } + return true +} + +func failWantMap() { + failf("map merge requires map or sequence of maps as the value") +} + +func (d *decoder) merge(n *Node, out reflect.Value) { + switch n.Kind { + case MappingNode: + d.unmarshal(n, out) + case AliasNode: + if n.Alias != nil && n.Alias.Kind != MappingNode { + failWantMap() + } + d.unmarshal(n, out) + case SequenceNode: + // Step backwards as earlier nodes take precedence. + for i := len(n.Content) - 1; i >= 0; i-- { + ni := n.Content[i] + if ni.Kind == AliasNode { + if ni.Alias != nil && ni.Alias.Kind != MappingNode { + failWantMap() + } + } else if ni.Kind != MappingNode { + failWantMap() + } + d.unmarshal(ni, out) + } + default: + failWantMap() + } +} + +func isMerge(n *Node) bool { + return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag) +} diff --git a/vendor/gopkg.in/yaml.v3/emitterc.go b/vendor/gopkg.in/yaml.v3/emitterc.go new file mode 100644 index 00000000..0f47c9ca --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/emitterc.go @@ -0,0 +1,2020 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package yaml + +import ( + "bytes" + "fmt" +) + +// Flush the buffer if needed. +func flush(emitter *yaml_emitter_t) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) { + return yaml_emitter_flush(emitter) + } + return true +} + +// Put a character to the output buffer. +func put(emitter *yaml_emitter_t, value byte) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { + return false + } + emitter.buffer[emitter.buffer_pos] = value + emitter.buffer_pos++ + emitter.column++ + return true +} + +// Put a line break to the output buffer. +func put_break(emitter *yaml_emitter_t) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { + return false + } + switch emitter.line_break { + case yaml_CR_BREAK: + emitter.buffer[emitter.buffer_pos] = '\r' + emitter.buffer_pos += 1 + case yaml_LN_BREAK: + emitter.buffer[emitter.buffer_pos] = '\n' + emitter.buffer_pos += 1 + case yaml_CRLN_BREAK: + emitter.buffer[emitter.buffer_pos+0] = '\r' + emitter.buffer[emitter.buffer_pos+1] = '\n' + emitter.buffer_pos += 2 + default: + panic("unknown line break setting") + } + if emitter.column == 0 { + emitter.space_above = true + } + emitter.column = 0 + emitter.line++ + // [Go] Do this here and below and drop from everywhere else (see commented lines). + emitter.indention = true + return true +} + +// Copy a character from a string into buffer. +func write(emitter *yaml_emitter_t, s []byte, i *int) bool { + if emitter.buffer_pos+5 >= len(emitter.buffer) && !yaml_emitter_flush(emitter) { + return false + } + p := emitter.buffer_pos + w := width(s[*i]) + switch w { + case 4: + emitter.buffer[p+3] = s[*i+3] + fallthrough + case 3: + emitter.buffer[p+2] = s[*i+2] + fallthrough + case 2: + emitter.buffer[p+1] = s[*i+1] + fallthrough + case 1: + emitter.buffer[p+0] = s[*i+0] + default: + panic("unknown character width") + } + emitter.column++ + emitter.buffer_pos += w + *i += w + return true +} + +// Write a whole string into buffer. +func write_all(emitter *yaml_emitter_t, s []byte) bool { + for i := 0; i < len(s); { + if !write(emitter, s, &i) { + return false + } + } + return true +} + +// Copy a line break character from a string into buffer. +func write_break(emitter *yaml_emitter_t, s []byte, i *int) bool { + if s[*i] == '\n' { + if !put_break(emitter) { + return false + } + *i++ + } else { + if !write(emitter, s, i) { + return false + } + if emitter.column == 0 { + emitter.space_above = true + } + emitter.column = 0 + emitter.line++ + // [Go] Do this here and above and drop from everywhere else (see commented lines). + emitter.indention = true + } + return true +} + +// Set an emitter error and return false. +func yaml_emitter_set_emitter_error(emitter *yaml_emitter_t, problem string) bool { + emitter.error = yaml_EMITTER_ERROR + emitter.problem = problem + return false +} + +// Emit an event. +func yaml_emitter_emit(emitter *yaml_emitter_t, event *yaml_event_t) bool { + emitter.events = append(emitter.events, *event) + for !yaml_emitter_need_more_events(emitter) { + event := &emitter.events[emitter.events_head] + if !yaml_emitter_analyze_event(emitter, event) { + return false + } + if !yaml_emitter_state_machine(emitter, event) { + return false + } + yaml_event_delete(event) + emitter.events_head++ + } + return true +} + +// Check if we need to accumulate more events before emitting. +// +// We accumulate extra +// - 1 event for DOCUMENT-START +// - 2 events for SEQUENCE-START +// - 3 events for MAPPING-START +// +func yaml_emitter_need_more_events(emitter *yaml_emitter_t) bool { + if emitter.events_head == len(emitter.events) { + return true + } + var accumulate int + switch emitter.events[emitter.events_head].typ { + case yaml_DOCUMENT_START_EVENT: + accumulate = 1 + break + case yaml_SEQUENCE_START_EVENT: + accumulate = 2 + break + case yaml_MAPPING_START_EVENT: + accumulate = 3 + break + default: + return false + } + if len(emitter.events)-emitter.events_head > accumulate { + return false + } + var level int + for i := emitter.events_head; i < len(emitter.events); i++ { + switch emitter.events[i].typ { + case yaml_STREAM_START_EVENT, yaml_DOCUMENT_START_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT: + level++ + case yaml_STREAM_END_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_END_EVENT, yaml_MAPPING_END_EVENT: + level-- + } + if level == 0 { + return false + } + } + return true +} + +// Append a directive to the directives stack. +func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_directive_t, allow_duplicates bool) bool { + for i := 0; i < len(emitter.tag_directives); i++ { + if bytes.Equal(value.handle, emitter.tag_directives[i].handle) { + if allow_duplicates { + return true + } + return yaml_emitter_set_emitter_error(emitter, "duplicate %TAG directive") + } + } + + // [Go] Do we actually need to copy this given garbage collection + // and the lack of deallocating destructors? + tag_copy := yaml_tag_directive_t{ + handle: make([]byte, len(value.handle)), + prefix: make([]byte, len(value.prefix)), + } + copy(tag_copy.handle, value.handle) + copy(tag_copy.prefix, value.prefix) + emitter.tag_directives = append(emitter.tag_directives, tag_copy) + return true +} + +// Increase the indentation level. +func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool { + emitter.indents = append(emitter.indents, emitter.indent) + if emitter.indent < 0 { + if flow { + emitter.indent = emitter.best_indent + } else { + emitter.indent = 0 + } + } else if !indentless { + // [Go] This was changed so that indentations are more regular. + if emitter.states[len(emitter.states)-1] == yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE { + // The first indent inside a sequence will just skip the "- " indicator. + emitter.indent += 2 + } else { + // Everything else aligns to the chosen indentation. + emitter.indent = emitter.best_indent*((emitter.indent+emitter.best_indent)/emitter.best_indent) + } + } + return true +} + +// State dispatcher. +func yaml_emitter_state_machine(emitter *yaml_emitter_t, event *yaml_event_t) bool { + switch emitter.state { + default: + case yaml_EMIT_STREAM_START_STATE: + return yaml_emitter_emit_stream_start(emitter, event) + + case yaml_EMIT_FIRST_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, true) + + case yaml_EMIT_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, false) + + case yaml_EMIT_DOCUMENT_CONTENT_STATE: + return yaml_emitter_emit_document_content(emitter, event) + + case yaml_EMIT_DOCUMENT_END_STATE: + return yaml_emitter_emit_document_end(emitter, event) + + case yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, true, false) + + case yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, false, true) + + case yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, false, false) + + case yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, true, false) + + case yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, false, true) + + case yaml_EMIT_FLOW_MAPPING_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, false, false) + + case yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, true) + + case yaml_EMIT_FLOW_MAPPING_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, false) + + case yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, true) + + case yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, false) + + case yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, true) + + case yaml_EMIT_BLOCK_MAPPING_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, false) + + case yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, true) + + case yaml_EMIT_BLOCK_MAPPING_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, false) + + case yaml_EMIT_END_STATE: + return yaml_emitter_set_emitter_error(emitter, "expected nothing after STREAM-END") + } + panic("invalid emitter state") +} + +// Expect STREAM-START. +func yaml_emitter_emit_stream_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if event.typ != yaml_STREAM_START_EVENT { + return yaml_emitter_set_emitter_error(emitter, "expected STREAM-START") + } + if emitter.encoding == yaml_ANY_ENCODING { + emitter.encoding = event.encoding + if emitter.encoding == yaml_ANY_ENCODING { + emitter.encoding = yaml_UTF8_ENCODING + } + } + if emitter.best_indent < 2 || emitter.best_indent > 9 { + emitter.best_indent = 2 + } + if emitter.best_width >= 0 && emitter.best_width <= emitter.best_indent*2 { + emitter.best_width = 80 + } + if emitter.best_width < 0 { + emitter.best_width = 1<<31 - 1 + } + if emitter.line_break == yaml_ANY_BREAK { + emitter.line_break = yaml_LN_BREAK + } + + emitter.indent = -1 + emitter.line = 0 + emitter.column = 0 + emitter.whitespace = true + emitter.indention = true + emitter.space_above = true + emitter.foot_indent = -1 + + if emitter.encoding != yaml_UTF8_ENCODING { + if !yaml_emitter_write_bom(emitter) { + return false + } + } + emitter.state = yaml_EMIT_FIRST_DOCUMENT_START_STATE + return true +} + +// Expect DOCUMENT-START or STREAM-END. +func yaml_emitter_emit_document_start(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + + if event.typ == yaml_DOCUMENT_START_EVENT { + + if event.version_directive != nil { + if !yaml_emitter_analyze_version_directive(emitter, event.version_directive) { + return false + } + } + + for i := 0; i < len(event.tag_directives); i++ { + tag_directive := &event.tag_directives[i] + if !yaml_emitter_analyze_tag_directive(emitter, tag_directive) { + return false + } + if !yaml_emitter_append_tag_directive(emitter, tag_directive, false) { + return false + } + } + + for i := 0; i < len(default_tag_directives); i++ { + tag_directive := &default_tag_directives[i] + if !yaml_emitter_append_tag_directive(emitter, tag_directive, true) { + return false + } + } + + implicit := event.implicit + if !first || emitter.canonical { + implicit = false + } + + if emitter.open_ended && (event.version_directive != nil || len(event.tag_directives) > 0) { + if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if event.version_directive != nil { + implicit = false + if !yaml_emitter_write_indicator(emitter, []byte("%YAML"), true, false, false) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte("1.1"), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if len(event.tag_directives) > 0 { + implicit = false + for i := 0; i < len(event.tag_directives); i++ { + tag_directive := &event.tag_directives[i] + if !yaml_emitter_write_indicator(emitter, []byte("%TAG"), true, false, false) { + return false + } + if !yaml_emitter_write_tag_handle(emitter, tag_directive.handle) { + return false + } + if !yaml_emitter_write_tag_content(emitter, tag_directive.prefix, true) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + } + + if yaml_emitter_check_empty_document(emitter) { + implicit = false + } + if !implicit { + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte("---"), true, false, false) { + return false + } + if emitter.canonical || true { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + } + + if len(emitter.head_comment) > 0 { + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if !put_break(emitter) { + return false + } + } + + emitter.state = yaml_EMIT_DOCUMENT_CONTENT_STATE + return true + } + + if event.typ == yaml_STREAM_END_EVENT { + if emitter.open_ended { + if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_flush(emitter) { + return false + } + emitter.state = yaml_EMIT_END_STATE + return true + } + + return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-START or STREAM-END") +} + +// Expect the root node. +func yaml_emitter_emit_document_content(emitter *yaml_emitter_t, event *yaml_event_t) bool { + emitter.states = append(emitter.states, yaml_EMIT_DOCUMENT_END_STATE) + + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if !yaml_emitter_emit_node(emitter, event, true, false, false, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +// Expect DOCUMENT-END. +func yaml_emitter_emit_document_end(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if event.typ != yaml_DOCUMENT_END_EVENT { + return yaml_emitter_set_emitter_error(emitter, "expected DOCUMENT-END") + } + // [Go] Force document foot separation. + emitter.foot_indent = 0 + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + emitter.foot_indent = -1 + if !yaml_emitter_write_indent(emitter) { + return false + } + if !event.implicit { + // [Go] Allocate the slice elsewhere. + if !yaml_emitter_write_indicator(emitter, []byte("..."), true, false, false) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_flush(emitter) { + return false + } + emitter.state = yaml_EMIT_DOCUMENT_START_STATE + emitter.tag_directives = emitter.tag_directives[:0] + return true +} + +// Expect a flow item node. +func yaml_emitter_emit_flow_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool { + if first { + if !yaml_emitter_write_indicator(emitter, []byte{'['}, true, true, false) { + return false + } + if !yaml_emitter_increase_indent(emitter, true, false) { + return false + } + emitter.flow_level++ + } + + if event.typ == yaml_SEQUENCE_END_EVENT { + if emitter.canonical && !first && !trail { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + emitter.flow_level-- + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + if emitter.column == 0 || emitter.canonical && !first { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{']'}, false, false, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + + return true + } + + if !first && !trail { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if emitter.column == 0 { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if emitter.canonical || emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE) + } else { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE) + } + if !yaml_emitter_emit_node(emitter, event, false, true, false, false) { + return false + } + if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + if !yaml_emitter_process_line_comment(emitter) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +// Expect a flow key node. +func yaml_emitter_emit_flow_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first, trail bool) bool { + if first { + if !yaml_emitter_write_indicator(emitter, []byte{'{'}, true, true, false) { + return false + } + if !yaml_emitter_increase_indent(emitter, true, false) { + return false + } + emitter.flow_level++ + } + + if event.typ == yaml_MAPPING_END_EVENT { + if (emitter.canonical || len(emitter.head_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0) && !first && !trail { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + if !yaml_emitter_process_head_comment(emitter) { + return false + } + emitter.flow_level-- + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + if emitter.canonical && !first { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{'}'}, false, false, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true + } + + if !first && !trail { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + + if !yaml_emitter_process_head_comment(emitter) { + return false + } + + if emitter.column == 0 { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if emitter.canonical || emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + + if !emitter.canonical && yaml_emitter_check_simple_key(emitter) { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, true) + } + if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, false) { + return false + } + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, false) +} + +// Expect a flow value node. +func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { + if simple { + if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { + return false + } + } else { + if emitter.canonical || emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, false) { + return false + } + } + if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE) + } else { + emitter.states = append(emitter.states, yaml_EMIT_FLOW_MAPPING_KEY_STATE) + } + if !yaml_emitter_emit_node(emitter, event, false, false, true, false) { + return false + } + if len(emitter.line_comment)+len(emitter.foot_comment)+len(emitter.tail_comment) > 0 { + if !yaml_emitter_write_indicator(emitter, []byte{','}, false, false, false) { + return false + } + } + if !yaml_emitter_process_line_comment(emitter) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +// Expect a block item node. +func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + if first { + if !yaml_emitter_increase_indent(emitter, false, false) { + return false + } + } + if event.typ == yaml_SEQUENCE_END_EVENT { + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true + } + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte{'-'}, true, false, true) { + return false + } + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE) + if !yaml_emitter_emit_node(emitter, event, false, true, false, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +// Expect a block key node. +func yaml_emitter_emit_block_mapping_key(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { + if first { + if !yaml_emitter_increase_indent(emitter, false, false) { + return false + } + } + if !yaml_emitter_process_head_comment(emitter) { + return false + } + if event.typ == yaml_MAPPING_END_EVENT { + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if len(emitter.line_comment) > 0 { + // [Go] A line comment was provided for the key. That's unusual as the + // scanner associates line comments with the value. Either way, + // save the line comment and render it appropriately later. + emitter.key_line_comment = emitter.line_comment + emitter.line_comment = nil + } + if yaml_emitter_check_simple_key(emitter) { + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, true) + } + if !yaml_emitter_write_indicator(emitter, []byte{'?'}, true, false, true) { + return false + } + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_VALUE_STATE) + return yaml_emitter_emit_node(emitter, event, false, false, true, false) +} + +// Expect a block value node. +func yaml_emitter_emit_block_mapping_value(emitter *yaml_emitter_t, event *yaml_event_t, simple bool) bool { + if simple { + if !yaml_emitter_write_indicator(emitter, []byte{':'}, false, false, false) { + return false + } + } else { + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte{':'}, true, false, true) { + return false + } + } + if len(emitter.key_line_comment) > 0 { + // [Go] Line comments are generally associated with the value, but when there's + // no value on the same line as a mapping key they end up attached to the + // key itself. + if event.typ == yaml_SCALAR_EVENT { + if len(emitter.line_comment) == 0 { + // A scalar is coming and it has no line comments by itself yet, + // so just let it handle the line comment as usual. If it has a + // line comment, we can't have both so the one from the key is lost. + emitter.line_comment = emitter.key_line_comment + emitter.key_line_comment = nil + } + } else if event.sequence_style() != yaml_FLOW_SEQUENCE_STYLE && (event.typ == yaml_MAPPING_START_EVENT || event.typ == yaml_SEQUENCE_START_EVENT) { + // An indented block follows, so write the comment right now. + emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment + if !yaml_emitter_process_line_comment(emitter) { + return false + } + emitter.line_comment, emitter.key_line_comment = emitter.key_line_comment, emitter.line_comment + } + } + emitter.states = append(emitter.states, yaml_EMIT_BLOCK_MAPPING_KEY_STATE) + if !yaml_emitter_emit_node(emitter, event, false, false, true, false) { + return false + } + if !yaml_emitter_process_line_comment(emitter) { + return false + } + if !yaml_emitter_process_foot_comment(emitter) { + return false + } + return true +} + +func yaml_emitter_silent_nil_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { + return event.typ == yaml_SCALAR_EVENT && event.implicit && !emitter.canonical && len(emitter.scalar_data.value) == 0 +} + +// Expect a node. +func yaml_emitter_emit_node(emitter *yaml_emitter_t, event *yaml_event_t, + root bool, sequence bool, mapping bool, simple_key bool) bool { + + emitter.root_context = root + emitter.sequence_context = sequence + emitter.mapping_context = mapping + emitter.simple_key_context = simple_key + + switch event.typ { + case yaml_ALIAS_EVENT: + return yaml_emitter_emit_alias(emitter, event) + case yaml_SCALAR_EVENT: + return yaml_emitter_emit_scalar(emitter, event) + case yaml_SEQUENCE_START_EVENT: + return yaml_emitter_emit_sequence_start(emitter, event) + case yaml_MAPPING_START_EVENT: + return yaml_emitter_emit_mapping_start(emitter, event) + default: + return yaml_emitter_set_emitter_error(emitter, + fmt.Sprintf("expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got %v", event.typ)) + } +} + +// Expect ALIAS. +func yaml_emitter_emit_alias(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_process_anchor(emitter) { + return false + } + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true +} + +// Expect SCALAR. +func yaml_emitter_emit_scalar(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_select_scalar_style(emitter, event) { + return false + } + if !yaml_emitter_process_anchor(emitter) { + return false + } + if !yaml_emitter_process_tag(emitter) { + return false + } + if !yaml_emitter_increase_indent(emitter, true, false) { + return false + } + if !yaml_emitter_process_scalar(emitter) { + return false + } + emitter.indent = emitter.indents[len(emitter.indents)-1] + emitter.indents = emitter.indents[:len(emitter.indents)-1] + emitter.state = emitter.states[len(emitter.states)-1] + emitter.states = emitter.states[:len(emitter.states)-1] + return true +} + +// Expect SEQUENCE-START. +func yaml_emitter_emit_sequence_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_process_anchor(emitter) { + return false + } + if !yaml_emitter_process_tag(emitter) { + return false + } + if emitter.flow_level > 0 || emitter.canonical || event.sequence_style() == yaml_FLOW_SEQUENCE_STYLE || + yaml_emitter_check_empty_sequence(emitter) { + emitter.state = yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE + } else { + emitter.state = yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE + } + return true +} + +// Expect MAPPING-START. +func yaml_emitter_emit_mapping_start(emitter *yaml_emitter_t, event *yaml_event_t) bool { + if !yaml_emitter_process_anchor(emitter) { + return false + } + if !yaml_emitter_process_tag(emitter) { + return false + } + if emitter.flow_level > 0 || emitter.canonical || event.mapping_style() == yaml_FLOW_MAPPING_STYLE || + yaml_emitter_check_empty_mapping(emitter) { + emitter.state = yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE + } else { + emitter.state = yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE + } + return true +} + +// Check if the document content is an empty scalar. +func yaml_emitter_check_empty_document(emitter *yaml_emitter_t) bool { + return false // [Go] Huh? +} + +// Check if the next events represent an empty sequence. +func yaml_emitter_check_empty_sequence(emitter *yaml_emitter_t) bool { + if len(emitter.events)-emitter.events_head < 2 { + return false + } + return emitter.events[emitter.events_head].typ == yaml_SEQUENCE_START_EVENT && + emitter.events[emitter.events_head+1].typ == yaml_SEQUENCE_END_EVENT +} + +// Check if the next events represent an empty mapping. +func yaml_emitter_check_empty_mapping(emitter *yaml_emitter_t) bool { + if len(emitter.events)-emitter.events_head < 2 { + return false + } + return emitter.events[emitter.events_head].typ == yaml_MAPPING_START_EVENT && + emitter.events[emitter.events_head+1].typ == yaml_MAPPING_END_EVENT +} + +// Check if the next node can be expressed as a simple key. +func yaml_emitter_check_simple_key(emitter *yaml_emitter_t) bool { + length := 0 + switch emitter.events[emitter.events_head].typ { + case yaml_ALIAS_EVENT: + length += len(emitter.anchor_data.anchor) + case yaml_SCALAR_EVENT: + if emitter.scalar_data.multiline { + return false + } + length += len(emitter.anchor_data.anchor) + + len(emitter.tag_data.handle) + + len(emitter.tag_data.suffix) + + len(emitter.scalar_data.value) + case yaml_SEQUENCE_START_EVENT: + if !yaml_emitter_check_empty_sequence(emitter) { + return false + } + length += len(emitter.anchor_data.anchor) + + len(emitter.tag_data.handle) + + len(emitter.tag_data.suffix) + case yaml_MAPPING_START_EVENT: + if !yaml_emitter_check_empty_mapping(emitter) { + return false + } + length += len(emitter.anchor_data.anchor) + + len(emitter.tag_data.handle) + + len(emitter.tag_data.suffix) + default: + return false + } + return length <= 128 +} + +// Determine an acceptable scalar style. +func yaml_emitter_select_scalar_style(emitter *yaml_emitter_t, event *yaml_event_t) bool { + + no_tag := len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 + if no_tag && !event.implicit && !event.quoted_implicit { + return yaml_emitter_set_emitter_error(emitter, "neither tag nor implicit flags are specified") + } + + style := event.scalar_style() + if style == yaml_ANY_SCALAR_STYLE { + style = yaml_PLAIN_SCALAR_STYLE + } + if emitter.canonical { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + if emitter.simple_key_context && emitter.scalar_data.multiline { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + + if style == yaml_PLAIN_SCALAR_STYLE { + if emitter.flow_level > 0 && !emitter.scalar_data.flow_plain_allowed || + emitter.flow_level == 0 && !emitter.scalar_data.block_plain_allowed { + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + } + if len(emitter.scalar_data.value) == 0 && (emitter.flow_level > 0 || emitter.simple_key_context) { + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + } + if no_tag && !event.implicit { + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + } + } + if style == yaml_SINGLE_QUOTED_SCALAR_STYLE { + if !emitter.scalar_data.single_quoted_allowed { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + } + if style == yaml_LITERAL_SCALAR_STYLE || style == yaml_FOLDED_SCALAR_STYLE { + if !emitter.scalar_data.block_allowed || emitter.flow_level > 0 || emitter.simple_key_context { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + } + + if no_tag && !event.quoted_implicit && style != yaml_PLAIN_SCALAR_STYLE { + emitter.tag_data.handle = []byte{'!'} + } + emitter.scalar_data.style = style + return true +} + +// Write an anchor. +func yaml_emitter_process_anchor(emitter *yaml_emitter_t) bool { + if emitter.anchor_data.anchor == nil { + return true + } + c := []byte{'&'} + if emitter.anchor_data.alias { + c[0] = '*' + } + if !yaml_emitter_write_indicator(emitter, c, true, false, false) { + return false + } + return yaml_emitter_write_anchor(emitter, emitter.anchor_data.anchor) +} + +// Write a tag. +func yaml_emitter_process_tag(emitter *yaml_emitter_t) bool { + if len(emitter.tag_data.handle) == 0 && len(emitter.tag_data.suffix) == 0 { + return true + } + if len(emitter.tag_data.handle) > 0 { + if !yaml_emitter_write_tag_handle(emitter, emitter.tag_data.handle) { + return false + } + if len(emitter.tag_data.suffix) > 0 { + if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { + return false + } + } + } else { + // [Go] Allocate these slices elsewhere. + if !yaml_emitter_write_indicator(emitter, []byte("!<"), true, false, false) { + return false + } + if !yaml_emitter_write_tag_content(emitter, emitter.tag_data.suffix, false) { + return false + } + if !yaml_emitter_write_indicator(emitter, []byte{'>'}, false, false, false) { + return false + } + } + return true +} + +// Write a scalar. +func yaml_emitter_process_scalar(emitter *yaml_emitter_t) bool { + switch emitter.scalar_data.style { + case yaml_PLAIN_SCALAR_STYLE: + return yaml_emitter_write_plain_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) + + case yaml_SINGLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_single_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) + + case yaml_DOUBLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_double_quoted_scalar(emitter, emitter.scalar_data.value, !emitter.simple_key_context) + + case yaml_LITERAL_SCALAR_STYLE: + return yaml_emitter_write_literal_scalar(emitter, emitter.scalar_data.value) + + case yaml_FOLDED_SCALAR_STYLE: + return yaml_emitter_write_folded_scalar(emitter, emitter.scalar_data.value) + } + panic("unknown scalar style") +} + +// Write a head comment. +func yaml_emitter_process_head_comment(emitter *yaml_emitter_t) bool { + if len(emitter.tail_comment) > 0 { + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_comment(emitter, emitter.tail_comment) { + return false + } + emitter.tail_comment = emitter.tail_comment[:0] + emitter.foot_indent = emitter.indent + if emitter.foot_indent < 0 { + emitter.foot_indent = 0 + } + } + + if len(emitter.head_comment) == 0 { + return true + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_comment(emitter, emitter.head_comment) { + return false + } + emitter.head_comment = emitter.head_comment[:0] + return true +} + +// Write an line comment. +func yaml_emitter_process_line_comment(emitter *yaml_emitter_t) bool { + if len(emitter.line_comment) == 0 { + return true + } + if !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + if !yaml_emitter_write_comment(emitter, emitter.line_comment) { + return false + } + emitter.line_comment = emitter.line_comment[:0] + return true +} + +// Write a foot comment. +func yaml_emitter_process_foot_comment(emitter *yaml_emitter_t) bool { + if len(emitter.foot_comment) == 0 { + return true + } + if !yaml_emitter_write_indent(emitter) { + return false + } + if !yaml_emitter_write_comment(emitter, emitter.foot_comment) { + return false + } + emitter.foot_comment = emitter.foot_comment[:0] + emitter.foot_indent = emitter.indent + if emitter.foot_indent < 0 { + emitter.foot_indent = 0 + } + return true +} + +// Check if a %YAML directive is valid. +func yaml_emitter_analyze_version_directive(emitter *yaml_emitter_t, version_directive *yaml_version_directive_t) bool { + if version_directive.major != 1 || version_directive.minor != 1 { + return yaml_emitter_set_emitter_error(emitter, "incompatible %YAML directive") + } + return true +} + +// Check if a %TAG directive is valid. +func yaml_emitter_analyze_tag_directive(emitter *yaml_emitter_t, tag_directive *yaml_tag_directive_t) bool { + handle := tag_directive.handle + prefix := tag_directive.prefix + if len(handle) == 0 { + return yaml_emitter_set_emitter_error(emitter, "tag handle must not be empty") + } + if handle[0] != '!' { + return yaml_emitter_set_emitter_error(emitter, "tag handle must start with '!'") + } + if handle[len(handle)-1] != '!' { + return yaml_emitter_set_emitter_error(emitter, "tag handle must end with '!'") + } + for i := 1; i < len(handle)-1; i += width(handle[i]) { + if !is_alpha(handle, i) { + return yaml_emitter_set_emitter_error(emitter, "tag handle must contain alphanumerical characters only") + } + } + if len(prefix) == 0 { + return yaml_emitter_set_emitter_error(emitter, "tag prefix must not be empty") + } + return true +} + +// Check if an anchor is valid. +func yaml_emitter_analyze_anchor(emitter *yaml_emitter_t, anchor []byte, alias bool) bool { + if len(anchor) == 0 { + problem := "anchor value must not be empty" + if alias { + problem = "alias value must not be empty" + } + return yaml_emitter_set_emitter_error(emitter, problem) + } + for i := 0; i < len(anchor); i += width(anchor[i]) { + if !is_alpha(anchor, i) { + problem := "anchor value must contain alphanumerical characters only" + if alias { + problem = "alias value must contain alphanumerical characters only" + } + return yaml_emitter_set_emitter_error(emitter, problem) + } + } + emitter.anchor_data.anchor = anchor + emitter.anchor_data.alias = alias + return true +} + +// Check if a tag is valid. +func yaml_emitter_analyze_tag(emitter *yaml_emitter_t, tag []byte) bool { + if len(tag) == 0 { + return yaml_emitter_set_emitter_error(emitter, "tag value must not be empty") + } + for i := 0; i < len(emitter.tag_directives); i++ { + tag_directive := &emitter.tag_directives[i] + if bytes.HasPrefix(tag, tag_directive.prefix) { + emitter.tag_data.handle = tag_directive.handle + emitter.tag_data.suffix = tag[len(tag_directive.prefix):] + return true + } + } + emitter.tag_data.suffix = tag + return true +} + +// Check if a scalar is valid. +func yaml_emitter_analyze_scalar(emitter *yaml_emitter_t, value []byte) bool { + var ( + block_indicators = false + flow_indicators = false + line_breaks = false + special_characters = false + tab_characters = false + + leading_space = false + leading_break = false + trailing_space = false + trailing_break = false + break_space = false + space_break = false + + preceded_by_whitespace = false + followed_by_whitespace = false + previous_space = false + previous_break = false + ) + + emitter.scalar_data.value = value + + if len(value) == 0 { + emitter.scalar_data.multiline = false + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = true + emitter.scalar_data.single_quoted_allowed = true + emitter.scalar_data.block_allowed = false + return true + } + + if len(value) >= 3 && ((value[0] == '-' && value[1] == '-' && value[2] == '-') || (value[0] == '.' && value[1] == '.' && value[2] == '.')) { + block_indicators = true + flow_indicators = true + } + + preceded_by_whitespace = true + for i, w := 0, 0; i < len(value); i += w { + w = width(value[i]) + followed_by_whitespace = i+w >= len(value) || is_blank(value, i+w) + + if i == 0 { + switch value[i] { + case '#', ',', '[', ']', '{', '}', '&', '*', '!', '|', '>', '\'', '"', '%', '@', '`': + flow_indicators = true + block_indicators = true + case '?', ':': + flow_indicators = true + if followed_by_whitespace { + block_indicators = true + } + case '-': + if followed_by_whitespace { + flow_indicators = true + block_indicators = true + } + } + } else { + switch value[i] { + case ',', '?', '[', ']', '{', '}': + flow_indicators = true + case ':': + flow_indicators = true + if followed_by_whitespace { + block_indicators = true + } + case '#': + if preceded_by_whitespace { + flow_indicators = true + block_indicators = true + } + } + } + + if value[i] == '\t' { + tab_characters = true + } else if !is_printable(value, i) || !is_ascii(value, i) && !emitter.unicode { + special_characters = true + } + if is_space(value, i) { + if i == 0 { + leading_space = true + } + if i+width(value[i]) == len(value) { + trailing_space = true + } + if previous_break { + break_space = true + } + previous_space = true + previous_break = false + } else if is_break(value, i) { + line_breaks = true + if i == 0 { + leading_break = true + } + if i+width(value[i]) == len(value) { + trailing_break = true + } + if previous_space { + space_break = true + } + previous_space = false + previous_break = true + } else { + previous_space = false + previous_break = false + } + + // [Go]: Why 'z'? Couldn't be the end of the string as that's the loop condition. + preceded_by_whitespace = is_blankz(value, i) + } + + emitter.scalar_data.multiline = line_breaks + emitter.scalar_data.flow_plain_allowed = true + emitter.scalar_data.block_plain_allowed = true + emitter.scalar_data.single_quoted_allowed = true + emitter.scalar_data.block_allowed = true + + if leading_space || leading_break || trailing_space || trailing_break { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + } + if trailing_space { + emitter.scalar_data.block_allowed = false + } + if break_space { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + emitter.scalar_data.single_quoted_allowed = false + } + if space_break || tab_characters || special_characters { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + emitter.scalar_data.single_quoted_allowed = false + } + if space_break || special_characters { + emitter.scalar_data.block_allowed = false + } + if line_breaks { + emitter.scalar_data.flow_plain_allowed = false + emitter.scalar_data.block_plain_allowed = false + } + if flow_indicators { + emitter.scalar_data.flow_plain_allowed = false + } + if block_indicators { + emitter.scalar_data.block_plain_allowed = false + } + return true +} + +// Check if the event data is valid. +func yaml_emitter_analyze_event(emitter *yaml_emitter_t, event *yaml_event_t) bool { + + emitter.anchor_data.anchor = nil + emitter.tag_data.handle = nil + emitter.tag_data.suffix = nil + emitter.scalar_data.value = nil + + if len(event.head_comment) > 0 { + emitter.head_comment = event.head_comment + } + if len(event.line_comment) > 0 { + emitter.line_comment = event.line_comment + } + if len(event.foot_comment) > 0 { + emitter.foot_comment = event.foot_comment + } + if len(event.tail_comment) > 0 { + emitter.tail_comment = event.tail_comment + } + + switch event.typ { + case yaml_ALIAS_EVENT: + if !yaml_emitter_analyze_anchor(emitter, event.anchor, true) { + return false + } + + case yaml_SCALAR_EVENT: + if len(event.anchor) > 0 { + if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { + return false + } + } + if len(event.tag) > 0 && (emitter.canonical || (!event.implicit && !event.quoted_implicit)) { + if !yaml_emitter_analyze_tag(emitter, event.tag) { + return false + } + } + if !yaml_emitter_analyze_scalar(emitter, event.value) { + return false + } + + case yaml_SEQUENCE_START_EVENT: + if len(event.anchor) > 0 { + if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { + return false + } + } + if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { + if !yaml_emitter_analyze_tag(emitter, event.tag) { + return false + } + } + + case yaml_MAPPING_START_EVENT: + if len(event.anchor) > 0 { + if !yaml_emitter_analyze_anchor(emitter, event.anchor, false) { + return false + } + } + if len(event.tag) > 0 && (emitter.canonical || !event.implicit) { + if !yaml_emitter_analyze_tag(emitter, event.tag) { + return false + } + } + } + return true +} + +// Write the BOM character. +func yaml_emitter_write_bom(emitter *yaml_emitter_t) bool { + if !flush(emitter) { + return false + } + pos := emitter.buffer_pos + emitter.buffer[pos+0] = '\xEF' + emitter.buffer[pos+1] = '\xBB' + emitter.buffer[pos+2] = '\xBF' + emitter.buffer_pos += 3 + return true +} + +func yaml_emitter_write_indent(emitter *yaml_emitter_t) bool { + indent := emitter.indent + if indent < 0 { + indent = 0 + } + if !emitter.indention || emitter.column > indent || (emitter.column == indent && !emitter.whitespace) { + if !put_break(emitter) { + return false + } + } + if emitter.foot_indent == indent { + if !put_break(emitter) { + return false + } + } + for emitter.column < indent { + if !put(emitter, ' ') { + return false + } + } + emitter.whitespace = true + //emitter.indention = true + emitter.space_above = false + emitter.foot_indent = -1 + return true +} + +func yaml_emitter_write_indicator(emitter *yaml_emitter_t, indicator []byte, need_whitespace, is_whitespace, is_indention bool) bool { + if need_whitespace && !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + if !write_all(emitter, indicator) { + return false + } + emitter.whitespace = is_whitespace + emitter.indention = (emitter.indention && is_indention) + emitter.open_ended = false + return true +} + +func yaml_emitter_write_anchor(emitter *yaml_emitter_t, value []byte) bool { + if !write_all(emitter, value) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_tag_handle(emitter *yaml_emitter_t, value []byte) bool { + if !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + if !write_all(emitter, value) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_tag_content(emitter *yaml_emitter_t, value []byte, need_whitespace bool) bool { + if need_whitespace && !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + for i := 0; i < len(value); { + var must_write bool + switch value[i] { + case ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')', '[', ']': + must_write = true + default: + must_write = is_alpha(value, i) + } + if must_write { + if !write(emitter, value, &i) { + return false + } + } else { + w := width(value[i]) + for k := 0; k < w; k++ { + octet := value[i] + i++ + if !put(emitter, '%') { + return false + } + + c := octet >> 4 + if c < 10 { + c += '0' + } else { + c += 'A' - 10 + } + if !put(emitter, c) { + return false + } + + c = octet & 0x0f + if c < 10 { + c += '0' + } else { + c += 'A' - 10 + } + if !put(emitter, c) { + return false + } + } + } + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_plain_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { + if len(value) > 0 && !emitter.whitespace { + if !put(emitter, ' ') { + return false + } + } + + spaces := false + breaks := false + for i := 0; i < len(value); { + if is_space(value, i) { + if allow_breaks && !spaces && emitter.column > emitter.best_width && !is_space(value, i+1) { + if !yaml_emitter_write_indent(emitter) { + return false + } + i += width(value[i]) + } else { + if !write(emitter, value, &i) { + return false + } + } + spaces = true + } else if is_break(value, i) { + if !breaks && value[i] == '\n' { + if !put_break(emitter) { + return false + } + } + if !write_break(emitter, value, &i) { + return false + } + //emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !write(emitter, value, &i) { + return false + } + emitter.indention = false + spaces = false + breaks = false + } + } + + if len(value) > 0 { + emitter.whitespace = false + } + emitter.indention = false + if emitter.root_context { + emitter.open_ended = true + } + + return true +} + +func yaml_emitter_write_single_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { + + if !yaml_emitter_write_indicator(emitter, []byte{'\''}, true, false, false) { + return false + } + + spaces := false + breaks := false + for i := 0; i < len(value); { + if is_space(value, i) { + if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 && !is_space(value, i+1) { + if !yaml_emitter_write_indent(emitter) { + return false + } + i += width(value[i]) + } else { + if !write(emitter, value, &i) { + return false + } + } + spaces = true + } else if is_break(value, i) { + if !breaks && value[i] == '\n' { + if !put_break(emitter) { + return false + } + } + if !write_break(emitter, value, &i) { + return false + } + //emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if value[i] == '\'' { + if !put(emitter, '\'') { + return false + } + } + if !write(emitter, value, &i) { + return false + } + emitter.indention = false + spaces = false + breaks = false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{'\''}, false, false, false) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_double_quoted_scalar(emitter *yaml_emitter_t, value []byte, allow_breaks bool) bool { + spaces := false + if !yaml_emitter_write_indicator(emitter, []byte{'"'}, true, false, false) { + return false + } + + for i := 0; i < len(value); { + if !is_printable(value, i) || (!emitter.unicode && !is_ascii(value, i)) || + is_bom(value, i) || is_break(value, i) || + value[i] == '"' || value[i] == '\\' { + + octet := value[i] + + var w int + var v rune + switch { + case octet&0x80 == 0x00: + w, v = 1, rune(octet&0x7F) + case octet&0xE0 == 0xC0: + w, v = 2, rune(octet&0x1F) + case octet&0xF0 == 0xE0: + w, v = 3, rune(octet&0x0F) + case octet&0xF8 == 0xF0: + w, v = 4, rune(octet&0x07) + } + for k := 1; k < w; k++ { + octet = value[i+k] + v = (v << 6) + (rune(octet) & 0x3F) + } + i += w + + if !put(emitter, '\\') { + return false + } + + var ok bool + switch v { + case 0x00: + ok = put(emitter, '0') + case 0x07: + ok = put(emitter, 'a') + case 0x08: + ok = put(emitter, 'b') + case 0x09: + ok = put(emitter, 't') + case 0x0A: + ok = put(emitter, 'n') + case 0x0b: + ok = put(emitter, 'v') + case 0x0c: + ok = put(emitter, 'f') + case 0x0d: + ok = put(emitter, 'r') + case 0x1b: + ok = put(emitter, 'e') + case 0x22: + ok = put(emitter, '"') + case 0x5c: + ok = put(emitter, '\\') + case 0x85: + ok = put(emitter, 'N') + case 0xA0: + ok = put(emitter, '_') + case 0x2028: + ok = put(emitter, 'L') + case 0x2029: + ok = put(emitter, 'P') + default: + if v <= 0xFF { + ok = put(emitter, 'x') + w = 2 + } else if v <= 0xFFFF { + ok = put(emitter, 'u') + w = 4 + } else { + ok = put(emitter, 'U') + w = 8 + } + for k := (w - 1) * 4; ok && k >= 0; k -= 4 { + digit := byte((v >> uint(k)) & 0x0F) + if digit < 10 { + ok = put(emitter, digit+'0') + } else { + ok = put(emitter, digit+'A'-10) + } + } + } + if !ok { + return false + } + spaces = false + } else if is_space(value, i) { + if allow_breaks && !spaces && emitter.column > emitter.best_width && i > 0 && i < len(value)-1 { + if !yaml_emitter_write_indent(emitter) { + return false + } + if is_space(value, i+1) { + if !put(emitter, '\\') { + return false + } + } + i += width(value[i]) + } else if !write(emitter, value, &i) { + return false + } + spaces = true + } else { + if !write(emitter, value, &i) { + return false + } + spaces = false + } + } + if !yaml_emitter_write_indicator(emitter, []byte{'"'}, false, false, false) { + return false + } + emitter.whitespace = false + emitter.indention = false + return true +} + +func yaml_emitter_write_block_scalar_hints(emitter *yaml_emitter_t, value []byte) bool { + if is_space(value, 0) || is_break(value, 0) { + indent_hint := []byte{'0' + byte(emitter.best_indent)} + if !yaml_emitter_write_indicator(emitter, indent_hint, false, false, false) { + return false + } + } + + emitter.open_ended = false + + var chomp_hint [1]byte + if len(value) == 0 { + chomp_hint[0] = '-' + } else { + i := len(value) - 1 + for value[i]&0xC0 == 0x80 { + i-- + } + if !is_break(value, i) { + chomp_hint[0] = '-' + } else if i == 0 { + chomp_hint[0] = '+' + emitter.open_ended = true + } else { + i-- + for value[i]&0xC0 == 0x80 { + i-- + } + if is_break(value, i) { + chomp_hint[0] = '+' + emitter.open_ended = true + } + } + } + if chomp_hint[0] != 0 { + if !yaml_emitter_write_indicator(emitter, chomp_hint[:], false, false, false) { + return false + } + } + return true +} + +func yaml_emitter_write_literal_scalar(emitter *yaml_emitter_t, value []byte) bool { + if !yaml_emitter_write_indicator(emitter, []byte{'|'}, true, false, false) { + return false + } + if !yaml_emitter_write_block_scalar_hints(emitter, value) { + return false + } + if !yaml_emitter_process_line_comment(emitter) { + return false + } + //emitter.indention = true + emitter.whitespace = true + breaks := true + for i := 0; i < len(value); { + if is_break(value, i) { + if !write_break(emitter, value, &i) { + return false + } + //emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + } + if !write(emitter, value, &i) { + return false + } + emitter.indention = false + breaks = false + } + } + + return true +} + +func yaml_emitter_write_folded_scalar(emitter *yaml_emitter_t, value []byte) bool { + if !yaml_emitter_write_indicator(emitter, []byte{'>'}, true, false, false) { + return false + } + if !yaml_emitter_write_block_scalar_hints(emitter, value) { + return false + } + if !yaml_emitter_process_line_comment(emitter) { + return false + } + + //emitter.indention = true + emitter.whitespace = true + + breaks := true + leading_spaces := true + for i := 0; i < len(value); { + if is_break(value, i) { + if !breaks && !leading_spaces && value[i] == '\n' { + k := 0 + for is_break(value, k) { + k += width(value[k]) + } + if !is_blankz(value, k) { + if !put_break(emitter) { + return false + } + } + } + if !write_break(emitter, value, &i) { + return false + } + //emitter.indention = true + breaks = true + } else { + if breaks { + if !yaml_emitter_write_indent(emitter) { + return false + } + leading_spaces = is_blank(value, i) + } + if !breaks && is_space(value, i) && !is_space(value, i+1) && emitter.column > emitter.best_width { + if !yaml_emitter_write_indent(emitter) { + return false + } + i += width(value[i]) + } else { + if !write(emitter, value, &i) { + return false + } + } + emitter.indention = false + breaks = false + } + } + return true +} + +func yaml_emitter_write_comment(emitter *yaml_emitter_t, comment []byte) bool { + breaks := false + pound := false + for i := 0; i < len(comment); { + if is_break(comment, i) { + if !write_break(emitter, comment, &i) { + return false + } + //emitter.indention = true + breaks = true + pound = false + } else { + if breaks && !yaml_emitter_write_indent(emitter) { + return false + } + if !pound { + if comment[i] != '#' && (!put(emitter, '#') || !put(emitter, ' ')) { + return false + } + pound = true + } + if !write(emitter, comment, &i) { + return false + } + emitter.indention = false + breaks = false + } + } + if !breaks && !put_break(emitter) { + return false + } + + emitter.whitespace = true + //emitter.indention = true + return true +} diff --git a/vendor/gopkg.in/yaml.v3/encode.go b/vendor/gopkg.in/yaml.v3/encode.go new file mode 100644 index 00000000..de9e72a3 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/encode.go @@ -0,0 +1,577 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package yaml + +import ( + "encoding" + "fmt" + "io" + "reflect" + "regexp" + "sort" + "strconv" + "strings" + "time" + "unicode/utf8" +) + +type encoder struct { + emitter yaml_emitter_t + event yaml_event_t + out []byte + flow bool + indent int + doneInit bool +} + +func newEncoder() *encoder { + e := &encoder{} + yaml_emitter_initialize(&e.emitter) + yaml_emitter_set_output_string(&e.emitter, &e.out) + yaml_emitter_set_unicode(&e.emitter, true) + return e +} + +func newEncoderWithWriter(w io.Writer) *encoder { + e := &encoder{} + yaml_emitter_initialize(&e.emitter) + yaml_emitter_set_output_writer(&e.emitter, w) + yaml_emitter_set_unicode(&e.emitter, true) + return e +} + +func (e *encoder) init() { + if e.doneInit { + return + } + if e.indent == 0 { + e.indent = 4 + } + e.emitter.best_indent = e.indent + yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING) + e.emit() + e.doneInit = true +} + +func (e *encoder) finish() { + e.emitter.open_ended = false + yaml_stream_end_event_initialize(&e.event) + e.emit() +} + +func (e *encoder) destroy() { + yaml_emitter_delete(&e.emitter) +} + +func (e *encoder) emit() { + // This will internally delete the e.event value. + e.must(yaml_emitter_emit(&e.emitter, &e.event)) +} + +func (e *encoder) must(ok bool) { + if !ok { + msg := e.emitter.problem + if msg == "" { + msg = "unknown problem generating YAML content" + } + failf("%s", msg) + } +} + +func (e *encoder) marshalDoc(tag string, in reflect.Value) { + e.init() + var node *Node + if in.IsValid() { + node, _ = in.Interface().(*Node) + } + if node != nil && node.Kind == DocumentNode { + e.nodev(in) + } else { + yaml_document_start_event_initialize(&e.event, nil, nil, true) + e.emit() + e.marshal(tag, in) + yaml_document_end_event_initialize(&e.event, true) + e.emit() + } +} + +func (e *encoder) marshal(tag string, in reflect.Value) { + tag = shortTag(tag) + if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() { + e.nilv() + return + } + iface := in.Interface() + switch value := iface.(type) { + case *Node: + e.nodev(in) + return + case Node: + if !in.CanAddr() { + var n = reflect.New(in.Type()).Elem() + n.Set(in) + in = n + } + e.nodev(in.Addr()) + return + case time.Time: + e.timev(tag, in) + return + case *time.Time: + e.timev(tag, in.Elem()) + return + case time.Duration: + e.stringv(tag, reflect.ValueOf(value.String())) + return + case Marshaler: + v, err := value.MarshalYAML() + if err != nil { + fail(err) + } + if v == nil { + e.nilv() + return + } + e.marshal(tag, reflect.ValueOf(v)) + return + case encoding.TextMarshaler: + text, err := value.MarshalText() + if err != nil { + fail(err) + } + in = reflect.ValueOf(string(text)) + case nil: + e.nilv() + return + } + switch in.Kind() { + case reflect.Interface: + e.marshal(tag, in.Elem()) + case reflect.Map: + e.mapv(tag, in) + case reflect.Ptr: + e.marshal(tag, in.Elem()) + case reflect.Struct: + e.structv(tag, in) + case reflect.Slice, reflect.Array: + e.slicev(tag, in) + case reflect.String: + e.stringv(tag, in) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + e.intv(tag, in) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + e.uintv(tag, in) + case reflect.Float32, reflect.Float64: + e.floatv(tag, in) + case reflect.Bool: + e.boolv(tag, in) + default: + panic("cannot marshal type: " + in.Type().String()) + } +} + +func (e *encoder) mapv(tag string, in reflect.Value) { + e.mappingv(tag, func() { + keys := keyList(in.MapKeys()) + sort.Sort(keys) + for _, k := range keys { + e.marshal("", k) + e.marshal("", in.MapIndex(k)) + } + }) +} + +func (e *encoder) fieldByIndex(v reflect.Value, index []int) (field reflect.Value) { + for _, num := range index { + for { + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return reflect.Value{} + } + v = v.Elem() + continue + } + break + } + v = v.Field(num) + } + return v +} + +func (e *encoder) structv(tag string, in reflect.Value) { + sinfo, err := getStructInfo(in.Type()) + if err != nil { + panic(err) + } + e.mappingv(tag, func() { + for _, info := range sinfo.FieldsList { + var value reflect.Value + if info.Inline == nil { + value = in.Field(info.Num) + } else { + value = e.fieldByIndex(in, info.Inline) + if !value.IsValid() { + continue + } + } + if info.OmitEmpty && isZero(value) { + continue + } + e.marshal("", reflect.ValueOf(info.Key)) + e.flow = info.Flow + e.marshal("", value) + } + if sinfo.InlineMap >= 0 { + m := in.Field(sinfo.InlineMap) + if m.Len() > 0 { + e.flow = false + keys := keyList(m.MapKeys()) + sort.Sort(keys) + for _, k := range keys { + if _, found := sinfo.FieldsMap[k.String()]; found { + panic(fmt.Sprintf("cannot have key %q in inlined map: conflicts with struct field", k.String())) + } + e.marshal("", k) + e.flow = false + e.marshal("", m.MapIndex(k)) + } + } + } + }) +} + +func (e *encoder) mappingv(tag string, f func()) { + implicit := tag == "" + style := yaml_BLOCK_MAPPING_STYLE + if e.flow { + e.flow = false + style = yaml_FLOW_MAPPING_STYLE + } + yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style) + e.emit() + f() + yaml_mapping_end_event_initialize(&e.event) + e.emit() +} + +func (e *encoder) slicev(tag string, in reflect.Value) { + implicit := tag == "" + style := yaml_BLOCK_SEQUENCE_STYLE + if e.flow { + e.flow = false + style = yaml_FLOW_SEQUENCE_STYLE + } + e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) + e.emit() + n := in.Len() + for i := 0; i < n; i++ { + e.marshal("", in.Index(i)) + } + e.must(yaml_sequence_end_event_initialize(&e.event)) + e.emit() +} + +// isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. +// +// The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported +// in YAML 1.2 and by this package, but these should be marshalled quoted for +// the time being for compatibility with other parsers. +func isBase60Float(s string) (result bool) { + // Fast path. + if s == "" { + return false + } + c := s[0] + if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { + return false + } + // Do the full match. + return base60float.MatchString(s) +} + +// From http://yaml.org/type/float.html, except the regular expression there +// is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. +var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) + +// isOldBool returns whether s is bool notation as defined in YAML 1.1. +// +// We continue to force strings that YAML 1.1 would interpret as booleans to be +// rendered as quotes strings so that the marshalled output valid for YAML 1.1 +// parsing. +func isOldBool(s string) (result bool) { + switch s { + case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON", + "n", "N", "no", "No", "NO", "off", "Off", "OFF": + return true + default: + return false + } +} + +func (e *encoder) stringv(tag string, in reflect.Value) { + var style yaml_scalar_style_t + s := in.String() + canUsePlain := true + switch { + case !utf8.ValidString(s): + if tag == binaryTag { + failf("explicitly tagged !!binary data must be base64-encoded") + } + if tag != "" { + failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) + } + // It can't be encoded directly as YAML so use a binary tag + // and encode it as base64. + tag = binaryTag + s = encodeBase64(s) + case tag == "": + // Check to see if it would resolve to a specific + // tag when encoded unquoted. If it doesn't, + // there's no need to quote it. + rtag, _ := resolve("", s) + canUsePlain = rtag == strTag && !(isBase60Float(s) || isOldBool(s)) + } + // Note: it's possible for user code to emit invalid YAML + // if they explicitly specify a tag and a string containing + // text that's incompatible with that tag. + switch { + case strings.Contains(s, "\n"): + if e.flow { + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } else { + style = yaml_LITERAL_SCALAR_STYLE + } + case canUsePlain: + style = yaml_PLAIN_SCALAR_STYLE + default: + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + e.emitScalar(s, "", tag, style, nil, nil, nil, nil) +} + +func (e *encoder) boolv(tag string, in reflect.Value) { + var s string + if in.Bool() { + s = "true" + } else { + s = "false" + } + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) intv(tag string, in reflect.Value) { + s := strconv.FormatInt(in.Int(), 10) + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) uintv(tag string, in reflect.Value) { + s := strconv.FormatUint(in.Uint(), 10) + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) timev(tag string, in reflect.Value) { + t := in.Interface().(time.Time) + s := t.Format(time.RFC3339Nano) + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) floatv(tag string, in reflect.Value) { + // Issue #352: When formatting, use the precision of the underlying value + precision := 64 + if in.Kind() == reflect.Float32 { + precision = 32 + } + + s := strconv.FormatFloat(in.Float(), 'g', -1, precision) + switch s { + case "+Inf": + s = ".inf" + case "-Inf": + s = "-.inf" + case "NaN": + s = ".nan" + } + e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) nilv() { + e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE, nil, nil, nil, nil) +} + +func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t, head, line, foot, tail []byte) { + // TODO Kill this function. Replace all initialize calls by their underlining Go literals. + implicit := tag == "" + if !implicit { + tag = longTag(tag) + } + e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) + e.event.head_comment = head + e.event.line_comment = line + e.event.foot_comment = foot + e.event.tail_comment = tail + e.emit() +} + +func (e *encoder) nodev(in reflect.Value) { + e.node(in.Interface().(*Node), "") +} + +func (e *encoder) node(node *Node, tail string) { + // Zero nodes behave as nil. + if node.Kind == 0 && node.IsZero() { + e.nilv() + return + } + + // If the tag was not explicitly requested, and dropping it won't change the + // implicit tag of the value, don't include it in the presentation. + var tag = node.Tag + var stag = shortTag(tag) + var forceQuoting bool + if tag != "" && node.Style&TaggedStyle == 0 { + if node.Kind == ScalarNode { + if stag == strTag && node.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0 { + tag = "" + } else { + rtag, _ := resolve("", node.Value) + if rtag == stag { + tag = "" + } else if stag == strTag { + tag = "" + forceQuoting = true + } + } + } else { + var rtag string + switch node.Kind { + case MappingNode: + rtag = mapTag + case SequenceNode: + rtag = seqTag + } + if rtag == stag { + tag = "" + } + } + } + + switch node.Kind { + case DocumentNode: + yaml_document_start_event_initialize(&e.event, nil, nil, true) + e.event.head_comment = []byte(node.HeadComment) + e.emit() + for _, node := range node.Content { + e.node(node, "") + } + yaml_document_end_event_initialize(&e.event, true) + e.event.foot_comment = []byte(node.FootComment) + e.emit() + + case SequenceNode: + style := yaml_BLOCK_SEQUENCE_STYLE + if node.Style&FlowStyle != 0 { + style = yaml_FLOW_SEQUENCE_STYLE + } + e.must(yaml_sequence_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style)) + e.event.head_comment = []byte(node.HeadComment) + e.emit() + for _, node := range node.Content { + e.node(node, "") + } + e.must(yaml_sequence_end_event_initialize(&e.event)) + e.event.line_comment = []byte(node.LineComment) + e.event.foot_comment = []byte(node.FootComment) + e.emit() + + case MappingNode: + style := yaml_BLOCK_MAPPING_STYLE + if node.Style&FlowStyle != 0 { + style = yaml_FLOW_MAPPING_STYLE + } + yaml_mapping_start_event_initialize(&e.event, []byte(node.Anchor), []byte(longTag(tag)), tag == "", style) + e.event.tail_comment = []byte(tail) + e.event.head_comment = []byte(node.HeadComment) + e.emit() + + // The tail logic below moves the foot comment of prior keys to the following key, + // since the value for each key may be a nested structure and the foot needs to be + // processed only the entirety of the value is streamed. The last tail is processed + // with the mapping end event. + var tail string + for i := 0; i+1 < len(node.Content); i += 2 { + k := node.Content[i] + foot := k.FootComment + if foot != "" { + kopy := *k + kopy.FootComment = "" + k = &kopy + } + e.node(k, tail) + tail = foot + + v := node.Content[i+1] + e.node(v, "") + } + + yaml_mapping_end_event_initialize(&e.event) + e.event.tail_comment = []byte(tail) + e.event.line_comment = []byte(node.LineComment) + e.event.foot_comment = []byte(node.FootComment) + e.emit() + + case AliasNode: + yaml_alias_event_initialize(&e.event, []byte(node.Value)) + e.event.head_comment = []byte(node.HeadComment) + e.event.line_comment = []byte(node.LineComment) + e.event.foot_comment = []byte(node.FootComment) + e.emit() + + case ScalarNode: + value := node.Value + if !utf8.ValidString(value) { + if stag == binaryTag { + failf("explicitly tagged !!binary data must be base64-encoded") + } + if stag != "" { + failf("cannot marshal invalid UTF-8 data as %s", stag) + } + // It can't be encoded directly as YAML so use a binary tag + // and encode it as base64. + tag = binaryTag + value = encodeBase64(value) + } + + style := yaml_PLAIN_SCALAR_STYLE + switch { + case node.Style&DoubleQuotedStyle != 0: + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + case node.Style&SingleQuotedStyle != 0: + style = yaml_SINGLE_QUOTED_SCALAR_STYLE + case node.Style&LiteralStyle != 0: + style = yaml_LITERAL_SCALAR_STYLE + case node.Style&FoldedStyle != 0: + style = yaml_FOLDED_SCALAR_STYLE + case strings.Contains(value, "\n"): + style = yaml_LITERAL_SCALAR_STYLE + case forceQuoting: + style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + + e.emitScalar(value, node.Anchor, tag, style, []byte(node.HeadComment), []byte(node.LineComment), []byte(node.FootComment), []byte(tail)) + default: + failf("cannot encode node with unknown kind %d", node.Kind) + } +} diff --git a/vendor/gopkg.in/yaml.v3/go.mod b/vendor/gopkg.in/yaml.v3/go.mod new file mode 100644 index 00000000..f407ea32 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/go.mod @@ -0,0 +1,5 @@ +module "gopkg.in/yaml.v3" + +require ( + "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 +) diff --git a/vendor/gopkg.in/yaml.v3/parserc.go b/vendor/gopkg.in/yaml.v3/parserc.go new file mode 100644 index 00000000..ac66fccc --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/parserc.go @@ -0,0 +1,1249 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package yaml + +import ( + "bytes" +) + +// The parser implements the following grammar: +// +// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END +// implicit_document ::= block_node DOCUMENT-END* +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// block_node_or_indentless_sequence ::= +// ALIAS +// | properties (block_content | indentless_block_sequence)? +// | block_content +// | indentless_block_sequence +// block_node ::= ALIAS +// | properties block_content? +// | block_content +// flow_node ::= ALIAS +// | properties flow_content? +// | flow_content +// properties ::= TAG ANCHOR? | ANCHOR TAG? +// block_content ::= block_collection | flow_collection | SCALAR +// flow_content ::= flow_collection | SCALAR +// block_collection ::= block_sequence | block_mapping +// flow_collection ::= flow_sequence | flow_mapping +// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END +// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ +// block_mapping ::= BLOCK-MAPPING_START +// ((KEY block_node_or_indentless_sequence?)? +// (VALUE block_node_or_indentless_sequence?)?)* +// BLOCK-END +// flow_sequence ::= FLOW-SEQUENCE-START +// (flow_sequence_entry FLOW-ENTRY)* +// flow_sequence_entry? +// FLOW-SEQUENCE-END +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// flow_mapping ::= FLOW-MAPPING-START +// (flow_mapping_entry FLOW-ENTRY)* +// flow_mapping_entry? +// FLOW-MAPPING-END +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + +// Peek the next token in the token queue. +func peek_token(parser *yaml_parser_t) *yaml_token_t { + if parser.token_available || yaml_parser_fetch_more_tokens(parser) { + token := &parser.tokens[parser.tokens_head] + yaml_parser_unfold_comments(parser, token) + return token + } + return nil +} + +// yaml_parser_unfold_comments walks through the comments queue and joins all +// comments behind the position of the provided token into the respective +// top-level comment slices in the parser. +func yaml_parser_unfold_comments(parser *yaml_parser_t, token *yaml_token_t) { + for parser.comments_head < len(parser.comments) && token.start_mark.index >= parser.comments[parser.comments_head].token_mark.index { + comment := &parser.comments[parser.comments_head] + if len(comment.head) > 0 { + if token.typ == yaml_BLOCK_END_TOKEN { + // No heads on ends, so keep comment.head for a follow up token. + break + } + if len(parser.head_comment) > 0 { + parser.head_comment = append(parser.head_comment, '\n') + } + parser.head_comment = append(parser.head_comment, comment.head...) + } + if len(comment.foot) > 0 { + if len(parser.foot_comment) > 0 { + parser.foot_comment = append(parser.foot_comment, '\n') + } + parser.foot_comment = append(parser.foot_comment, comment.foot...) + } + if len(comment.line) > 0 { + if len(parser.line_comment) > 0 { + parser.line_comment = append(parser.line_comment, '\n') + } + parser.line_comment = append(parser.line_comment, comment.line...) + } + *comment = yaml_comment_t{} + parser.comments_head++ + } +} + +// Remove the next token from the queue (must be called after peek_token). +func skip_token(parser *yaml_parser_t) { + parser.token_available = false + parser.tokens_parsed++ + parser.stream_end_produced = parser.tokens[parser.tokens_head].typ == yaml_STREAM_END_TOKEN + parser.tokens_head++ +} + +// Get the next event. +func yaml_parser_parse(parser *yaml_parser_t, event *yaml_event_t) bool { + // Erase the event object. + *event = yaml_event_t{} + + // No events after the end of the stream or error. + if parser.stream_end_produced || parser.error != yaml_NO_ERROR || parser.state == yaml_PARSE_END_STATE { + return true + } + + // Generate the next event. + return yaml_parser_state_machine(parser, event) +} + +// Set parser error. +func yaml_parser_set_parser_error(parser *yaml_parser_t, problem string, problem_mark yaml_mark_t) bool { + parser.error = yaml_PARSER_ERROR + parser.problem = problem + parser.problem_mark = problem_mark + return false +} + +func yaml_parser_set_parser_error_context(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string, problem_mark yaml_mark_t) bool { + parser.error = yaml_PARSER_ERROR + parser.context = context + parser.context_mark = context_mark + parser.problem = problem + parser.problem_mark = problem_mark + return false +} + +// State dispatcher. +func yaml_parser_state_machine(parser *yaml_parser_t, event *yaml_event_t) bool { + //trace("yaml_parser_state_machine", "state:", parser.state.String()) + + switch parser.state { + case yaml_PARSE_STREAM_START_STATE: + return yaml_parser_parse_stream_start(parser, event) + + case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, true) + + case yaml_PARSE_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, false) + + case yaml_PARSE_DOCUMENT_CONTENT_STATE: + return yaml_parser_parse_document_content(parser, event) + + case yaml_PARSE_DOCUMENT_END_STATE: + return yaml_parser_parse_document_end(parser, event) + + case yaml_PARSE_BLOCK_NODE_STATE: + return yaml_parser_parse_node(parser, event, true, false) + + case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: + return yaml_parser_parse_node(parser, event, true, true) + + case yaml_PARSE_FLOW_NODE_STATE: + return yaml_parser_parse_node(parser, event, false, false) + + case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, true) + + case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, false) + + case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_indentless_sequence_entry(parser, event) + + case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, true) + + case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, false) + + case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: + return yaml_parser_parse_block_mapping_value(parser, event) + + case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, true) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, false) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event) + + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event) + + case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, true) + + case yaml_PARSE_FLOW_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, false) + + case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, false) + + case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, true) + + default: + panic("invalid parser state") + } +} + +// Parse the production: +// stream ::= STREAM-START implicit_document? explicit_document* STREAM-END +// ************ +func yaml_parser_parse_stream_start(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_STREAM_START_TOKEN { + return yaml_parser_set_parser_error(parser, "did not find expected ", token.start_mark) + } + parser.state = yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE + *event = yaml_event_t{ + typ: yaml_STREAM_START_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + encoding: token.encoding, + } + skip_token(parser) + return true +} + +// Parse the productions: +// implicit_document ::= block_node DOCUMENT-END* +// * +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// ************************* +func yaml_parser_parse_document_start(parser *yaml_parser_t, event *yaml_event_t, implicit bool) bool { + + token := peek_token(parser) + if token == nil { + return false + } + + // Parse extra document end indicators. + if !implicit { + for token.typ == yaml_DOCUMENT_END_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + } + + if implicit && token.typ != yaml_VERSION_DIRECTIVE_TOKEN && + token.typ != yaml_TAG_DIRECTIVE_TOKEN && + token.typ != yaml_DOCUMENT_START_TOKEN && + token.typ != yaml_STREAM_END_TOKEN { + // Parse an implicit document. + if !yaml_parser_process_directives(parser, nil, nil) { + return false + } + parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) + parser.state = yaml_PARSE_BLOCK_NODE_STATE + + var head_comment []byte + if len(parser.head_comment) > 0 { + // [Go] Scan the header comment backwards, and if an empty line is found, break + // the header so the part before the last empty line goes into the + // document header, while the bottom of it goes into a follow up event. + for i := len(parser.head_comment) - 1; i > 0; i-- { + if parser.head_comment[i] == '\n' { + if i == len(parser.head_comment)-1 { + head_comment = parser.head_comment[:i] + parser.head_comment = parser.head_comment[i+1:] + break + } else if parser.head_comment[i-1] == '\n' { + head_comment = parser.head_comment[:i-1] + parser.head_comment = parser.head_comment[i+1:] + break + } + } + } + } + + *event = yaml_event_t{ + typ: yaml_DOCUMENT_START_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + + head_comment: head_comment, + } + + } else if token.typ != yaml_STREAM_END_TOKEN { + // Parse an explicit document. + var version_directive *yaml_version_directive_t + var tag_directives []yaml_tag_directive_t + start_mark := token.start_mark + if !yaml_parser_process_directives(parser, &version_directive, &tag_directives) { + return false + } + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_DOCUMENT_START_TOKEN { + yaml_parser_set_parser_error(parser, + "did not find expected ", token.start_mark) + return false + } + parser.states = append(parser.states, yaml_PARSE_DOCUMENT_END_STATE) + parser.state = yaml_PARSE_DOCUMENT_CONTENT_STATE + end_mark := token.end_mark + + *event = yaml_event_t{ + typ: yaml_DOCUMENT_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + version_directive: version_directive, + tag_directives: tag_directives, + implicit: false, + } + skip_token(parser) + + } else { + // Parse the stream end. + parser.state = yaml_PARSE_END_STATE + *event = yaml_event_t{ + typ: yaml_STREAM_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + skip_token(parser) + } + + return true +} + +// Parse the productions: +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// *********** +// +func yaml_parser_parse_document_content(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_VERSION_DIRECTIVE_TOKEN || + token.typ == yaml_TAG_DIRECTIVE_TOKEN || + token.typ == yaml_DOCUMENT_START_TOKEN || + token.typ == yaml_DOCUMENT_END_TOKEN || + token.typ == yaml_STREAM_END_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + return yaml_parser_process_empty_scalar(parser, event, + token.start_mark) + } + return yaml_parser_parse_node(parser, event, true, false) +} + +// Parse the productions: +// implicit_document ::= block_node DOCUMENT-END* +// ************* +// explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* +// +func yaml_parser_parse_document_end(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + + start_mark := token.start_mark + end_mark := token.start_mark + + implicit := true + if token.typ == yaml_DOCUMENT_END_TOKEN { + end_mark = token.end_mark + skip_token(parser) + implicit = false + } + + parser.tag_directives = parser.tag_directives[:0] + + parser.state = yaml_PARSE_DOCUMENT_START_STATE + *event = yaml_event_t{ + typ: yaml_DOCUMENT_END_EVENT, + start_mark: start_mark, + end_mark: end_mark, + implicit: implicit, + } + yaml_parser_set_event_comments(parser, event) + if len(event.head_comment) > 0 && len(event.foot_comment) == 0 { + event.foot_comment = event.head_comment + event.head_comment = nil + } + return true +} + +func yaml_parser_set_event_comments(parser *yaml_parser_t, event *yaml_event_t) { + event.head_comment = parser.head_comment + event.line_comment = parser.line_comment + event.foot_comment = parser.foot_comment + parser.head_comment = nil + parser.line_comment = nil + parser.foot_comment = nil + parser.tail_comment = nil + parser.stem_comment = nil +} + +// Parse the productions: +// block_node_or_indentless_sequence ::= +// ALIAS +// ***** +// | properties (block_content | indentless_block_sequence)? +// ********** * +// | block_content | indentless_block_sequence +// * +// block_node ::= ALIAS +// ***** +// | properties block_content? +// ********** * +// | block_content +// * +// flow_node ::= ALIAS +// ***** +// | properties flow_content? +// ********** * +// | flow_content +// * +// properties ::= TAG ANCHOR? | ANCHOR TAG? +// ************************* +// block_content ::= block_collection | flow_collection | SCALAR +// ****** +// flow_content ::= flow_collection | SCALAR +// ****** +func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, indentless_sequence bool) bool { + //defer trace("yaml_parser_parse_node", "block:", block, "indentless_sequence:", indentless_sequence)() + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_ALIAS_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + *event = yaml_event_t{ + typ: yaml_ALIAS_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + anchor: token.value, + } + yaml_parser_set_event_comments(parser, event) + skip_token(parser) + return true + } + + start_mark := token.start_mark + end_mark := token.start_mark + + var tag_token bool + var tag_handle, tag_suffix, anchor []byte + var tag_mark yaml_mark_t + if token.typ == yaml_ANCHOR_TOKEN { + anchor = token.value + start_mark = token.start_mark + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_TAG_TOKEN { + tag_token = true + tag_handle = token.value + tag_suffix = token.suffix + tag_mark = token.start_mark + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + } else if token.typ == yaml_TAG_TOKEN { + tag_token = true + tag_handle = token.value + tag_suffix = token.suffix + start_mark = token.start_mark + tag_mark = token.start_mark + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_ANCHOR_TOKEN { + anchor = token.value + end_mark = token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + } + + var tag []byte + if tag_token { + if len(tag_handle) == 0 { + tag = tag_suffix + tag_suffix = nil + } else { + for i := range parser.tag_directives { + if bytes.Equal(parser.tag_directives[i].handle, tag_handle) { + tag = append([]byte(nil), parser.tag_directives[i].prefix...) + tag = append(tag, tag_suffix...) + break + } + } + if len(tag) == 0 { + yaml_parser_set_parser_error_context(parser, + "while parsing a node", start_mark, + "found undefined tag handle", tag_mark) + return false + } + } + } + + implicit := len(tag) == 0 + if indentless_sequence && token.typ == yaml_BLOCK_ENTRY_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), + } + return true + } + if token.typ == yaml_SCALAR_TOKEN { + var plain_implicit, quoted_implicit bool + end_mark = token.end_mark + if (len(tag) == 0 && token.style == yaml_PLAIN_SCALAR_STYLE) || (len(tag) == 1 && tag[0] == '!') { + plain_implicit = true + } else if len(tag) == 0 { + quoted_implicit = true + } + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + value: token.value, + implicit: plain_implicit, + quoted_implicit: quoted_implicit, + style: yaml_style_t(token.style), + } + yaml_parser_set_event_comments(parser, event) + skip_token(parser) + return true + } + if token.typ == yaml_FLOW_SEQUENCE_START_TOKEN { + // [Go] Some of the events below can be merged as they differ only on style. + end_mark = token.end_mark + parser.state = yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_FLOW_SEQUENCE_STYLE), + } + yaml_parser_set_event_comments(parser, event) + return true + } + if token.typ == yaml_FLOW_MAPPING_START_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), + } + yaml_parser_set_event_comments(parser, event) + return true + } + if block && token.typ == yaml_BLOCK_SEQUENCE_START_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_SEQUENCE_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_BLOCK_SEQUENCE_STYLE), + } + if parser.stem_comment != nil { + event.head_comment = parser.stem_comment + parser.stem_comment = nil + } + return true + } + if block && token.typ == yaml_BLOCK_MAPPING_START_TOKEN { + end_mark = token.end_mark + parser.state = yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + style: yaml_style_t(yaml_BLOCK_MAPPING_STYLE), + } + if parser.stem_comment != nil { + event.head_comment = parser.stem_comment + parser.stem_comment = nil + } + return true + } + if len(anchor) > 0 || len(tag) > 0 { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + start_mark: start_mark, + end_mark: end_mark, + anchor: anchor, + tag: tag, + implicit: implicit, + quoted_implicit: false, + style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), + } + return true + } + + context := "while parsing a flow node" + if block { + context = "while parsing a block node" + } + yaml_parser_set_parser_error_context(parser, context, start_mark, + "did not find expected node content", token.start_mark) + return false +} + +// Parse the productions: +// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END +// ******************** *********** * ********* +// +func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_BLOCK_ENTRY_TOKEN { + mark := token.end_mark + prior_head_len := len(parser.head_comment) + skip_token(parser) + yaml_parser_split_stem_comment(parser, prior_head_len) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_BLOCK_ENTRY_TOKEN && token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE) + return yaml_parser_parse_node(parser, event, true, false) + } else { + parser.state = yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + } + if token.typ == yaml_BLOCK_END_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + + skip_token(parser) + return true + } + + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a block collection", context_mark, + "did not find expected '-' indicator", token.start_mark) +} + +// Parse the productions: +// indentless_sequence ::= (BLOCK-ENTRY block_node?)+ +// *********** * +func yaml_parser_parse_indentless_sequence_entry(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ == yaml_BLOCK_ENTRY_TOKEN { + mark := token.end_mark + prior_head_len := len(parser.head_comment) + skip_token(parser) + yaml_parser_split_stem_comment(parser, prior_head_len) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_BLOCK_ENTRY_TOKEN && + token.typ != yaml_KEY_TOKEN && + token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE) + return yaml_parser_parse_node(parser, event, true, false) + } + parser.state = yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + start_mark: token.start_mark, + end_mark: token.start_mark, // [Go] Shouldn't this be token.end_mark? + } + return true +} + +// Split stem comment from head comment. +// +// When a sequence or map is found under a sequence entry, the former head comment +// is assigned to the underlying sequence or map as a whole, not the individual +// sequence or map entry as would be expected otherwise. To handle this case the +// previous head comment is moved aside as the stem comment. +func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) { + if stem_len == 0 { + return + } + + token := peek_token(parser) + if token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN { + return + } + + parser.stem_comment = parser.head_comment[:stem_len] + if len(parser.head_comment) == stem_len { + parser.head_comment = nil + } else { + // Copy suffix to prevent very strange bugs if someone ever appends + // further bytes to the prefix in the stem_comment slice above. + parser.head_comment = append([]byte(nil), parser.head_comment[stem_len+1:]...) + } +} + +// Parse the productions: +// block_mapping ::= BLOCK-MAPPING_START +// ******************* +// ((KEY block_node_or_indentless_sequence?)? +// *** * +// (VALUE block_node_or_indentless_sequence?)?)* +// +// BLOCK-END +// ********* +// +func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + + token := peek_token(parser) + if token == nil { + return false + } + + // [Go] A tail comment was left from the prior mapping value processed. Emit an event + // as it needs to be processed with that value and not the following key. + if len(parser.tail_comment) > 0 { + *event = yaml_event_t{ + typ: yaml_TAIL_COMMENT_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + foot_comment: parser.tail_comment, + } + parser.tail_comment = nil + return true + } + + if token.typ == yaml_KEY_TOKEN { + mark := token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_KEY_TOKEN && + token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_VALUE_STATE) + return yaml_parser_parse_node(parser, event, true, true) + } else { + parser.state = yaml_PARSE_BLOCK_MAPPING_VALUE_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + } else if token.typ == yaml_BLOCK_END_TOKEN { + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + yaml_parser_set_event_comments(parser, event) + skip_token(parser) + return true + } + + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a block mapping", context_mark, + "did not find expected key", token.start_mark) +} + +// Parse the productions: +// block_mapping ::= BLOCK-MAPPING_START +// +// ((KEY block_node_or_indentless_sequence?)? +// +// (VALUE block_node_or_indentless_sequence?)?)* +// ***** * +// BLOCK-END +// +// +func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_VALUE_TOKEN { + mark := token.end_mark + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_KEY_TOKEN && + token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_BLOCK_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_BLOCK_MAPPING_KEY_STATE) + return yaml_parser_parse_node(parser, event, true, true) + } + parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) + } + parser.state = yaml_PARSE_BLOCK_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) +} + +// Parse the productions: +// flow_sequence ::= FLOW-SEQUENCE-START +// ******************* +// (flow_sequence_entry FLOW-ENTRY)* +// * ********** +// flow_sequence_entry? +// * +// FLOW-SEQUENCE-END +// ***************** +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * +// +func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + if !first { + if token.typ == yaml_FLOW_ENTRY_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } else { + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow sequence", context_mark, + "did not find expected ',' or ']'", token.start_mark) + } + } + + if token.typ == yaml_KEY_TOKEN { + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_START_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + implicit: true, + style: yaml_style_t(yaml_FLOW_MAPPING_STYLE), + } + skip_token(parser) + return true + } else if token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + + *event = yaml_event_t{ + typ: yaml_SEQUENCE_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + yaml_parser_set_event_comments(parser, event) + + skip_token(parser) + return true +} + +// +// Parse the productions: +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// *** * +// +func yaml_parser_parse_flow_sequence_entry_mapping_key(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_FLOW_ENTRY_TOKEN && + token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + mark := token.end_mark + skip_token(parser) + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE + return yaml_parser_process_empty_scalar(parser, event, mark) +} + +// Parse the productions: +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// ***** * +// +func yaml_parser_parse_flow_sequence_entry_mapping_value(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + if token.typ == yaml_VALUE_TOKEN { + skip_token(parser) + token := peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_SEQUENCE_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) +} + +// Parse the productions: +// flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * +// +func yaml_parser_parse_flow_sequence_entry_mapping_end(parser *yaml_parser_t, event *yaml_event_t) bool { + token := peek_token(parser) + if token == nil { + return false + } + parser.state = yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + start_mark: token.start_mark, + end_mark: token.start_mark, // [Go] Shouldn't this be end_mark? + } + return true +} + +// Parse the productions: +// flow_mapping ::= FLOW-MAPPING-START +// ****************** +// (flow_mapping_entry FLOW-ENTRY)* +// * ********** +// flow_mapping_entry? +// ****************** +// FLOW-MAPPING-END +// **************** +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * *** * +// +func yaml_parser_parse_flow_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { + if first { + token := peek_token(parser) + parser.marks = append(parser.marks, token.start_mark) + skip_token(parser) + } + + token := peek_token(parser) + if token == nil { + return false + } + + if token.typ != yaml_FLOW_MAPPING_END_TOKEN { + if !first { + if token.typ == yaml_FLOW_ENTRY_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } else { + context_mark := parser.marks[len(parser.marks)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow mapping", context_mark, + "did not find expected ',' or '}'", token.start_mark) + } + } + + if token.typ == yaml_KEY_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_VALUE_TOKEN && + token.typ != yaml_FLOW_ENTRY_TOKEN && + token.typ != yaml_FLOW_MAPPING_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_VALUE_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } else { + parser.state = yaml_PARSE_FLOW_MAPPING_VALUE_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) + } + } else if token.typ != yaml_FLOW_MAPPING_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + + parser.state = parser.states[len(parser.states)-1] + parser.states = parser.states[:len(parser.states)-1] + parser.marks = parser.marks[:len(parser.marks)-1] + *event = yaml_event_t{ + typ: yaml_MAPPING_END_EVENT, + start_mark: token.start_mark, + end_mark: token.end_mark, + } + yaml_parser_set_event_comments(parser, event) + skip_token(parser) + return true +} + +// Parse the productions: +// flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? +// * ***** * +// +func yaml_parser_parse_flow_mapping_value(parser *yaml_parser_t, event *yaml_event_t, empty bool) bool { + token := peek_token(parser) + if token == nil { + return false + } + if empty { + parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) + } + if token.typ == yaml_VALUE_TOKEN { + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + if token.typ != yaml_FLOW_ENTRY_TOKEN && token.typ != yaml_FLOW_MAPPING_END_TOKEN { + parser.states = append(parser.states, yaml_PARSE_FLOW_MAPPING_KEY_STATE) + return yaml_parser_parse_node(parser, event, false, false) + } + } + parser.state = yaml_PARSE_FLOW_MAPPING_KEY_STATE + return yaml_parser_process_empty_scalar(parser, event, token.start_mark) +} + +// Generate an empty scalar event. +func yaml_parser_process_empty_scalar(parser *yaml_parser_t, event *yaml_event_t, mark yaml_mark_t) bool { + *event = yaml_event_t{ + typ: yaml_SCALAR_EVENT, + start_mark: mark, + end_mark: mark, + value: nil, // Empty + implicit: true, + style: yaml_style_t(yaml_PLAIN_SCALAR_STYLE), + } + return true +} + +var default_tag_directives = []yaml_tag_directive_t{ + {[]byte("!"), []byte("!")}, + {[]byte("!!"), []byte("tag:yaml.org,2002:")}, +} + +// Parse directives. +func yaml_parser_process_directives(parser *yaml_parser_t, + version_directive_ref **yaml_version_directive_t, + tag_directives_ref *[]yaml_tag_directive_t) bool { + + var version_directive *yaml_version_directive_t + var tag_directives []yaml_tag_directive_t + + token := peek_token(parser) + if token == nil { + return false + } + + for token.typ == yaml_VERSION_DIRECTIVE_TOKEN || token.typ == yaml_TAG_DIRECTIVE_TOKEN { + if token.typ == yaml_VERSION_DIRECTIVE_TOKEN { + if version_directive != nil { + yaml_parser_set_parser_error(parser, + "found duplicate %YAML directive", token.start_mark) + return false + } + if token.major != 1 || token.minor != 1 { + yaml_parser_set_parser_error(parser, + "found incompatible YAML document", token.start_mark) + return false + } + version_directive = &yaml_version_directive_t{ + major: token.major, + minor: token.minor, + } + } else if token.typ == yaml_TAG_DIRECTIVE_TOKEN { + value := yaml_tag_directive_t{ + handle: token.value, + prefix: token.prefix, + } + if !yaml_parser_append_tag_directive(parser, value, false, token.start_mark) { + return false + } + tag_directives = append(tag_directives, value) + } + + skip_token(parser) + token = peek_token(parser) + if token == nil { + return false + } + } + + for i := range default_tag_directives { + if !yaml_parser_append_tag_directive(parser, default_tag_directives[i], true, token.start_mark) { + return false + } + } + + if version_directive_ref != nil { + *version_directive_ref = version_directive + } + if tag_directives_ref != nil { + *tag_directives_ref = tag_directives + } + return true +} + +// Append a tag directive to the directives stack. +func yaml_parser_append_tag_directive(parser *yaml_parser_t, value yaml_tag_directive_t, allow_duplicates bool, mark yaml_mark_t) bool { + for i := range parser.tag_directives { + if bytes.Equal(value.handle, parser.tag_directives[i].handle) { + if allow_duplicates { + return true + } + return yaml_parser_set_parser_error(parser, "found duplicate %TAG directive", mark) + } + } + + // [Go] I suspect the copy is unnecessary. This was likely done + // because there was no way to track ownership of the data. + value_copy := yaml_tag_directive_t{ + handle: make([]byte, len(value.handle)), + prefix: make([]byte, len(value.prefix)), + } + copy(value_copy.handle, value.handle) + copy(value_copy.prefix, value.prefix) + parser.tag_directives = append(parser.tag_directives, value_copy) + return true +} diff --git a/vendor/gopkg.in/yaml.v3/readerc.go b/vendor/gopkg.in/yaml.v3/readerc.go new file mode 100644 index 00000000..b7de0a89 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/readerc.go @@ -0,0 +1,434 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package yaml + +import ( + "io" +) + +// Set the reader error and return 0. +func yaml_parser_set_reader_error(parser *yaml_parser_t, problem string, offset int, value int) bool { + parser.error = yaml_READER_ERROR + parser.problem = problem + parser.problem_offset = offset + parser.problem_value = value + return false +} + +// Byte order marks. +const ( + bom_UTF8 = "\xef\xbb\xbf" + bom_UTF16LE = "\xff\xfe" + bom_UTF16BE = "\xfe\xff" +) + +// Determine the input stream encoding by checking the BOM symbol. If no BOM is +// found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. +func yaml_parser_determine_encoding(parser *yaml_parser_t) bool { + // Ensure that we had enough bytes in the raw buffer. + for !parser.eof && len(parser.raw_buffer)-parser.raw_buffer_pos < 3 { + if !yaml_parser_update_raw_buffer(parser) { + return false + } + } + + // Determine the encoding. + buf := parser.raw_buffer + pos := parser.raw_buffer_pos + avail := len(buf) - pos + if avail >= 2 && buf[pos] == bom_UTF16LE[0] && buf[pos+1] == bom_UTF16LE[1] { + parser.encoding = yaml_UTF16LE_ENCODING + parser.raw_buffer_pos += 2 + parser.offset += 2 + } else if avail >= 2 && buf[pos] == bom_UTF16BE[0] && buf[pos+1] == bom_UTF16BE[1] { + parser.encoding = yaml_UTF16BE_ENCODING + parser.raw_buffer_pos += 2 + parser.offset += 2 + } else if avail >= 3 && buf[pos] == bom_UTF8[0] && buf[pos+1] == bom_UTF8[1] && buf[pos+2] == bom_UTF8[2] { + parser.encoding = yaml_UTF8_ENCODING + parser.raw_buffer_pos += 3 + parser.offset += 3 + } else { + parser.encoding = yaml_UTF8_ENCODING + } + return true +} + +// Update the raw buffer. +func yaml_parser_update_raw_buffer(parser *yaml_parser_t) bool { + size_read := 0 + + // Return if the raw buffer is full. + if parser.raw_buffer_pos == 0 && len(parser.raw_buffer) == cap(parser.raw_buffer) { + return true + } + + // Return on EOF. + if parser.eof { + return true + } + + // Move the remaining bytes in the raw buffer to the beginning. + if parser.raw_buffer_pos > 0 && parser.raw_buffer_pos < len(parser.raw_buffer) { + copy(parser.raw_buffer, parser.raw_buffer[parser.raw_buffer_pos:]) + } + parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)-parser.raw_buffer_pos] + parser.raw_buffer_pos = 0 + + // Call the read handler to fill the buffer. + size_read, err := parser.read_handler(parser, parser.raw_buffer[len(parser.raw_buffer):cap(parser.raw_buffer)]) + parser.raw_buffer = parser.raw_buffer[:len(parser.raw_buffer)+size_read] + if err == io.EOF { + parser.eof = true + } else if err != nil { + return yaml_parser_set_reader_error(parser, "input error: "+err.Error(), parser.offset, -1) + } + return true +} + +// Ensure that the buffer contains at least `length` characters. +// Return true on success, false on failure. +// +// The length is supposed to be significantly less that the buffer size. +func yaml_parser_update_buffer(parser *yaml_parser_t, length int) bool { + if parser.read_handler == nil { + panic("read handler must be set") + } + + // [Go] This function was changed to guarantee the requested length size at EOF. + // The fact we need to do this is pretty awful, but the description above implies + // for that to be the case, and there are tests + + // If the EOF flag is set and the raw buffer is empty, do nothing. + if parser.eof && parser.raw_buffer_pos == len(parser.raw_buffer) { + // [Go] ACTUALLY! Read the documentation of this function above. + // This is just broken. To return true, we need to have the + // given length in the buffer. Not doing that means every single + // check that calls this function to make sure the buffer has a + // given length is Go) panicking; or C) accessing invalid memory. + //return true + } + + // Return if the buffer contains enough characters. + if parser.unread >= length { + return true + } + + // Determine the input encoding if it is not known yet. + if parser.encoding == yaml_ANY_ENCODING { + if !yaml_parser_determine_encoding(parser) { + return false + } + } + + // Move the unread characters to the beginning of the buffer. + buffer_len := len(parser.buffer) + if parser.buffer_pos > 0 && parser.buffer_pos < buffer_len { + copy(parser.buffer, parser.buffer[parser.buffer_pos:]) + buffer_len -= parser.buffer_pos + parser.buffer_pos = 0 + } else if parser.buffer_pos == buffer_len { + buffer_len = 0 + parser.buffer_pos = 0 + } + + // Open the whole buffer for writing, and cut it before returning. + parser.buffer = parser.buffer[:cap(parser.buffer)] + + // Fill the buffer until it has enough characters. + first := true + for parser.unread < length { + + // Fill the raw buffer if necessary. + if !first || parser.raw_buffer_pos == len(parser.raw_buffer) { + if !yaml_parser_update_raw_buffer(parser) { + parser.buffer = parser.buffer[:buffer_len] + return false + } + } + first = false + + // Decode the raw buffer. + inner: + for parser.raw_buffer_pos != len(parser.raw_buffer) { + var value rune + var width int + + raw_unread := len(parser.raw_buffer) - parser.raw_buffer_pos + + // Decode the next character. + switch parser.encoding { + case yaml_UTF8_ENCODING: + // Decode a UTF-8 character. Check RFC 3629 + // (http://www.ietf.org/rfc/rfc3629.txt) for more details. + // + // The following table (taken from the RFC) is used for + // decoding. + // + // Char. number range | UTF-8 octet sequence + // (hexadecimal) | (binary) + // --------------------+------------------------------------ + // 0000 0000-0000 007F | 0xxxxxxx + // 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + // 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + // 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + // + // Additionally, the characters in the range 0xD800-0xDFFF + // are prohibited as they are reserved for use with UTF-16 + // surrogate pairs. + + // Determine the length of the UTF-8 sequence. + octet := parser.raw_buffer[parser.raw_buffer_pos] + switch { + case octet&0x80 == 0x00: + width = 1 + case octet&0xE0 == 0xC0: + width = 2 + case octet&0xF0 == 0xE0: + width = 3 + case octet&0xF8 == 0xF0: + width = 4 + default: + // The leading octet is invalid. + return yaml_parser_set_reader_error(parser, + "invalid leading UTF-8 octet", + parser.offset, int(octet)) + } + + // Check if the raw buffer contains an incomplete character. + if width > raw_unread { + if parser.eof { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-8 octet sequence", + parser.offset, -1) + } + break inner + } + + // Decode the leading octet. + switch { + case octet&0x80 == 0x00: + value = rune(octet & 0x7F) + case octet&0xE0 == 0xC0: + value = rune(octet & 0x1F) + case octet&0xF0 == 0xE0: + value = rune(octet & 0x0F) + case octet&0xF8 == 0xF0: + value = rune(octet & 0x07) + default: + value = 0 + } + + // Check and decode the trailing octets. + for k := 1; k < width; k++ { + octet = parser.raw_buffer[parser.raw_buffer_pos+k] + + // Check if the octet is valid. + if (octet & 0xC0) != 0x80 { + return yaml_parser_set_reader_error(parser, + "invalid trailing UTF-8 octet", + parser.offset+k, int(octet)) + } + + // Decode the octet. + value = (value << 6) + rune(octet&0x3F) + } + + // Check the length of the sequence against the value. + switch { + case width == 1: + case width == 2 && value >= 0x80: + case width == 3 && value >= 0x800: + case width == 4 && value >= 0x10000: + default: + return yaml_parser_set_reader_error(parser, + "invalid length of a UTF-8 sequence", + parser.offset, -1) + } + + // Check the range of the value. + if value >= 0xD800 && value <= 0xDFFF || value > 0x10FFFF { + return yaml_parser_set_reader_error(parser, + "invalid Unicode character", + parser.offset, int(value)) + } + + case yaml_UTF16LE_ENCODING, yaml_UTF16BE_ENCODING: + var low, high int + if parser.encoding == yaml_UTF16LE_ENCODING { + low, high = 0, 1 + } else { + low, high = 1, 0 + } + + // The UTF-16 encoding is not as simple as one might + // naively think. Check RFC 2781 + // (http://www.ietf.org/rfc/rfc2781.txt). + // + // Normally, two subsequent bytes describe a Unicode + // character. However a special technique (called a + // surrogate pair) is used for specifying character + // values larger than 0xFFFF. + // + // A surrogate pair consists of two pseudo-characters: + // high surrogate area (0xD800-0xDBFF) + // low surrogate area (0xDC00-0xDFFF) + // + // The following formulas are used for decoding + // and encoding characters using surrogate pairs: + // + // U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) + // U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) + // W1 = 110110yyyyyyyyyy + // W2 = 110111xxxxxxxxxx + // + // where U is the character value, W1 is the high surrogate + // area, W2 is the low surrogate area. + + // Check for incomplete UTF-16 character. + if raw_unread < 2 { + if parser.eof { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 character", + parser.offset, -1) + } + break inner + } + + // Get the character. + value = rune(parser.raw_buffer[parser.raw_buffer_pos+low]) + + (rune(parser.raw_buffer[parser.raw_buffer_pos+high]) << 8) + + // Check for unexpected low surrogate area. + if value&0xFC00 == 0xDC00 { + return yaml_parser_set_reader_error(parser, + "unexpected low surrogate area", + parser.offset, int(value)) + } + + // Check for a high surrogate area. + if value&0xFC00 == 0xD800 { + width = 4 + + // Check for incomplete surrogate pair. + if raw_unread < 4 { + if parser.eof { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 surrogate pair", + parser.offset, -1) + } + break inner + } + + // Get the next character. + value2 := rune(parser.raw_buffer[parser.raw_buffer_pos+low+2]) + + (rune(parser.raw_buffer[parser.raw_buffer_pos+high+2]) << 8) + + // Check for a low surrogate area. + if value2&0xFC00 != 0xDC00 { + return yaml_parser_set_reader_error(parser, + "expected low surrogate area", + parser.offset+2, int(value2)) + } + + // Generate the value of the surrogate pair. + value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF) + } else { + width = 2 + } + + default: + panic("impossible") + } + + // Check if the character is in the allowed range: + // #x9 | #xA | #xD | [#x20-#x7E] (8 bit) + // | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) + // | [#x10000-#x10FFFF] (32 bit) + switch { + case value == 0x09: + case value == 0x0A: + case value == 0x0D: + case value >= 0x20 && value <= 0x7E: + case value == 0x85: + case value >= 0xA0 && value <= 0xD7FF: + case value >= 0xE000 && value <= 0xFFFD: + case value >= 0x10000 && value <= 0x10FFFF: + default: + return yaml_parser_set_reader_error(parser, + "control characters are not allowed", + parser.offset, int(value)) + } + + // Move the raw pointers. + parser.raw_buffer_pos += width + parser.offset += width + + // Finally put the character into the buffer. + if value <= 0x7F { + // 0000 0000-0000 007F . 0xxxxxxx + parser.buffer[buffer_len+0] = byte(value) + buffer_len += 1 + } else if value <= 0x7FF { + // 0000 0080-0000 07FF . 110xxxxx 10xxxxxx + parser.buffer[buffer_len+0] = byte(0xC0 + (value >> 6)) + parser.buffer[buffer_len+1] = byte(0x80 + (value & 0x3F)) + buffer_len += 2 + } else if value <= 0xFFFF { + // 0000 0800-0000 FFFF . 1110xxxx 10xxxxxx 10xxxxxx + parser.buffer[buffer_len+0] = byte(0xE0 + (value >> 12)) + parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 6) & 0x3F)) + parser.buffer[buffer_len+2] = byte(0x80 + (value & 0x3F)) + buffer_len += 3 + } else { + // 0001 0000-0010 FFFF . 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + parser.buffer[buffer_len+0] = byte(0xF0 + (value >> 18)) + parser.buffer[buffer_len+1] = byte(0x80 + ((value >> 12) & 0x3F)) + parser.buffer[buffer_len+2] = byte(0x80 + ((value >> 6) & 0x3F)) + parser.buffer[buffer_len+3] = byte(0x80 + (value & 0x3F)) + buffer_len += 4 + } + + parser.unread++ + } + + // On EOF, put NUL into the buffer and return. + if parser.eof { + parser.buffer[buffer_len] = 0 + buffer_len++ + parser.unread++ + break + } + } + // [Go] Read the documentation of this function above. To return true, + // we need to have the given length in the buffer. Not doing that means + // every single check that calls this function to make sure the buffer + // has a given length is Go) panicking; or C) accessing invalid memory. + // This happens here due to the EOF above breaking early. + for buffer_len < length { + parser.buffer[buffer_len] = 0 + buffer_len++ + } + parser.buffer = parser.buffer[:buffer_len] + return true +} diff --git a/vendor/gopkg.in/yaml.v3/resolve.go b/vendor/gopkg.in/yaml.v3/resolve.go new file mode 100644 index 00000000..64ae8880 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/resolve.go @@ -0,0 +1,326 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package yaml + +import ( + "encoding/base64" + "math" + "regexp" + "strconv" + "strings" + "time" +) + +type resolveMapItem struct { + value interface{} + tag string +} + +var resolveTable = make([]byte, 256) +var resolveMap = make(map[string]resolveMapItem) + +func init() { + t := resolveTable + t[int('+')] = 'S' // Sign + t[int('-')] = 'S' + for _, c := range "0123456789" { + t[int(c)] = 'D' // Digit + } + for _, c := range "yYnNtTfFoO~" { + t[int(c)] = 'M' // In map + } + t[int('.')] = '.' // Float (potentially in map) + + var resolveMapList = []struct { + v interface{} + tag string + l []string + }{ + {true, boolTag, []string{"true", "True", "TRUE"}}, + {false, boolTag, []string{"false", "False", "FALSE"}}, + {nil, nullTag, []string{"", "~", "null", "Null", "NULL"}}, + {math.NaN(), floatTag, []string{".nan", ".NaN", ".NAN"}}, + {math.Inf(+1), floatTag, []string{".inf", ".Inf", ".INF"}}, + {math.Inf(+1), floatTag, []string{"+.inf", "+.Inf", "+.INF"}}, + {math.Inf(-1), floatTag, []string{"-.inf", "-.Inf", "-.INF"}}, + {"<<", mergeTag, []string{"<<"}}, + } + + m := resolveMap + for _, item := range resolveMapList { + for _, s := range item.l { + m[s] = resolveMapItem{item.v, item.tag} + } + } +} + +const ( + nullTag = "!!null" + boolTag = "!!bool" + strTag = "!!str" + intTag = "!!int" + floatTag = "!!float" + timestampTag = "!!timestamp" + seqTag = "!!seq" + mapTag = "!!map" + binaryTag = "!!binary" + mergeTag = "!!merge" +) + +var longTags = make(map[string]string) +var shortTags = make(map[string]string) + +func init() { + for _, stag := range []string{nullTag, boolTag, strTag, intTag, floatTag, timestampTag, seqTag, mapTag, binaryTag, mergeTag} { + ltag := longTag(stag) + longTags[stag] = ltag + shortTags[ltag] = stag + } +} + +const longTagPrefix = "tag:yaml.org,2002:" + +func shortTag(tag string) string { + if strings.HasPrefix(tag, longTagPrefix) { + if stag, ok := shortTags[tag]; ok { + return stag + } + return "!!" + tag[len(longTagPrefix):] + } + return tag +} + +func longTag(tag string) string { + if strings.HasPrefix(tag, "!!") { + if ltag, ok := longTags[tag]; ok { + return ltag + } + return longTagPrefix + tag[2:] + } + return tag +} + +func resolvableTag(tag string) bool { + switch tag { + case "", strTag, boolTag, intTag, floatTag, nullTag, timestampTag: + return true + } + return false +} + +var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`) + +func resolve(tag string, in string) (rtag string, out interface{}) { + tag = shortTag(tag) + if !resolvableTag(tag) { + return tag, in + } + + defer func() { + switch tag { + case "", rtag, strTag, binaryTag: + return + case floatTag: + if rtag == intTag { + switch v := out.(type) { + case int64: + rtag = floatTag + out = float64(v) + return + case int: + rtag = floatTag + out = float64(v) + return + } + } + } + failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) + }() + + // Any data is accepted as a !!str or !!binary. + // Otherwise, the prefix is enough of a hint about what it might be. + hint := byte('N') + if in != "" { + hint = resolveTable[in[0]] + } + if hint != 0 && tag != strTag && tag != binaryTag { + // Handle things we can lookup in a map. + if item, ok := resolveMap[in]; ok { + return item.tag, item.value + } + + // Base 60 floats are a bad idea, were dropped in YAML 1.2, and + // are purposefully unsupported here. They're still quoted on + // the way out for compatibility with other parser, though. + + switch hint { + case 'M': + // We've already checked the map above. + + case '.': + // Not in the map, so maybe a normal float. + floatv, err := strconv.ParseFloat(in, 64) + if err == nil { + return floatTag, floatv + } + + case 'D', 'S': + // Int, float, or timestamp. + // Only try values as a timestamp if the value is unquoted or there's an explicit + // !!timestamp tag. + if tag == "" || tag == timestampTag { + t, ok := parseTimestamp(in) + if ok { + return timestampTag, t + } + } + + plain := strings.Replace(in, "_", "", -1) + intv, err := strconv.ParseInt(plain, 0, 64) + if err == nil { + if intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + uintv, err := strconv.ParseUint(plain, 0, 64) + if err == nil { + return intTag, uintv + } + if yamlStyleFloat.MatchString(plain) { + floatv, err := strconv.ParseFloat(plain, 64) + if err == nil { + return floatTag, floatv + } + } + if strings.HasPrefix(plain, "0b") { + intv, err := strconv.ParseInt(plain[2:], 2, 64) + if err == nil { + if intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + uintv, err := strconv.ParseUint(plain[2:], 2, 64) + if err == nil { + return intTag, uintv + } + } else if strings.HasPrefix(plain, "-0b") { + intv, err := strconv.ParseInt("-"+plain[3:], 2, 64) + if err == nil { + if true || intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + } + // Octals as introduced in version 1.2 of the spec. + // Octals from the 1.1 spec, spelled as 0777, are still + // decoded by default in v3 as well for compatibility. + // May be dropped in v4 depending on how usage evolves. + if strings.HasPrefix(plain, "0o") { + intv, err := strconv.ParseInt(plain[2:], 8, 64) + if err == nil { + if intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + uintv, err := strconv.ParseUint(plain[2:], 8, 64) + if err == nil { + return intTag, uintv + } + } else if strings.HasPrefix(plain, "-0o") { + intv, err := strconv.ParseInt("-"+plain[3:], 8, 64) + if err == nil { + if true || intv == int64(int(intv)) { + return intTag, int(intv) + } else { + return intTag, intv + } + } + } + default: + panic("internal error: missing handler for resolver table: " + string(rune(hint)) + " (with " + in + ")") + } + } + return strTag, in +} + +// encodeBase64 encodes s as base64 that is broken up into multiple lines +// as appropriate for the resulting length. +func encodeBase64(s string) string { + const lineLen = 70 + encLen := base64.StdEncoding.EncodedLen(len(s)) + lines := encLen/lineLen + 1 + buf := make([]byte, encLen*2+lines) + in := buf[0:encLen] + out := buf[encLen:] + base64.StdEncoding.Encode(in, []byte(s)) + k := 0 + for i := 0; i < len(in); i += lineLen { + j := i + lineLen + if j > len(in) { + j = len(in) + } + k += copy(out[k:], in[i:j]) + if lines > 1 { + out[k] = '\n' + k++ + } + } + return string(out[:k]) +} + +// This is a subset of the formats allowed by the regular expression +// defined at http://yaml.org/type/timestamp.html. +var allowedTimestampFormats = []string{ + "2006-1-2T15:4:5.999999999Z07:00", // RCF3339Nano with short date fields. + "2006-1-2t15:4:5.999999999Z07:00", // RFC3339Nano with short date fields and lower-case "t". + "2006-1-2 15:4:5.999999999", // space separated with no time zone + "2006-1-2", // date only + // Notable exception: time.Parse cannot handle: "2001-12-14 21:59:43.10 -5" + // from the set of examples. +} + +// parseTimestamp parses s as a timestamp string and +// returns the timestamp and reports whether it succeeded. +// Timestamp formats are defined at http://yaml.org/type/timestamp.html +func parseTimestamp(s string) (time.Time, bool) { + // TODO write code to check all the formats supported by + // http://yaml.org/type/timestamp.html instead of using time.Parse. + + // Quick check: all date formats start with YYYY-. + i := 0 + for ; i < len(s); i++ { + if c := s[i]; c < '0' || c > '9' { + break + } + } + if i != 4 || i == len(s) || s[i] != '-' { + return time.Time{}, false + } + for _, format := range allowedTimestampFormats { + if t, err := time.Parse(format, s); err == nil { + return t, true + } + } + return time.Time{}, false +} diff --git a/vendor/gopkg.in/yaml.v3/scannerc.go b/vendor/gopkg.in/yaml.v3/scannerc.go new file mode 100644 index 00000000..ca007010 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/scannerc.go @@ -0,0 +1,3038 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package yaml + +import ( + "bytes" + "fmt" +) + +// Introduction +// ************ +// +// The following notes assume that you are familiar with the YAML specification +// (http://yaml.org/spec/1.2/spec.html). We mostly follow it, although in +// some cases we are less restrictive that it requires. +// +// The process of transforming a YAML stream into a sequence of events is +// divided on two steps: Scanning and Parsing. +// +// The Scanner transforms the input stream into a sequence of tokens, while the +// parser transform the sequence of tokens produced by the Scanner into a +// sequence of parsing events. +// +// The Scanner is rather clever and complicated. The Parser, on the contrary, +// is a straightforward implementation of a recursive-descendant parser (or, +// LL(1) parser, as it is usually called). +// +// Actually there are two issues of Scanning that might be called "clever", the +// rest is quite straightforward. The issues are "block collection start" and +// "simple keys". Both issues are explained below in details. +// +// Here the Scanning step is explained and implemented. We start with the list +// of all the tokens produced by the Scanner together with short descriptions. +// +// Now, tokens: +// +// STREAM-START(encoding) # The stream start. +// STREAM-END # The stream end. +// VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. +// TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. +// DOCUMENT-START # '---' +// DOCUMENT-END # '...' +// BLOCK-SEQUENCE-START # Indentation increase denoting a block +// BLOCK-MAPPING-START # sequence or a block mapping. +// BLOCK-END # Indentation decrease. +// FLOW-SEQUENCE-START # '[' +// FLOW-SEQUENCE-END # ']' +// BLOCK-SEQUENCE-START # '{' +// BLOCK-SEQUENCE-END # '}' +// BLOCK-ENTRY # '-' +// FLOW-ENTRY # ',' +// KEY # '?' or nothing (simple keys). +// VALUE # ':' +// ALIAS(anchor) # '*anchor' +// ANCHOR(anchor) # '&anchor' +// TAG(handle,suffix) # '!handle!suffix' +// SCALAR(value,style) # A scalar. +// +// The following two tokens are "virtual" tokens denoting the beginning and the +// end of the stream: +// +// STREAM-START(encoding) +// STREAM-END +// +// We pass the information about the input stream encoding with the +// STREAM-START token. +// +// The next two tokens are responsible for tags: +// +// VERSION-DIRECTIVE(major,minor) +// TAG-DIRECTIVE(handle,prefix) +// +// Example: +// +// %YAML 1.1 +// %TAG ! !foo +// %TAG !yaml! tag:yaml.org,2002: +// --- +// +// The correspoding sequence of tokens: +// +// STREAM-START(utf-8) +// VERSION-DIRECTIVE(1,1) +// TAG-DIRECTIVE("!","!foo") +// TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") +// DOCUMENT-START +// STREAM-END +// +// Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole +// line. +// +// The document start and end indicators are represented by: +// +// DOCUMENT-START +// DOCUMENT-END +// +// Note that if a YAML stream contains an implicit document (without '---' +// and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be +// produced. +// +// In the following examples, we present whole documents together with the +// produced tokens. +// +// 1. An implicit document: +// +// 'a scalar' +// +// Tokens: +// +// STREAM-START(utf-8) +// SCALAR("a scalar",single-quoted) +// STREAM-END +// +// 2. An explicit document: +// +// --- +// 'a scalar' +// ... +// +// Tokens: +// +// STREAM-START(utf-8) +// DOCUMENT-START +// SCALAR("a scalar",single-quoted) +// DOCUMENT-END +// STREAM-END +// +// 3. Several documents in a stream: +// +// 'a scalar' +// --- +// 'another scalar' +// --- +// 'yet another scalar' +// +// Tokens: +// +// STREAM-START(utf-8) +// SCALAR("a scalar",single-quoted) +// DOCUMENT-START +// SCALAR("another scalar",single-quoted) +// DOCUMENT-START +// SCALAR("yet another scalar",single-quoted) +// STREAM-END +// +// We have already introduced the SCALAR token above. The following tokens are +// used to describe aliases, anchors, tag, and scalars: +// +// ALIAS(anchor) +// ANCHOR(anchor) +// TAG(handle,suffix) +// SCALAR(value,style) +// +// The following series of examples illustrate the usage of these tokens: +// +// 1. A recursive sequence: +// +// &A [ *A ] +// +// Tokens: +// +// STREAM-START(utf-8) +// ANCHOR("A") +// FLOW-SEQUENCE-START +// ALIAS("A") +// FLOW-SEQUENCE-END +// STREAM-END +// +// 2. A tagged scalar: +// +// !!float "3.14" # A good approximation. +// +// Tokens: +// +// STREAM-START(utf-8) +// TAG("!!","float") +// SCALAR("3.14",double-quoted) +// STREAM-END +// +// 3. Various scalar styles: +// +// --- # Implicit empty plain scalars do not produce tokens. +// --- a plain scalar +// --- 'a single-quoted scalar' +// --- "a double-quoted scalar" +// --- |- +// a literal scalar +// --- >- +// a folded +// scalar +// +// Tokens: +// +// STREAM-START(utf-8) +// DOCUMENT-START +// DOCUMENT-START +// SCALAR("a plain scalar",plain) +// DOCUMENT-START +// SCALAR("a single-quoted scalar",single-quoted) +// DOCUMENT-START +// SCALAR("a double-quoted scalar",double-quoted) +// DOCUMENT-START +// SCALAR("a literal scalar",literal) +// DOCUMENT-START +// SCALAR("a folded scalar",folded) +// STREAM-END +// +// Now it's time to review collection-related tokens. We will start with +// flow collections: +// +// FLOW-SEQUENCE-START +// FLOW-SEQUENCE-END +// FLOW-MAPPING-START +// FLOW-MAPPING-END +// FLOW-ENTRY +// KEY +// VALUE +// +// The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and +// FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' +// correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the +// indicators '?' and ':', which are used for denoting mapping keys and values, +// are represented by the KEY and VALUE tokens. +// +// The following examples show flow collections: +// +// 1. A flow sequence: +// +// [item 1, item 2, item 3] +// +// Tokens: +// +// STREAM-START(utf-8) +// FLOW-SEQUENCE-START +// SCALAR("item 1",plain) +// FLOW-ENTRY +// SCALAR("item 2",plain) +// FLOW-ENTRY +// SCALAR("item 3",plain) +// FLOW-SEQUENCE-END +// STREAM-END +// +// 2. A flow mapping: +// +// { +// a simple key: a value, # Note that the KEY token is produced. +// ? a complex key: another value, +// } +// +// Tokens: +// +// STREAM-START(utf-8) +// FLOW-MAPPING-START +// KEY +// SCALAR("a simple key",plain) +// VALUE +// SCALAR("a value",plain) +// FLOW-ENTRY +// KEY +// SCALAR("a complex key",plain) +// VALUE +// SCALAR("another value",plain) +// FLOW-ENTRY +// FLOW-MAPPING-END +// STREAM-END +// +// A simple key is a key which is not denoted by the '?' indicator. Note that +// the Scanner still produce the KEY token whenever it encounters a simple key. +// +// For scanning block collections, the following tokens are used (note that we +// repeat KEY and VALUE here): +// +// BLOCK-SEQUENCE-START +// BLOCK-MAPPING-START +// BLOCK-END +// BLOCK-ENTRY +// KEY +// VALUE +// +// The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation +// increase that precedes a block collection (cf. the INDENT token in Python). +// The token BLOCK-END denote indentation decrease that ends a block collection +// (cf. the DEDENT token in Python). However YAML has some syntax pecularities +// that makes detections of these tokens more complex. +// +// The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators +// '-', '?', and ':' correspondingly. +// +// The following examples show how the tokens BLOCK-SEQUENCE-START, +// BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: +// +// 1. Block sequences: +// +// - item 1 +// - item 2 +// - +// - item 3.1 +// - item 3.2 +// - +// key 1: value 1 +// key 2: value 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-ENTRY +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 3.1",plain) +// BLOCK-ENTRY +// SCALAR("item 3.2",plain) +// BLOCK-END +// BLOCK-ENTRY +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// 2. Block mappings: +// +// a simple key: a value # The KEY token is produced here. +// ? a complex key +// : another value +// a mapping: +// key 1: value 1 +// key 2: value 2 +// a sequence: +// - item 1 +// - item 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-MAPPING-START +// KEY +// SCALAR("a simple key",plain) +// VALUE +// SCALAR("a value",plain) +// KEY +// SCALAR("a complex key",plain) +// VALUE +// SCALAR("another value",plain) +// KEY +// SCALAR("a mapping",plain) +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// KEY +// SCALAR("a sequence",plain) +// VALUE +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// YAML does not always require to start a new block collection from a new +// line. If the current line contains only '-', '?', and ':' indicators, a new +// block collection may start at the current line. The following examples +// illustrate this case: +// +// 1. Collections in a sequence: +// +// - - item 1 +// - item 2 +// - key 1: value 1 +// key 2: value 2 +// - ? complex key +// : complex value +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// BLOCK-ENTRY +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// BLOCK-ENTRY +// BLOCK-MAPPING-START +// KEY +// SCALAR("complex key") +// VALUE +// SCALAR("complex value") +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// 2. Collections in a mapping: +// +// ? a sequence +// : - item 1 +// - item 2 +// ? a mapping +// : key 1: value 1 +// key 2: value 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-MAPPING-START +// KEY +// SCALAR("a sequence",plain) +// VALUE +// BLOCK-SEQUENCE-START +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// KEY +// SCALAR("a mapping",plain) +// VALUE +// BLOCK-MAPPING-START +// KEY +// SCALAR("key 1",plain) +// VALUE +// SCALAR("value 1",plain) +// KEY +// SCALAR("key 2",plain) +// VALUE +// SCALAR("value 2",plain) +// BLOCK-END +// BLOCK-END +// STREAM-END +// +// YAML also permits non-indented sequences if they are included into a block +// mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: +// +// key: +// - item 1 # BLOCK-SEQUENCE-START is NOT produced here. +// - item 2 +// +// Tokens: +// +// STREAM-START(utf-8) +// BLOCK-MAPPING-START +// KEY +// SCALAR("key",plain) +// VALUE +// BLOCK-ENTRY +// SCALAR("item 1",plain) +// BLOCK-ENTRY +// SCALAR("item 2",plain) +// BLOCK-END +// + +// Ensure that the buffer contains the required number of characters. +// Return true on success, false on failure (reader error or memory error). +func cache(parser *yaml_parser_t, length int) bool { + // [Go] This was inlined: !cache(A, B) -> unread < B && !update(A, B) + return parser.unread >= length || yaml_parser_update_buffer(parser, length) +} + +// Advance the buffer pointer. +func skip(parser *yaml_parser_t) { + if !is_blank(parser.buffer, parser.buffer_pos) { + parser.newlines = 0 + } + parser.mark.index++ + parser.mark.column++ + parser.unread-- + parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) +} + +func skip_line(parser *yaml_parser_t) { + if is_crlf(parser.buffer, parser.buffer_pos) { + parser.mark.index += 2 + parser.mark.column = 0 + parser.mark.line++ + parser.unread -= 2 + parser.buffer_pos += 2 + parser.newlines++ + } else if is_break(parser.buffer, parser.buffer_pos) { + parser.mark.index++ + parser.mark.column = 0 + parser.mark.line++ + parser.unread-- + parser.buffer_pos += width(parser.buffer[parser.buffer_pos]) + parser.newlines++ + } +} + +// Copy a character to a string buffer and advance pointers. +func read(parser *yaml_parser_t, s []byte) []byte { + if !is_blank(parser.buffer, parser.buffer_pos) { + parser.newlines = 0 + } + w := width(parser.buffer[parser.buffer_pos]) + if w == 0 { + panic("invalid character sequence") + } + if len(s) == 0 { + s = make([]byte, 0, 32) + } + if w == 1 && len(s)+w <= cap(s) { + s = s[:len(s)+1] + s[len(s)-1] = parser.buffer[parser.buffer_pos] + parser.buffer_pos++ + } else { + s = append(s, parser.buffer[parser.buffer_pos:parser.buffer_pos+w]...) + parser.buffer_pos += w + } + parser.mark.index++ + parser.mark.column++ + parser.unread-- + return s +} + +// Copy a line break character to a string buffer and advance pointers. +func read_line(parser *yaml_parser_t, s []byte) []byte { + buf := parser.buffer + pos := parser.buffer_pos + switch { + case buf[pos] == '\r' && buf[pos+1] == '\n': + // CR LF . LF + s = append(s, '\n') + parser.buffer_pos += 2 + parser.mark.index++ + parser.unread-- + case buf[pos] == '\r' || buf[pos] == '\n': + // CR|LF . LF + s = append(s, '\n') + parser.buffer_pos += 1 + case buf[pos] == '\xC2' && buf[pos+1] == '\x85': + // NEL . LF + s = append(s, '\n') + parser.buffer_pos += 2 + case buf[pos] == '\xE2' && buf[pos+1] == '\x80' && (buf[pos+2] == '\xA8' || buf[pos+2] == '\xA9'): + // LS|PS . LS|PS + s = append(s, buf[parser.buffer_pos:pos+3]...) + parser.buffer_pos += 3 + default: + return s + } + parser.mark.index++ + parser.mark.column = 0 + parser.mark.line++ + parser.unread-- + parser.newlines++ + return s +} + +// Get the next token. +func yaml_parser_scan(parser *yaml_parser_t, token *yaml_token_t) bool { + // Erase the token object. + *token = yaml_token_t{} // [Go] Is this necessary? + + // No tokens after STREAM-END or error. + if parser.stream_end_produced || parser.error != yaml_NO_ERROR { + return true + } + + // Ensure that the tokens queue contains enough tokens. + if !parser.token_available { + if !yaml_parser_fetch_more_tokens(parser) { + return false + } + } + + // Fetch the next token from the queue. + *token = parser.tokens[parser.tokens_head] + parser.tokens_head++ + parser.tokens_parsed++ + parser.token_available = false + + if token.typ == yaml_STREAM_END_TOKEN { + parser.stream_end_produced = true + } + return true +} + +// Set the scanner error and return false. +func yaml_parser_set_scanner_error(parser *yaml_parser_t, context string, context_mark yaml_mark_t, problem string) bool { + parser.error = yaml_SCANNER_ERROR + parser.context = context + parser.context_mark = context_mark + parser.problem = problem + parser.problem_mark = parser.mark + return false +} + +func yaml_parser_set_scanner_tag_error(parser *yaml_parser_t, directive bool, context_mark yaml_mark_t, problem string) bool { + context := "while parsing a tag" + if directive { + context = "while parsing a %TAG directive" + } + return yaml_parser_set_scanner_error(parser, context, context_mark, problem) +} + +func trace(args ...interface{}) func() { + pargs := append([]interface{}{"+++"}, args...) + fmt.Println(pargs...) + pargs = append([]interface{}{"---"}, args...) + return func() { fmt.Println(pargs...) } +} + +// Ensure that the tokens queue contains at least one token which can be +// returned to the Parser. +func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { + // While we need more tokens to fetch, do it. + for { + // [Go] The comment parsing logic requires a lookahead of two tokens + // so that foot comments may be parsed in time of associating them + // with the tokens that are parsed before them, and also for line + // comments to be transformed into head comments in some edge cases. + if parser.tokens_head < len(parser.tokens)-2 { + // If a potential simple key is at the head position, we need to fetch + // the next token to disambiguate it. + head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed] + if !ok { + break + } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok { + return false + } else if !valid { + break + } + } + // Fetch the next token. + if !yaml_parser_fetch_next_token(parser) { + return false + } + } + + parser.token_available = true + return true +} + +// The dispatcher for token fetchers. +func yaml_parser_fetch_next_token(parser *yaml_parser_t) (ok bool) { + // Ensure that the buffer is initialized. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // Check if we just started scanning. Fetch STREAM-START then. + if !parser.stream_start_produced { + return yaml_parser_fetch_stream_start(parser) + } + + scan_mark := parser.mark + + // Eat whitespaces and comments until we reach the next token. + if !yaml_parser_scan_to_next_token(parser) { + return false + } + + // [Go] While unrolling indents, transform the head comments of prior + // indentation levels observed after scan_start into foot comments at + // the respective indexes. + + // Check the indentation level against the current column. + if !yaml_parser_unroll_indent(parser, parser.mark.column, scan_mark) { + return false + } + + // Ensure that the buffer contains at least 4 characters. 4 is the length + // of the longest indicators ('--- ' and '... '). + if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { + return false + } + + // Is it the end of the stream? + if is_z(parser.buffer, parser.buffer_pos) { + return yaml_parser_fetch_stream_end(parser) + } + + // Is it a directive? + if parser.mark.column == 0 && parser.buffer[parser.buffer_pos] == '%' { + return yaml_parser_fetch_directive(parser) + } + + buf := parser.buffer + pos := parser.buffer_pos + + // Is it the document start indicator? + if parser.mark.column == 0 && buf[pos] == '-' && buf[pos+1] == '-' && buf[pos+2] == '-' && is_blankz(buf, pos+3) { + return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_START_TOKEN) + } + + // Is it the document end indicator? + if parser.mark.column == 0 && buf[pos] == '.' && buf[pos+1] == '.' && buf[pos+2] == '.' && is_blankz(buf, pos+3) { + return yaml_parser_fetch_document_indicator(parser, yaml_DOCUMENT_END_TOKEN) + } + + comment_mark := parser.mark + if len(parser.tokens) > 0 && (parser.flow_level == 0 && buf[pos] == ':' || parser.flow_level > 0 && buf[pos] == ',') { + // Associate any following comments with the prior token. + comment_mark = parser.tokens[len(parser.tokens)-1].start_mark + } + defer func() { + if !ok { + return + } + if len(parser.tokens) > 0 && parser.tokens[len(parser.tokens)-1].typ == yaml_BLOCK_ENTRY_TOKEN { + // Sequence indicators alone have no line comments. It becomes + // a head comment for whatever follows. + return + } + if !yaml_parser_scan_line_comment(parser, comment_mark) { + ok = false + return + } + }() + + // Is it the flow sequence start indicator? + if buf[pos] == '[' { + return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_SEQUENCE_START_TOKEN) + } + + // Is it the flow mapping start indicator? + if parser.buffer[parser.buffer_pos] == '{' { + return yaml_parser_fetch_flow_collection_start(parser, yaml_FLOW_MAPPING_START_TOKEN) + } + + // Is it the flow sequence end indicator? + if parser.buffer[parser.buffer_pos] == ']' { + return yaml_parser_fetch_flow_collection_end(parser, + yaml_FLOW_SEQUENCE_END_TOKEN) + } + + // Is it the flow mapping end indicator? + if parser.buffer[parser.buffer_pos] == '}' { + return yaml_parser_fetch_flow_collection_end(parser, + yaml_FLOW_MAPPING_END_TOKEN) + } + + // Is it the flow entry indicator? + if parser.buffer[parser.buffer_pos] == ',' { + return yaml_parser_fetch_flow_entry(parser) + } + + // Is it the block entry indicator? + if parser.buffer[parser.buffer_pos] == '-' && is_blankz(parser.buffer, parser.buffer_pos+1) { + return yaml_parser_fetch_block_entry(parser) + } + + // Is it the key indicator? + if parser.buffer[parser.buffer_pos] == '?' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { + return yaml_parser_fetch_key(parser) + } + + // Is it the value indicator? + if parser.buffer[parser.buffer_pos] == ':' && (parser.flow_level > 0 || is_blankz(parser.buffer, parser.buffer_pos+1)) { + return yaml_parser_fetch_value(parser) + } + + // Is it an alias? + if parser.buffer[parser.buffer_pos] == '*' { + return yaml_parser_fetch_anchor(parser, yaml_ALIAS_TOKEN) + } + + // Is it an anchor? + if parser.buffer[parser.buffer_pos] == '&' { + return yaml_parser_fetch_anchor(parser, yaml_ANCHOR_TOKEN) + } + + // Is it a tag? + if parser.buffer[parser.buffer_pos] == '!' { + return yaml_parser_fetch_tag(parser) + } + + // Is it a literal scalar? + if parser.buffer[parser.buffer_pos] == '|' && parser.flow_level == 0 { + return yaml_parser_fetch_block_scalar(parser, true) + } + + // Is it a folded scalar? + if parser.buffer[parser.buffer_pos] == '>' && parser.flow_level == 0 { + return yaml_parser_fetch_block_scalar(parser, false) + } + + // Is it a single-quoted scalar? + if parser.buffer[parser.buffer_pos] == '\'' { + return yaml_parser_fetch_flow_scalar(parser, true) + } + + // Is it a double-quoted scalar? + if parser.buffer[parser.buffer_pos] == '"' { + return yaml_parser_fetch_flow_scalar(parser, false) + } + + // Is it a plain scalar? + // + // A plain scalar may start with any non-blank characters except + // + // '-', '?', ':', ',', '[', ']', '{', '}', + // '#', '&', '*', '!', '|', '>', '\'', '\"', + // '%', '@', '`'. + // + // In the block context (and, for the '-' indicator, in the flow context + // too), it may also start with the characters + // + // '-', '?', ':' + // + // if it is followed by a non-space character. + // + // The last rule is more restrictive than the specification requires. + // [Go] TODO Make this logic more reasonable. + //switch parser.buffer[parser.buffer_pos] { + //case '-', '?', ':', ',', '?', '-', ',', ':', ']', '[', '}', '{', '&', '#', '!', '*', '>', '|', '"', '\'', '@', '%', '-', '`': + //} + if !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '-' || + parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':' || + parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '[' || + parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || + parser.buffer[parser.buffer_pos] == '}' || parser.buffer[parser.buffer_pos] == '#' || + parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '*' || + parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '|' || + parser.buffer[parser.buffer_pos] == '>' || parser.buffer[parser.buffer_pos] == '\'' || + parser.buffer[parser.buffer_pos] == '"' || parser.buffer[parser.buffer_pos] == '%' || + parser.buffer[parser.buffer_pos] == '@' || parser.buffer[parser.buffer_pos] == '`') || + (parser.buffer[parser.buffer_pos] == '-' && !is_blank(parser.buffer, parser.buffer_pos+1)) || + (parser.flow_level == 0 && + (parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == ':') && + !is_blankz(parser.buffer, parser.buffer_pos+1)) { + return yaml_parser_fetch_plain_scalar(parser) + } + + // If we don't determine the token type so far, it is an error. + return yaml_parser_set_scanner_error(parser, + "while scanning for the next token", parser.mark, + "found character that cannot start any token") +} + +func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) { + if !simple_key.possible { + return false, true + } + + // The 1.2 specification says: + // + // "If the ? indicator is omitted, parsing needs to see past the + // implicit key to recognize it as such. To limit the amount of + // lookahead required, the “:” indicator must appear at most 1024 + // Unicode characters beyond the start of the key. In addition, the key + // is restricted to a single line." + // + if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index { + // Check if the potential simple key to be removed is required. + if simple_key.required { + return false, yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key.mark, + "could not find expected ':'") + } + simple_key.possible = false + return false, true + } + return true, true +} + +// Check if a simple key may start at the current position and add it if +// needed. +func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { + // A simple key is required at the current position if the scanner is in + // the block context and the current column coincides with the indentation + // level. + + required := parser.flow_level == 0 && parser.indent == parser.mark.column + + // + // If the current position may start a simple key, save it. + // + if parser.simple_key_allowed { + simple_key := yaml_simple_key_t{ + possible: true, + required: required, + token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), + mark: parser.mark, + } + + if !yaml_parser_remove_simple_key(parser) { + return false + } + parser.simple_keys[len(parser.simple_keys)-1] = simple_key + parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1 + } + return true +} + +// Remove a potential simple key at the current flow level. +func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { + i := len(parser.simple_keys) - 1 + if parser.simple_keys[i].possible { + // If the key is required, it is an error. + if parser.simple_keys[i].required { + return yaml_parser_set_scanner_error(parser, + "while scanning a simple key", parser.simple_keys[i].mark, + "could not find expected ':'") + } + // Remove the key from the stack. + parser.simple_keys[i].possible = false + delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number) + } + return true +} + +// max_flow_level limits the flow_level +const max_flow_level = 10000 + +// Increase the flow level and resize the simple key list if needed. +func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { + // Reset the simple key on the next level. + parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{ + possible: false, + required: false, + token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), + mark: parser.mark, + }) + + // Increase the flow level. + parser.flow_level++ + if parser.flow_level > max_flow_level { + return yaml_parser_set_scanner_error(parser, + "while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark, + fmt.Sprintf("exceeded max depth of %d", max_flow_level)) + } + return true +} + +// Decrease the flow level. +func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { + if parser.flow_level > 0 { + parser.flow_level-- + last := len(parser.simple_keys) - 1 + delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number) + parser.simple_keys = parser.simple_keys[:last] + } + return true +} + +// max_indents limits the indents stack size +const max_indents = 10000 + +// Push the current indentation level to the stack and set the new level +// the current column is greater than the indentation level. In this case, +// append or insert the specified token into the token queue. +func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml_token_type_t, mark yaml_mark_t) bool { + // In the flow context, do nothing. + if parser.flow_level > 0 { + return true + } + + if parser.indent < column { + // Push the current indentation level to the stack and set the new + // indentation level. + parser.indents = append(parser.indents, parser.indent) + parser.indent = column + if len(parser.indents) > max_indents { + return yaml_parser_set_scanner_error(parser, + "while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark, + fmt.Sprintf("exceeded max depth of %d", max_indents)) + } + + // Create a token and insert it into the queue. + token := yaml_token_t{ + typ: typ, + start_mark: mark, + end_mark: mark, + } + if number > -1 { + number -= parser.tokens_parsed + } + yaml_insert_token(parser, number, &token) + } + return true +} + +// Pop indentation levels from the indents stack until the current level +// becomes less or equal to the column. For each indentation level, append +// the BLOCK-END token. +func yaml_parser_unroll_indent(parser *yaml_parser_t, column int, scan_mark yaml_mark_t) bool { + // In the flow context, do nothing. + if parser.flow_level > 0 { + return true + } + + block_mark := scan_mark + block_mark.index-- + + // Loop through the indentation levels in the stack. + for parser.indent > column { + + // [Go] Reposition the end token before potential following + // foot comments of parent blocks. For that, search + // backwards for recent comments that were at the same + // indent as the block that is ending now. + stop_index := block_mark.index + for i := len(parser.comments) - 1; i >= 0; i-- { + comment := &parser.comments[i] + + if comment.end_mark.index < stop_index { + // Don't go back beyond the start of the comment/whitespace scan, unless column < 0. + // If requested indent column is < 0, then the document is over and everything else + // is a foot anyway. + break + } + if comment.start_mark.column == parser.indent+1 { + // This is a good match. But maybe there's a former comment + // at that same indent level, so keep searching. + block_mark = comment.start_mark + } + + // While the end of the former comment matches with + // the start of the following one, we know there's + // nothing in between and scanning is still safe. + stop_index = comment.scan_mark.index + } + + // Create a token and append it to the queue. + token := yaml_token_t{ + typ: yaml_BLOCK_END_TOKEN, + start_mark: block_mark, + end_mark: block_mark, + } + yaml_insert_token(parser, -1, &token) + + // Pop the indentation level. + parser.indent = parser.indents[len(parser.indents)-1] + parser.indents = parser.indents[:len(parser.indents)-1] + } + return true +} + +// Initialize the scanner and produce the STREAM-START token. +func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { + + // Set the initial indentation. + parser.indent = -1 + + // Initialize the simple key stack. + parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) + + parser.simple_keys_by_tok = make(map[int]int) + + // A simple key is allowed at the beginning of the stream. + parser.simple_key_allowed = true + + // We have started. + parser.stream_start_produced = true + + // Create the STREAM-START token and append it to the queue. + token := yaml_token_t{ + typ: yaml_STREAM_START_TOKEN, + start_mark: parser.mark, + end_mark: parser.mark, + encoding: parser.encoding, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the STREAM-END token and shut down the scanner. +func yaml_parser_fetch_stream_end(parser *yaml_parser_t) bool { + + // Force new line. + if parser.mark.column != 0 { + parser.mark.column = 0 + parser.mark.line++ + } + + // Reset the indentation level. + if !yaml_parser_unroll_indent(parser, -1, parser.mark) { + return false + } + + // Reset simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + parser.simple_key_allowed = false + + // Create the STREAM-END token and append it to the queue. + token := yaml_token_t{ + typ: yaml_STREAM_END_TOKEN, + start_mark: parser.mark, + end_mark: parser.mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. +func yaml_parser_fetch_directive(parser *yaml_parser_t) bool { + // Reset the indentation level. + if !yaml_parser_unroll_indent(parser, -1, parser.mark) { + return false + } + + // Reset simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + parser.simple_key_allowed = false + + // Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. + token := yaml_token_t{} + if !yaml_parser_scan_directive(parser, &token) { + return false + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the DOCUMENT-START or DOCUMENT-END token. +func yaml_parser_fetch_document_indicator(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // Reset the indentation level. + if !yaml_parser_unroll_indent(parser, -1, parser.mark) { + return false + } + + // Reset simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + parser.simple_key_allowed = false + + // Consume the token. + start_mark := parser.mark + + skip(parser) + skip(parser) + skip(parser) + + end_mark := parser.mark + + // Create the DOCUMENT-START or DOCUMENT-END token. + token := yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. +func yaml_parser_fetch_flow_collection_start(parser *yaml_parser_t, typ yaml_token_type_t) bool { + + // The indicators '[' and '{' may start a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // Increase the flow level. + if !yaml_parser_increase_flow_level(parser) { + return false + } + + // A simple key may follow the indicators '[' and '{'. + parser.simple_key_allowed = true + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. + token := yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. +func yaml_parser_fetch_flow_collection_end(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // Reset any potential simple key on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Decrease the flow level. + if !yaml_parser_decrease_flow_level(parser) { + return false + } + + // No simple keys after the indicators ']' and '}'. + parser.simple_key_allowed = false + + // Consume the token. + + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. + token := yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + } + // Append the token to the queue. + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the FLOW-ENTRY token. +func yaml_parser_fetch_flow_entry(parser *yaml_parser_t) bool { + // Reset any potential simple keys on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Simple keys are allowed after ','. + parser.simple_key_allowed = true + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the FLOW-ENTRY token and append it to the queue. + token := yaml_token_t{ + typ: yaml_FLOW_ENTRY_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the BLOCK-ENTRY token. +func yaml_parser_fetch_block_entry(parser *yaml_parser_t) bool { + // Check if the scanner is in the block context. + if parser.flow_level == 0 { + // Check if we are allowed to start a new entry. + if !parser.simple_key_allowed { + return yaml_parser_set_scanner_error(parser, "", parser.mark, + "block sequence entries are not allowed in this context") + } + // Add the BLOCK-SEQUENCE-START token if needed. + if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_SEQUENCE_START_TOKEN, parser.mark) { + return false + } + } else { + // It is an error for the '-' indicator to occur in the flow context, + // but we let the Parser detect and report about it because the Parser + // is able to point to the context. + } + + // Reset any potential simple keys on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Simple keys are allowed after '-'. + parser.simple_key_allowed = true + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the BLOCK-ENTRY token and append it to the queue. + token := yaml_token_t{ + typ: yaml_BLOCK_ENTRY_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the KEY token. +func yaml_parser_fetch_key(parser *yaml_parser_t) bool { + + // In the block context, additional checks are required. + if parser.flow_level == 0 { + // Check if we are allowed to start a new key (not nessesary simple). + if !parser.simple_key_allowed { + return yaml_parser_set_scanner_error(parser, "", parser.mark, + "mapping keys are not allowed in this context") + } + // Add the BLOCK-MAPPING-START token if needed. + if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { + return false + } + } + + // Reset any potential simple keys on the current flow level. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // Simple keys are allowed after '?' in the block context. + parser.simple_key_allowed = parser.flow_level == 0 + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the KEY token and append it to the queue. + token := yaml_token_t{ + typ: yaml_KEY_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the VALUE token. +func yaml_parser_fetch_value(parser *yaml_parser_t) bool { + + simple_key := &parser.simple_keys[len(parser.simple_keys)-1] + + // Have we found a simple key? + if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok { + return false + + } else if valid { + + // Create the KEY token and insert it into the queue. + token := yaml_token_t{ + typ: yaml_KEY_TOKEN, + start_mark: simple_key.mark, + end_mark: simple_key.mark, + } + yaml_insert_token(parser, simple_key.token_number-parser.tokens_parsed, &token) + + // In the block context, we may need to add the BLOCK-MAPPING-START token. + if !yaml_parser_roll_indent(parser, simple_key.mark.column, + simple_key.token_number, + yaml_BLOCK_MAPPING_START_TOKEN, simple_key.mark) { + return false + } + + // Remove the simple key. + simple_key.possible = false + delete(parser.simple_keys_by_tok, simple_key.token_number) + + // A simple key cannot follow another simple key. + parser.simple_key_allowed = false + + } else { + // The ':' indicator follows a complex key. + + // In the block context, extra checks are required. + if parser.flow_level == 0 { + + // Check if we are allowed to start a complex value. + if !parser.simple_key_allowed { + return yaml_parser_set_scanner_error(parser, "", parser.mark, + "mapping values are not allowed in this context") + } + + // Add the BLOCK-MAPPING-START token if needed. + if !yaml_parser_roll_indent(parser, parser.mark.column, -1, yaml_BLOCK_MAPPING_START_TOKEN, parser.mark) { + return false + } + } + + // Simple keys after ':' are allowed in the block context. + parser.simple_key_allowed = parser.flow_level == 0 + } + + // Consume the token. + start_mark := parser.mark + skip(parser) + end_mark := parser.mark + + // Create the VALUE token and append it to the queue. + token := yaml_token_t{ + typ: yaml_VALUE_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the ALIAS or ANCHOR token. +func yaml_parser_fetch_anchor(parser *yaml_parser_t, typ yaml_token_type_t) bool { + // An anchor or an alias could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow an anchor or an alias. + parser.simple_key_allowed = false + + // Create the ALIAS or ANCHOR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_anchor(parser, &token, typ) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the TAG token. +func yaml_parser_fetch_tag(parser *yaml_parser_t) bool { + // A tag could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow a tag. + parser.simple_key_allowed = false + + // Create the TAG token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_tag(parser, &token) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. +func yaml_parser_fetch_block_scalar(parser *yaml_parser_t, literal bool) bool { + // Remove any potential simple keys. + if !yaml_parser_remove_simple_key(parser) { + return false + } + + // A simple key may follow a block scalar. + parser.simple_key_allowed = true + + // Create the SCALAR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_block_scalar(parser, &token, literal) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. +func yaml_parser_fetch_flow_scalar(parser *yaml_parser_t, single bool) bool { + // A plain scalar could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow a flow scalar. + parser.simple_key_allowed = false + + // Create the SCALAR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_flow_scalar(parser, &token, single) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Produce the SCALAR(...,plain) token. +func yaml_parser_fetch_plain_scalar(parser *yaml_parser_t) bool { + // A plain scalar could be a simple key. + if !yaml_parser_save_simple_key(parser) { + return false + } + + // A simple key cannot follow a flow scalar. + parser.simple_key_allowed = false + + // Create the SCALAR token and append it to the queue. + var token yaml_token_t + if !yaml_parser_scan_plain_scalar(parser, &token) { + return false + } + yaml_insert_token(parser, -1, &token) + return true +} + +// Eat whitespaces and comments until the next token is found. +func yaml_parser_scan_to_next_token(parser *yaml_parser_t) bool { + + scan_mark := parser.mark + + // Until the next token is not found. + for { + // Allow the BOM mark to start a line. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if parser.mark.column == 0 && is_bom(parser.buffer, parser.buffer_pos) { + skip(parser) + } + + // Eat whitespaces. + // Tabs are allowed: + // - in the flow context + // - in the block context, but not at the beginning of the line or + // after '-', '?', or ':' (complex value). + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for parser.buffer[parser.buffer_pos] == ' ' || ((parser.flow_level > 0 || !parser.simple_key_allowed) && parser.buffer[parser.buffer_pos] == '\t') { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if we just had a line comment under a sequence entry that + // looks more like a header to the following content. Similar to this: + // + // - # The comment + // - Some data + // + // If so, transform the line comment to a head comment and reposition. + if len(parser.comments) > 0 && len(parser.tokens) > 1 { + tokenA := parser.tokens[len(parser.tokens)-2] + tokenB := parser.tokens[len(parser.tokens)-1] + comment := &parser.comments[len(parser.comments)-1] + if tokenA.typ == yaml_BLOCK_SEQUENCE_START_TOKEN && tokenB.typ == yaml_BLOCK_ENTRY_TOKEN && len(comment.line) > 0 && !is_break(parser.buffer, parser.buffer_pos) { + // If it was in the prior line, reposition so it becomes a + // header of the follow up token. Otherwise, keep it in place + // so it becomes a header of the former. + comment.head = comment.line + comment.line = nil + if comment.start_mark.line == parser.mark.line-1 { + comment.token_mark = parser.mark + } + } + } + + // Eat a comment until a line break. + if parser.buffer[parser.buffer_pos] == '#' { + if !yaml_parser_scan_comments(parser, scan_mark) { + return false + } + } + + // If it is a line break, eat it. + if is_break(parser.buffer, parser.buffer_pos) { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + + // In the block context, a new line may start a simple key. + if parser.flow_level == 0 { + parser.simple_key_allowed = true + } + } else { + break // We have found a token. + } + } + + return true +} + +// Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// +func yaml_parser_scan_directive(parser *yaml_parser_t, token *yaml_token_t) bool { + // Eat '%'. + start_mark := parser.mark + skip(parser) + + // Scan the directive name. + var name []byte + if !yaml_parser_scan_directive_name(parser, start_mark, &name) { + return false + } + + // Is it a YAML directive? + if bytes.Equal(name, []byte("YAML")) { + // Scan the VERSION directive value. + var major, minor int8 + if !yaml_parser_scan_version_directive_value(parser, start_mark, &major, &minor) { + return false + } + end_mark := parser.mark + + // Create a VERSION-DIRECTIVE token. + *token = yaml_token_t{ + typ: yaml_VERSION_DIRECTIVE_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + major: major, + minor: minor, + } + + // Is it a TAG directive? + } else if bytes.Equal(name, []byte("TAG")) { + // Scan the TAG directive value. + var handle, prefix []byte + if !yaml_parser_scan_tag_directive_value(parser, start_mark, &handle, &prefix) { + return false + } + end_mark := parser.mark + + // Create a TAG-DIRECTIVE token. + *token = yaml_token_t{ + typ: yaml_TAG_DIRECTIVE_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: handle, + prefix: prefix, + } + + // Unknown directive. + } else { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unknown directive name") + return false + } + + // Eat the rest of the line including any comments. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + if parser.buffer[parser.buffer_pos] == '#' { + // [Go] Discard this inline comment for the time being. + //if !yaml_parser_scan_line_comment(parser, start_mark) { + // return false + //} + for !is_breakz(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + } + + // Check if we are at the end of the line. + if !is_breakz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "did not find expected comment or line break") + return false + } + + // Eat a line break. + if is_break(parser.buffer, parser.buffer_pos) { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } + + return true +} + +// Scan the directive name. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^^^^ +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^ +// +func yaml_parser_scan_directive_name(parser *yaml_parser_t, start_mark yaml_mark_t, name *[]byte) bool { + // Consume the directive name. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + var s []byte + for is_alpha(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if the name is empty. + if len(s) == 0 { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "could not find expected directive name") + return false + } + + // Check for an blank character after the name. + if !is_blankz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unexpected non-alphabetical character") + return false + } + *name = s + return true +} + +// Scan the value of VERSION-DIRECTIVE. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^^^^^^ +func yaml_parser_scan_version_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, major, minor *int8) bool { + // Eat whitespaces. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Consume the major version number. + if !yaml_parser_scan_version_directive_number(parser, start_mark, major) { + return false + } + + // Eat '.'. + if parser.buffer[parser.buffer_pos] != '.' { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected digit or '.' character") + } + + skip(parser) + + // Consume the minor version number. + if !yaml_parser_scan_version_directive_number(parser, start_mark, minor) { + return false + } + return true +} + +const max_number_length = 2 + +// Scan the version number of VERSION-DIRECTIVE. +// +// Scope: +// %YAML 1.1 # a comment \n +// ^ +// %YAML 1.1 # a comment \n +// ^ +func yaml_parser_scan_version_directive_number(parser *yaml_parser_t, start_mark yaml_mark_t, number *int8) bool { + + // Repeat while the next character is digit. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + var value, length int8 + for is_digit(parser.buffer, parser.buffer_pos) { + // Check if the number is too long. + length++ + if length > max_number_length { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "found extremely long version number") + } + value = value*10 + int8(as_digit(parser.buffer, parser.buffer_pos)) + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if the number was present. + if length == 0 { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected version number") + } + *number = value + return true +} + +// Scan the value of a TAG-DIRECTIVE token. +// +// Scope: +// %TAG !yaml! tag:yaml.org,2002: \n +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +// +func yaml_parser_scan_tag_directive_value(parser *yaml_parser_t, start_mark yaml_mark_t, handle, prefix *[]byte) bool { + var handle_value, prefix_value []byte + + // Eat whitespaces. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Scan a handle. + if !yaml_parser_scan_tag_handle(parser, true, start_mark, &handle_value) { + return false + } + + // Expect a whitespace. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if !is_blank(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace") + return false + } + + // Eat whitespaces. + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Scan a prefix. + if !yaml_parser_scan_tag_uri(parser, true, nil, start_mark, &prefix_value) { + return false + } + + // Expect a whitespace or line break. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if !is_blankz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace or line break") + return false + } + + *handle = handle_value + *prefix = prefix_value + return true +} + +func yaml_parser_scan_anchor(parser *yaml_parser_t, token *yaml_token_t, typ yaml_token_type_t) bool { + var s []byte + + // Eat the indicator character. + start_mark := parser.mark + skip(parser) + + // Consume the value. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_alpha(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + end_mark := parser.mark + + /* + * Check if length of the anchor is greater than 0 and it is followed by + * a whitespace character or one of the indicators: + * + * '?', ':', ',', ']', '}', '%', '@', '`'. + */ + + if len(s) == 0 || + !(is_blankz(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == '?' || + parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == ',' || + parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '}' || + parser.buffer[parser.buffer_pos] == '%' || parser.buffer[parser.buffer_pos] == '@' || + parser.buffer[parser.buffer_pos] == '`') { + context := "while scanning an alias" + if typ == yaml_ANCHOR_TOKEN { + context = "while scanning an anchor" + } + yaml_parser_set_scanner_error(parser, context, start_mark, + "did not find expected alphabetic or numeric character") + return false + } + + // Create a token. + *token = yaml_token_t{ + typ: typ, + start_mark: start_mark, + end_mark: end_mark, + value: s, + } + + return true +} + +/* + * Scan a TAG token. + */ + +func yaml_parser_scan_tag(parser *yaml_parser_t, token *yaml_token_t) bool { + var handle, suffix []byte + + start_mark := parser.mark + + // Check if the tag is in the canonical form. + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + if parser.buffer[parser.buffer_pos+1] == '<' { + // Keep the handle as '' + + // Eat '!<' + skip(parser) + skip(parser) + + // Consume the tag value. + if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { + return false + } + + // Check for '>' and eat it. + if parser.buffer[parser.buffer_pos] != '>' { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find the expected '>'") + return false + } + + skip(parser) + } else { + // The tag has either the '!suffix' or the '!handle!suffix' form. + + // First, try to scan a handle. + if !yaml_parser_scan_tag_handle(parser, false, start_mark, &handle) { + return false + } + + // Check if it is, indeed, handle. + if handle[0] == '!' && len(handle) > 1 && handle[len(handle)-1] == '!' { + // Scan the suffix now. + if !yaml_parser_scan_tag_uri(parser, false, nil, start_mark, &suffix) { + return false + } + } else { + // It wasn't a handle after all. Scan the rest of the tag. + if !yaml_parser_scan_tag_uri(parser, false, handle, start_mark, &suffix) { + return false + } + + // Set the handle to '!'. + handle = []byte{'!'} + + // A special case: the '!' tag. Set the handle to '' and the + // suffix to '!'. + if len(suffix) == 0 { + handle, suffix = suffix, handle + } + } + } + + // Check the character which ends the tag. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if !is_blankz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find expected whitespace or line break") + return false + } + + end_mark := parser.mark + + // Create a token. + *token = yaml_token_t{ + typ: yaml_TAG_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: handle, + suffix: suffix, + } + return true +} + +// Scan a tag handle. +func yaml_parser_scan_tag_handle(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, handle *[]byte) bool { + // Check the initial '!' character. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if parser.buffer[parser.buffer_pos] != '!' { + yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find expected '!'") + return false + } + + var s []byte + + // Copy the '!' character. + s = read(parser, s) + + // Copy all subsequent alphabetical and numerical characters. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for is_alpha(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check if the trailing character is '!' and copy it. + if parser.buffer[parser.buffer_pos] == '!' { + s = read(parser, s) + } else { + // It's either the '!' tag or not really a tag handle. If it's a %TAG + // directive, it's an error. If it's a tag token, it must be a part of URI. + if directive && string(s) != "!" { + yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find expected '!'") + return false + } + } + + *handle = s + return true +} + +// Scan a tag. +func yaml_parser_scan_tag_uri(parser *yaml_parser_t, directive bool, head []byte, start_mark yaml_mark_t, uri *[]byte) bool { + //size_t length = head ? strlen((char *)head) : 0 + var s []byte + hasTag := len(head) > 0 + + // Copy the head if needed. + // + // Note that we don't copy the leading '!' character. + if len(head) > 1 { + s = append(s, head[1:]...) + } + + // Scan the tag. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // The set of characters that may appear in URI is as follows: + // + // '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', + // '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', + // '%'. + // [Go] TODO Convert this into more reasonable logic. + for is_alpha(parser.buffer, parser.buffer_pos) || parser.buffer[parser.buffer_pos] == ';' || + parser.buffer[parser.buffer_pos] == '/' || parser.buffer[parser.buffer_pos] == '?' || + parser.buffer[parser.buffer_pos] == ':' || parser.buffer[parser.buffer_pos] == '@' || + parser.buffer[parser.buffer_pos] == '&' || parser.buffer[parser.buffer_pos] == '=' || + parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '$' || + parser.buffer[parser.buffer_pos] == ',' || parser.buffer[parser.buffer_pos] == '.' || + parser.buffer[parser.buffer_pos] == '!' || parser.buffer[parser.buffer_pos] == '~' || + parser.buffer[parser.buffer_pos] == '*' || parser.buffer[parser.buffer_pos] == '\'' || + parser.buffer[parser.buffer_pos] == '(' || parser.buffer[parser.buffer_pos] == ')' || + parser.buffer[parser.buffer_pos] == '[' || parser.buffer[parser.buffer_pos] == ']' || + parser.buffer[parser.buffer_pos] == '%' { + // Check if it is a URI-escape sequence. + if parser.buffer[parser.buffer_pos] == '%' { + if !yaml_parser_scan_uri_escapes(parser, directive, start_mark, &s) { + return false + } + } else { + s = read(parser, s) + } + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + hasTag = true + } + + if !hasTag { + yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find expected tag URI") + return false + } + *uri = s + return true +} + +// Decode an URI-escape sequence corresponding to a single UTF-8 character. +func yaml_parser_scan_uri_escapes(parser *yaml_parser_t, directive bool, start_mark yaml_mark_t, s *[]byte) bool { + + // Decode the required number of characters. + w := 1024 + for w > 0 { + // Check for a URI-escaped octet. + if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { + return false + } + + if !(parser.buffer[parser.buffer_pos] == '%' && + is_hex(parser.buffer, parser.buffer_pos+1) && + is_hex(parser.buffer, parser.buffer_pos+2)) { + return yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "did not find URI escaped octet") + } + + // Get the octet. + octet := byte((as_hex(parser.buffer, parser.buffer_pos+1) << 4) + as_hex(parser.buffer, parser.buffer_pos+2)) + + // If it is the leading octet, determine the length of the UTF-8 sequence. + if w == 1024 { + w = width(octet) + if w == 0 { + return yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "found an incorrect leading UTF-8 octet") + } + } else { + // Check if the trailing octet is correct. + if octet&0xC0 != 0x80 { + return yaml_parser_set_scanner_tag_error(parser, directive, + start_mark, "found an incorrect trailing UTF-8 octet") + } + } + + // Copy the octet and move the pointers. + *s = append(*s, octet) + skip(parser) + skip(parser) + skip(parser) + w-- + } + return true +} + +// Scan a block scalar. +func yaml_parser_scan_block_scalar(parser *yaml_parser_t, token *yaml_token_t, literal bool) bool { + // Eat the indicator '|' or '>'. + start_mark := parser.mark + skip(parser) + + // Scan the additional block scalar indicators. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // Check for a chomping indicator. + var chomping, increment int + if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { + // Set the chomping method and eat the indicator. + if parser.buffer[parser.buffer_pos] == '+' { + chomping = +1 + } else { + chomping = -1 + } + skip(parser) + + // Check for an indentation indicator. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if is_digit(parser.buffer, parser.buffer_pos) { + // Check that the indentation is greater than 0. + if parser.buffer[parser.buffer_pos] == '0' { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an indentation indicator equal to 0") + return false + } + + // Get the indentation level and eat the indicator. + increment = as_digit(parser.buffer, parser.buffer_pos) + skip(parser) + } + + } else if is_digit(parser.buffer, parser.buffer_pos) { + // Do the same as above, but in the opposite order. + + if parser.buffer[parser.buffer_pos] == '0' { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an indentation indicator equal to 0") + return false + } + increment = as_digit(parser.buffer, parser.buffer_pos) + skip(parser) + + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if parser.buffer[parser.buffer_pos] == '+' || parser.buffer[parser.buffer_pos] == '-' { + if parser.buffer[parser.buffer_pos] == '+' { + chomping = +1 + } else { + chomping = -1 + } + skip(parser) + } + } + + // Eat whitespaces and comments to the end of the line. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for is_blank(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + if parser.buffer[parser.buffer_pos] == '#' { + if !yaml_parser_scan_line_comment(parser, start_mark) { + return false + } + for !is_breakz(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + } + + // Check if we are at the end of the line. + if !is_breakz(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "did not find expected comment or line break") + return false + } + + // Eat a line break. + if is_break(parser.buffer, parser.buffer_pos) { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } + + end_mark := parser.mark + + // Set the indentation level if it was specified. + var indent int + if increment > 0 { + if parser.indent >= 0 { + indent = parser.indent + increment + } else { + indent = increment + } + } + + // Scan the leading line breaks and determine the indentation level if needed. + var s, leading_break, trailing_breaks []byte + if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { + return false + } + + // Scan the block scalar content. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + var leading_blank, trailing_blank bool + for parser.mark.column == indent && !is_z(parser.buffer, parser.buffer_pos) { + // We are at the beginning of a non-empty line. + + // Is it a trailing whitespace? + trailing_blank = is_blank(parser.buffer, parser.buffer_pos) + + // Check if we need to fold the leading line break. + if !literal && !leading_blank && !trailing_blank && len(leading_break) > 0 && leading_break[0] == '\n' { + // Do we need to join the lines by space? + if len(trailing_breaks) == 0 { + s = append(s, ' ') + } + } else { + s = append(s, leading_break...) + } + leading_break = leading_break[:0] + + // Append the remaining line breaks. + s = append(s, trailing_breaks...) + trailing_breaks = trailing_breaks[:0] + + // Is it a leading whitespace? + leading_blank = is_blank(parser.buffer, parser.buffer_pos) + + // Consume the current line. + for !is_breakz(parser.buffer, parser.buffer_pos) { + s = read(parser, s) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Consume the line break. + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + leading_break = read_line(parser, leading_break) + + // Eat the following indentation spaces and line breaks. + if !yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, start_mark, &end_mark) { + return false + } + } + + // Chomp the tail. + if chomping != -1 { + s = append(s, leading_break...) + } + if chomping == 1 { + s = append(s, trailing_breaks...) + } + + // Create a token. + *token = yaml_token_t{ + typ: yaml_SCALAR_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: s, + style: yaml_LITERAL_SCALAR_STYLE, + } + if !literal { + token.style = yaml_FOLDED_SCALAR_STYLE + } + return true +} + +// Scan indentation spaces and line breaks for a block scalar. Determine the +// indentation level if needed. +func yaml_parser_scan_block_scalar_breaks(parser *yaml_parser_t, indent *int, breaks *[]byte, start_mark yaml_mark_t, end_mark *yaml_mark_t) bool { + *end_mark = parser.mark + + // Eat the indentation spaces and line breaks. + max_indent := 0 + for { + // Eat the indentation spaces. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + for (*indent == 0 || parser.mark.column < *indent) && is_space(parser.buffer, parser.buffer_pos) { + skip(parser) + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + if parser.mark.column > max_indent { + max_indent = parser.mark.column + } + + // Check for a tab character messing the indentation. + if (*indent == 0 || parser.mark.column < *indent) && is_tab(parser.buffer, parser.buffer_pos) { + return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found a tab character where an indentation space is expected") + } + + // Have we found a non-empty line? + if !is_break(parser.buffer, parser.buffer_pos) { + break + } + + // Consume the line break. + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + // [Go] Should really be returning breaks instead. + *breaks = read_line(parser, *breaks) + *end_mark = parser.mark + } + + // Determine the indentation level if needed. + if *indent == 0 { + *indent = max_indent + if *indent < parser.indent+1 { + *indent = parser.indent + 1 + } + if *indent < 1 { + *indent = 1 + } + } + return true +} + +// Scan a quoted scalar. +func yaml_parser_scan_flow_scalar(parser *yaml_parser_t, token *yaml_token_t, single bool) bool { + // Eat the left quote. + start_mark := parser.mark + skip(parser) + + // Consume the content of the quoted scalar. + var s, leading_break, trailing_breaks, whitespaces []byte + for { + // Check that there are no document indicators at the beginning of the line. + if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { + return false + } + + if parser.mark.column == 0 && + ((parser.buffer[parser.buffer_pos+0] == '-' && + parser.buffer[parser.buffer_pos+1] == '-' && + parser.buffer[parser.buffer_pos+2] == '-') || + (parser.buffer[parser.buffer_pos+0] == '.' && + parser.buffer[parser.buffer_pos+1] == '.' && + parser.buffer[parser.buffer_pos+2] == '.')) && + is_blankz(parser.buffer, parser.buffer_pos+3) { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected document indicator") + return false + } + + // Check for EOF. + if is_z(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected end of stream") + return false + } + + // Consume non-blank characters. + leading_blanks := false + for !is_blankz(parser.buffer, parser.buffer_pos) { + if single && parser.buffer[parser.buffer_pos] == '\'' && parser.buffer[parser.buffer_pos+1] == '\'' { + // Is is an escaped single quote. + s = append(s, '\'') + skip(parser) + skip(parser) + + } else if single && parser.buffer[parser.buffer_pos] == '\'' { + // It is a right single quote. + break + } else if !single && parser.buffer[parser.buffer_pos] == '"' { + // It is a right double quote. + break + + } else if !single && parser.buffer[parser.buffer_pos] == '\\' && is_break(parser.buffer, parser.buffer_pos+1) { + // It is an escaped line break. + if parser.unread < 3 && !yaml_parser_update_buffer(parser, 3) { + return false + } + skip(parser) + skip_line(parser) + leading_blanks = true + break + + } else if !single && parser.buffer[parser.buffer_pos] == '\\' { + // It is an escape sequence. + code_length := 0 + + // Check the escape character. + switch parser.buffer[parser.buffer_pos+1] { + case '0': + s = append(s, 0) + case 'a': + s = append(s, '\x07') + case 'b': + s = append(s, '\x08') + case 't', '\t': + s = append(s, '\x09') + case 'n': + s = append(s, '\x0A') + case 'v': + s = append(s, '\x0B') + case 'f': + s = append(s, '\x0C') + case 'r': + s = append(s, '\x0D') + case 'e': + s = append(s, '\x1B') + case ' ': + s = append(s, '\x20') + case '"': + s = append(s, '"') + case '\'': + s = append(s, '\'') + case '\\': + s = append(s, '\\') + case 'N': // NEL (#x85) + s = append(s, '\xC2') + s = append(s, '\x85') + case '_': // #xA0 + s = append(s, '\xC2') + s = append(s, '\xA0') + case 'L': // LS (#x2028) + s = append(s, '\xE2') + s = append(s, '\x80') + s = append(s, '\xA8') + case 'P': // PS (#x2029) + s = append(s, '\xE2') + s = append(s, '\x80') + s = append(s, '\xA9') + case 'x': + code_length = 2 + case 'u': + code_length = 4 + case 'U': + code_length = 8 + default: + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found unknown escape character") + return false + } + + skip(parser) + skip(parser) + + // Consume an arbitrary escape code. + if code_length > 0 { + var value int + + // Scan the character value. + if parser.unread < code_length && !yaml_parser_update_buffer(parser, code_length) { + return false + } + for k := 0; k < code_length; k++ { + if !is_hex(parser.buffer, parser.buffer_pos+k) { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "did not find expected hexdecimal number") + return false + } + value = (value << 4) + as_hex(parser.buffer, parser.buffer_pos+k) + } + + // Check the value and write the character. + if (value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found invalid Unicode character escape code") + return false + } + if value <= 0x7F { + s = append(s, byte(value)) + } else if value <= 0x7FF { + s = append(s, byte(0xC0+(value>>6))) + s = append(s, byte(0x80+(value&0x3F))) + } else if value <= 0xFFFF { + s = append(s, byte(0xE0+(value>>12))) + s = append(s, byte(0x80+((value>>6)&0x3F))) + s = append(s, byte(0x80+(value&0x3F))) + } else { + s = append(s, byte(0xF0+(value>>18))) + s = append(s, byte(0x80+((value>>12)&0x3F))) + s = append(s, byte(0x80+((value>>6)&0x3F))) + s = append(s, byte(0x80+(value&0x3F))) + } + + // Advance the pointer. + for k := 0; k < code_length; k++ { + skip(parser) + } + } + } else { + // It is a non-escaped non-blank character. + s = read(parser, s) + } + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + } + + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + // Check if we are at the end of the scalar. + if single { + if parser.buffer[parser.buffer_pos] == '\'' { + break + } + } else { + if parser.buffer[parser.buffer_pos] == '"' { + break + } + } + + // Consume blank characters. + for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { + if is_blank(parser.buffer, parser.buffer_pos) { + // Consume a space or a tab character. + if !leading_blanks { + whitespaces = read(parser, whitespaces) + } else { + skip(parser) + } + } else { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + // Check if it is a first line break. + if !leading_blanks { + whitespaces = whitespaces[:0] + leading_break = read_line(parser, leading_break) + leading_blanks = true + } else { + trailing_breaks = read_line(parser, trailing_breaks) + } + } + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Join the whitespaces or fold line breaks. + if leading_blanks { + // Do we need to fold line breaks? + if len(leading_break) > 0 && leading_break[0] == '\n' { + if len(trailing_breaks) == 0 { + s = append(s, ' ') + } else { + s = append(s, trailing_breaks...) + } + } else { + s = append(s, leading_break...) + s = append(s, trailing_breaks...) + } + trailing_breaks = trailing_breaks[:0] + leading_break = leading_break[:0] + } else { + s = append(s, whitespaces...) + whitespaces = whitespaces[:0] + } + } + + // Eat the right quote. + skip(parser) + end_mark := parser.mark + + // Create a token. + *token = yaml_token_t{ + typ: yaml_SCALAR_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: s, + style: yaml_SINGLE_QUOTED_SCALAR_STYLE, + } + if !single { + token.style = yaml_DOUBLE_QUOTED_SCALAR_STYLE + } + return true +} + +// Scan a plain scalar. +func yaml_parser_scan_plain_scalar(parser *yaml_parser_t, token *yaml_token_t) bool { + + var s, leading_break, trailing_breaks, whitespaces []byte + var leading_blanks bool + var indent = parser.indent + 1 + + start_mark := parser.mark + end_mark := parser.mark + + // Consume the content of the plain scalar. + for { + // Check for a document indicator. + if parser.unread < 4 && !yaml_parser_update_buffer(parser, 4) { + return false + } + if parser.mark.column == 0 && + ((parser.buffer[parser.buffer_pos+0] == '-' && + parser.buffer[parser.buffer_pos+1] == '-' && + parser.buffer[parser.buffer_pos+2] == '-') || + (parser.buffer[parser.buffer_pos+0] == '.' && + parser.buffer[parser.buffer_pos+1] == '.' && + parser.buffer[parser.buffer_pos+2] == '.')) && + is_blankz(parser.buffer, parser.buffer_pos+3) { + break + } + + // Check for a comment. + if parser.buffer[parser.buffer_pos] == '#' { + break + } + + // Consume non-blank characters. + for !is_blankz(parser.buffer, parser.buffer_pos) { + + // Check for indicators that may end a plain scalar. + if (parser.buffer[parser.buffer_pos] == ':' && is_blankz(parser.buffer, parser.buffer_pos+1)) || + (parser.flow_level > 0 && + (parser.buffer[parser.buffer_pos] == ',' || + parser.buffer[parser.buffer_pos] == '?' || parser.buffer[parser.buffer_pos] == '[' || + parser.buffer[parser.buffer_pos] == ']' || parser.buffer[parser.buffer_pos] == '{' || + parser.buffer[parser.buffer_pos] == '}')) { + break + } + + // Check if we need to join whitespaces and breaks. + if leading_blanks || len(whitespaces) > 0 { + if leading_blanks { + // Do we need to fold line breaks? + if leading_break[0] == '\n' { + if len(trailing_breaks) == 0 { + s = append(s, ' ') + } else { + s = append(s, trailing_breaks...) + } + } else { + s = append(s, leading_break...) + s = append(s, trailing_breaks...) + } + trailing_breaks = trailing_breaks[:0] + leading_break = leading_break[:0] + leading_blanks = false + } else { + s = append(s, whitespaces...) + whitespaces = whitespaces[:0] + } + } + + // Copy the character. + s = read(parser, s) + + end_mark = parser.mark + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + } + + // Is it the end? + if !(is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos)) { + break + } + + // Consume blank characters. + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + + for is_blank(parser.buffer, parser.buffer_pos) || is_break(parser.buffer, parser.buffer_pos) { + if is_blank(parser.buffer, parser.buffer_pos) { + + // Check for tab characters that abuse indentation. + if leading_blanks && parser.mark.column < indent && is_tab(parser.buffer, parser.buffer_pos) { + yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", + start_mark, "found a tab character that violates indentation") + return false + } + + // Consume a space or a tab character. + if !leading_blanks { + whitespaces = read(parser, whitespaces) + } else { + skip(parser) + } + } else { + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + + // Check if it is a first line break. + if !leading_blanks { + whitespaces = whitespaces[:0] + leading_break = read_line(parser, leading_break) + leading_blanks = true + } else { + trailing_breaks = read_line(parser, trailing_breaks) + } + } + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + } + + // Check indentation level. + if parser.flow_level == 0 && parser.mark.column < indent { + break + } + } + + // Create a token. + *token = yaml_token_t{ + typ: yaml_SCALAR_TOKEN, + start_mark: start_mark, + end_mark: end_mark, + value: s, + style: yaml_PLAIN_SCALAR_STYLE, + } + + // Note that we change the 'simple_key_allowed' flag. + if leading_blanks { + parser.simple_key_allowed = true + } + return true +} + +func yaml_parser_scan_line_comment(parser *yaml_parser_t, token_mark yaml_mark_t) bool { + if parser.newlines > 0 { + return true + } + + var start_mark yaml_mark_t + var text []byte + + for peek := 0; peek < 512; peek++ { + if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) { + break + } + if is_blank(parser.buffer, parser.buffer_pos+peek) { + continue + } + if parser.buffer[parser.buffer_pos+peek] == '#' { + seen := parser.mark.index+peek + for { + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if is_breakz(parser.buffer, parser.buffer_pos) { + if parser.mark.index >= seen { + break + } + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } else if parser.mark.index >= seen { + if len(text) == 0 { + start_mark = parser.mark + } + text = read(parser, text) + } else { + skip(parser) + } + } + } + break + } + if len(text) > 0 { + parser.comments = append(parser.comments, yaml_comment_t{ + token_mark: token_mark, + start_mark: start_mark, + line: text, + }) + } + return true +} + +func yaml_parser_scan_comments(parser *yaml_parser_t, scan_mark yaml_mark_t) bool { + token := parser.tokens[len(parser.tokens)-1] + + if token.typ == yaml_FLOW_ENTRY_TOKEN && len(parser.tokens) > 1 { + token = parser.tokens[len(parser.tokens)-2] + } + + var token_mark = token.start_mark + var start_mark yaml_mark_t + var next_indent = parser.indent + if next_indent < 0 { + next_indent = 0 + } + + var recent_empty = false + var first_empty = parser.newlines <= 1 + + var line = parser.mark.line + var column = parser.mark.column + + var text []byte + + // The foot line is the place where a comment must start to + // still be considered as a foot of the prior content. + // If there's some content in the currently parsed line, then + // the foot is the line below it. + var foot_line = -1 + if scan_mark.line > 0 { + foot_line = parser.mark.line-parser.newlines+1 + if parser.newlines == 0 && parser.mark.column > 1 { + foot_line++ + } + } + + var peek = 0 + for ; peek < 512; peek++ { + if parser.unread < peek+1 && !yaml_parser_update_buffer(parser, peek+1) { + break + } + column++ + if is_blank(parser.buffer, parser.buffer_pos+peek) { + continue + } + c := parser.buffer[parser.buffer_pos+peek] + var close_flow = parser.flow_level > 0 && (c == ']' || c == '}') + if close_flow || is_breakz(parser.buffer, parser.buffer_pos+peek) { + // Got line break or terminator. + if close_flow || !recent_empty { + if close_flow || first_empty && (start_mark.line == foot_line && token.typ != yaml_VALUE_TOKEN || start_mark.column-1 < next_indent) { + // This is the first empty line and there were no empty lines before, + // so this initial part of the comment is a foot of the prior token + // instead of being a head for the following one. Split it up. + // Alternatively, this might also be the last comment inside a flow + // scope, so it must be a footer. + if len(text) > 0 { + if start_mark.column-1 < next_indent { + // If dedented it's unrelated to the prior token. + token_mark = start_mark + } + parser.comments = append(parser.comments, yaml_comment_t{ + scan_mark: scan_mark, + token_mark: token_mark, + start_mark: start_mark, + end_mark: yaml_mark_t{parser.mark.index + peek, line, column}, + foot: text, + }) + scan_mark = yaml_mark_t{parser.mark.index + peek, line, column} + token_mark = scan_mark + text = nil + } + } else { + if len(text) > 0 && parser.buffer[parser.buffer_pos+peek] != 0 { + text = append(text, '\n') + } + } + } + if !is_break(parser.buffer, parser.buffer_pos+peek) { + break + } + first_empty = false + recent_empty = true + column = 0 + line++ + continue + } + + if len(text) > 0 && (close_flow || column-1 < next_indent && column != start_mark.column) { + // The comment at the different indentation is a foot of the + // preceding data rather than a head of the upcoming one. + parser.comments = append(parser.comments, yaml_comment_t{ + scan_mark: scan_mark, + token_mark: token_mark, + start_mark: start_mark, + end_mark: yaml_mark_t{parser.mark.index + peek, line, column}, + foot: text, + }) + scan_mark = yaml_mark_t{parser.mark.index + peek, line, column} + token_mark = scan_mark + text = nil + } + + if parser.buffer[parser.buffer_pos+peek] != '#' { + break + } + + if len(text) == 0 { + start_mark = yaml_mark_t{parser.mark.index + peek, line, column} + } else { + text = append(text, '\n') + } + + recent_empty = false + + // Consume until after the consumed comment line. + seen := parser.mark.index+peek + for { + if parser.unread < 1 && !yaml_parser_update_buffer(parser, 1) { + return false + } + if is_breakz(parser.buffer, parser.buffer_pos) { + if parser.mark.index >= seen { + break + } + if parser.unread < 2 && !yaml_parser_update_buffer(parser, 2) { + return false + } + skip_line(parser) + } else if parser.mark.index >= seen { + text = read(parser, text) + } else { + skip(parser) + } + } + + peek = 0 + column = 0 + line = parser.mark.line + next_indent = parser.indent + if next_indent < 0 { + next_indent = 0 + } + } + + if len(text) > 0 { + parser.comments = append(parser.comments, yaml_comment_t{ + scan_mark: scan_mark, + token_mark: start_mark, + start_mark: start_mark, + end_mark: yaml_mark_t{parser.mark.index + peek - 1, line, column}, + head: text, + }) + } + return true +} diff --git a/vendor/gopkg.in/yaml.v3/sorter.go b/vendor/gopkg.in/yaml.v3/sorter.go new file mode 100644 index 00000000..9210ece7 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/sorter.go @@ -0,0 +1,134 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package yaml + +import ( + "reflect" + "unicode" +) + +type keyList []reflect.Value + +func (l keyList) Len() int { return len(l) } +func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l keyList) Less(i, j int) bool { + a := l[i] + b := l[j] + ak := a.Kind() + bk := b.Kind() + for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { + a = a.Elem() + ak = a.Kind() + } + for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { + b = b.Elem() + bk = b.Kind() + } + af, aok := keyFloat(a) + bf, bok := keyFloat(b) + if aok && bok { + if af != bf { + return af < bf + } + if ak != bk { + return ak < bk + } + return numLess(a, b) + } + if ak != reflect.String || bk != reflect.String { + return ak < bk + } + ar, br := []rune(a.String()), []rune(b.String()) + digits := false + for i := 0; i < len(ar) && i < len(br); i++ { + if ar[i] == br[i] { + digits = unicode.IsDigit(ar[i]) + continue + } + al := unicode.IsLetter(ar[i]) + bl := unicode.IsLetter(br[i]) + if al && bl { + return ar[i] < br[i] + } + if al || bl { + if digits { + return al + } else { + return bl + } + } + var ai, bi int + var an, bn int64 + if ar[i] == '0' || br[i] == '0' { + for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- { + if ar[j] != '0' { + an = 1 + bn = 1 + break + } + } + } + for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { + an = an*10 + int64(ar[ai]-'0') + } + for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { + bn = bn*10 + int64(br[bi]-'0') + } + if an != bn { + return an < bn + } + if ai != bi { + return ai < bi + } + return ar[i] < br[i] + } + return len(ar) < len(br) +} + +// keyFloat returns a float value for v if it is a number/bool +// and whether it is a number/bool or not. +func keyFloat(v reflect.Value) (f float64, ok bool) { + switch v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return float64(v.Int()), true + case reflect.Float32, reflect.Float64: + return v.Float(), true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return float64(v.Uint()), true + case reflect.Bool: + if v.Bool() { + return 1, true + } + return 0, true + } + return 0, false +} + +// numLess returns whether a < b. +// a and b must necessarily have the same kind. +func numLess(a, b reflect.Value) bool { + switch a.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return a.Int() < b.Int() + case reflect.Float32, reflect.Float64: + return a.Float() < b.Float() + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return a.Uint() < b.Uint() + case reflect.Bool: + return !a.Bool() && b.Bool() + } + panic("not a number") +} diff --git a/vendor/gopkg.in/yaml.v3/writerc.go b/vendor/gopkg.in/yaml.v3/writerc.go new file mode 100644 index 00000000..b8a116bf --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/writerc.go @@ -0,0 +1,48 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package yaml + +// Set the writer error and return false. +func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { + emitter.error = yaml_WRITER_ERROR + emitter.problem = problem + return false +} + +// Flush the output buffer. +func yaml_emitter_flush(emitter *yaml_emitter_t) bool { + if emitter.write_handler == nil { + panic("write handler not set") + } + + // Check if the buffer is empty. + if emitter.buffer_pos == 0 { + return true + } + + if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { + return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) + } + emitter.buffer_pos = 0 + return true +} diff --git a/vendor/gopkg.in/yaml.v3/yaml.go b/vendor/gopkg.in/yaml.v3/yaml.go new file mode 100644 index 00000000..8cec6da4 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/yaml.go @@ -0,0 +1,698 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package yaml implements YAML support for the Go language. +// +// Source code and other details for the project are available at GitHub: +// +// https://github.com/go-yaml/yaml +// +package yaml + +import ( + "errors" + "fmt" + "io" + "reflect" + "strings" + "sync" + "unicode/utf8" +) + +// The Unmarshaler interface may be implemented by types to customize their +// behavior when being unmarshaled from a YAML document. +type Unmarshaler interface { + UnmarshalYAML(value *Node) error +} + +type obsoleteUnmarshaler interface { + UnmarshalYAML(unmarshal func(interface{}) error) error +} + +// The Marshaler interface may be implemented by types to customize their +// behavior when being marshaled into a YAML document. The returned value +// is marshaled in place of the original value implementing Marshaler. +// +// If an error is returned by MarshalYAML, the marshaling procedure stops +// and returns with the provided error. +type Marshaler interface { + MarshalYAML() (interface{}, error) +} + +// Unmarshal decodes the first document found within the in byte slice +// and assigns decoded values into the out value. +// +// Maps and pointers (to a struct, string, int, etc) are accepted as out +// values. If an internal pointer within a struct is not initialized, +// the yaml package will initialize it if necessary for unmarshalling +// the provided data. The out parameter must not be nil. +// +// The type of the decoded values should be compatible with the respective +// values in out. If one or more values cannot be decoded due to a type +// mismatches, decoding continues partially until the end of the YAML +// content, and a *yaml.TypeError is returned with details for all +// missed values. +// +// Struct fields are only unmarshalled if they are exported (have an +// upper case first letter), and are unmarshalled using the field name +// lowercased as the default key. Custom keys may be defined via the +// "yaml" name in the field tag: the content preceding the first comma +// is used as the key, and the following comma-separated options are +// used to tweak the marshalling process (see Marshal). +// Conflicting names result in a runtime error. +// +// For example: +// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// var t T +// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t) +// +// See the documentation of Marshal for the format of tags and a list of +// supported tag options. +// +func Unmarshal(in []byte, out interface{}) (err error) { + return unmarshal(in, out, false) +} + +// A Decoder reads and decodes YAML values from an input stream. +type Decoder struct { + parser *parser + knownFields bool +} + +// NewDecoder returns a new decoder that reads from r. +// +// The decoder introduces its own buffering and may read +// data from r beyond the YAML values requested. +func NewDecoder(r io.Reader) *Decoder { + return &Decoder{ + parser: newParserFromReader(r), + } +} + +// KnownFields ensures that the keys in decoded mappings to +// exist as fields in the struct being decoded into. +func (dec *Decoder) KnownFields(enable bool) { + dec.knownFields = enable +} + +// Decode reads the next YAML-encoded value from its input +// and stores it in the value pointed to by v. +// +// See the documentation for Unmarshal for details about the +// conversion of YAML into a Go value. +func (dec *Decoder) Decode(v interface{}) (err error) { + d := newDecoder() + d.knownFields = dec.knownFields + defer handleErr(&err) + node := dec.parser.parse() + if node == nil { + return io.EOF + } + out := reflect.ValueOf(v) + if out.Kind() == reflect.Ptr && !out.IsNil() { + out = out.Elem() + } + d.unmarshal(node, out) + if len(d.terrors) > 0 { + return &TypeError{d.terrors} + } + return nil +} + +// Decode decodes the node and stores its data into the value pointed to by v. +// +// See the documentation for Unmarshal for details about the +// conversion of YAML into a Go value. +func (n *Node) Decode(v interface{}) (err error) { + d := newDecoder() + defer handleErr(&err) + out := reflect.ValueOf(v) + if out.Kind() == reflect.Ptr && !out.IsNil() { + out = out.Elem() + } + d.unmarshal(n, out) + if len(d.terrors) > 0 { + return &TypeError{d.terrors} + } + return nil +} + +func unmarshal(in []byte, out interface{}, strict bool) (err error) { + defer handleErr(&err) + d := newDecoder() + p := newParser(in) + defer p.destroy() + node := p.parse() + if node != nil { + v := reflect.ValueOf(out) + if v.Kind() == reflect.Ptr && !v.IsNil() { + v = v.Elem() + } + d.unmarshal(node, v) + } + if len(d.terrors) > 0 { + return &TypeError{d.terrors} + } + return nil +} + +// Marshal serializes the value provided into a YAML document. The structure +// of the generated document will reflect the structure of the value itself. +// Maps and pointers (to struct, string, int, etc) are accepted as the in value. +// +// Struct fields are only marshalled if they are exported (have an upper case +// first letter), and are marshalled using the field name lowercased as the +// default key. Custom keys may be defined via the "yaml" name in the field +// tag: the content preceding the first comma is used as the key, and the +// following comma-separated options are used to tweak the marshalling process. +// Conflicting names result in a runtime error. +// +// The field tag format accepted is: +// +// `(...) yaml:"[][,[,]]" (...)` +// +// The following flags are currently supported: +// +// omitempty Only include the field if it's not set to the zero +// value for the type or to empty slices or maps. +// Zero valued structs will be omitted if all their public +// fields are zero, unless they implement an IsZero +// method (see the IsZeroer interface type), in which +// case the field will be excluded if IsZero returns true. +// +// flow Marshal using a flow style (useful for structs, +// sequences and maps). +// +// inline Inline the field, which must be a struct or a map, +// causing all of its fields or keys to be processed as if +// they were part of the outer struct. For maps, keys must +// not conflict with the yaml keys of other struct fields. +// +// In addition, if the key is "-", the field is ignored. +// +// For example: +// +// type T struct { +// F int `yaml:"a,omitempty"` +// B int +// } +// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n" +// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n" +// +func Marshal(in interface{}) (out []byte, err error) { + defer handleErr(&err) + e := newEncoder() + defer e.destroy() + e.marshalDoc("", reflect.ValueOf(in)) + e.finish() + out = e.out + return +} + +// An Encoder writes YAML values to an output stream. +type Encoder struct { + encoder *encoder +} + +// NewEncoder returns a new encoder that writes to w. +// The Encoder should be closed after use to flush all data +// to w. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{ + encoder: newEncoderWithWriter(w), + } +} + +// Encode writes the YAML encoding of v to the stream. +// If multiple items are encoded to the stream, the +// second and subsequent document will be preceded +// with a "---" document separator, but the first will not. +// +// See the documentation for Marshal for details about the conversion of Go +// values to YAML. +func (e *Encoder) Encode(v interface{}) (err error) { + defer handleErr(&err) + e.encoder.marshalDoc("", reflect.ValueOf(v)) + return nil +} + +// Encode encodes value v and stores its representation in n. +// +// See the documentation for Marshal for details about the +// conversion of Go values into YAML. +func (n *Node) Encode(v interface{}) (err error) { + defer handleErr(&err) + e := newEncoder() + defer e.destroy() + e.marshalDoc("", reflect.ValueOf(v)) + e.finish() + p := newParser(e.out) + p.textless = true + defer p.destroy() + doc := p.parse() + *n = *doc.Content[0] + return nil +} + +// SetIndent changes the used indentation used when encoding. +func (e *Encoder) SetIndent(spaces int) { + if spaces < 0 { + panic("yaml: cannot indent to a negative number of spaces") + } + e.encoder.indent = spaces +} + +// Close closes the encoder by writing any remaining data. +// It does not write a stream terminating string "...". +func (e *Encoder) Close() (err error) { + defer handleErr(&err) + e.encoder.finish() + return nil +} + +func handleErr(err *error) { + if v := recover(); v != nil { + if e, ok := v.(yamlError); ok { + *err = e.err + } else { + panic(v) + } + } +} + +type yamlError struct { + err error +} + +func fail(err error) { + panic(yamlError{err}) +} + +func failf(format string, args ...interface{}) { + panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) +} + +// A TypeError is returned by Unmarshal when one or more fields in +// the YAML document cannot be properly decoded into the requested +// types. When this error is returned, the value is still +// unmarshaled partially. +type TypeError struct { + Errors []string +} + +func (e *TypeError) Error() string { + return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) +} + +type Kind uint32 + +const ( + DocumentNode Kind = 1 << iota + SequenceNode + MappingNode + ScalarNode + AliasNode +) + +type Style uint32 + +const ( + TaggedStyle Style = 1 << iota + DoubleQuotedStyle + SingleQuotedStyle + LiteralStyle + FoldedStyle + FlowStyle +) + +// Node represents an element in the YAML document hierarchy. While documents +// are typically encoded and decoded into higher level types, such as structs +// and maps, Node is an intermediate representation that allows detailed +// control over the content being decoded or encoded. +// +// It's worth noting that although Node offers access into details such as +// line numbers, colums, and comments, the content when re-encoded will not +// have its original textual representation preserved. An effort is made to +// render the data plesantly, and to preserve comments near the data they +// describe, though. +// +// Values that make use of the Node type interact with the yaml package in the +// same way any other type would do, by encoding and decoding yaml data +// directly or indirectly into them. +// +// For example: +// +// var person struct { +// Name string +// Address yaml.Node +// } +// err := yaml.Unmarshal(data, &person) +// +// Or by itself: +// +// var person Node +// err := yaml.Unmarshal(data, &person) +// +type Node struct { + // Kind defines whether the node is a document, a mapping, a sequence, + // a scalar value, or an alias to another node. The specific data type of + // scalar nodes may be obtained via the ShortTag and LongTag methods. + Kind Kind + + // Style allows customizing the apperance of the node in the tree. + Style Style + + // Tag holds the YAML tag defining the data type for the value. + // When decoding, this field will always be set to the resolved tag, + // even when it wasn't explicitly provided in the YAML content. + // When encoding, if this field is unset the value type will be + // implied from the node properties, and if it is set, it will only + // be serialized into the representation if TaggedStyle is used or + // the implicit tag diverges from the provided one. + Tag string + + // Value holds the unescaped and unquoted represenation of the value. + Value string + + // Anchor holds the anchor name for this node, which allows aliases to point to it. + Anchor string + + // Alias holds the node that this alias points to. Only valid when Kind is AliasNode. + Alias *Node + + // Content holds contained nodes for documents, mappings, and sequences. + Content []*Node + + // HeadComment holds any comments in the lines preceding the node and + // not separated by an empty line. + HeadComment string + + // LineComment holds any comments at the end of the line where the node is in. + LineComment string + + // FootComment holds any comments following the node and before empty lines. + FootComment string + + // Line and Column hold the node position in the decoded YAML text. + // These fields are not respected when encoding the node. + Line int + Column int +} + +// IsZero returns whether the node has all of its fields unset. +func (n *Node) IsZero() bool { + return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil && + n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0 +} + + +// LongTag returns the long form of the tag that indicates the data type for +// the node. If the Tag field isn't explicitly defined, one will be computed +// based on the node properties. +func (n *Node) LongTag() string { + return longTag(n.ShortTag()) +} + +// ShortTag returns the short form of the YAML tag that indicates data type for +// the node. If the Tag field isn't explicitly defined, one will be computed +// based on the node properties. +func (n *Node) ShortTag() string { + if n.indicatedString() { + return strTag + } + if n.Tag == "" || n.Tag == "!" { + switch n.Kind { + case MappingNode: + return mapTag + case SequenceNode: + return seqTag + case AliasNode: + if n.Alias != nil { + return n.Alias.ShortTag() + } + case ScalarNode: + tag, _ := resolve("", n.Value) + return tag + case 0: + // Special case to make the zero value convenient. + if n.IsZero() { + return nullTag + } + } + return "" + } + return shortTag(n.Tag) +} + +func (n *Node) indicatedString() bool { + return n.Kind == ScalarNode && + (shortTag(n.Tag) == strTag || + (n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0) +} + +// SetString is a convenience function that sets the node to a string value +// and defines its style in a pleasant way depending on its content. +func (n *Node) SetString(s string) { + n.Kind = ScalarNode + if utf8.ValidString(s) { + n.Value = s + n.Tag = strTag + } else { + n.Value = encodeBase64(s) + n.Tag = binaryTag + } + if strings.Contains(n.Value, "\n") { + n.Style = LiteralStyle + } +} + +// -------------------------------------------------------------------------- +// Maintain a mapping of keys to structure field indexes + +// The code in this section was copied from mgo/bson. + +// structInfo holds details for the serialization of fields of +// a given struct. +type structInfo struct { + FieldsMap map[string]fieldInfo + FieldsList []fieldInfo + + // InlineMap is the number of the field in the struct that + // contains an ,inline map, or -1 if there's none. + InlineMap int + + // InlineUnmarshalers holds indexes to inlined fields that + // contain unmarshaler values. + InlineUnmarshalers [][]int +} + +type fieldInfo struct { + Key string + Num int + OmitEmpty bool + Flow bool + // Id holds the unique field identifier, so we can cheaply + // check for field duplicates without maintaining an extra map. + Id int + + // Inline holds the field index if the field is part of an inlined struct. + Inline []int +} + +var structMap = make(map[reflect.Type]*structInfo) +var fieldMapMutex sync.RWMutex +var unmarshalerType reflect.Type + +func init() { + var v Unmarshaler + unmarshalerType = reflect.ValueOf(&v).Elem().Type() +} + +func getStructInfo(st reflect.Type) (*structInfo, error) { + fieldMapMutex.RLock() + sinfo, found := structMap[st] + fieldMapMutex.RUnlock() + if found { + return sinfo, nil + } + + n := st.NumField() + fieldsMap := make(map[string]fieldInfo) + fieldsList := make([]fieldInfo, 0, n) + inlineMap := -1 + inlineUnmarshalers := [][]int(nil) + for i := 0; i != n; i++ { + field := st.Field(i) + if field.PkgPath != "" && !field.Anonymous { + continue // Private field + } + + info := fieldInfo{Num: i} + + tag := field.Tag.Get("yaml") + if tag == "" && strings.Index(string(field.Tag), ":") < 0 { + tag = string(field.Tag) + } + if tag == "-" { + continue + } + + inline := false + fields := strings.Split(tag, ",") + if len(fields) > 1 { + for _, flag := range fields[1:] { + switch flag { + case "omitempty": + info.OmitEmpty = true + case "flow": + info.Flow = true + case "inline": + inline = true + default: + return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st)) + } + } + tag = fields[0] + } + + if inline { + switch field.Type.Kind() { + case reflect.Map: + if inlineMap >= 0 { + return nil, errors.New("multiple ,inline maps in struct " + st.String()) + } + if field.Type.Key() != reflect.TypeOf("") { + return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String()) + } + inlineMap = info.Num + case reflect.Struct, reflect.Ptr: + ftype := field.Type + for ftype.Kind() == reflect.Ptr { + ftype = ftype.Elem() + } + if ftype.Kind() != reflect.Struct { + return nil, errors.New("option ,inline may only be used on a struct or map field") + } + if reflect.PtrTo(ftype).Implements(unmarshalerType) { + inlineUnmarshalers = append(inlineUnmarshalers, []int{i}) + } else { + sinfo, err := getStructInfo(ftype) + if err != nil { + return nil, err + } + for _, index := range sinfo.InlineUnmarshalers { + inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...)) + } + for _, finfo := range sinfo.FieldsList { + if _, found := fieldsMap[finfo.Key]; found { + msg := "duplicated key '" + finfo.Key + "' in struct " + st.String() + return nil, errors.New(msg) + } + if finfo.Inline == nil { + finfo.Inline = []int{i, finfo.Num} + } else { + finfo.Inline = append([]int{i}, finfo.Inline...) + } + finfo.Id = len(fieldsList) + fieldsMap[finfo.Key] = finfo + fieldsList = append(fieldsList, finfo) + } + } + default: + return nil, errors.New("option ,inline may only be used on a struct or map field") + } + continue + } + + if tag != "" { + info.Key = tag + } else { + info.Key = strings.ToLower(field.Name) + } + + if _, found = fieldsMap[info.Key]; found { + msg := "duplicated key '" + info.Key + "' in struct " + st.String() + return nil, errors.New(msg) + } + + info.Id = len(fieldsList) + fieldsList = append(fieldsList, info) + fieldsMap[info.Key] = info + } + + sinfo = &structInfo{ + FieldsMap: fieldsMap, + FieldsList: fieldsList, + InlineMap: inlineMap, + InlineUnmarshalers: inlineUnmarshalers, + } + + fieldMapMutex.Lock() + structMap[st] = sinfo + fieldMapMutex.Unlock() + return sinfo, nil +} + +// IsZeroer is used to check whether an object is zero to +// determine whether it should be omitted when marshaling +// with the omitempty flag. One notable implementation +// is time.Time. +type IsZeroer interface { + IsZero() bool +} + +func isZero(v reflect.Value) bool { + kind := v.Kind() + if z, ok := v.Interface().(IsZeroer); ok { + if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() { + return true + } + return z.IsZero() + } + switch kind { + case reflect.String: + return len(v.String()) == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + case reflect.Slice: + return v.Len() == 0 + case reflect.Map: + return v.Len() == 0 + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Struct: + vt := v.Type() + for i := v.NumField() - 1; i >= 0; i-- { + if vt.Field(i).PkgPath != "" { + continue // Private field + } + if !isZero(v.Field(i)) { + return false + } + } + return true + } + return false +} diff --git a/vendor/gopkg.in/yaml.v3/yamlh.go b/vendor/gopkg.in/yaml.v3/yamlh.go new file mode 100644 index 00000000..7c6d0077 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/yamlh.go @@ -0,0 +1,807 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package yaml + +import ( + "fmt" + "io" +) + +// The version directive data. +type yaml_version_directive_t struct { + major int8 // The major version number. + minor int8 // The minor version number. +} + +// The tag directive data. +type yaml_tag_directive_t struct { + handle []byte // The tag handle. + prefix []byte // The tag prefix. +} + +type yaml_encoding_t int + +// The stream encoding. +const ( + // Let the parser choose the encoding. + yaml_ANY_ENCODING yaml_encoding_t = iota + + yaml_UTF8_ENCODING // The default UTF-8 encoding. + yaml_UTF16LE_ENCODING // The UTF-16-LE encoding with BOM. + yaml_UTF16BE_ENCODING // The UTF-16-BE encoding with BOM. +) + +type yaml_break_t int + +// Line break types. +const ( + // Let the parser choose the break type. + yaml_ANY_BREAK yaml_break_t = iota + + yaml_CR_BREAK // Use CR for line breaks (Mac style). + yaml_LN_BREAK // Use LN for line breaks (Unix style). + yaml_CRLN_BREAK // Use CR LN for line breaks (DOS style). +) + +type yaml_error_type_t int + +// Many bad things could happen with the parser and emitter. +const ( + // No error is produced. + yaml_NO_ERROR yaml_error_type_t = iota + + yaml_MEMORY_ERROR // Cannot allocate or reallocate a block of memory. + yaml_READER_ERROR // Cannot read or decode the input stream. + yaml_SCANNER_ERROR // Cannot scan the input stream. + yaml_PARSER_ERROR // Cannot parse the input stream. + yaml_COMPOSER_ERROR // Cannot compose a YAML document. + yaml_WRITER_ERROR // Cannot write to the output stream. + yaml_EMITTER_ERROR // Cannot emit a YAML stream. +) + +// The pointer position. +type yaml_mark_t struct { + index int // The position index. + line int // The position line. + column int // The position column. +} + +// Node Styles + +type yaml_style_t int8 + +type yaml_scalar_style_t yaml_style_t + +// Scalar styles. +const ( + // Let the emitter choose the style. + yaml_ANY_SCALAR_STYLE yaml_scalar_style_t = 0 + + yaml_PLAIN_SCALAR_STYLE yaml_scalar_style_t = 1 << iota // The plain scalar style. + yaml_SINGLE_QUOTED_SCALAR_STYLE // The single-quoted scalar style. + yaml_DOUBLE_QUOTED_SCALAR_STYLE // The double-quoted scalar style. + yaml_LITERAL_SCALAR_STYLE // The literal scalar style. + yaml_FOLDED_SCALAR_STYLE // The folded scalar style. +) + +type yaml_sequence_style_t yaml_style_t + +// Sequence styles. +const ( + // Let the emitter choose the style. + yaml_ANY_SEQUENCE_STYLE yaml_sequence_style_t = iota + + yaml_BLOCK_SEQUENCE_STYLE // The block sequence style. + yaml_FLOW_SEQUENCE_STYLE // The flow sequence style. +) + +type yaml_mapping_style_t yaml_style_t + +// Mapping styles. +const ( + // Let the emitter choose the style. + yaml_ANY_MAPPING_STYLE yaml_mapping_style_t = iota + + yaml_BLOCK_MAPPING_STYLE // The block mapping style. + yaml_FLOW_MAPPING_STYLE // The flow mapping style. +) + +// Tokens + +type yaml_token_type_t int + +// Token types. +const ( + // An empty token. + yaml_NO_TOKEN yaml_token_type_t = iota + + yaml_STREAM_START_TOKEN // A STREAM-START token. + yaml_STREAM_END_TOKEN // A STREAM-END token. + + yaml_VERSION_DIRECTIVE_TOKEN // A VERSION-DIRECTIVE token. + yaml_TAG_DIRECTIVE_TOKEN // A TAG-DIRECTIVE token. + yaml_DOCUMENT_START_TOKEN // A DOCUMENT-START token. + yaml_DOCUMENT_END_TOKEN // A DOCUMENT-END token. + + yaml_BLOCK_SEQUENCE_START_TOKEN // A BLOCK-SEQUENCE-START token. + yaml_BLOCK_MAPPING_START_TOKEN // A BLOCK-SEQUENCE-END token. + yaml_BLOCK_END_TOKEN // A BLOCK-END token. + + yaml_FLOW_SEQUENCE_START_TOKEN // A FLOW-SEQUENCE-START token. + yaml_FLOW_SEQUENCE_END_TOKEN // A FLOW-SEQUENCE-END token. + yaml_FLOW_MAPPING_START_TOKEN // A FLOW-MAPPING-START token. + yaml_FLOW_MAPPING_END_TOKEN // A FLOW-MAPPING-END token. + + yaml_BLOCK_ENTRY_TOKEN // A BLOCK-ENTRY token. + yaml_FLOW_ENTRY_TOKEN // A FLOW-ENTRY token. + yaml_KEY_TOKEN // A KEY token. + yaml_VALUE_TOKEN // A VALUE token. + + yaml_ALIAS_TOKEN // An ALIAS token. + yaml_ANCHOR_TOKEN // An ANCHOR token. + yaml_TAG_TOKEN // A TAG token. + yaml_SCALAR_TOKEN // A SCALAR token. +) + +func (tt yaml_token_type_t) String() string { + switch tt { + case yaml_NO_TOKEN: + return "yaml_NO_TOKEN" + case yaml_STREAM_START_TOKEN: + return "yaml_STREAM_START_TOKEN" + case yaml_STREAM_END_TOKEN: + return "yaml_STREAM_END_TOKEN" + case yaml_VERSION_DIRECTIVE_TOKEN: + return "yaml_VERSION_DIRECTIVE_TOKEN" + case yaml_TAG_DIRECTIVE_TOKEN: + return "yaml_TAG_DIRECTIVE_TOKEN" + case yaml_DOCUMENT_START_TOKEN: + return "yaml_DOCUMENT_START_TOKEN" + case yaml_DOCUMENT_END_TOKEN: + return "yaml_DOCUMENT_END_TOKEN" + case yaml_BLOCK_SEQUENCE_START_TOKEN: + return "yaml_BLOCK_SEQUENCE_START_TOKEN" + case yaml_BLOCK_MAPPING_START_TOKEN: + return "yaml_BLOCK_MAPPING_START_TOKEN" + case yaml_BLOCK_END_TOKEN: + return "yaml_BLOCK_END_TOKEN" + case yaml_FLOW_SEQUENCE_START_TOKEN: + return "yaml_FLOW_SEQUENCE_START_TOKEN" + case yaml_FLOW_SEQUENCE_END_TOKEN: + return "yaml_FLOW_SEQUENCE_END_TOKEN" + case yaml_FLOW_MAPPING_START_TOKEN: + return "yaml_FLOW_MAPPING_START_TOKEN" + case yaml_FLOW_MAPPING_END_TOKEN: + return "yaml_FLOW_MAPPING_END_TOKEN" + case yaml_BLOCK_ENTRY_TOKEN: + return "yaml_BLOCK_ENTRY_TOKEN" + case yaml_FLOW_ENTRY_TOKEN: + return "yaml_FLOW_ENTRY_TOKEN" + case yaml_KEY_TOKEN: + return "yaml_KEY_TOKEN" + case yaml_VALUE_TOKEN: + return "yaml_VALUE_TOKEN" + case yaml_ALIAS_TOKEN: + return "yaml_ALIAS_TOKEN" + case yaml_ANCHOR_TOKEN: + return "yaml_ANCHOR_TOKEN" + case yaml_TAG_TOKEN: + return "yaml_TAG_TOKEN" + case yaml_SCALAR_TOKEN: + return "yaml_SCALAR_TOKEN" + } + return "" +} + +// The token structure. +type yaml_token_t struct { + // The token type. + typ yaml_token_type_t + + // The start/end of the token. + start_mark, end_mark yaml_mark_t + + // The stream encoding (for yaml_STREAM_START_TOKEN). + encoding yaml_encoding_t + + // The alias/anchor/scalar value or tag/tag directive handle + // (for yaml_ALIAS_TOKEN, yaml_ANCHOR_TOKEN, yaml_SCALAR_TOKEN, yaml_TAG_TOKEN, yaml_TAG_DIRECTIVE_TOKEN). + value []byte + + // The tag suffix (for yaml_TAG_TOKEN). + suffix []byte + + // The tag directive prefix (for yaml_TAG_DIRECTIVE_TOKEN). + prefix []byte + + // The scalar style (for yaml_SCALAR_TOKEN). + style yaml_scalar_style_t + + // The version directive major/minor (for yaml_VERSION_DIRECTIVE_TOKEN). + major, minor int8 +} + +// Events + +type yaml_event_type_t int8 + +// Event types. +const ( + // An empty event. + yaml_NO_EVENT yaml_event_type_t = iota + + yaml_STREAM_START_EVENT // A STREAM-START event. + yaml_STREAM_END_EVENT // A STREAM-END event. + yaml_DOCUMENT_START_EVENT // A DOCUMENT-START event. + yaml_DOCUMENT_END_EVENT // A DOCUMENT-END event. + yaml_ALIAS_EVENT // An ALIAS event. + yaml_SCALAR_EVENT // A SCALAR event. + yaml_SEQUENCE_START_EVENT // A SEQUENCE-START event. + yaml_SEQUENCE_END_EVENT // A SEQUENCE-END event. + yaml_MAPPING_START_EVENT // A MAPPING-START event. + yaml_MAPPING_END_EVENT // A MAPPING-END event. + yaml_TAIL_COMMENT_EVENT +) + +var eventStrings = []string{ + yaml_NO_EVENT: "none", + yaml_STREAM_START_EVENT: "stream start", + yaml_STREAM_END_EVENT: "stream end", + yaml_DOCUMENT_START_EVENT: "document start", + yaml_DOCUMENT_END_EVENT: "document end", + yaml_ALIAS_EVENT: "alias", + yaml_SCALAR_EVENT: "scalar", + yaml_SEQUENCE_START_EVENT: "sequence start", + yaml_SEQUENCE_END_EVENT: "sequence end", + yaml_MAPPING_START_EVENT: "mapping start", + yaml_MAPPING_END_EVENT: "mapping end", + yaml_TAIL_COMMENT_EVENT: "tail comment", +} + +func (e yaml_event_type_t) String() string { + if e < 0 || int(e) >= len(eventStrings) { + return fmt.Sprintf("unknown event %d", e) + } + return eventStrings[e] +} + +// The event structure. +type yaml_event_t struct { + + // The event type. + typ yaml_event_type_t + + // The start and end of the event. + start_mark, end_mark yaml_mark_t + + // The document encoding (for yaml_STREAM_START_EVENT). + encoding yaml_encoding_t + + // The version directive (for yaml_DOCUMENT_START_EVENT). + version_directive *yaml_version_directive_t + + // The list of tag directives (for yaml_DOCUMENT_START_EVENT). + tag_directives []yaml_tag_directive_t + + // The comments + head_comment []byte + line_comment []byte + foot_comment []byte + tail_comment []byte + + // The anchor (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_ALIAS_EVENT). + anchor []byte + + // The tag (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). + tag []byte + + // The scalar value (for yaml_SCALAR_EVENT). + value []byte + + // Is the document start/end indicator implicit, or the tag optional? + // (for yaml_DOCUMENT_START_EVENT, yaml_DOCUMENT_END_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT, yaml_SCALAR_EVENT). + implicit bool + + // Is the tag optional for any non-plain style? (for yaml_SCALAR_EVENT). + quoted_implicit bool + + // The style (for yaml_SCALAR_EVENT, yaml_SEQUENCE_START_EVENT, yaml_MAPPING_START_EVENT). + style yaml_style_t +} + +func (e *yaml_event_t) scalar_style() yaml_scalar_style_t { return yaml_scalar_style_t(e.style) } +func (e *yaml_event_t) sequence_style() yaml_sequence_style_t { return yaml_sequence_style_t(e.style) } +func (e *yaml_event_t) mapping_style() yaml_mapping_style_t { return yaml_mapping_style_t(e.style) } + +// Nodes + +const ( + yaml_NULL_TAG = "tag:yaml.org,2002:null" // The tag !!null with the only possible value: null. + yaml_BOOL_TAG = "tag:yaml.org,2002:bool" // The tag !!bool with the values: true and false. + yaml_STR_TAG = "tag:yaml.org,2002:str" // The tag !!str for string values. + yaml_INT_TAG = "tag:yaml.org,2002:int" // The tag !!int for integer values. + yaml_FLOAT_TAG = "tag:yaml.org,2002:float" // The tag !!float for float values. + yaml_TIMESTAMP_TAG = "tag:yaml.org,2002:timestamp" // The tag !!timestamp for date and time values. + + yaml_SEQ_TAG = "tag:yaml.org,2002:seq" // The tag !!seq is used to denote sequences. + yaml_MAP_TAG = "tag:yaml.org,2002:map" // The tag !!map is used to denote mapping. + + // Not in original libyaml. + yaml_BINARY_TAG = "tag:yaml.org,2002:binary" + yaml_MERGE_TAG = "tag:yaml.org,2002:merge" + + yaml_DEFAULT_SCALAR_TAG = yaml_STR_TAG // The default scalar tag is !!str. + yaml_DEFAULT_SEQUENCE_TAG = yaml_SEQ_TAG // The default sequence tag is !!seq. + yaml_DEFAULT_MAPPING_TAG = yaml_MAP_TAG // The default mapping tag is !!map. +) + +type yaml_node_type_t int + +// Node types. +const ( + // An empty node. + yaml_NO_NODE yaml_node_type_t = iota + + yaml_SCALAR_NODE // A scalar node. + yaml_SEQUENCE_NODE // A sequence node. + yaml_MAPPING_NODE // A mapping node. +) + +// An element of a sequence node. +type yaml_node_item_t int + +// An element of a mapping node. +type yaml_node_pair_t struct { + key int // The key of the element. + value int // The value of the element. +} + +// The node structure. +type yaml_node_t struct { + typ yaml_node_type_t // The node type. + tag []byte // The node tag. + + // The node data. + + // The scalar parameters (for yaml_SCALAR_NODE). + scalar struct { + value []byte // The scalar value. + length int // The length of the scalar value. + style yaml_scalar_style_t // The scalar style. + } + + // The sequence parameters (for YAML_SEQUENCE_NODE). + sequence struct { + items_data []yaml_node_item_t // The stack of sequence items. + style yaml_sequence_style_t // The sequence style. + } + + // The mapping parameters (for yaml_MAPPING_NODE). + mapping struct { + pairs_data []yaml_node_pair_t // The stack of mapping pairs (key, value). + pairs_start *yaml_node_pair_t // The beginning of the stack. + pairs_end *yaml_node_pair_t // The end of the stack. + pairs_top *yaml_node_pair_t // The top of the stack. + style yaml_mapping_style_t // The mapping style. + } + + start_mark yaml_mark_t // The beginning of the node. + end_mark yaml_mark_t // The end of the node. + +} + +// The document structure. +type yaml_document_t struct { + + // The document nodes. + nodes []yaml_node_t + + // The version directive. + version_directive *yaml_version_directive_t + + // The list of tag directives. + tag_directives_data []yaml_tag_directive_t + tag_directives_start int // The beginning of the tag directives list. + tag_directives_end int // The end of the tag directives list. + + start_implicit int // Is the document start indicator implicit? + end_implicit int // Is the document end indicator implicit? + + // The start/end of the document. + start_mark, end_mark yaml_mark_t +} + +// The prototype of a read handler. +// +// The read handler is called when the parser needs to read more bytes from the +// source. The handler should write not more than size bytes to the buffer. +// The number of written bytes should be set to the size_read variable. +// +// [in,out] data A pointer to an application data specified by +// yaml_parser_set_input(). +// [out] buffer The buffer to write the data from the source. +// [in] size The size of the buffer. +// [out] size_read The actual number of bytes read from the source. +// +// On success, the handler should return 1. If the handler failed, +// the returned value should be 0. On EOF, the handler should set the +// size_read to 0 and return 1. +type yaml_read_handler_t func(parser *yaml_parser_t, buffer []byte) (n int, err error) + +// This structure holds information about a potential simple key. +type yaml_simple_key_t struct { + possible bool // Is a simple key possible? + required bool // Is a simple key required? + token_number int // The number of the token. + mark yaml_mark_t // The position mark. +} + +// The states of the parser. +type yaml_parser_state_t int + +const ( + yaml_PARSE_STREAM_START_STATE yaml_parser_state_t = iota + + yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE // Expect the beginning of an implicit document. + yaml_PARSE_DOCUMENT_START_STATE // Expect DOCUMENT-START. + yaml_PARSE_DOCUMENT_CONTENT_STATE // Expect the content of a document. + yaml_PARSE_DOCUMENT_END_STATE // Expect DOCUMENT-END. + yaml_PARSE_BLOCK_NODE_STATE // Expect a block node. + yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE // Expect a block node or indentless sequence. + yaml_PARSE_FLOW_NODE_STATE // Expect a flow node. + yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a block sequence. + yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE // Expect an entry of a block sequence. + yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE // Expect an entry of an indentless sequence. + yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. + yaml_PARSE_BLOCK_MAPPING_KEY_STATE // Expect a block mapping key. + yaml_PARSE_BLOCK_MAPPING_VALUE_STATE // Expect a block mapping value. + yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE // Expect the first entry of a flow sequence. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE // Expect an entry of a flow sequence. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE // Expect a key of an ordered mapping. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE // Expect a value of an ordered mapping. + yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE // Expect the and of an ordered mapping entry. + yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. + yaml_PARSE_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. + yaml_PARSE_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. + yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE // Expect an empty value of a flow mapping. + yaml_PARSE_END_STATE // Expect nothing. +) + +func (ps yaml_parser_state_t) String() string { + switch ps { + case yaml_PARSE_STREAM_START_STATE: + return "yaml_PARSE_STREAM_START_STATE" + case yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE: + return "yaml_PARSE_IMPLICIT_DOCUMENT_START_STATE" + case yaml_PARSE_DOCUMENT_START_STATE: + return "yaml_PARSE_DOCUMENT_START_STATE" + case yaml_PARSE_DOCUMENT_CONTENT_STATE: + return "yaml_PARSE_DOCUMENT_CONTENT_STATE" + case yaml_PARSE_DOCUMENT_END_STATE: + return "yaml_PARSE_DOCUMENT_END_STATE" + case yaml_PARSE_BLOCK_NODE_STATE: + return "yaml_PARSE_BLOCK_NODE_STATE" + case yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: + return "yaml_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE" + case yaml_PARSE_FLOW_NODE_STATE: + return "yaml_PARSE_FLOW_NODE_STATE" + case yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: + return "yaml_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE" + case yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: + return "yaml_PARSE_BLOCK_SEQUENCE_ENTRY_STATE" + case yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: + return "yaml_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE" + case yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: + return "yaml_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE" + case yaml_PARSE_BLOCK_MAPPING_KEY_STATE: + return "yaml_PARSE_BLOCK_MAPPING_KEY_STATE" + case yaml_PARSE_BLOCK_MAPPING_VALUE_STATE: + return "yaml_PARSE_BLOCK_MAPPING_VALUE_STATE" + case yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE" + case yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: + return "yaml_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE" + case yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: + return "yaml_PARSE_FLOW_MAPPING_FIRST_KEY_STATE" + case yaml_PARSE_FLOW_MAPPING_KEY_STATE: + return "yaml_PARSE_FLOW_MAPPING_KEY_STATE" + case yaml_PARSE_FLOW_MAPPING_VALUE_STATE: + return "yaml_PARSE_FLOW_MAPPING_VALUE_STATE" + case yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: + return "yaml_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE" + case yaml_PARSE_END_STATE: + return "yaml_PARSE_END_STATE" + } + return "" +} + +// This structure holds aliases data. +type yaml_alias_data_t struct { + anchor []byte // The anchor. + index int // The node id. + mark yaml_mark_t // The anchor mark. +} + +// The parser structure. +// +// All members are internal. Manage the structure using the +// yaml_parser_ family of functions. +type yaml_parser_t struct { + + // Error handling + + error yaml_error_type_t // Error type. + + problem string // Error description. + + // The byte about which the problem occurred. + problem_offset int + problem_value int + problem_mark yaml_mark_t + + // The error context. + context string + context_mark yaml_mark_t + + // Reader stuff + + read_handler yaml_read_handler_t // Read handler. + + input_reader io.Reader // File input data. + input []byte // String input data. + input_pos int + + eof bool // EOF flag + + buffer []byte // The working buffer. + buffer_pos int // The current position of the buffer. + + unread int // The number of unread characters in the buffer. + + newlines int // The number of line breaks since last non-break/non-blank character + + raw_buffer []byte // The raw buffer. + raw_buffer_pos int // The current position of the buffer. + + encoding yaml_encoding_t // The input encoding. + + offset int // The offset of the current position (in bytes). + mark yaml_mark_t // The mark of the current position. + + // Comments + + head_comment []byte // The current head comments + line_comment []byte // The current line comments + foot_comment []byte // The current foot comments + tail_comment []byte // Foot comment that happens at the end of a block. + stem_comment []byte // Comment in item preceding a nested structure (list inside list item, etc) + + comments []yaml_comment_t // The folded comments for all parsed tokens + comments_head int + + // Scanner stuff + + stream_start_produced bool // Have we started to scan the input stream? + stream_end_produced bool // Have we reached the end of the input stream? + + flow_level int // The number of unclosed '[' and '{' indicators. + + tokens []yaml_token_t // The tokens queue. + tokens_head int // The head of the tokens queue. + tokens_parsed int // The number of tokens fetched from the queue. + token_available bool // Does the tokens queue contain a token ready for dequeueing. + + indent int // The current indentation level. + indents []int // The indentation levels stack. + + simple_key_allowed bool // May a simple key occur at the current position? + simple_keys []yaml_simple_key_t // The stack of simple keys. + simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number + + // Parser stuff + + state yaml_parser_state_t // The current parser state. + states []yaml_parser_state_t // The parser states stack. + marks []yaml_mark_t // The stack of marks. + tag_directives []yaml_tag_directive_t // The list of TAG directives. + + // Dumper stuff + + aliases []yaml_alias_data_t // The alias data. + + document *yaml_document_t // The currently parsed document. +} + +type yaml_comment_t struct { + + scan_mark yaml_mark_t // Position where scanning for comments started + token_mark yaml_mark_t // Position after which tokens will be associated with this comment + start_mark yaml_mark_t // Position of '#' comment mark + end_mark yaml_mark_t // Position where comment terminated + + head []byte + line []byte + foot []byte +} + +// Emitter Definitions + +// The prototype of a write handler. +// +// The write handler is called when the emitter needs to flush the accumulated +// characters to the output. The handler should write @a size bytes of the +// @a buffer to the output. +// +// @param[in,out] data A pointer to an application data specified by +// yaml_emitter_set_output(). +// @param[in] buffer The buffer with bytes to be written. +// @param[in] size The size of the buffer. +// +// @returns On success, the handler should return @c 1. If the handler failed, +// the returned value should be @c 0. +// +type yaml_write_handler_t func(emitter *yaml_emitter_t, buffer []byte) error + +type yaml_emitter_state_t int + +// The emitter states. +const ( + // Expect STREAM-START. + yaml_EMIT_STREAM_START_STATE yaml_emitter_state_t = iota + + yaml_EMIT_FIRST_DOCUMENT_START_STATE // Expect the first DOCUMENT-START or STREAM-END. + yaml_EMIT_DOCUMENT_START_STATE // Expect DOCUMENT-START or STREAM-END. + yaml_EMIT_DOCUMENT_CONTENT_STATE // Expect the content of a document. + yaml_EMIT_DOCUMENT_END_STATE // Expect DOCUMENT-END. + yaml_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a flow sequence. + yaml_EMIT_FLOW_SEQUENCE_TRAIL_ITEM_STATE // Expect the next item of a flow sequence, with the comma already written out + yaml_EMIT_FLOW_SEQUENCE_ITEM_STATE // Expect an item of a flow sequence. + yaml_EMIT_FLOW_MAPPING_FIRST_KEY_STATE // Expect the first key of a flow mapping. + yaml_EMIT_FLOW_MAPPING_TRAIL_KEY_STATE // Expect the next key of a flow mapping, with the comma already written out + yaml_EMIT_FLOW_MAPPING_KEY_STATE // Expect a key of a flow mapping. + yaml_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a flow mapping. + yaml_EMIT_FLOW_MAPPING_VALUE_STATE // Expect a value of a flow mapping. + yaml_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE // Expect the first item of a block sequence. + yaml_EMIT_BLOCK_SEQUENCE_ITEM_STATE // Expect an item of a block sequence. + yaml_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE // Expect the first key of a block mapping. + yaml_EMIT_BLOCK_MAPPING_KEY_STATE // Expect the key of a block mapping. + yaml_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE // Expect a value for a simple key of a block mapping. + yaml_EMIT_BLOCK_MAPPING_VALUE_STATE // Expect a value of a block mapping. + yaml_EMIT_END_STATE // Expect nothing. +) + +// The emitter structure. +// +// All members are internal. Manage the structure using the @c yaml_emitter_ +// family of functions. +type yaml_emitter_t struct { + + // Error handling + + error yaml_error_type_t // Error type. + problem string // Error description. + + // Writer stuff + + write_handler yaml_write_handler_t // Write handler. + + output_buffer *[]byte // String output data. + output_writer io.Writer // File output data. + + buffer []byte // The working buffer. + buffer_pos int // The current position of the buffer. + + raw_buffer []byte // The raw buffer. + raw_buffer_pos int // The current position of the buffer. + + encoding yaml_encoding_t // The stream encoding. + + // Emitter stuff + + canonical bool // If the output is in the canonical style? + best_indent int // The number of indentation spaces. + best_width int // The preferred width of the output lines. + unicode bool // Allow unescaped non-ASCII characters? + line_break yaml_break_t // The preferred line break. + + state yaml_emitter_state_t // The current emitter state. + states []yaml_emitter_state_t // The stack of states. + + events []yaml_event_t // The event queue. + events_head int // The head of the event queue. + + indents []int // The stack of indentation levels. + + tag_directives []yaml_tag_directive_t // The list of tag directives. + + indent int // The current indentation level. + + flow_level int // The current flow level. + + root_context bool // Is it the document root context? + sequence_context bool // Is it a sequence context? + mapping_context bool // Is it a mapping context? + simple_key_context bool // Is it a simple mapping key context? + + line int // The current line. + column int // The current column. + whitespace bool // If the last character was a whitespace? + indention bool // If the last character was an indentation character (' ', '-', '?', ':')? + open_ended bool // If an explicit document end is required? + + space_above bool // Is there's an empty line above? + foot_indent int // The indent used to write the foot comment above, or -1 if none. + + // Anchor analysis. + anchor_data struct { + anchor []byte // The anchor value. + alias bool // Is it an alias? + } + + // Tag analysis. + tag_data struct { + handle []byte // The tag handle. + suffix []byte // The tag suffix. + } + + // Scalar analysis. + scalar_data struct { + value []byte // The scalar value. + multiline bool // Does the scalar contain line breaks? + flow_plain_allowed bool // Can the scalar be expessed in the flow plain style? + block_plain_allowed bool // Can the scalar be expressed in the block plain style? + single_quoted_allowed bool // Can the scalar be expressed in the single quoted style? + block_allowed bool // Can the scalar be expressed in the literal or folded styles? + style yaml_scalar_style_t // The output style. + } + + // Comments + head_comment []byte + line_comment []byte + foot_comment []byte + tail_comment []byte + + key_line_comment []byte + + // Dumper stuff + + opened bool // If the stream was already opened? + closed bool // If the stream was already closed? + + // The information associated with the document nodes. + anchors *struct { + references int // The number of references. + anchor int // The anchor id. + serialized bool // If the node has been emitted? + } + + last_anchor_id int // The last assigned anchor id. + + document *yaml_document_t // The currently emitted document. +} diff --git a/vendor/gopkg.in/yaml.v3/yamlprivateh.go b/vendor/gopkg.in/yaml.v3/yamlprivateh.go new file mode 100644 index 00000000..e88f9c54 --- /dev/null +++ b/vendor/gopkg.in/yaml.v3/yamlprivateh.go @@ -0,0 +1,198 @@ +// +// Copyright (c) 2011-2019 Canonical Ltd +// Copyright (c) 2006-2010 Kirill Simonov +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +// of the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package yaml + +const ( + // The size of the input raw buffer. + input_raw_buffer_size = 512 + + // The size of the input buffer. + // It should be possible to decode the whole raw buffer. + input_buffer_size = input_raw_buffer_size * 3 + + // The size of the output buffer. + output_buffer_size = 128 + + // The size of the output raw buffer. + // It should be possible to encode the whole output buffer. + output_raw_buffer_size = (output_buffer_size*2 + 2) + + // The size of other stacks and queues. + initial_stack_size = 16 + initial_queue_size = 16 + initial_string_size = 16 +) + +// Check if the character at the specified position is an alphabetical +// character, a digit, '_', or '-'. +func is_alpha(b []byte, i int) bool { + return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' +} + +// Check if the character at the specified position is a digit. +func is_digit(b []byte, i int) bool { + return b[i] >= '0' && b[i] <= '9' +} + +// Get the value of a digit. +func as_digit(b []byte, i int) int { + return int(b[i]) - '0' +} + +// Check if the character at the specified position is a hex-digit. +func is_hex(b []byte, i int) bool { + return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' +} + +// Get the value of a hex-digit. +func as_hex(b []byte, i int) int { + bi := b[i] + if bi >= 'A' && bi <= 'F' { + return int(bi) - 'A' + 10 + } + if bi >= 'a' && bi <= 'f' { + return int(bi) - 'a' + 10 + } + return int(bi) - '0' +} + +// Check if the character is ASCII. +func is_ascii(b []byte, i int) bool { + return b[i] <= 0x7F +} + +// Check if the character at the start of the buffer can be printed unescaped. +func is_printable(b []byte, i int) bool { + return ((b[i] == 0x0A) || // . == #x0A + (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E + (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF + (b[i] > 0xC2 && b[i] < 0xED) || + (b[i] == 0xED && b[i+1] < 0xA0) || + (b[i] == 0xEE) || + (b[i] == 0xEF && // #xE000 <= . <= #xFFFD + !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF + !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) +} + +// Check if the character at the specified position is NUL. +func is_z(b []byte, i int) bool { + return b[i] == 0x00 +} + +// Check if the beginning of the buffer is a BOM. +func is_bom(b []byte, i int) bool { + return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF +} + +// Check if the character at the specified position is space. +func is_space(b []byte, i int) bool { + return b[i] == ' ' +} + +// Check if the character at the specified position is tab. +func is_tab(b []byte, i int) bool { + return b[i] == '\t' +} + +// Check if the character at the specified position is blank (space or tab). +func is_blank(b []byte, i int) bool { + //return is_space(b, i) || is_tab(b, i) + return b[i] == ' ' || b[i] == '\t' +} + +// Check if the character at the specified position is a line break. +func is_break(b []byte, i int) bool { + return (b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) +} + +func is_crlf(b []byte, i int) bool { + return b[i] == '\r' && b[i+1] == '\n' +} + +// Check if the character is a line break or NUL. +func is_breakz(b []byte, i int) bool { + //return is_break(b, i) || is_z(b, i) + return ( + // is_break: + b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) + // is_z: + b[i] == 0) +} + +// Check if the character is a line break, space, or NUL. +func is_spacez(b []byte, i int) bool { + //return is_space(b, i) || is_breakz(b, i) + return ( + // is_space: + b[i] == ' ' || + // is_breakz: + b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) + b[i] == 0) +} + +// Check if the character is a line break, space, tab, or NUL. +func is_blankz(b []byte, i int) bool { + //return is_blank(b, i) || is_breakz(b, i) + return ( + // is_blank: + b[i] == ' ' || b[i] == '\t' || + // is_breakz: + b[i] == '\r' || // CR (#xD) + b[i] == '\n' || // LF (#xA) + b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) + b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) + b[i] == 0) +} + +// Determine the width of the character. +func width(b byte) int { + // Don't replace these by a switch without first + // confirming that it is being inlined. + if b&0x80 == 0x00 { + return 1 + } + if b&0xE0 == 0xC0 { + return 2 + } + if b&0xF0 == 0xE0 { + return 3 + } + if b&0xF8 == 0xF0 { + return 4 + } + return 0 + +} diff --git a/vendor/modules.txt b/vendor/modules.txt index dfbc9bb4..ed85ab74 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -56,6 +56,8 @@ github.com/aws/aws-sdk-go/service/sts/stsiface # github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 ## explicit github.com/aybabtme/rgbterm +# github.com/beevik/etree v1.1.0 +github.com/beevik/etree # github.com/calebcase/tmpfile v1.0.3 github.com/calebcase/tmpfile # github.com/creack/pty v1.1.18 @@ -69,6 +71,15 @@ github.com/cretz/bine/tor github.com/cretz/bine/torutil github.com/cretz/bine/torutil/ed25519 github.com/cretz/bine/torutil/ed25519/internal/edwards25519 +# github.com/crewjam/httperr v0.2.0 +github.com/crewjam/httperr +# github.com/davecgh/go-spew v1.1.1 +github.com/davecgh/go-spew/spew +# github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 +github.com/decred/dcrd/dcrec/secp256k1/v3 +# github.com/duosecurity/duo_universal_golang v1.0.3 +## explicit +github.com/duosecurity/duo_universal_golang/duouniversal # github.com/emirpasic/gods v1.12.0 github.com/emirpasic/gods/containers github.com/emirpasic/gods/lists @@ -79,19 +90,29 @@ github.com/emirpasic/gods/utils # github.com/go-sql-driver/mysql v1.5.0 ## explicit github.com/go-sql-driver/mysql +# github.com/goccy/go-json v0.7.4 +github.com/goccy/go-json +github.com/goccy/go-json/internal/decoder +github.com/goccy/go-json/internal/encoder +github.com/goccy/go-json/internal/encoder/vm +github.com/goccy/go-json/internal/encoder/vm_color +github.com/goccy/go-json/internal/encoder/vm_color_indent +github.com/goccy/go-json/internal/encoder/vm_indent +github.com/goccy/go-json/internal/errors +github.com/goccy/go-json/internal/runtime # github.com/gogo/protobuf v1.3.2 github.com/gogo/protobuf/jsonpb github.com/gogo/protobuf/proto github.com/gogo/protobuf/sortkeys github.com/gogo/protobuf/types +# github.com/golang-jwt/jwt/v4 v4.4.2 +github.com/golang-jwt/jwt/v4 # github.com/golang/protobuf v1.5.2 github.com/golang/protobuf/proto github.com/golang/protobuf/ptypes github.com/golang/protobuf/ptypes/any github.com/golang/protobuf/ptypes/duration github.com/golang/protobuf/ptypes/timestamp -# github.com/google/go-cmp v0.5.8 -## explicit # github.com/google/uuid v1.3.0 github.com/google/uuid # github.com/googleapis/gax-go/v2 v2.0.5 @@ -122,14 +143,50 @@ github.com/hirochachacha/go-smb2/internal/utf16le github.com/jbenet/go-context/io # github.com/jmespath/go-jmespath v0.4.0 github.com/jmespath/go-jmespath +# github.com/jonboulle/clockwork v0.2.2 +github.com/jonboulle/clockwork # github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/kballard/go-shellquote # github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd github.com/kevinburke/ssh_config # github.com/kr/fs v0.1.0 github.com/kr/fs -# github.com/kr/pretty v0.3.0 -## explicit +# github.com/lestrrat-go/backoff/v2 v2.0.7 +github.com/lestrrat-go/backoff/v2 +# github.com/lestrrat-go/blackmagic v1.0.0 +github.com/lestrrat-go/blackmagic +# github.com/lestrrat-go/httpcc v1.0.0 +github.com/lestrrat-go/httpcc +# github.com/lestrrat-go/iter v1.0.1 +github.com/lestrrat-go/iter/arrayiter +github.com/lestrrat-go/iter/mapiter +# github.com/lestrrat-go/jwx v1.2.4 +github.com/lestrrat-go/jwx +github.com/lestrrat-go/jwx/internal/base64 +github.com/lestrrat-go/jwx/internal/ecutil +github.com/lestrrat-go/jwx/internal/iter +github.com/lestrrat-go/jwx/internal/json +github.com/lestrrat-go/jwx/internal/keyconv +github.com/lestrrat-go/jwx/internal/pool +github.com/lestrrat-go/jwx/jwa +github.com/lestrrat-go/jwx/jwe +github.com/lestrrat-go/jwx/jwe/internal/aescbc +github.com/lestrrat-go/jwx/jwe/internal/cipher +github.com/lestrrat-go/jwx/jwe/internal/concatkdf +github.com/lestrrat-go/jwx/jwe/internal/content_crypt +github.com/lestrrat-go/jwx/jwe/internal/keyenc +github.com/lestrrat-go/jwx/jwe/internal/keygen +github.com/lestrrat-go/jwx/jwk +github.com/lestrrat-go/jwx/jws +github.com/lestrrat-go/jwx/jwt +github.com/lestrrat-go/jwx/jwt/internal/types +github.com/lestrrat-go/jwx/x25519 +# github.com/lestrrat-go/option v1.0.0 +github.com/lestrrat-go/option +# github.com/lestrrat-go/pdebug/v3 v3.0.1 +github.com/lestrrat-go/pdebug/v3 +# github.com/mattermost/xml-roundtrip-validator v0.1.0 +github.com/mattermost/xml-roundtrip-validator # github.com/mattn/go-isatty v0.0.16 github.com/mattn/go-isatty # github.com/mattn/go-sqlite3 v2.0.2+incompatible @@ -139,6 +196,12 @@ github.com/mattn/go-sqlite3 ## explicit github.com/mickael-kerjean/net/webdav github.com/mickael-kerjean/net/webdav/internal/xml +# github.com/mickael-kerjean/saml v0.0.0-20221221152539-19783715740c +## explicit +github.com/mickael-kerjean/saml +github.com/mickael-kerjean/saml/logger +github.com/mickael-kerjean/saml/samlsp +github.com/mickael-kerjean/saml/xmlenc # github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir # github.com/mitchellh/hashstructure v1.0.0 @@ -155,6 +218,8 @@ github.com/pkg/errors # github.com/pkg/sftp v1.11.0 ## explicit github.com/pkg/sftp +# github.com/pmezard/go-difflib v1.0.0 +github.com/pmezard/go-difflib/difflib # github.com/prasad83/goftp v0.0.0-20210325080443-f57aaed46a32 ## explicit github.com/prasad83/goftp @@ -168,8 +233,10 @@ github.com/qeesung/image2ascii/terminal github.com/rasky/go-xdr/xdr2 # github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 github.com/remyoudompheng/bigfft -# github.com/rogpeppe/go-internal v1.8.0 -## explicit +# github.com/russellhaering/goxmldsig v1.1.1 +github.com/russellhaering/goxmldsig +github.com/russellhaering/goxmldsig/etreeutils +github.com/russellhaering/goxmldsig/types # github.com/secsy/goftp v0.0.0-20200609142545-aa2de14babf4 ## explicit # github.com/sergi/go-diff v1.0.0 @@ -188,6 +255,9 @@ github.com/srwiley/oksvg # github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef ## explicit github.com/srwiley/rasterx +# github.com/stretchr/testify v1.7.0 +## explicit +github.com/stretchr/testify/assert # github.com/suyashkumar/dicom v1.0.5 ## explicit github.com/suyashkumar/dicom @@ -271,6 +341,8 @@ golang.org/x/crypto/openpgp/elgamal golang.org/x/crypto/openpgp/errors golang.org/x/crypto/openpgp/packet golang.org/x/crypto/openpgp/s2k +golang.org/x/crypto/pbkdf2 +golang.org/x/crypto/ripemd160 golang.org/x/crypto/salsa20/salsa golang.org/x/crypto/sha3 golang.org/x/crypto/ssh @@ -453,11 +525,12 @@ google.golang.org/protobuf/types/known/timestamppb gopkg.in/alexcesaro/quotedprintable.v3 # gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d gopkg.in/asn1-ber.v1 -# gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c -## explicit # gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df ## explicit gopkg.in/gomail.v2 +# gopkg.in/ldap.v2 v2.5.1 +## explicit +gopkg.in/ldap.v2 # gopkg.in/ldap.v3 v3.1.0 ## explicit gopkg.in/ldap.v3 @@ -513,7 +586,7 @@ gopkg.in/src-d/go-git.v4/utils/merkletrie/noder # gopkg.in/warnings.v0 v0.1.2 gopkg.in/warnings.v0 # gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b -## explicit +gopkg.in/yaml.v3 # lukechampine.com/uint128 v1.1.1 lukechampine.com/uint128 # modernc.org/cc/v3 v3.38.1