From e2cc3bbd0008b9b3ecedf118ad03788f8c676bd5 Mon Sep 17 00:00:00 2001 From: Andrew Zhu Date: Wed, 12 Aug 2026 01:54:28 +0400 Subject: [PATCH 01/14] Bump Go to 1.26 to match local toolchain Update the `go` directive in go.mod (1.23.3 -> 1.26.5) and the builder image in the Dockerfile (golang:1.23 -> golang:1.26). This keeps the build environment aligned with the local toolchain and unblocks dependencies that require a newer Go. Co-Authored-By: Claude Opus 4.8 --- Dockerfile | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index e88dfc7..4354e2e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23 +FROM golang:1.26 ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ diff --git a/go.mod b/go.mod index 6905b4d..47292c2 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/dir01/bookworm -go 1.23.3 +go 1.26.5 require ( github.com/fsnotify/fsnotify v1.8.0 From ca1bf27c26a2ca8445ca59ae469bad64218c3050 Mon Sep 17 00:00:00 2001 From: Andrew Zhu Date: Wed, 12 Aug 2026 02:05:21 +0400 Subject: [PATCH 02/14] Add EPUB and ZIM (Project Gutenberg) support bookworm previously indexed only .fb2 files and .zip archives of .fb2. This adds two new input formats: - .epub files: a new OPF/Dublin Core metadata reader (epub.go) extracts title, author (split via opf:file-as), language, subjects and cover. - .zim archives: enumerate the EPUB entries of a ZIM (e.g. a Kiwix Project Gutenberg library) via github.com/tim-st/go-zim, reading each book's metadata from its embedded EPUB (zim.go). One row per book, reopened on download by its namespace/URL reference. The download path (GetBook) is unified around an openSource helper that yields the raw bytes plus their source format. When the requested output format matches the source it is streamed as-is (so an EPUB source needs no conversion); otherwise convertBook shells out to ebook-convert, now generalized to any in/out format pair. GetBook always returns a callable cleanup, avoiding a nil-deref in the HTTP handler. The scan worker is refactored into per-format indexFB2/indexZip/ indexEPUB/indexZIM methods; the zip indexer now guards its shared slice with a mutex and closes entry readers. EPUB parsing is covered by unit + service tests using a synthetic epub. ZIM parsing is covered against a real Project Gutenberg archive committed in testdata (the smallest Kiwix Gutenberg ZIM that still contains a book, ~2 MB); both tests run unconditionally. Co-Authored-By: Claude Opus 4.8 --- README.md | 10 +- epub.go | 206 + epub_test.go | 176 + go.mod | 3 + go.sum | 6 + service.go | 310 +- testdata/README.md | 8 +- testdata/gutenberg_csb_all_2025-10.zim | Bin 0 -> 2111462 bytes .../klauspost/compress/.gitattributes | 3 + .../github.com/klauspost/compress/.gitignore | 32 + .../klauspost/compress/.goreleaser.yml | 132 + vendor/github.com/klauspost/compress/LICENSE | 304 ++ .../github.com/klauspost/compress/README.md | 712 +++ .../github.com/klauspost/compress/SECURITY.md | 25 + .../klauspost/compress/compressible.go | 85 + .../klauspost/compress/fse/README.md | 79 + .../klauspost/compress/fse/bitreader.go | 122 + .../klauspost/compress/fse/bitwriter.go | 167 + .../klauspost/compress/fse/bytereader.go | 47 + .../klauspost/compress/fse/compress.go | 683 +++ .../klauspost/compress/fse/decompress.go | 376 ++ .../github.com/klauspost/compress/fse/fse.go | 144 + vendor/github.com/klauspost/compress/gen.sh | 4 + .../klauspost/compress/huff0/.gitignore | 1 + .../klauspost/compress/huff0/README.md | 89 + .../klauspost/compress/huff0/bitreader.go | 224 + .../klauspost/compress/huff0/bitwriter.go | 102 + .../klauspost/compress/huff0/build_table.go | 168 + .../klauspost/compress/huff0/compress.go | 742 +++ .../klauspost/compress/huff0/decompress.go | 1161 +++++ .../compress/huff0/decompress_amd64.go | 49 + .../compress/huff0/decompress_amd64.s | 830 ++++ .../compress/huff0/decompress_arm64.go | 37 + .../compress/huff0/decompress_arm64.s | 851 ++++ .../compress/huff0/decompress_asm.go | 193 + .../compress/huff0/decompress_generic.go | 298 ++ .../klauspost/compress/huff0/huff0.go | 337 ++ .../compress/internal/cpuinfo/cpuinfo.go | 34 + .../internal/cpuinfo/cpuinfo_amd64.go | 10 + .../compress/internal/cpuinfo/cpuinfo_amd64.s | 36 + .../klauspost/compress/internal/le/le.go | 5 + .../compress/internal/le/unsafe_disabled.go | 42 + .../compress/internal/le/unsafe_enabled.go | 52 + .../compress/internal/snapref/LICENSE | 27 + .../compress/internal/snapref/decode.go | 264 ++ .../compress/internal/snapref/decode_other.go | 113 + .../compress/internal/snapref/encode.go | 291 ++ .../compress/internal/snapref/encode_other.go | 250 + .../compress/internal/snapref/snappy.go | 98 + vendor/github.com/klauspost/compress/s2sx.mod | 3 + vendor/github.com/klauspost/compress/s2sx.sum | 0 .../klauspost/compress/zstd/README.md | 474 ++ .../klauspost/compress/zstd/bitreader.go | 135 + .../klauspost/compress/zstd/bitwriter.go | 112 + .../klauspost/compress/zstd/blockdec.go | 709 +++ .../klauspost/compress/zstd/blockenc.go | 893 ++++ .../compress/zstd/blocktype_string.go | 85 + .../klauspost/compress/zstd/bytebuf.go | 131 + .../klauspost/compress/zstd/bytereader.go | 82 + .../klauspost/compress/zstd/decodeheader.go | 261 ++ .../klauspost/compress/zstd/decoder.go | 957 ++++ .../compress/zstd/decoder_options.go | 213 + .../klauspost/compress/zstd/dict.go | 603 +++ .../klauspost/compress/zstd/enc_base.go | 199 + .../klauspost/compress/zstd/enc_best.go | 568 +++ .../klauspost/compress/zstd/enc_better.go | 1256 +++++ .../klauspost/compress/zstd/enc_dfast.go | 1123 +++++ .../klauspost/compress/zstd/enc_fast.go | 892 ++++ .../klauspost/compress/zstd/enc_jobs.go | 352 ++ .../klauspost/compress/zstd/encoder.go | 873 ++++ .../compress/zstd/encoder_options.go | 415 ++ .../klauspost/compress/zstd/framedec.go | 412 ++ .../klauspost/compress/zstd/frameenc.go | 137 + .../klauspost/compress/zstd/fse_decoder.go | 307 ++ .../compress/zstd/fse_decoder_amd64.s | 126 + .../compress/zstd/fse_decoder_arm64.s | 153 + .../compress/zstd/fse_decoder_asm.go | 68 + .../compress/zstd/fse_decoder_generic.go | 72 + .../klauspost/compress/zstd/fse_encoder.go | 701 +++ .../klauspost/compress/zstd/fse_predefined.go | 158 + .../klauspost/compress/zstd/hash.go | 35 + .../klauspost/compress/zstd/history.go | 116 + .../compress/zstd/internal/xxhash/LICENSE.txt | 22 + .../compress/zstd/internal/xxhash/README.md | 71 + .../compress/zstd/internal/xxhash/xxhash.go | 230 + .../zstd/internal/xxhash/xxhash_amd64.s | 210 + .../zstd/internal/xxhash/xxhash_arm64.s | 184 + .../zstd/internal/xxhash/xxhash_asm.go | 16 + .../zstd/internal/xxhash/xxhash_other.go | 75 + .../zstd/internal/xxhash/xxhash_safe.go | 11 + .../klauspost/compress/zstd/matchlen_amd64.go | 15 + .../klauspost/compress/zstd/matchlen_amd64.s | 66 + .../compress/zstd/matchlen_generic.go | 37 + .../klauspost/compress/zstd/seqdec.go | 500 ++ .../klauspost/compress/zstd/seqdec_amd64.go | 105 + .../klauspost/compress/zstd/seqdec_amd64.s | 4151 +++++++++++++++++ .../klauspost/compress/zstd/seqdec_arm64.go | 70 + .../klauspost/compress/zstd/seqdec_arm64.s | 2750 +++++++++++ .../klauspost/compress/zstd/seqdec_asm.go | 316 ++ .../klauspost/compress/zstd/seqdec_generic.go | 236 + .../klauspost/compress/zstd/seqenc.go | 112 + .../klauspost/compress/zstd/simple_go124.go | 56 + .../klauspost/compress/zstd/snappy.go | 435 ++ .../github.com/klauspost/compress/zstd/zip.go | 141 + .../klauspost/compress/zstd/zstd.go | 126 + vendor/github.com/tim-st/go-zim/LICENSE | 201 + vendor/github.com/tim-st/go-zim/README.md | 48 + .../github.com/tim-st/go-zim/blob_reader.go | 76 + vendor/github.com/tim-st/go-zim/checksum.go | 47 + vendor/github.com/tim-st/go-zim/cluster.go | 148 + vendor/github.com/tim-st/go-zim/entry.go | 191 + .../github.com/tim-st/go-zim/entry_search.go | 234 + vendor/github.com/tim-st/go-zim/file.go | 91 + .../tim-st/go-zim/file_operations.go | 93 + vendor/github.com/tim-st/go-zim/header.go | 63 + vendor/github.com/tim-st/go-zim/metadata.go | 73 + vendor/github.com/tim-st/go-zim/mimetype.go | 30 + vendor/github.com/tim-st/go-zim/namespace.go | 20 + vendor/github.com/xi2/xz/AUTHORS | 8 + vendor/github.com/xi2/xz/LICENSE | 18 + vendor/github.com/xi2/xz/README.md | 10 + vendor/github.com/xi2/xz/dec_bcj.go | 461 ++ vendor/github.com/xi2/xz/dec_delta.go | 55 + vendor/github.com/xi2/xz/dec_lzma2.go | 1235 +++++ vendor/github.com/xi2/xz/dec_stream.go | 932 ++++ vendor/github.com/xi2/xz/dec_util.go | 52 + vendor/github.com/xi2/xz/dec_xz.go | 124 + vendor/github.com/xi2/xz/doc.go | 35 + vendor/github.com/xi2/xz/reader.go | 256 + vendor/modules.txt | 16 + zim.go | 108 + zim_test.go | 147 + 132 files changed, 37164 insertions(+), 102 deletions(-) create mode 100644 epub.go create mode 100644 epub_test.go create mode 100644 testdata/gutenberg_csb_all_2025-10.zim create mode 100644 vendor/github.com/klauspost/compress/.gitattributes create mode 100644 vendor/github.com/klauspost/compress/.gitignore create mode 100644 vendor/github.com/klauspost/compress/.goreleaser.yml create mode 100644 vendor/github.com/klauspost/compress/LICENSE create mode 100644 vendor/github.com/klauspost/compress/README.md create mode 100644 vendor/github.com/klauspost/compress/SECURITY.md create mode 100644 vendor/github.com/klauspost/compress/compressible.go create mode 100644 vendor/github.com/klauspost/compress/fse/README.md create mode 100644 vendor/github.com/klauspost/compress/fse/bitreader.go create mode 100644 vendor/github.com/klauspost/compress/fse/bitwriter.go create mode 100644 vendor/github.com/klauspost/compress/fse/bytereader.go create mode 100644 vendor/github.com/klauspost/compress/fse/compress.go create mode 100644 vendor/github.com/klauspost/compress/fse/decompress.go create mode 100644 vendor/github.com/klauspost/compress/fse/fse.go create mode 100644 vendor/github.com/klauspost/compress/gen.sh create mode 100644 vendor/github.com/klauspost/compress/huff0/.gitignore create mode 100644 vendor/github.com/klauspost/compress/huff0/README.md create mode 100644 vendor/github.com/klauspost/compress/huff0/bitreader.go create mode 100644 vendor/github.com/klauspost/compress/huff0/bitwriter.go create mode 100644 vendor/github.com/klauspost/compress/huff0/build_table.go create mode 100644 vendor/github.com/klauspost/compress/huff0/compress.go create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress.go create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress_amd64.go create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress_amd64.s create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress_arm64.go create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress_arm64.s create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress_asm.go create mode 100644 vendor/github.com/klauspost/compress/huff0/decompress_generic.go create mode 100644 vendor/github.com/klauspost/compress/huff0/huff0.go create mode 100644 vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go create mode 100644 vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go create mode 100644 vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s create mode 100644 vendor/github.com/klauspost/compress/internal/le/le.go create mode 100644 vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go create mode 100644 vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/LICENSE create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/decode.go create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/decode_other.go create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/encode.go create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/encode_other.go create mode 100644 vendor/github.com/klauspost/compress/internal/snapref/snappy.go create mode 100644 vendor/github.com/klauspost/compress/s2sx.mod create mode 100644 vendor/github.com/klauspost/compress/s2sx.sum create mode 100644 vendor/github.com/klauspost/compress/zstd/README.md create mode 100644 vendor/github.com/klauspost/compress/zstd/bitreader.go create mode 100644 vendor/github.com/klauspost/compress/zstd/bitwriter.go create mode 100644 vendor/github.com/klauspost/compress/zstd/blockdec.go create mode 100644 vendor/github.com/klauspost/compress/zstd/blockenc.go create mode 100644 vendor/github.com/klauspost/compress/zstd/blocktype_string.go create mode 100644 vendor/github.com/klauspost/compress/zstd/bytebuf.go create mode 100644 vendor/github.com/klauspost/compress/zstd/bytereader.go create mode 100644 vendor/github.com/klauspost/compress/zstd/decodeheader.go create mode 100644 vendor/github.com/klauspost/compress/zstd/decoder.go create mode 100644 vendor/github.com/klauspost/compress/zstd/decoder_options.go create mode 100644 vendor/github.com/klauspost/compress/zstd/dict.go create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_base.go create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_best.go create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_better.go create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_dfast.go create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_fast.go create mode 100644 vendor/github.com/klauspost/compress/zstd/enc_jobs.go create mode 100644 vendor/github.com/klauspost/compress/zstd/encoder.go create mode 100644 vendor/github.com/klauspost/compress/zstd/encoder_options.go create mode 100644 vendor/github.com/klauspost/compress/zstd/framedec.go create mode 100644 vendor/github.com/klauspost/compress/zstd/frameenc.go create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_decoder.go create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_decoder_asm.go create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_encoder.go create mode 100644 vendor/github.com/klauspost/compress/zstd/fse_predefined.go create mode 100644 vendor/github.com/klauspost/compress/zstd/hash.go create mode 100644 vendor/github.com/klauspost/compress/zstd/history.go create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/README.md create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_asm.go create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go create mode 100644 vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_safe.go create mode 100644 vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go create mode 100644 vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s create mode 100644 vendor/github.com/klauspost/compress/zstd/matchlen_generic.go create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec.go create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec_arm64.go create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec_asm.go create mode 100644 vendor/github.com/klauspost/compress/zstd/seqdec_generic.go create mode 100644 vendor/github.com/klauspost/compress/zstd/seqenc.go create mode 100644 vendor/github.com/klauspost/compress/zstd/simple_go124.go create mode 100644 vendor/github.com/klauspost/compress/zstd/snappy.go create mode 100644 vendor/github.com/klauspost/compress/zstd/zip.go create mode 100644 vendor/github.com/klauspost/compress/zstd/zstd.go create mode 100644 vendor/github.com/tim-st/go-zim/LICENSE create mode 100644 vendor/github.com/tim-st/go-zim/README.md create mode 100644 vendor/github.com/tim-st/go-zim/blob_reader.go create mode 100644 vendor/github.com/tim-st/go-zim/checksum.go create mode 100644 vendor/github.com/tim-st/go-zim/cluster.go create mode 100644 vendor/github.com/tim-st/go-zim/entry.go create mode 100644 vendor/github.com/tim-st/go-zim/entry_search.go create mode 100644 vendor/github.com/tim-st/go-zim/file.go create mode 100644 vendor/github.com/tim-st/go-zim/file_operations.go create mode 100644 vendor/github.com/tim-st/go-zim/header.go create mode 100644 vendor/github.com/tim-st/go-zim/metadata.go create mode 100644 vendor/github.com/tim-st/go-zim/mimetype.go create mode 100644 vendor/github.com/tim-st/go-zim/namespace.go create mode 100644 vendor/github.com/xi2/xz/AUTHORS create mode 100644 vendor/github.com/xi2/xz/LICENSE create mode 100644 vendor/github.com/xi2/xz/README.md create mode 100644 vendor/github.com/xi2/xz/dec_bcj.go create mode 100644 vendor/github.com/xi2/xz/dec_delta.go create mode 100644 vendor/github.com/xi2/xz/dec_lzma2.go create mode 100644 vendor/github.com/xi2/xz/dec_stream.go create mode 100644 vendor/github.com/xi2/xz/dec_util.go create mode 100644 vendor/github.com/xi2/xz/dec_xz.go create mode 100644 vendor/github.com/xi2/xz/doc.go create mode 100644 vendor/github.com/xi2/xz/reader.go create mode 100644 zim.go create mode 100644 zim_test.go diff --git a/README.md b/README.md index f01a699..8b859d6 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,15 @@ ![GitHub](https://img.shields.io/github/license/dir01/bookworm) `bookworm` allows you to : -- index your books archive (directory containing `.fb2` files or `.zip` archives with `.fb2` files inside) +- index your books archive, a directory containing any of: + - `.fb2` files + - `.zip` archives with `.fb2` files inside + - `.epub` files + - `.zim` archives with `.epub` files inside (e.g. a [Project Gutenberg](https://download.kiwix.org/zim/gutenberg/) library from Kiwix) - search for books (by title or author) - get the books (as `.fb2` or `.epub`) +Books are served in their original format when possible (an `.epub` source is +streamed as-is); conversion between `.fb2` and `.epub` uses Calibre's +`ebook-convert`. + diff --git a/epub.go b/epub.go new file mode 100644 index 0000000..d250df9 --- /dev/null +++ b/epub.go @@ -0,0 +1,206 @@ +package main + +import ( + "archive/zip" + "bytes" + "encoding/xml" + "fmt" + "strings" +) + +// epubContainer models META-INF/container.xml, which points at the OPF package +// document via the first . +type epubContainer struct { + Rootfiles []struct { + FullPath string `xml:"full-path,attr"` + } `xml:"rootfiles>rootfile"` +} + +// opfPackage models the parts of the OPF package document we care about: the +// Dublin Core metadata block and the manifest (used to detect a cover image). +type opfPackage struct { + Metadata opfMetadata `xml:"metadata"` + Manifest struct { + Items []struct { + ID string `xml:"id,attr"` + Properties string `xml:"properties,attr"` + } `xml:"item"` + } `xml:"manifest"` +} + +type opfMetadata struct { + Titles []string `xml:"title"` + Creators []opfAuthor `xml:"creator"` + Languages []string `xml:"language"` + Subjects []string `xml:"subject"` + Dates []string `xml:"date"` + Descriptions []string `xml:"description"` + Metas []opfMeta `xml:"meta"` +} + +type opfAuthor struct { + // FileAs is the opf:file-as attribute, conventionally "Last, First". + FileAs string `xml:"file-as,attr"` + Value string `xml:",chardata"` +} + +type opfMeta struct { + Name string `xml:"name,attr"` + Content string `xml:"content,attr"` +} + +// readEPUBMetadataFromFile extracts book metadata from an .epub file on disk. +func readEPUBMetadataFromFile(path string) (*BookMetadata, error) { + zr, err := zip.OpenReader(path) + if err != nil { + return nil, fmt.Errorf("error opening epub %q: %w", path, err) + } + defer zr.Close() + return readEPUBMetadata(&zr.Reader) +} + +// readEPUBMetadataFromBytes extracts book metadata from an in-memory .epub +// (e.g. a blob read out of a ZIM archive). +func readEPUBMetadataFromBytes(b []byte) (*BookMetadata, error) { + zr, err := zip.NewReader(bytes.NewReader(b), int64(len(b))) + if err != nil { + return nil, fmt.Errorf("error reading epub bytes: %w", err) + } + return readEPUBMetadata(zr) +} + +// readEPUBMetadata reads the OPF package document referenced by container.xml +// and maps its Dublin Core metadata onto a BookMetadata. FileType, FilePath and +// SubFilepath are left for the caller to fill in. +func readEPUBMetadata(zr *zip.Reader) (*BookMetadata, error) { + opfPath, err := epubOPFPath(zr) + if err != nil { + return nil, err + } + + pkg, err := parseOPF(zr, opfPath) + if err != nil { + return nil, err + } + + m := &BookMetadata{} + if len(pkg.Metadata.Titles) > 0 { + m.Title = strings.TrimSpace(pkg.Metadata.Titles[0]) + } + if len(pkg.Metadata.Creators) > 0 { + m.AuthorLastName, m.AuthorFirstName = splitAuthor(pkg.Metadata.Creators[0]) + } + if len(pkg.Metadata.Languages) > 0 { + m.Language = strings.TrimSpace(pkg.Metadata.Languages[0]) + } + if len(pkg.Metadata.Descriptions) > 0 { + m.Annotation = strings.TrimSpace(pkg.Metadata.Descriptions[0]) + } + if len(pkg.Metadata.Dates) > 0 { + m.Date = strings.TrimSpace(pkg.Metadata.Dates[0]) + } + var subjects []string + for _, s := range pkg.Metadata.Subjects { + if s = strings.TrimSpace(s); s != "" { + subjects = append(subjects, s) + } + } + m.Genre = strings.Join(subjects, ", ") + m.HasCover = epubHasCover(pkg) + + return m, nil +} + +func epubOPFPath(zr *zip.Reader) (string, error) { + f := findZipEntry(zr, "META-INF/container.xml") + if f == nil { + return "", fmt.Errorf("epub: missing META-INF/container.xml") + } + rc, err := f.Open() + if err != nil { + return "", fmt.Errorf("epub: opening container.xml: %w", err) + } + defer rc.Close() + + var c epubContainer + if err := xml.NewDecoder(rc).Decode(&c); err != nil { + return "", fmt.Errorf("epub: parsing container.xml: %w", err) + } + if len(c.Rootfiles) == 0 || c.Rootfiles[0].FullPath == "" { + return "", fmt.Errorf("epub: no rootfile in container.xml") + } + return c.Rootfiles[0].FullPath, nil +} + +func parseOPF(zr *zip.Reader, opfPath string) (*opfPackage, error) { + f := findZipEntry(zr, opfPath) + if f == nil { + return nil, fmt.Errorf("epub: opf %q not found", opfPath) + } + rc, err := f.Open() + if err != nil { + return nil, fmt.Errorf("epub: opening opf %q: %w", opfPath, err) + } + defer rc.Close() + + var pkg opfPackage + if err := xml.NewDecoder(rc).Decode(&pkg); err != nil { + return nil, fmt.Errorf("epub: parsing opf %q: %w", opfPath, err) + } + return &pkg, nil +} + +// findZipEntry returns the zip entry with the given name, matching +// case-insensitively as a fallback (zip names are technically case-sensitive, +// but "META-INF" casing varies in the wild). +func findZipEntry(zr *zip.Reader, name string) *zip.File { + for _, f := range zr.File { + if f.Name == name { + return f + } + } + for _, f := range zr.File { + if strings.EqualFold(f.Name, name) { + return f + } + } + return nil +} + +// splitAuthor derives (last, first) name parts from a dc:creator. It prefers the +// opf:file-as attribute ("Last, First"); otherwise it falls back to the display +// name, splitting "First Last" on the final space. +func splitAuthor(a opfAuthor) (last, first string) { + if name := strings.TrimSpace(a.FileAs); name != "" { + if before, after, found := strings.Cut(name, ","); found { + return strings.TrimSpace(before), strings.TrimSpace(after) + } + return name, "" + } + + name := strings.TrimSpace(a.Value) + if name == "" { + return "", "" + } + if before, after, found := strings.Cut(name, ","); found { + return strings.TrimSpace(before), strings.TrimSpace(after) + } + if i := strings.LastIndex(name, " "); i >= 0 { + return strings.TrimSpace(name[i+1:]), strings.TrimSpace(name[:i]) + } + return name, "" +} + +func epubHasCover(pkg *opfPackage) bool { + for _, m := range pkg.Metadata.Metas { + if strings.EqualFold(m.Name, "cover") && m.Content != "" { + return true + } + } + for _, it := range pkg.Manifest.Items { + if strings.Contains(it.Properties, "cover-image") { + return true + } + } + return false +} diff --git a/epub_test.go b/epub_test.go new file mode 100644 index 0000000..146ee24 --- /dev/null +++ b/epub_test.go @@ -0,0 +1,176 @@ +package main + +import ( + "archive/zip" + "bytes" + "context" + "io" + "os" + "path/filepath" + "testing" + "time" + + "github.com/jmoiron/sqlx" + _ "github.com/mattn/go-sqlite3" + migrate "github.com/rubenv/sql-migrate" +) + +const testContainerXML = ` + + +` + +const testOPF = ` + + + Pride and Prejudice + Jane Austen + en + Fiction + Romance + 1813 + A classic novel. + + + + + +` + +// buildTestEPUB returns the bytes of a minimal but valid .epub built from the +// given OPF package document. +func buildTestEPUB(t *testing.T, opf string) []byte { + t.Helper() + + var buf bytes.Buffer + w := zip.NewWriter(&buf) + + write := func(name, content string) { + f, err := w.Create(name) + if err != nil { + t.Fatalf("create %q: %v", name, err) + } + if _, err := io.WriteString(f, content); err != nil { + t.Fatalf("write %q: %v", name, err) + } + } + + write("mimetype", "application/epub+zip") + write("META-INF/container.xml", testContainerXML) + write("content.opf", opf) + + if err := w.Close(); err != nil { + t.Fatalf("close zip: %v", err) + } + return buf.Bytes() +} + +func TestReadEPUBMetadata(t *testing.T) { + md, err := readEPUBMetadataFromBytes(buildTestEPUB(t, testOPF)) + if err != nil { + t.Fatalf("readEPUBMetadataFromBytes: %v", err) + } + + checks := map[string]struct{ got, want string }{ + "title": {md.Title, "Pride and Prejudice"}, + "last name": {md.AuthorLastName, "Austen"}, + "first name": {md.AuthorFirstName, "Jane"}, + "language": {md.Language, "en"}, + "genre": {md.Genre, "Fiction, Romance"}, + "date": {md.Date, "1813"}, + "annotation": {md.Annotation, "A classic novel."}, + } + for field, c := range checks { + if c.got != c.want { + t.Errorf("%s = %q, want %q", field, c.got, c.want) + } + } + if !md.HasCover { + t.Errorf("HasCover = false, want true") + } +} + +func TestSplitAuthor(t *testing.T) { + cases := []struct { + name string + author opfAuthor + wantLast string + wantFirst string + }{ + {"file-as comma", opfAuthor{FileAs: "Austen, Jane", Value: "Jane Austen"}, "Austen", "Jane"}, + {"display name only", opfAuthor{Value: "Mark Twain"}, "Twain", "Mark"}, + {"single token", opfAuthor{Value: "Homer"}, "Homer", ""}, + {"comma in value", opfAuthor{Value: "Twain, Mark"}, "Twain", "Mark"}, + {"empty", opfAuthor{}, "", ""}, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + last, first := splitAuthor(c.author) + if last != c.wantLast || first != c.wantFirst { + t.Errorf("splitAuthor(%+v) = (%q, %q), want (%q, %q)", c.author, last, first, c.wantLast, c.wantFirst) + } + }) + } +} + +// TestServiceIndexesEPUB verifies an .epub on disk is scanned, indexed and then +// served back unchanged (EPUB -> EPUB is a passthrough, so no ebook-convert is +// required). +func TestServiceIndexesEPUB(t *testing.T) { + db := sqlx.MustConnect("sqlite3", ":memory:") + store := NewSqliteStore(db) + if _, err := migrate.Exec(db.DB, "sqlite3", &migrate.FileMigrationSource{Dir: "./db/migrations"}, migrate.Up); err != nil { + t.Fatalf("migrations: %v", err) + } + + tempDir := t.TempDir() + epubBytes := buildTestEPUB(t, testOPF) + if err := os.WriteFile(filepath.Join(tempDir, "pride.epub"), epubBytes, 0o644); err != nil { + t.Fatalf("write epub: %v", err) + } + + svc, err := NewService(tempDir, store) + if err != nil { + t.Fatalf("NewService: %v", err) + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + if err := svc.Run(ctx); err != nil { + t.Fatalf("Run: %v", err) + } + if err := svc.Scan(ctx); err != nil { + t.Fatalf("Scan: %v", err) + } + + var book *BookMetadata + eventually(t, 2*time.Second, 100*time.Millisecond, func() (bool, error) { + res, err := svc.Search(ctx, "Austen") + if err != nil { + return false, err + } + if len(res) == 1 { + book = res[0] + return true, nil + } + return false, nil + }) + + if book.FileType != EPUB { + t.Fatalf("FileType = %q, want %q", book.FileType, EPUB) + } + + reader, cleanup, err := svc.GetBook(ctx, book.ID, EPUB) + if err != nil { + t.Fatalf("GetBook: %v", err) + } + defer cleanup() + + got, err := io.ReadAll(reader) + if err != nil { + t.Fatalf("read book: %v", err) + } + if !bytes.Equal(got, epubBytes) { + t.Fatalf("served epub differs from source (got %d bytes, want %d)", len(got), len(epubBytes)) + } +} diff --git a/go.mod b/go.mod index 47292c2..ccdabc4 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.24 github.com/rubenv/sql-migrate v1.7.1 github.com/tamerh/xml-stream-parser v1.5.0 + github.com/tim-st/go-zim v0.1.3 gopkg.in/telebot.v3 v3.3.8 ) @@ -33,6 +34,7 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.5.0 // indirect + github.com/klauspost/compress v1.19.2 // indirect github.com/lib/pq v1.10.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -48,6 +50,7 @@ require ( github.com/shopspring/decimal v1.4.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/tamerh/xpath v1.0.0 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect golang.org/x/sys v0.28.0 // indirect diff --git a/go.sum b/go.sum index d64be8f..119d96a 100644 --- a/go.sum +++ b/go.sum @@ -319,6 +319,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= +github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -474,7 +476,11 @@ github.com/tamerh/xml-stream-parser v1.5.0 h1:aOb4PX/UgX+rsEXEzOMeP6kNI3yaz0NXvm github.com/tamerh/xml-stream-parser v1.5.0/go.mod h1:U2cbOazFpRFXP3OiVZUbQVOtZ2T1gBKdeHOlEajksgo= github.com/tamerh/xpath v1.0.0 h1:NccMES/Ej8slPCFDff73Kf6V1xu9hdbuKf2RyDsxf5Q= github.com/tamerh/xpath v1.0.0/go.mod h1:t0wnh72FQlOVEO20f2Dl3EoVxso9GnLREh1WTpvNmJQ= +github.com/tim-st/go-zim v0.1.3 h1:KTpSHKzxjn4tLjymDxCPtAIo1nZyQs8kt7RG2MupINc= +github.com/tim-st/go-zim v0.1.3/go.mod h1:ac2eYM1a06s/lJofEdg/6uheVCiTFlRHOo7e+NvuUFQ= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/service.go b/service.go index 8ff95a1..a410be5 100644 --- a/service.go +++ b/service.go @@ -23,6 +23,19 @@ type FileType string const FB2 FileType = "fb2" const ZIP FileType = "zip" const EPUB FileType = "epub" +const ZIM FileType = "zim" + +// supportedExtensions are the file suffixes the scanner will index. +var supportedExtensions = []string{".fb2", ".zip", ".epub", ".zim"} + +func isSupportedFile(path string) bool { + for _, ext := range supportedExtensions { + if strings.HasSuffix(path, ext) { + return true + } + } + return false +} type BookMetadata struct { // Database ID @@ -99,7 +112,7 @@ func (s *Service) Run(ctx context.Context) error { return nil } -// Scan recursively extracts metadata from all .zip and .fb2 files in the directory and stores them in the database. +// Scan recursively extracts metadata from all supported files (.fb2, .zip, .epub, .zim) in the directory and stores them in the database. func (s *Service) Scan(ctx context.Context) error { return filepath.Walk(s.dirPath, func(path string, info os.FileInfo, err error) error { if err != nil { @@ -125,85 +138,139 @@ func (s *Service) Search(ctx context.Context, searchTerm string) ([]*BookMetadat } } -// GetBook returns a file reader for a book with id in outFormat format +// GetBook returns a file reader for a book with id in outFormat format. +// If the stored source is already in outFormat it is streamed as-is, otherwise +// it is converted (via ebook-convert). func (s *Service) GetBook(ctx context.Context, id int64, outFormat FileType) ( file io.Reader, cleanup func(), err error, ) { + noop := func() {} + if outFormat != EPUB && outFormat != FB2 { - return nil, nil, fmt.Errorf("unsupported output format %q", outFormat) + return nil, noop, fmt.Errorf("unsupported output format %q", outFormat) } bookMetadata, err := s.store.GetBook(ctx, id) if err != nil { - return nil, nil, fmt.Errorf("error getting book metadata: %w", err) + return nil, noop, fmt.Errorf("error getting book metadata: %w", err) } + source, sourceFormat, closeSource, err := s.openSource(bookMetadata) + if err != nil { + return nil, closeSource, err + } + + if outFormat == sourceFormat { + return source, closeSource, nil + } + + converted, removeConverted, err := s.convertBook(source, sourceFormat, outFormat) + cleanup = func() { + removeConverted() + closeSource() + } + if err != nil { + return nil, cleanup, err + } + return converted, cleanup, nil +} + +// openSource returns a reader for the raw book bytes together with the format +// they are in. For books that live inside a container (a .zip or a .zim) the +// entry is read fully into memory so the container handle can be closed +// immediately; book files are small enough for this to be cheap. +func (s *Service) openSource(md *BookMetadata) (reader io.Reader, format FileType, cleanup func(), err error) { cleanup = func() {} - var sourceFile io.Reader - switch bookMetadata.FileType { - case FB2: - sourceFile, err = os.Open(bookMetadata.FilePath) + switch md.FileType { + case FB2, EPUB: + f, err := os.Open(md.FilePath) if err != nil { - return nil, cleanup, fmt.Errorf("error opening file %q: %w", bookMetadata.FilePath, err) + return nil, "", cleanup, fmt.Errorf("error opening file %q: %w", md.FilePath, err) } + return f, md.FileType, func() { f.Close() }, nil case ZIP: - z, err := zip.OpenReader(bookMetadata.FilePath) + buf, name, err := readZipEntry(md.FilePath, md.SubFilepath) if err != nil { - return nil, cleanup, fmt.Errorf("error opening zip path %q: %w", bookMetadata.FilePath, err) + return nil, "", cleanup, err } - for _, f := range z.File { - if f.Name == bookMetadata.SubFilepath { - sourceFile, err = f.Open() - if err != nil { - return nil, cleanup, fmt.Errorf("error opening file %q in zip archive %q: %w", f.Name, bookMetadata.FilePath, err) - } - goto convert // we might need to format the file, so we can't return here - } + return bytes.NewReader(buf), formatFromExt(name), cleanup, nil + case ZIM: + buf, err := openZIMEntry(md.FilePath, md.SubFilepath) + if err != nil { + return nil, "", cleanup, err } - return nil, cleanup, fmt.Errorf("file %q not found in zip archive %q", bookMetadata.SubFilepath, bookMetadata.FilePath) + return bytes.NewReader(buf), EPUB, cleanup, nil default: - return nil, cleanup, fmt.Errorf("unknown file type %q", bookMetadata.FileType) + return nil, "", cleanup, fmt.Errorf("unknown file type %q", md.FileType) } +} -convert: - switch outFormat { - case FB2: - return sourceFile, cleanup, nil - case EPUB: - return s.convertBook(sourceFile, EPUB) +// readZipEntry reads a single named entry from a zip archive into memory and +// returns its bytes and name. +func readZipEntry(zipPath, subPath string) ([]byte, string, error) { + z, err := zip.OpenReader(zipPath) + if err != nil { + return nil, "", fmt.Errorf("error opening zip path %q: %w", zipPath, err) + } + defer z.Close() + + for _, f := range z.File { + if f.Name != subPath { + continue + } + rc, err := f.Open() + if err != nil { + return nil, "", fmt.Errorf("error opening file %q in zip archive %q: %w", f.Name, zipPath, err) + } + defer rc.Close() + buf, err := io.ReadAll(rc) + if err != nil { + return nil, "", fmt.Errorf("error reading file %q in zip archive %q: %w", f.Name, zipPath, err) + } + return buf, f.Name, nil + } + return nil, "", fmt.Errorf("file %q not found in zip archive %q", subPath, zipPath) +} + +func formatFromExt(name string) FileType { + switch { + case strings.HasSuffix(name, ".epub"): + return EPUB + case strings.HasSuffix(name, ".fb2"): + return FB2 default: - return nil, cleanup, fmt.Errorf("unsupported output format %q", outFormat) + return FileType(strings.TrimPrefix(filepath.Ext(name), ".")) } } +// convertBook converts reader from inFormat to outFormat using ebook-convert. func (s *Service) convertBook( reader io.Reader, - outFormat FileType, + inFormat, outFormat FileType, ) ( file io.Reader, cleanup func(), err error, ) { - if outFormat != EPUB { - return nil, nil, fmt.Errorf("only epub format is supported") - } + cleanup = func() {} - sourceTemp := filepath.Join(os.TempDir(), fmt.Sprintf("source-%d.fb2", time.Now().UnixNano())) + sourceTemp := filepath.Join(os.TempDir(), fmt.Sprintf("source-%d.%s", time.Now().UnixNano(), inFormat)) sourceTempFile, err := os.Create(sourceTemp) if err != nil { - return nil, nil, fmt.Errorf("error creating temporary file: %w", err) + return nil, cleanup, fmt.Errorf("error creating temporary file: %w", err) } + defer os.Remove(sourceTemp) if _, err = io.Copy(sourceTempFile, reader); err != nil { - return nil, nil, fmt.Errorf("error copying file to temporary file: %w", err) + sourceTempFile.Close() + return nil, cleanup, fmt.Errorf("error copying file to temporary file: %w", err) } + sourceTempFile.Close() - outTemp := sourceTemp + ".epub" - - defer os.Remove(sourceTemp) + outTemp := sourceTemp + "." + string(outFormat) cleanup = func() { os.Remove(outTemp) } @@ -224,7 +291,7 @@ func (s *Service) convertBook( } func (s *Service) processFile(path string) { - if !strings.HasSuffix(path, ".zip") && !strings.HasSuffix(path, ".fb2") { + if !isSupportedFile(path) { return } s.filesChan <- path @@ -237,7 +304,7 @@ func (s *Service) startFileWorker(ctx context.Context) { log.Println("[service] file worker done") return case path := <-s.filesChan: - if !strings.HasSuffix(path, ".zip") && !strings.HasSuffix(path, ".fb2") { + if !isSupportedFile(path) { continue } @@ -251,82 +318,125 @@ func (s *Service) startFileWorker(ctx context.Context) { log.Printf("[service] processing file %q\n", path) - if strings.HasSuffix(path, ".fb2") { - r, err := os.Open(path) - if err != nil { - log.Printf("[service] error opening file %q: %v\n", path, err) - continue - } + switch { + case strings.HasSuffix(path, ".fb2"): + s.indexFB2(ctx, path) + case strings.HasSuffix(path, ".zip"): + s.indexZip(ctx, path) + case strings.HasSuffix(path, ".epub"): + s.indexEPUB(ctx, path) + case strings.HasSuffix(path, ".zim"): + s.indexZIM(ctx, path) + } + } + } +} - metadata, err := s.readFB2Metadata(r) - if err != nil { - log.Printf("[service] error reading metadata from file %q: %v\n", path, err) - continue - } +func (s *Service) indexFB2(ctx context.Context, path string) { + r, err := os.Open(path) + if err != nil { + log.Printf("[service] error opening file %q: %v\n", path, err) + return + } + defer r.Close() - metadata.FileType = FB2 - metadata.FilePath = path + metadata, err := s.readFB2Metadata(r) + if err != nil { + log.Printf("[service] error reading metadata from file %q: %v\n", path, err) + return + } - if err := s.store.Store(ctx, []*BookMetadata{metadata}); err != nil { - log.Printf("[service] error storing metadata from file %q: %v\n", path, err) - continue - } - } + metadata.FileType = FB2 + metadata.FilePath = path - if strings.HasSuffix(path, ".zip") { - z, err := zip.OpenReader(path) - if err != nil { - log.Printf("[service] error opening zip path %q: %v\n", path, err) - continue - } + if err := s.store.Store(ctx, []*BookMetadata{metadata}); err != nil { + log.Printf("[service] error storing metadata from file %q: %v\n", path, err) + } +} - var mds []*BookMetadata - var wg sync.WaitGroup +func (s *Service) indexZip(ctx context.Context, path string) { + z, err := zip.OpenReader(path) + if err != nil { + log.Printf("[service] error opening zip path %q: %v\n", path, err) + return + } + defer z.Close() - for _, f := range z.File { - if !strings.HasSuffix(f.Name, ".fb2") { - continue - } + var mds []*BookMetadata + var mu sync.Mutex + var wg sync.WaitGroup - wg.Add(1) + for _, f := range z.File { + if !strings.HasSuffix(f.Name, ".fb2") { + continue + } - go func(f *zip.File) { - defer wg.Done() + wg.Add(1) - r, err := f.Open() - if err != nil { - log.Printf("[service] error opening file %s in zip archive %s: %v\n", f.Name, path, err) - return - } + go func(f *zip.File) { + defer wg.Done() - metadata, err := s.readFB2Metadata(r) - if err != nil { - log.Printf("[service] error reading metadata from file %s in zip archive %s: %v\n", f.Name, path, err) - return - } + r, err := f.Open() + if err != nil { + log.Printf("[service] error opening file %s in zip archive %s: %v\n", f.Name, path, err) + return + } + defer r.Close() - metadata.FileType = ZIP - metadata.FilePath = path - metadata.SubFilepath = f.Name - mds = append(mds, metadata) - }(f) - } + metadata, err := s.readFB2Metadata(r) + if err != nil { + log.Printf("[service] error reading metadata from file %s in zip archive %s: %v\n", f.Name, path, err) + return + } - log.Printf("[service] waiting for %d workers to finish processing %s\n", len(z.File), path) + metadata.FileType = ZIP + metadata.FilePath = path + metadata.SubFilepath = f.Name - wg.Wait() + mu.Lock() + mds = append(mds, metadata) + mu.Unlock() + }(f) + } - log.Printf("[service] storing %d metadatas from %s\n", len(mds), path) + wg.Wait() - if len(mds) > 0 { - if err := s.store.Store(ctx, mds); err != nil { - log.Printf("[service] ERROR storing metadata from file %q: %v\n", path, err) - continue - } - } + log.Printf("[service] storing %d metadatas from %s\n", len(mds), path) - z.Close() - } + if len(mds) > 0 { + if err := s.store.Store(ctx, mds); err != nil { + log.Printf("[service] ERROR storing metadata from file %q: %v\n", path, err) + } + } +} + +func (s *Service) indexEPUB(ctx context.Context, path string) { + metadata, err := readEPUBMetadataFromFile(path) + if err != nil { + log.Printf("[service] error reading metadata from epub %q: %v\n", path, err) + return + } + + metadata.FileType = EPUB + metadata.FilePath = path + + if err := s.store.Store(ctx, []*BookMetadata{metadata}); err != nil { + log.Printf("[service] error storing metadata from epub %q: %v\n", path, err) + } +} + +func (s *Service) indexZIM(ctx context.Context, path string) { + mds, err := readZIMBooks(path) + if err != nil { + log.Printf("[service] error reading zim %q: %v\n", path, err) + return + } + + log.Printf("[service] storing %d books from zim %s\n", len(mds), path) + + if len(mds) > 0 { + if err := s.store.Store(ctx, mds); err != nil { + log.Printf("[service] ERROR storing metadata from zim %q: %v\n", path, err) } } } diff --git a/testdata/README.md b/testdata/README.md index 68da362..b2d8b92 100644 --- a/testdata/README.md +++ b/testdata/README.md @@ -1 +1,7 @@ -Those public domain ebooks were downloaded from https://onemorelibrary.com/ \ No newline at end of file +Those public domain ebooks were downloaded from https://onemorelibrary.com/ + +`gutenberg_csb_all_2025-10.zim` is a Project Gutenberg ZIM archive from Kiwix +(https://download.kiwix.org/zim/gutenberg/), used as a fixture for the ZIM +reader tests. It is the smallest Gutenberg archive that still contains a book +(the Kashubian library, a single title), kept small on purpose to avoid bloating +the repo. \ No newline at end of file diff --git a/testdata/gutenberg_csb_all_2025-10.zim b/testdata/gutenberg_csb_all_2025-10.zim new file mode 100644 index 0000000000000000000000000000000000000000..354007ebc5c9e769c193a4e422193736dbf90ae6 GIT binary patch literal 2111462 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 z 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%0ALth4JM}%v3hDg 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%0A3NfN>0|Cu91XVV(Nb`zo^*HiA<3g}McD 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%0D7~Gy;FP{KL{kR$-!NMEQqf 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ṛ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 z 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 z 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

)`ngHCF+8Si_+dx8%&#B#2Onk?Nq|JBm* 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

    P#7zhYN(tX{$sa|muf4z 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 Cg;xjw literal 0 HcmV?d00001 diff --git a/vendor/github.com/klauspost/compress/.gitattributes b/vendor/github.com/klauspost/compress/.gitattributes new file mode 100644 index 0000000..57aa648 --- /dev/null +++ b/vendor/github.com/klauspost/compress/.gitattributes @@ -0,0 +1,3 @@ +* -text +*.bin -text -diff +*.md text eol=lf diff --git a/vendor/github.com/klauspost/compress/.gitignore b/vendor/github.com/klauspost/compress/.gitignore new file mode 100644 index 0000000..d31b378 --- /dev/null +++ b/vendor/github.com/klauspost/compress/.gitignore @@ -0,0 +1,32 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +/s2/cmd/_s2sx/sfx-exe + +# Linux perf files +perf.data +perf.data.old + +# gdb history +.gdb_history diff --git a/vendor/github.com/klauspost/compress/.goreleaser.yml b/vendor/github.com/klauspost/compress/.goreleaser.yml new file mode 100644 index 0000000..804a201 --- /dev/null +++ b/vendor/github.com/klauspost/compress/.goreleaser.yml @@ -0,0 +1,132 @@ +version: 2 + +before: + hooks: + - ./gen.sh + +builds: + - + id: "s2c" + binary: s2c + main: ./s2/cmd/s2c/main.go + flags: + - -trimpath + env: + - CGO_ENABLED=0 + goos: + - aix + - linux + - freebsd + - netbsd + - windows + - darwin + goarch: + - 386 + - amd64 + - arm + - arm64 + - ppc64 + - ppc64le + - mips64 + - mips64le + goarm: + - 7 + ignore: + - goos: windows + goarch: arm + - + id: "s2d" + binary: s2d + main: ./s2/cmd/s2d/main.go + flags: + - -trimpath + env: + - CGO_ENABLED=0 + goos: + - aix + - linux + - freebsd + - netbsd + - windows + - darwin + goarch: + - 386 + - amd64 + - arm + - arm64 + - ppc64 + - ppc64le + - mips64 + - mips64le + goarm: + - 7 + ignore: + - goos: windows + goarch: arm + - + id: "s2sx" + binary: s2sx + main: ./s2/cmd/_s2sx/main.go + flags: + - -modfile=s2sx.mod + - -trimpath + env: + - CGO_ENABLED=0 + goos: + - aix + - linux + - freebsd + - netbsd + - windows + - darwin + goarch: + - 386 + - amd64 + - arm + - arm64 + - ppc64 + - ppc64le + - mips64 + - mips64le + goarm: + - 7 + ignore: + - goos: windows + goarch: arm + +archives: + - + id: s2-binaries + name_template: "s2-{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" + format_overrides: + - goos: windows + formats: ['zip'] + files: + - unpack/* + - s2/LICENSE + - s2/README.md +checksum: + name_template: 'checksums.txt' +snapshot: + version_template: "{{ .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^doc:' + - '^docs:' + - '^test:' + - '^tests:' + - '^Update\sREADME.md' + +nfpms: + - + file_name_template: "s2_package__{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" + vendor: Klaus Post + homepage: https://github.com/klauspost/compress + maintainer: Klaus Post + description: S2 Compression Tool + license: BSD 3-Clause + formats: + - deb + - rpm diff --git a/vendor/github.com/klauspost/compress/LICENSE b/vendor/github.com/klauspost/compress/LICENSE new file mode 100644 index 0000000..87d5574 --- /dev/null +++ b/vendor/github.com/klauspost/compress/LICENSE @@ -0,0 +1,304 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2019 Klaus Post. 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. + * Neither the name of Google Inc. nor the names of its +contributors may 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 +OWNER 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. + +------------------ + +Files: gzhttp/* + + 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. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016-2017 The New York Times Company + + 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. + +------------------ + +Files: s2/cmd/internal/readahead/* + +The MIT License (MIT) + +Copyright (c) 2015 Klaus Post + +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. + +--------------------- +Files: snappy/* +Files: internal/snapref/* + +Copyright (c) 2011 The Snappy-Go Authors. 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. + * Neither the name of Google Inc. nor the names of its +contributors may 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 +OWNER 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. + +----------------- + +Files: s2/cmd/internal/filepathx/* + +Copyright 2016 The filepathx 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/github.com/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md new file mode 100644 index 0000000..0e9f170 --- /dev/null +++ b/vendor/github.com/klauspost/compress/README.md @@ -0,0 +1,712 @@ +# compress + +This package provides various compression algorithms. + +* [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression in pure Go. +* [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) is a high performance replacement for Snappy. +* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). +* [snappy](https://github.com/klauspost/compress/tree/master/snappy) is a drop-in replacement for `github.com/golang/snappy` offering better compression and concurrent streams. +* [huff0](https://github.com/klauspost/compress/tree/master/huff0) and [FSE](https://github.com/klauspost/compress/tree/master/fse) implementations for raw entropy encoding. +* [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp) Provides client and server wrappers for handling gzipped/zstd HTTP requests efficiently. +* [pgzip](https://github.com/klauspost/pgzip) is a separate package that provides a very fast parallel gzip implementation. + +[![Go Reference](https://pkg.go.dev/badge/klauspost/compress.svg)](https://pkg.go.dev/github.com/klauspost/compress?tab=subdirectories) +[![Go](https://github.com/klauspost/compress/actions/workflows/go.yml/badge.svg)](https://github.com/klauspost/compress/actions/workflows/go.yml) +[![Sourcegraph Badge](https://sourcegraph.com/github.com/klauspost/compress/-/badge.svg)](https://sourcegraph.com/github.com/klauspost/compress?badge) + +# package usage + +Use `go get github.com/klauspost/compress@latest` to add it to your project. + +This package will support the current Go version and 2 versions back. + +* Use the `nounsafe` tag to disable all use of the "unsafe" package. +* Use the `noasm` tag to disable all assembly across packages. + +Use the links above for more information on each. + +# changelog + +* Jul 1st, 2026 [1.19.0](https://github.com/klauspost/compress/releases/tag/v1.19.0) + * zstd: Add true concurrent stream encodingin https://github.com/klauspost/compress/pull/1136 + * zstd: arm64 decoder asm by @lizthegrey in https://github.com/klauspost/compress/pull/1160 + * flate: Add inflate checkpoints in https://github.com/klauspost/compress/pull/1154 + * zstd: avoid unused BuildDict encoder allocation by @snissn in https://github.com/klauspost/compress/pull/1147 + * snappy/s2: Limit length of varint in `decodedLen` by @eustas in https://github.com/klauspost/compress/pull/1148 + * gzhttp: match qvalue parameter case-insensitively (RFC 7231) by @z9z in https://github.com/klauspost/compress/pull/1149 + * zip: add NameDecoder callback for legacy encoding rewrite by @SAY-5 in https://github.com/klauspost/compress/pull/1150 + * huff0: Allow building tables from histogram in https://github.com/klauspost/compress/pull/1155 + * huff0: Allow building table from oversized histogram in https://github.com/klauspost/compress/pull/1156 + * s2sx: Clean symlink targets in https://github.com/klauspost/compress/pull/1163 + +* Feb 9th, 2026 [1.18.4](https://github.com/klauspost/compress/releases/tag/v1.18.4) + * gzhttp: Add zstandard to server handler wrapper https://github.com/klauspost/compress/pull/1121 + * zstd: Add ResetWithOptions to encoder/decoder https://github.com/klauspost/compress/pull/1122 + * gzhttp: preserve qvalue when extra parameters follow in Accept-Encoding by @analytically in https://github.com/klauspost/compress/pull/1116 + +* Jan 16th, 2026 [1.18.3](https://github.com/klauspost/compress/releases/tag/v1.18.3) + * Downstream CVE-2025-61728. See [golang/go#77102](https://github.com/golang/go/issues/77102). + +* Dec 1st, 2025 - [1.18.2](https://github.com/klauspost/compress/releases/tag/v1.18.2) + * flate: Fix invalid encoding on level 9 with single value input in https://github.com/klauspost/compress/pull/1115 + * flate: reduce stateless allocations by @RXamzin in https://github.com/klauspost/compress/pull/1106 + +* Oct 20, 2025 - [1.18.1](https://github.com/klauspost/compress/releases/tag/v1.18.1) - RETRACTED + * zstd: Add simple zstd EncodeTo/DecodeTo functions https://github.com/klauspost/compress/pull/1079 + * zstd: Fix incorrect buffer size in dictionary encodes https://github.com/klauspost/compress/pull/1059 + * s2: check for cap, not len of buffer in EncodeBetter/Best by @vdarulis in https://github.com/klauspost/compress/pull/1080 + * zlib: Avoiding extra allocation in zlib.reader.Reset by @travelpolicy in https://github.com/klauspost/compress/pull/1086 + * gzhttp: remove redundant err check in zstdReader by @ryanfowler in https://github.com/klauspost/compress/pull/1090 + * flate: Faster load+store https://github.com/klauspost/compress/pull/1104 + * flate: Simplify matchlen https://github.com/klauspost/compress/pull/1101 + * flate: Use exact sizes for huffman tables https://github.com/klauspost/compress/pull/1103 + +* Feb 19th, 2025 - [1.18.0](https://github.com/klauspost/compress/releases/tag/v1.18.0) + * Add unsafe little endian loaders https://github.com/klauspost/compress/pull/1036 + * fix: check `r.err != nil` but return a nil value error `err` by @alingse in https://github.com/klauspost/compress/pull/1028 + * flate: Simplify L4-6 loading https://github.com/klauspost/compress/pull/1043 + * flate: Simplify matchlen (remove asm) https://github.com/klauspost/compress/pull/1045 + * s2: Improve small block compression speed w/o asm https://github.com/klauspost/compress/pull/1048 + * flate: Fix matchlen L5+L6 https://github.com/klauspost/compress/pull/1049 + * flate: Cleanup & reduce casts https://github.com/klauspost/compress/pull/1050 + +
    + See changes to v1.17.x + +* Oct 11th, 2024 - [1.17.11](https://github.com/klauspost/compress/releases/tag/v1.17.11) + * zstd: Fix extra CRC written with multiple Close calls https://github.com/klauspost/compress/pull/1017 + * s2: Don't use stack for index tables https://github.com/klauspost/compress/pull/1014 + * gzhttp: No content-type on no body response code by @juliens in https://github.com/klauspost/compress/pull/1011 + * gzhttp: Do not set the content-type when response has no body by @kevinpollet in https://github.com/klauspost/compress/pull/1013 + +* Sep 23rd, 2024 - [1.17.10](https://github.com/klauspost/compress/releases/tag/v1.17.10) + * gzhttp: Add TransportAlwaysDecompress option. https://github.com/klauspost/compress/pull/978 + * gzhttp: Add supported decompress request body by @mirecl in https://github.com/klauspost/compress/pull/1002 + * s2: Add EncodeBuffer buffer recycling callback https://github.com/klauspost/compress/pull/982 + * zstd: Improve memory usage on small streaming encodes https://github.com/klauspost/compress/pull/1007 + * flate: read data written with partial flush by @vajexal in https://github.com/klauspost/compress/pull/996 + +* Jun 12th, 2024 - [1.17.9](https://github.com/klauspost/compress/releases/tag/v1.17.9) + * s2: Reduce ReadFrom temporary allocations https://github.com/klauspost/compress/pull/949 + * flate, zstd: Shave some bytes off amd64 matchLen by @greatroar in https://github.com/klauspost/compress/pull/963 + * Upgrade zip/zlib to 1.22.4 upstream https://github.com/klauspost/compress/pull/970 https://github.com/klauspost/compress/pull/971 + * zstd: BuildDict fails with RLE table https://github.com/klauspost/compress/pull/951 + +* Apr 9th, 2024 - [1.17.8](https://github.com/klauspost/compress/releases/tag/v1.17.8) + * zstd: Reject blocks where reserved values are not 0 https://github.com/klauspost/compress/pull/885 + * zstd: Add RLE detection+encoding https://github.com/klauspost/compress/pull/938 + +* Feb 21st, 2024 - [1.17.7](https://github.com/klauspost/compress/releases/tag/v1.17.7) + * s2: Add AsyncFlush method: Complete the block without flushing by @Jille in https://github.com/klauspost/compress/pull/927 + * s2: Fix literal+repeat exceeds dst crash https://github.com/klauspost/compress/pull/930 + +* Feb 5th, 2024 - [1.17.6](https://github.com/klauspost/compress/releases/tag/v1.17.6) + * zstd: Fix incorrect repeat coding in best mode https://github.com/klauspost/compress/pull/923 + * s2: Fix DecodeConcurrent deadlock on errors https://github.com/klauspost/compress/pull/925 + +* Jan 26th, 2024 - [v1.17.5](https://github.com/klauspost/compress/releases/tag/v1.17.5) + * flate: Fix reset with dictionary on custom window encodes https://github.com/klauspost/compress/pull/912 + * zstd: Add Frame header encoding and stripping https://github.com/klauspost/compress/pull/908 + * zstd: Limit better/best default window to 8MB https://github.com/klauspost/compress/pull/913 + * zstd: Speed improvements by @greatroar in https://github.com/klauspost/compress/pull/896 https://github.com/klauspost/compress/pull/910 + * s2: Fix callbacks for skippable blocks and disallow 0xfe (Padding) by @Jille in https://github.com/klauspost/compress/pull/916 https://github.com/klauspost/compress/pull/917 +https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/compress/pull/918 + +* Dec 1st, 2023 - [v1.17.4](https://github.com/klauspost/compress/releases/tag/v1.17.4) + * huff0: Speed up symbol counting by @greatroar in https://github.com/klauspost/compress/pull/887 + * huff0: Remove byteReader by @greatroar in https://github.com/klauspost/compress/pull/886 + * gzhttp: Allow overriding decompression on transport https://github.com/klauspost/compress/pull/892 + * gzhttp: Clamp compression level https://github.com/klauspost/compress/pull/890 + * gzip: Error out if reserved bits are set https://github.com/klauspost/compress/pull/891 + +* Nov 15th, 2023 - [v1.17.3](https://github.com/klauspost/compress/releases/tag/v1.17.3) + * fse: Fix max header size https://github.com/klauspost/compress/pull/881 + * zstd: Improve better/best compression https://github.com/klauspost/compress/pull/877 + * gzhttp: Fix missing content type on Close https://github.com/klauspost/compress/pull/883 + +* Oct 22nd, 2023 - [v1.17.2](https://github.com/klauspost/compress/releases/tag/v1.17.2) + * zstd: Fix rare *CORRUPTION* output in "best" mode. See https://github.com/klauspost/compress/pull/876 + +* Oct 14th, 2023 - [v1.17.1](https://github.com/klauspost/compress/releases/tag/v1.17.1) + * s2: Fix S2 "best" dictionary wrong encoding https://github.com/klauspost/compress/pull/871 + * flate: Reduce allocations in decompressor and minor code improvements by @fakefloordiv in https://github.com/klauspost/compress/pull/869 + * s2: Fix EstimateBlockSize on 6&7 length input https://github.com/klauspost/compress/pull/867 + +* Sept 19th, 2023 - [v1.17.0](https://github.com/klauspost/compress/releases/tag/v1.17.0) + * Add experimental dictionary builder https://github.com/klauspost/compress/pull/853 + * Add xerial snappy read/writer https://github.com/klauspost/compress/pull/838 + * flate: Add limited window compression https://github.com/klauspost/compress/pull/843 + * s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839 + * flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837 + * gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860 + +
    +
    + See changes to v1.16.x + + +* July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7) + * zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829 + * s2: add GetBufferCapacity() method by @GiedriusS in https://github.com/klauspost/compress/pull/832 + +* June 13, 2023 - [v1.16.6](https://github.com/klauspost/compress/releases/tag/v1.16.6) + * zstd: correctly ignore WithEncoderPadding(1) by @ianlancetaylor in https://github.com/klauspost/compress/pull/806 + * zstd: Add amd64 match length assembly https://github.com/klauspost/compress/pull/824 + * gzhttp: Handle informational headers by @rtribotte in https://github.com/klauspost/compress/pull/815 + * s2: Improve Better compression slightly https://github.com/klauspost/compress/pull/663 + +* Apr 16, 2023 - [v1.16.5](https://github.com/klauspost/compress/releases/tag/v1.16.5) + * zstd: readByte needs to use io.ReadFull by @jnoxon in https://github.com/klauspost/compress/pull/802 + * gzip: Fix WriterTo after initial read https://github.com/klauspost/compress/pull/804 + +* Apr 5, 2023 - [v1.16.4](https://github.com/klauspost/compress/releases/tag/v1.16.4) + * zstd: Improve zstd best efficiency by @greatroar and @klauspost in https://github.com/klauspost/compress/pull/784 + * zstd: Respect WithAllLitEntropyCompression https://github.com/klauspost/compress/pull/792 + * zstd: Fix amd64 not always detecting corrupt data https://github.com/klauspost/compress/pull/785 + * zstd: Various minor improvements by @greatroar in https://github.com/klauspost/compress/pull/788 https://github.com/klauspost/compress/pull/794 https://github.com/klauspost/compress/pull/795 + * s2: Fix huge block overflow https://github.com/klauspost/compress/pull/779 + * s2: Allow CustomEncoder fallback https://github.com/klauspost/compress/pull/780 + * gzhttp: Support ResponseWriter Unwrap() in gzhttp handler by @jgimenez in https://github.com/klauspost/compress/pull/799 + +* Mar 13, 2023 - [v1.16.1](https://github.com/klauspost/compress/releases/tag/v1.16.1) + * zstd: Speed up + improve best encoder by @greatroar in https://github.com/klauspost/compress/pull/776 + * gzhttp: Add optional [BREACH mitigation](https://github.com/klauspost/compress/tree/master/gzhttp#breach-mitigation). https://github.com/klauspost/compress/pull/762 https://github.com/klauspost/compress/pull/768 https://github.com/klauspost/compress/pull/769 https://github.com/klauspost/compress/pull/770 https://github.com/klauspost/compress/pull/767 + * s2: Add Intel LZ4s converter https://github.com/klauspost/compress/pull/766 + * zstd: Minor bug fixes https://github.com/klauspost/compress/pull/771 https://github.com/klauspost/compress/pull/772 https://github.com/klauspost/compress/pull/773 + * huff0: Speed up compress1xDo by @greatroar in https://github.com/klauspost/compress/pull/774 + +* Feb 26, 2023 - [v1.16.0](https://github.com/klauspost/compress/releases/tag/v1.16.0) + * s2: Add [Dictionary](https://github.com/klauspost/compress/tree/master/s2#dictionaries) support. https://github.com/klauspost/compress/pull/685 + * s2: Add Compression Size Estimate. https://github.com/klauspost/compress/pull/752 + * s2: Add support for custom stream encoder. https://github.com/klauspost/compress/pull/755 + * s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748 + * s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747 + * s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746 +
    + +
    + See changes to v1.15.x + +* Jan 21st, 2023 (v1.15.15) + * deflate: Improve level 7-9 https://github.com/klauspost/compress/pull/739 + * zstd: Add delta encoding support by @greatroar in https://github.com/klauspost/compress/pull/728 + * zstd: Various speed improvements by @greatroar https://github.com/klauspost/compress/pull/741 https://github.com/klauspost/compress/pull/734 https://github.com/klauspost/compress/pull/736 https://github.com/klauspost/compress/pull/744 https://github.com/klauspost/compress/pull/743 https://github.com/klauspost/compress/pull/745 + * gzhttp: Add SuffixETag() and DropETag() options to prevent ETag collisions on compressed responses by @willbicks in https://github.com/klauspost/compress/pull/740 + +* Jan 3rd, 2023 (v1.15.14) + + * flate: Improve speed in big stateless blocks https://github.com/klauspost/compress/pull/718 + * zstd: Minor speed tweaks by @greatroar in https://github.com/klauspost/compress/pull/716 https://github.com/klauspost/compress/pull/720 + * export NoGzipResponseWriter for custom ResponseWriter wrappers by @harshavardhana in https://github.com/klauspost/compress/pull/722 + * s2: Add example for indexing and existing stream https://github.com/klauspost/compress/pull/723 + +* Dec 11, 2022 (v1.15.13) + * zstd: Add [MaxEncodedSize](https://pkg.go.dev/github.com/klauspost/compress@v1.15.13/zstd#Encoder.MaxEncodedSize) to encoder https://github.com/klauspost/compress/pull/691 + * zstd: Various tweaks and improvements https://github.com/klauspost/compress/pull/693 https://github.com/klauspost/compress/pull/695 https://github.com/klauspost/compress/pull/696 https://github.com/klauspost/compress/pull/701 https://github.com/klauspost/compress/pull/702 https://github.com/klauspost/compress/pull/703 https://github.com/klauspost/compress/pull/704 https://github.com/klauspost/compress/pull/705 https://github.com/klauspost/compress/pull/706 https://github.com/klauspost/compress/pull/707 https://github.com/klauspost/compress/pull/708 + +* Oct 26, 2022 (v1.15.12) + + * zstd: Tweak decoder allocs. https://github.com/klauspost/compress/pull/680 + * gzhttp: Always delete `HeaderNoCompression` https://github.com/klauspost/compress/pull/683 + +* Sept 26, 2022 (v1.15.11) + + * flate: Improve level 1-3 compression https://github.com/klauspost/compress/pull/678 + * zstd: Improve "best" compression by @nightwolfz in https://github.com/klauspost/compress/pull/677 + * zstd: Fix+reduce decompression allocations https://github.com/klauspost/compress/pull/668 + * zstd: Fix non-effective noescape tag https://github.com/klauspost/compress/pull/667 + +* Sept 16, 2022 (v1.15.10) + + * zstd: Add [WithDecodeAllCapLimit](https://pkg.go.dev/github.com/klauspost/compress@v1.15.10/zstd#WithDecodeAllCapLimit) https://github.com/klauspost/compress/pull/649 + * Add Go 1.19 - deprecate Go 1.16 https://github.com/klauspost/compress/pull/651 + * flate: Improve level 5+6 compression https://github.com/klauspost/compress/pull/656 + * zstd: Improve "better" compression https://github.com/klauspost/compress/pull/657 + * s2: Improve "best" compression https://github.com/klauspost/compress/pull/658 + * s2: Improve "better" compression. https://github.com/klauspost/compress/pull/635 + * s2: Slightly faster non-assembly decompression https://github.com/klauspost/compress/pull/646 + * Use arrays for constant size copies https://github.com/klauspost/compress/pull/659 + +* July 21, 2022 (v1.15.9) + + * zstd: Fix decoder crash on amd64 (no BMI) on invalid input https://github.com/klauspost/compress/pull/645 + * zstd: Disable decoder extended memory copies (amd64) due to possible crashes https://github.com/klauspost/compress/pull/644 + * zstd: Allow single segments up to "max decoded size" https://github.com/klauspost/compress/pull/643 + +* July 13, 2022 (v1.15.8) + + * gzip: fix stack exhaustion bug in Reader.Read https://github.com/klauspost/compress/pull/641 + * s2: Add Index header trim/restore https://github.com/klauspost/compress/pull/638 + * zstd: Optimize seqdeq amd64 asm by @greatroar in https://github.com/klauspost/compress/pull/636 + * zstd: Improve decoder memcopy https://github.com/klauspost/compress/pull/637 + * huff0: Pass a single bitReader pointer to asm by @greatroar in https://github.com/klauspost/compress/pull/634 + * zstd: Branchless getBits for amd64 w/o BMI2 by @greatroar in https://github.com/klauspost/compress/pull/640 + * gzhttp: Remove header before writing https://github.com/klauspost/compress/pull/639 + +* June 29, 2022 (v1.15.7) + + * s2: Fix absolute forward seeks https://github.com/klauspost/compress/pull/633 + * zip: Merge upstream https://github.com/klauspost/compress/pull/631 + * zip: Re-add zip64 fix https://github.com/klauspost/compress/pull/624 + * zstd: translate fseDecoder.buildDtable into asm by @WojciechMula in https://github.com/klauspost/compress/pull/598 + * flate: Faster histograms https://github.com/klauspost/compress/pull/620 + * deflate: Use compound hcode https://github.com/klauspost/compress/pull/622 + +* June 3, 2022 (v1.15.6) + * s2: Improve coding for long, close matches https://github.com/klauspost/compress/pull/613 + * s2c: Add Snappy/S2 stream recompression https://github.com/klauspost/compress/pull/611 + * zstd: Always use configured block size https://github.com/klauspost/compress/pull/605 + * zstd: Fix incorrect hash table placement for dict encoding in default https://github.com/klauspost/compress/pull/606 + * zstd: Apply default config to ZipDecompressor without options https://github.com/klauspost/compress/pull/608 + * gzhttp: Exclude more common archive formats https://github.com/klauspost/compress/pull/612 + * s2: Add ReaderIgnoreCRC https://github.com/klauspost/compress/pull/609 + * s2: Remove sanity load on index creation https://github.com/klauspost/compress/pull/607 + * snappy: Use dedicated function for scoring https://github.com/klauspost/compress/pull/614 + * s2c+s2d: Use official snappy framed extension https://github.com/klauspost/compress/pull/610 + +* May 25, 2022 (v1.15.5) + * s2: Add concurrent stream decompression https://github.com/klauspost/compress/pull/602 + * s2: Fix final emit oob read crash on amd64 https://github.com/klauspost/compress/pull/601 + * huff0: asm implementation of Decompress1X by @WojciechMula https://github.com/klauspost/compress/pull/596 + * zstd: Use 1 less goroutine for stream decoding https://github.com/klauspost/compress/pull/588 + * zstd: Copy literal in 16 byte blocks when possible https://github.com/klauspost/compress/pull/592 + * zstd: Speed up when WithDecoderLowmem(false) https://github.com/klauspost/compress/pull/599 + * zstd: faster next state update in BMI2 version of decode by @WojciechMula in https://github.com/klauspost/compress/pull/593 + * huff0: Do not check max size when reading table. https://github.com/klauspost/compress/pull/586 + * flate: Inplace hashing for level 7-9 https://github.com/klauspost/compress/pull/590 + + +* May 11, 2022 (v1.15.4) + * huff0: decompress directly into output by @WojciechMula in [#577](https://github.com/klauspost/compress/pull/577) + * inflate: Keep dict on stack [#581](https://github.com/klauspost/compress/pull/581) + * zstd: Faster decoding memcopy in asm [#583](https://github.com/klauspost/compress/pull/583) + * zstd: Fix ignored crc [#580](https://github.com/klauspost/compress/pull/580) + +* May 5, 2022 (v1.15.3) + * zstd: Allow to ignore checksum checking by @WojciechMula [#572](https://github.com/klauspost/compress/pull/572) + * s2: Fix incorrect seek for io.SeekEnd in [#575](https://github.com/klauspost/compress/pull/575) + +* Apr 26, 2022 (v1.15.2) + * zstd: Add x86-64 assembly for decompression on streams and blocks. Contributed by [@WojciechMula](https://github.com/WojciechMula). Typically 2x faster. [#528](https://github.com/klauspost/compress/pull/528) [#531](https://github.com/klauspost/compress/pull/531) [#545](https://github.com/klauspost/compress/pull/545) [#537](https://github.com/klauspost/compress/pull/537) + * zstd: Add options to ZipDecompressor and fixes [#539](https://github.com/klauspost/compress/pull/539) + * s2: Use sorted search for index [#555](https://github.com/klauspost/compress/pull/555) + * Minimum version is Go 1.16, added CI test on 1.18. + +* Mar 11, 2022 (v1.15.1) + * huff0: Add x86 assembly of Decode4X by @WojciechMula in [#512](https://github.com/klauspost/compress/pull/512) + * zstd: Reuse zip decoders in [#514](https://github.com/klauspost/compress/pull/514) + * zstd: Detect extra block data and report as corrupted in [#520](https://github.com/klauspost/compress/pull/520) + * zstd: Handle zero sized frame content size stricter in [#521](https://github.com/klauspost/compress/pull/521) + * zstd: Add stricter block size checks in [#523](https://github.com/klauspost/compress/pull/523) + +* Mar 3, 2022 (v1.15.0) + * zstd: Refactor decoder [#498](https://github.com/klauspost/compress/pull/498) + * zstd: Add stream encoding without goroutines [#505](https://github.com/klauspost/compress/pull/505) + * huff0: Prevent single blocks exceeding 16 bits by @klauspost in[#507](https://github.com/klauspost/compress/pull/507) + * flate: Inline literal emission [#509](https://github.com/klauspost/compress/pull/509) + * gzhttp: Add zstd to transport [#400](https://github.com/klauspost/compress/pull/400) + * gzhttp: Make content-type optional [#510](https://github.com/klauspost/compress/pull/510) + +Both compression and decompression now supports "synchronous" stream operations. This means that whenever "concurrency" is set to 1, they will operate without spawning goroutines. + +Stream decompression is now faster on asynchronous, since the goroutine allocation much more effectively splits the workload. On typical streams this will typically use 2 cores fully for decompression. When a stream has finished decoding no goroutines will be left over, so decoders can now safely be pooled and still be garbage collected. + +While the release has been extensively tested, it is recommended to testing when upgrading. + +
    + +
    + See changes to v1.14.x + +* Feb 22, 2022 (v1.14.4) + * flate: Fix rare huffman only (-2) corruption. [#503](https://github.com/klauspost/compress/pull/503) + * zip: Update deprecated CreateHeaderRaw to correctly call CreateRaw by @saracen in [#502](https://github.com/klauspost/compress/pull/502) + * zip: don't read data descriptor early by @saracen in [#501](https://github.com/klauspost/compress/pull/501) #501 + * huff0: Use static decompression buffer up to 30% faster [#499](https://github.com/klauspost/compress/pull/499) [#500](https://github.com/klauspost/compress/pull/500) + +* Feb 17, 2022 (v1.14.3) + * flate: Improve fastest levels compression speed ~10% more throughput. [#482](https://github.com/klauspost/compress/pull/482) [#489](https://github.com/klauspost/compress/pull/489) [#490](https://github.com/klauspost/compress/pull/490) [#491](https://github.com/klauspost/compress/pull/491) [#494](https://github.com/klauspost/compress/pull/494) [#478](https://github.com/klauspost/compress/pull/478) + * flate: Faster decompression speed, ~5-10%. [#483](https://github.com/klauspost/compress/pull/483) + * s2: Faster compression with Go v1.18 and amd64 microarch level 3+. [#484](https://github.com/klauspost/compress/pull/484) [#486](https://github.com/klauspost/compress/pull/486) + +* Jan 25, 2022 (v1.14.2) + * zstd: improve header decoder by @dsnet [#476](https://github.com/klauspost/compress/pull/476) + * zstd: Add bigger default blocks [#469](https://github.com/klauspost/compress/pull/469) + * zstd: Remove unused decompression buffer [#470](https://github.com/klauspost/compress/pull/470) + * zstd: Fix logically dead code by @ningmingxiao [#472](https://github.com/klauspost/compress/pull/472) + * flate: Improve level 7-9 [#471](https://github.com/klauspost/compress/pull/471) [#473](https://github.com/klauspost/compress/pull/473) + * zstd: Add noasm tag for xxhash [#475](https://github.com/klauspost/compress/pull/475) + +* Jan 11, 2022 (v1.14.1) + * s2: Add stream index in [#462](https://github.com/klauspost/compress/pull/462) + * flate: Speed and efficiency improvements in [#439](https://github.com/klauspost/compress/pull/439) [#461](https://github.com/klauspost/compress/pull/461) [#455](https://github.com/klauspost/compress/pull/455) [#452](https://github.com/klauspost/compress/pull/452) [#458](https://github.com/klauspost/compress/pull/458) + * zstd: Performance improvement in [#420]( https://github.com/klauspost/compress/pull/420) [#456](https://github.com/klauspost/compress/pull/456) [#437](https://github.com/klauspost/compress/pull/437) [#467](https://github.com/klauspost/compress/pull/467) [#468](https://github.com/klauspost/compress/pull/468) + * zstd: add arm64 xxhash assembly in [#464](https://github.com/klauspost/compress/pull/464) + * Add garbled for binaries for s2 in [#445](https://github.com/klauspost/compress/pull/445) +
    + +
    + See changes to v1.13.x + +* Aug 30, 2021 (v1.13.5) + * gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425) + * s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413) + * zstd: pooledZipWriter should return Writers to the same pool [#426](https://github.com/klauspost/compress/pull/426) + * Removed golang/snappy as external dependency for tests [#421](https://github.com/klauspost/compress/pull/421) + +* Aug 12, 2021 (v1.13.4) + * Add [snappy replacement package](https://github.com/klauspost/compress/tree/master/snappy). + * zstd: Fix incorrect encoding in "best" mode [#415](https://github.com/klauspost/compress/pull/415) + +* Aug 3, 2021 (v1.13.3) + * zstd: Improve Best compression [#404](https://github.com/klauspost/compress/pull/404) + * zstd: Fix WriteTo error forwarding [#411](https://github.com/klauspost/compress/pull/411) + * gzhttp: Return http.HandlerFunc instead of http.Handler. Unlikely breaking change. [#406](https://github.com/klauspost/compress/pull/406) + * s2sx: Fix max size error [#399](https://github.com/klauspost/compress/pull/399) + * zstd: Add optional stream content size on reset [#401](https://github.com/klauspost/compress/pull/401) + * zstd: use SpeedBestCompression for level >= 10 [#410](https://github.com/klauspost/compress/pull/410) + +* Jun 14, 2021 (v1.13.1) + * s2: Add full Snappy output support [#396](https://github.com/klauspost/compress/pull/396) + * zstd: Add configurable [Decoder window](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithDecoderMaxWindow) size [#394](https://github.com/klauspost/compress/pull/394) + * gzhttp: Add header to skip compression [#389](https://github.com/klauspost/compress/pull/389) + * s2: Improve speed with bigger output margin [#395](https://github.com/klauspost/compress/pull/395) + +* Jun 3, 2021 (v1.13.0) + * Added [gzhttp](https://github.com/klauspost/compress/tree/master/gzhttp#gzip-handler) which allows wrapping HTTP servers and clients with GZIP compressors. + * zstd: Detect short invalid signatures [#382](https://github.com/klauspost/compress/pull/382) + * zstd: Spawn decoder goroutine only if needed. [#380](https://github.com/klauspost/compress/pull/380) +
    + + +
    + See changes to v1.12.x + +* May 25, 2021 (v1.12.3) + * deflate: Better/faster Huffman encoding [#374](https://github.com/klauspost/compress/pull/374) + * deflate: Allocate less for history. [#375](https://github.com/klauspost/compress/pull/375) + * zstd: Forward read errors [#373](https://github.com/klauspost/compress/pull/373) + +* Apr 27, 2021 (v1.12.2) + * zstd: Improve better/best compression [#360](https://github.com/klauspost/compress/pull/360) [#364](https://github.com/klauspost/compress/pull/364) [#365](https://github.com/klauspost/compress/pull/365) + * zstd: Add helpers to compress/decompress zstd inside zip files [#363](https://github.com/klauspost/compress/pull/363) + * deflate: Improve level 5+6 compression [#367](https://github.com/klauspost/compress/pull/367) + * s2: Improve better/best compression [#358](https://github.com/klauspost/compress/pull/358) [#359](https://github.com/klauspost/compress/pull/358) + * s2: Load after checking src limit on amd64. [#362](https://github.com/klauspost/compress/pull/362) + * s2sx: Limit max executable size [#368](https://github.com/klauspost/compress/pull/368) + +* Apr 14, 2021 (v1.12.1) + * snappy package removed. Upstream added as dependency. + * s2: Better compression in "best" mode [#353](https://github.com/klauspost/compress/pull/353) + * s2sx: Add stdin input and detect pre-compressed from signature [#352](https://github.com/klauspost/compress/pull/352) + * s2c/s2d: Add http as possible input [#348](https://github.com/klauspost/compress/pull/348) + * s2c/s2d/s2sx: Always truncate when writing files [#352](https://github.com/klauspost/compress/pull/352) + * zstd: Reduce memory usage further when using [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) [#346](https://github.com/klauspost/compress/pull/346) + * s2: Fix potential problem with amd64 assembly and profilers [#349](https://github.com/klauspost/compress/pull/349) +
    + +
    + See changes to v1.11.x + +* Mar 26, 2021 (v1.11.13) + * zstd: Big speedup on small dictionary encodes [#344](https://github.com/klauspost/compress/pull/344) [#345](https://github.com/klauspost/compress/pull/345) + * zstd: Add [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) encoder option [#336](https://github.com/klauspost/compress/pull/336) + * deflate: Improve entropy compression [#338](https://github.com/klauspost/compress/pull/338) + * s2: Clean up and minor performance improvement in best [#341](https://github.com/klauspost/compress/pull/341) + +* Mar 5, 2021 (v1.11.12) + * s2: Add `s2sx` binary that creates [self extracting archives](https://github.com/klauspost/compress/tree/master/s2#s2sx-self-extracting-archives). + * s2: Speed up decompression on non-assembly platforms [#328](https://github.com/klauspost/compress/pull/328) + +* Mar 1, 2021 (v1.11.9) + * s2: Add ARM64 decompression assembly. Around 2x output speed. [#324](https://github.com/klauspost/compress/pull/324) + * s2: Improve "better" speed and efficiency. [#325](https://github.com/klauspost/compress/pull/325) + * s2: Fix binaries. + +* Feb 25, 2021 (v1.11.8) + * s2: Fixed occasional out-of-bounds write on amd64. Upgrade recommended. + * s2: Add AMD64 assembly for better mode. 25-50% faster. [#315](https://github.com/klauspost/compress/pull/315) + * s2: Less upfront decoder allocation. [#322](https://github.com/klauspost/compress/pull/322) + * zstd: Faster "compression" of incompressible data. [#314](https://github.com/klauspost/compress/pull/314) + * zip: Fix zip64 headers. [#313](https://github.com/klauspost/compress/pull/313) + +* Jan 14, 2021 (v1.11.7) + * Use Bytes() interface to get bytes across packages. [#309](https://github.com/klauspost/compress/pull/309) + * s2: Add 'best' compression option. [#310](https://github.com/klauspost/compress/pull/310) + * s2: Add ReaderMaxBlockSize, changes `s2.NewReader` signature to include varargs. [#311](https://github.com/klauspost/compress/pull/311) + * s2: Fix crash on small better buffers. [#308](https://github.com/klauspost/compress/pull/308) + * s2: Clean up decoder. [#312](https://github.com/klauspost/compress/pull/312) + +* Jan 7, 2021 (v1.11.6) + * zstd: Make decoder allocations smaller [#306](https://github.com/klauspost/compress/pull/306) + * zstd: Free Decoder resources when Reset is called with a nil io.Reader [#305](https://github.com/klauspost/compress/pull/305) + +* Dec 20, 2020 (v1.11.4) + * zstd: Add Best compression mode [#304](https://github.com/klauspost/compress/pull/304) + * Add header decoder [#299](https://github.com/klauspost/compress/pull/299) + * s2: Add uncompressed stream option [#297](https://github.com/klauspost/compress/pull/297) + * Simplify/speed up small blocks with known max size. [#300](https://github.com/klauspost/compress/pull/300) + * zstd: Always reset literal dict encoder [#303](https://github.com/klauspost/compress/pull/303) + +* Nov 15, 2020 (v1.11.3) + * inflate: 10-15% faster decompression [#293](https://github.com/klauspost/compress/pull/293) + * zstd: Tweak DecodeAll default allocation [#295](https://github.com/klauspost/compress/pull/295) + +* Oct 11, 2020 (v1.11.2) + * s2: Fix out of bounds read in "better" block compression [#291](https://github.com/klauspost/compress/pull/291) + +* Oct 1, 2020 (v1.11.1) + * zstd: Set allLitEntropy true in default configuration [#286](https://github.com/klauspost/compress/pull/286) + +* Sept 8, 2020 (v1.11.0) + * zstd: Add experimental compression [dictionaries](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) [#281](https://github.com/klauspost/compress/pull/281) + * zstd: Fix mixed Write and ReadFrom calls [#282](https://github.com/klauspost/compress/pull/282) + * inflate/gz: Limit variable shifts, ~5% faster decompression [#274](https://github.com/klauspost/compress/pull/274) +
    + +
    + See changes to v1.10.x + +* July 8, 2020 (v1.10.11) + * zstd: Fix extra block when compressing with ReadFrom. [#278](https://github.com/klauspost/compress/pull/278) + * huff0: Also populate compression table when reading decoding table. [#275](https://github.com/klauspost/compress/pull/275) + +* June 23, 2020 (v1.10.10) + * zstd: Skip entropy compression in fastest mode when no matches. [#270](https://github.com/klauspost/compress/pull/270) + +* June 16, 2020 (v1.10.9): + * zstd: API change for specifying dictionaries. See [#268](https://github.com/klauspost/compress/pull/268) + * zip: update CreateHeaderRaw to handle zip64 fields. [#266](https://github.com/klauspost/compress/pull/266) + * Fuzzit tests removed. The service has been purchased and is no longer available. + +* June 5, 2020 (v1.10.8): + * 1.15x faster zstd block decompression. [#265](https://github.com/klauspost/compress/pull/265) + +* June 1, 2020 (v1.10.7): + * Added zstd decompression [dictionary support](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) + * Increase zstd decompression speed up to 1.19x. [#259](https://github.com/klauspost/compress/pull/259) + * Remove internal reset call in zstd compression and reduce allocations. [#263](https://github.com/klauspost/compress/pull/263) + +* May 21, 2020: (v1.10.6) + * zstd: Reduce allocations while decoding. [#258](https://github.com/klauspost/compress/pull/258), [#252](https://github.com/klauspost/compress/pull/252) + * zstd: Stricter decompression checks. + +* April 12, 2020: (v1.10.5) + * s2-commands: Flush output when receiving SIGINT. [#239](https://github.com/klauspost/compress/pull/239) + +* Apr 8, 2020: (v1.10.4) + * zstd: Minor/special case optimizations. [#251](https://github.com/klauspost/compress/pull/251), [#250](https://github.com/klauspost/compress/pull/250), [#249](https://github.com/klauspost/compress/pull/249), [#247](https://github.com/klauspost/compress/pull/247) +* Mar 11, 2020: (v1.10.3) + * s2: Use S2 encoder in pure Go mode for Snappy output as well. [#245](https://github.com/klauspost/compress/pull/245) + * s2: Fix pure Go block encoder. [#244](https://github.com/klauspost/compress/pull/244) + * zstd: Added "better compression" mode. [#240](https://github.com/klauspost/compress/pull/240) + * zstd: Improve speed of fastest compression mode by 5-10% [#241](https://github.com/klauspost/compress/pull/241) + * zstd: Skip creating encoders when not needed. [#238](https://github.com/klauspost/compress/pull/238) + +* Feb 27, 2020: (v1.10.2) + * Close to 50% speedup in inflate (gzip/zip decompression). [#236](https://github.com/klauspost/compress/pull/236) [#234](https://github.com/klauspost/compress/pull/234) [#232](https://github.com/klauspost/compress/pull/232) + * Reduce deflate level 1-6 memory usage up to 59%. [#227](https://github.com/klauspost/compress/pull/227) + +* Feb 18, 2020: (v1.10.1) + * Fix zstd crash when resetting multiple times without sending data. [#226](https://github.com/klauspost/compress/pull/226) + * deflate: Fix dictionary use on level 1-6. [#224](https://github.com/klauspost/compress/pull/224) + * Remove deflate writer reference when closing. [#224](https://github.com/klauspost/compress/pull/224) + +* Feb 4, 2020: (v1.10.0) + * Add optional dictionary to [stateless deflate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc#StatelessDeflate). Breaking change, send `nil` for previous behaviour. [#216](https://github.com/klauspost/compress/pull/216) + * Fix buffer overflow on repeated small block deflate. [#218](https://github.com/klauspost/compress/pull/218) + * Allow copying content from an existing ZIP file without decompressing+compressing. [#214](https://github.com/klauspost/compress/pull/214) + * Added [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) AMD64 assembler and various optimizations. Stream speed >10GB/s. [#186](https://github.com/klauspost/compress/pull/186) + +
    + +
    + See changes prior to v1.10.0 + +* Jan 20,2020 (v1.9.8) Optimize gzip/deflate with better size estimates and faster table generation. [#207](https://github.com/klauspost/compress/pull/207) by [luyu6056](https://github.com/luyu6056), [#206](https://github.com/klauspost/compress/pull/206). +* Jan 11, 2020: S2 Encode/Decode will use provided buffer if capacity is big enough. [#204](https://github.com/klauspost/compress/pull/204) +* Jan 5, 2020: (v1.9.7) Fix another zstd regression in v1.9.5 - v1.9.6 removed. +* Jan 4, 2020: (v1.9.6) Regression in v1.9.5 fixed causing corrupt zstd encodes in rare cases. +* Jan 4, 2020: Faster IO in [s2c + s2d commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) compression/decompression. [#192](https://github.com/klauspost/compress/pull/192) +* Dec 29, 2019: Removed v1.9.5 since fuzz tests showed a compatibility problem with the reference zstandard decoder. +* Dec 29, 2019: (v1.9.5) zstd: 10-20% faster block compression. [#199](https://github.com/klauspost/compress/pull/199) +* Dec 29, 2019: [zip](https://godoc.org/github.com/klauspost/compress/zip) package updated with latest Go features +* Dec 29, 2019: zstd: Single segment flag condintions tweaked. [#197](https://github.com/klauspost/compress/pull/197) +* Dec 18, 2019: s2: Faster compression when ReadFrom is used. [#198](https://github.com/klauspost/compress/pull/198) +* Dec 10, 2019: s2: Fix repeat length output when just above at 16MB limit. +* Dec 10, 2019: zstd: Add function to get decoder as io.ReadCloser. [#191](https://github.com/klauspost/compress/pull/191) +* Dec 3, 2019: (v1.9.4) S2: limit max repeat length. [#188](https://github.com/klauspost/compress/pull/188) +* Dec 3, 2019: Add [WithNoEntropyCompression](https://godoc.org/github.com/klauspost/compress/zstd#WithNoEntropyCompression) to zstd [#187](https://github.com/klauspost/compress/pull/187) +* Dec 3, 2019: Reduce memory use for tests. Check for leaked goroutines. +* Nov 28, 2019 (v1.9.3) Less allocations in stateless deflate. +* Nov 28, 2019: 5-20% Faster huff0 decode. Impacts zstd as well. [#184](https://github.com/klauspost/compress/pull/184) +* Nov 12, 2019 (v1.9.2) Added [Stateless Compression](#stateless-compression) for gzip/deflate. +* Nov 12, 2019: Fixed zstd decompression of large single blocks. [#180](https://github.com/klauspost/compress/pull/180) +* Nov 11, 2019: Set default [s2c](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) block size to 4MB. +* Nov 11, 2019: Reduce inflate memory use by 1KB. +* Nov 10, 2019: Less allocations in deflate bit writer. +* Nov 10, 2019: Fix inconsistent error returned by zstd decoder. +* Oct 28, 2019 (v1.9.1) ztsd: Fix crash when compressing blocks. [#174](https://github.com/klauspost/compress/pull/174) +* Oct 24, 2019 (v1.9.0) zstd: Fix rare data corruption [#173](https://github.com/klauspost/compress/pull/173) +* Oct 24, 2019 zstd: Fix huff0 out of buffer write [#171](https://github.com/klauspost/compress/pull/171) and always return errors [#172](https://github.com/klauspost/compress/pull/172) +* Oct 10, 2019: Big deflate rewrite, 30-40% faster with better compression [#105](https://github.com/klauspost/compress/pull/105) + +
    + +
    + See changes prior to v1.9.0 + +* Oct 10, 2019: (v1.8.6) zstd: Allow partial reads to get flushed data. [#169](https://github.com/klauspost/compress/pull/169) +* Oct 3, 2019: Fix inconsistent results on broken zstd streams. +* Sep 25, 2019: Added `-rm` (remove source files) and `-q` (no output except errors) to `s2c` and `s2d` [commands](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) +* Sep 16, 2019: (v1.8.4) Add `s2c` and `s2d` [commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools). +* Sep 10, 2019: (v1.8.3) Fix s2 decoder [Skip](https://godoc.org/github.com/klauspost/compress/s2#Reader.Skip). +* Sep 7, 2019: zstd: Added [WithWindowSize](https://godoc.org/github.com/klauspost/compress/zstd#WithWindowSize), contributed by [ianwilkes](https://github.com/ianwilkes). +* Sep 5, 2019: (v1.8.2) Add [WithZeroFrames](https://godoc.org/github.com/klauspost/compress/zstd#WithZeroFrames) which adds full zero payload block encoding option. +* Sep 5, 2019: Lazy initialization of zstandard predefined en/decoder tables. +* Aug 26, 2019: (v1.8.1) S2: 1-2% compression increase in "better" compression mode. +* Aug 26, 2019: zstd: Check maximum size of Huffman 1X compressed literals while decoding. +* Aug 24, 2019: (v1.8.0) Added [S2 compression](https://github.com/klauspost/compress/tree/master/s2#s2-compression), a high performance replacement for Snappy. +* Aug 21, 2019: (v1.7.6) Fixed minor issues found by fuzzer. One could lead to zstd not decompressing. +* Aug 18, 2019: Add [fuzzit](https://fuzzit.dev/) continuous fuzzing. +* Aug 14, 2019: zstd: Skip incompressible data 2x faster. [#147](https://github.com/klauspost/compress/pull/147) +* Aug 4, 2019 (v1.7.5): Better literal compression. [#146](https://github.com/klauspost/compress/pull/146) +* Aug 4, 2019: Faster zstd compression. [#143](https://github.com/klauspost/compress/pull/143) [#144](https://github.com/klauspost/compress/pull/144) +* Aug 4, 2019: Faster zstd decompression. [#145](https://github.com/klauspost/compress/pull/145) [#143](https://github.com/klauspost/compress/pull/143) [#142](https://github.com/klauspost/compress/pull/142) +* July 15, 2019 (v1.7.4): Fix double EOF block in rare cases on zstd encoder. +* July 15, 2019 (v1.7.3): Minor speedup/compression increase in default zstd encoder. +* July 14, 2019: zstd decoder: Fix decompression error on multiple uses with mixed content. +* July 7, 2019 (v1.7.2): Snappy update, zstd decoder potential race fix. +* June 17, 2019: zstd decompression bugfix. +* June 17, 2019: fix 32 bit builds. +* June 17, 2019: Easier use in modules (less dependencies). +* June 9, 2019: New stronger "default" [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression mode. Matches zstd default compression ratio. +* June 5, 2019: 20-40% throughput in [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and better compression. +* June 5, 2019: deflate/gzip compression: Reduce memory usage of lower compression levels. +* June 2, 2019: Added [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression! +* May 25, 2019: deflate/gzip: 10% faster bit writer, mostly visible in lower levels. +* Apr 22, 2019: [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) decompression added. +* Aug 1, 2018: Added [huff0 README](https://github.com/klauspost/compress/tree/master/huff0#huff0-entropy-compression). +* Jul 8, 2018: Added [Performance Update 2018](#performance-update-2018) below. +* Jun 23, 2018: Merged [Go 1.11 inflate optimizations](https://go-review.googlesource.com/c/go/+/102235). Go 1.9 is now required. Backwards compatible version tagged with [v1.3.0](https://github.com/klauspost/compress/releases/tag/v1.3.0). +* Apr 2, 2018: Added [huff0](https://godoc.org/github.com/klauspost/compress/huff0) en/decoder. Experimental for now, API may change. +* Mar 4, 2018: Added [FSE Entropy](https://godoc.org/github.com/klauspost/compress/fse) en/decoder. Experimental for now, API may change. +* Nov 3, 2017: Add compression [Estimate](https://godoc.org/github.com/klauspost/compress#Estimate) function. +* May 28, 2017: Reduce allocations when resetting decoder. +* Apr 02, 2017: Change back to official crc32, since changes were merged in Go 1.7. +* Jan 14, 2017: Reduce stack pressure due to array copies. See [Issue #18625](https://github.com/golang/go/issues/18625). +* Oct 25, 2016: Level 2-4 have been rewritten and now offers significantly better performance than before. +* Oct 20, 2016: Port zlib changes from Go 1.7 to fix zlib writer issue. Please update. +* Oct 16, 2016: Go 1.7 changes merged. Apples to apples this package is a few percent faster, but has a significantly better balance between speed and compression per level. +* Mar 24, 2016: Always attempt Huffman encoding on level 4-7. This improves base 64 encoded data compression. +* Mar 24, 2016: Small speedup for level 1-3. +* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster. +* Feb 19, 2016: Handle small payloads faster in level 1-3. +* Feb 19, 2016: Added faster level 2 + 3 compression modes. +* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progression in terms of compression. New default level is 5. +* Feb 14, 2016: Snappy: Merge upstream changes. +* Feb 14, 2016: Snappy: Fix aggressive skipping. +* Feb 14, 2016: Snappy: Update benchmark. +* Feb 13, 2016: Deflate: Fixed assembler problem that could lead to sub-optimal compression. +* Feb 12, 2016: Snappy: Added AMD64 SSE 4.2 optimizations to matching, which makes easy to compress material run faster. Typical speedup is around 25%. +* Feb 9, 2016: Added Snappy package fork. This version is 5-7% faster, much more on hard to compress content. +* Jan 30, 2016: Optimize level 1 to 3 by not considering static dictionary or storing uncompressed. ~4-5% speedup. +* Jan 16, 2016: Optimization on deflate level 1,2,3 compression. +* Jan 8 2016: Merge [CL 18317](https://go-review.googlesource.com/#/c/18317): fix reading, writing of zip64 archives. +* Dec 8 2015: Make level 1 and -2 deterministic even if write size differs. +* Dec 8 2015: Split encoding functions, so hashing and matching can potentially be inlined. 1-3% faster on AMD64. 5% faster on other platforms. +* Dec 8 2015: Fixed rare [one byte out-of bounds read](https://github.com/klauspost/compress/issues/20). Please update! +* Nov 23 2015: Optimization on token writer. ~2-4% faster. Contributed by [@dsnet](https://github.com/dsnet). +* Nov 20 2015: Small optimization to bit writer on 64 bit systems. +* Nov 17 2015: Fixed out-of-bound errors if the underlying Writer returned an error. See [#15](https://github.com/klauspost/compress/issues/15). +* Nov 12 2015: Added [io.WriterTo](https://golang.org/pkg/io/#WriterTo) support to gzip/inflate. +* Nov 11 2015: Merged [CL 16669](https://go-review.googlesource.com/#/c/16669/4): archive/zip: enable overriding (de)compressors per file +* Oct 15 2015: Added skipping on uncompressible data. Random data speed up >5x. + +
    + +# deflate usage + +The packages are drop-in replacements for standard library [deflate](https://godoc.org/github.com/klauspost/compress/flate), [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip), and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). Simply replace the import path to use them: + +Typical speed is about 2x of the standard library packages. + +| old import | new import | Documentation | +|------------------|---------------------------------------|-------------------------------------------------------------------------| +| `compress/gzip` | `github.com/klauspost/compress/gzip` | [gzip](https://pkg.go.dev/github.com/klauspost/compress/gzip?tab=doc) | +| `compress/zlib` | `github.com/klauspost/compress/zlib` | [zlib](https://pkg.go.dev/github.com/klauspost/compress/zlib?tab=doc) | +| `archive/zip` | `github.com/klauspost/compress/zip` | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc) | +| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc) | + +You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop-in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages. + +The packages implement the same API as the standard library, so you can use the original godoc documentation: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/). + +Currently there is only minor speedup on decompression (mostly CRC32 calculation). + +Memory usage is typically 1MB for a Writer. stdlib is in the same range. +If you expect to have a lot of concurrently allocated Writers consider using +the stateless compression described below. + +For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing). + +To disable all assembly add `-tags=noasm`. This works across all packages. + +# Stateless compression + +This package offers stateless compression as a special option for gzip/deflate. +It will do compression but without maintaining any state between Write calls. + +This means there will be no memory kept between Write calls, but compression and speed will be suboptimal. + +This is only relevant in cases where you expect to run many thousands of compressors concurrently, +but with very little activity. This is *not* intended for regular web servers serving individual requests. + +Because of this, the size of actual Write calls will affect output size. + +In gzip, specify level `-3` / `gzip.StatelessCompression` to enable. + +For direct deflate use, NewStatelessWriter and StatelessDeflate are available. See [documentation](https://godoc.org/github.com/klauspost/compress/flate#NewStatelessWriter) + +A `bufio.Writer` can of course be used to control write sizes. For example, to use a 4KB buffer: + +```go + // replace 'ioutil.Discard' with your output. + gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression) + if err != nil { + return err + } + defer gzw.Close() + + w := bufio.NewWriterSize(gzw, 4096) + defer w.Flush() + + // Write to 'w' +``` + +This will only use up to 4KB in memory when the writer is idle. + +Compression is almost always worse than the fastest compression level +and each write will allocate (a little) memory. + + +# Other packages + +Here are other packages of good quality and pure Go (no cgo wrappers or autoconverted code): + +* [github.com/pierrec/lz4](https://github.com/pierrec/lz4) - strong multithreaded LZ4 compression. +* [github.com/cosnicolaou/pbzip2](https://github.com/cosnicolaou/pbzip2) - multithreaded bzip2 decompression. +* [github.com/dsnet/compress](https://github.com/dsnet/compress) - brotli decompression, bzip2 writer. +* [github.com/ronanh/intcomp](https://github.com/ronanh/intcomp) - Integer compression. +* [github.com/spenczar/fpc](https://github.com/spenczar/fpc) - Float compression. +* [github.com/minio/zipindex](https://github.com/minio/zipindex) - External ZIP directory index. +* [github.com/ybirader/pzip](https://github.com/ybirader/pzip) - Fast concurrent zip archiver and extractor. + +# license + +This code is licensed under the same conditions as the original Go code. See LICENSE file. + + + + + diff --git a/vendor/github.com/klauspost/compress/SECURITY.md b/vendor/github.com/klauspost/compress/SECURITY.md new file mode 100644 index 0000000..ca6685e --- /dev/null +++ b/vendor/github.com/klauspost/compress/SECURITY.md @@ -0,0 +1,25 @@ +# Security Policy + +## Supported Versions + +Security updates are applied only to the latest release. + +## Vulnerability Definition + +A security vulnerability is a bug that with certain input triggers a crash or an infinite loop. Most calls will have varying execution time and only in rare cases will slow operation be considered a security vulnerability. + +Corrupted output generally is not considered a security vulnerability, unless independent operations are able to affect each other. Note that not all functionality is re-entrant and safe to use concurrently. + +Out-of-memory crashes only applies if the en/decoder uses an abnormal amount of memory, with appropriate options applied, to limit maximum window size, concurrency, etc. However, if you are in doubt you are welcome to file a security issue. + +It is assumed that all callers are trusted, meaning internal data exposed through reflection or inspection of returned data structures is not considered a vulnerability. + +Vulnerabilities resulting from compiler/assembler errors should be reported upstream. Depending on the severity this package may or may not implement a workaround. + +## Reporting a Vulnerability + +If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. + +Please disclose it at [security advisory](https://github.com/klauspost/compress/security/advisories/new). If possible please provide a minimal reproducer. If the issue only applies to a single platform, it would be helpful to provide access to that. + +This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerabilities will be disclosed in a best effort base. diff --git a/vendor/github.com/klauspost/compress/compressible.go b/vendor/github.com/klauspost/compress/compressible.go new file mode 100644 index 0000000..ea5a692 --- /dev/null +++ b/vendor/github.com/klauspost/compress/compressible.go @@ -0,0 +1,85 @@ +package compress + +import "math" + +// Estimate returns a normalized compressibility estimate of block b. +// Values close to zero are likely uncompressible. +// Values above 0.1 are likely to be compressible. +// Values above 0.5 are very compressible. +// Very small lengths will return 0. +func Estimate(b []byte) float64 { + if len(b) < 16 { + return 0 + } + + // Correctly predicted order 1 + hits := 0 + lastMatch := false + var o1 [256]byte + var hist [256]int + c1 := byte(0) + for _, c := range b { + if c == o1[c1] { + // We only count a hit if there was two correct predictions in a row. + if lastMatch { + hits++ + } + lastMatch = true + } else { + lastMatch = false + } + o1[c1] = c + c1 = c + hist[c]++ + } + + // Use x^0.6 to give better spread + prediction := math.Pow(float64(hits)/float64(len(b)), 0.6) + + // Calculate histogram distribution + variance := float64(0) + avg := float64(len(b)) / 256 + + for _, v := range hist { + Δ := float64(v) - avg + variance += Δ * Δ + } + + stddev := math.Sqrt(float64(variance)) / float64(len(b)) + exp := math.Sqrt(1 / float64(len(b))) + + // Subtract expected stddev + stddev -= exp + if stddev < 0 { + stddev = 0 + } + stddev *= 1 + exp + + // Use x^0.4 to give better spread + entropy := math.Pow(stddev, 0.4) + + // 50/50 weight between prediction and histogram distribution + return math.Pow((prediction+entropy)/2, 0.9) +} + +// ShannonEntropyBits returns the number of bits minimum required to represent +// an entropy encoding of the input bytes. +// https://en.wiktionary.org/wiki/Shannon_entropy +func ShannonEntropyBits(b []byte) int { + if len(b) == 0 { + return 0 + } + var hist [256]int + for _, c := range b { + hist[c]++ + } + shannon := float64(0) + invTotal := 1.0 / float64(len(b)) + for _, v := range hist[:] { + if v > 0 { + n := float64(v) + shannon += math.Ceil(-math.Log2(n*invTotal) * n) + } + } + return int(math.Ceil(shannon)) +} diff --git a/vendor/github.com/klauspost/compress/fse/README.md b/vendor/github.com/klauspost/compress/fse/README.md new file mode 100644 index 0000000..27d8ed5 --- /dev/null +++ b/vendor/github.com/klauspost/compress/fse/README.md @@ -0,0 +1,79 @@ +# Finite State Entropy + +This package provides Finite State Entropy encoding and decoding. + +Finite State Entropy (also referenced as [tANS](https://en.wikipedia.org/wiki/Asymmetric_numeral_systems#tANS)) +encoding provides a fast near-optimal symbol encoding/decoding +for byte blocks as implemented in [zstandard](https://github.com/facebook/zstd). + +This can be used for compressing input with a lot of similar input values to the smallest number of bytes. +This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders, +but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding. + +* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/fse) + +## News + + * Feb 2018: First implementation released. Consider this beta software for now. + +# Usage + +This package provides a low level interface that allows to compress single independent blocks. + +Each block is separate, and there is no built in integrity checks. +This means that the caller should keep track of block sizes and also do checksums if needed. + +Compressing a block is done via the [`Compress`](https://godoc.org/github.com/klauspost/compress/fse#Compress) function. +You must provide input and will receive the output and maybe an error. + +These error values can be returned: + +| Error | Description | +|---------------------|-----------------------------------------------------------------------------| +| `` | Everything ok, output is returned | +| `ErrIncompressible` | Returned when input is judged to be too hard to compress | +| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated | +| `(error)` | An internal error occurred. | + +As can be seen above there are errors that will be returned even under normal operation so it is important to handle these. + +To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/fse#Scratch) object +that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same +object can be used for both. + +Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this +you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output. + +Decompressing is done by calling the [`Decompress`](https://godoc.org/github.com/klauspost/compress/fse#Decompress) function. +You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back +your input was likely corrupted. + +It is important to note that a successful decoding does *not* mean your output matches your original input. +There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid. + +For more detailed usage, see examples in the [godoc documentation](https://godoc.org/github.com/klauspost/compress/fse#pkg-examples). + +# Performance + +A lot of factors are affecting speed. Block sizes and compressibility of the material are primary factors. +All compression functions are currently only running on the calling goroutine so only one core will be used per block. + +The compressor is significantly faster if symbols are kept as small as possible. The highest byte value of the input +is used to reduce some of the processing, so if all your input is above byte value 64 for instance, it may be +beneficial to transpose all your input values down by 64. + +With moderate block sizes around 64k speed are typically 200MB/s per core for compression and +around 300MB/s decompression speed. + +The same hardware typically does Huffman (deflate) encoding at 125MB/s and decompression at 100MB/s. + +# Plans + +At one point, more internals will be exposed to facilitate more "expert" usage of the components. + +A streaming interface is also likely to be implemented. Likely compatible with [FSE stream format](https://github.com/Cyan4973/FiniteStateEntropy/blob/dev/programs/fileio.c#L261). + +# Contributing + +Contributions are always welcome. Be aware that adding public functions will require good justification and breaking +changes will likely not be accepted. If in doubt open an issue before writing the PR. \ No newline at end of file diff --git a/vendor/github.com/klauspost/compress/fse/bitreader.go b/vendor/github.com/klauspost/compress/fse/bitreader.go new file mode 100644 index 0000000..f65eb39 --- /dev/null +++ b/vendor/github.com/klauspost/compress/fse/bitreader.go @@ -0,0 +1,122 @@ +// Copyright 2018 Klaus Post. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// Based on work Copyright (c) 2013, Yann Collet, released under BSD License. + +package fse + +import ( + "encoding/binary" + "errors" + "io" +) + +// bitReader reads a bitstream in reverse. +// The last set bit indicates the start of the stream and is used +// for aligning the input. +type bitReader struct { + in []byte + off uint // next byte to read is at in[off - 1] + value uint64 + bitsRead uint8 +} + +// init initializes and resets the bit reader. +func (b *bitReader) init(in []byte) error { + if len(in) < 1 { + return errors.New("corrupt stream: too short") + } + b.in = in + b.off = uint(len(in)) + // The highest bit of the last byte indicates where to start + v := in[len(in)-1] + if v == 0 { + return errors.New("corrupt stream, did not find end of stream") + } + b.bitsRead = 64 + b.value = 0 + if len(in) >= 8 { + b.fillFastStart() + } else { + b.fill() + b.fill() + } + b.bitsRead += 8 - uint8(highBits(uint32(v))) + return nil +} + +// getBits will return n bits. n can be 0. +func (b *bitReader) getBits(n uint8) uint16 { + if n == 0 || b.bitsRead >= 64 { + return 0 + } + return b.getBitsFast(n) +} + +// getBitsFast requires that at least one bit is requested every time. +// There are no checks if the buffer is filled. +func (b *bitReader) getBitsFast(n uint8) uint16 { + const regMask = 64 - 1 + v := uint16((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask)) + b.bitsRead += n + return v +} + +// fillFast() will make sure at least 32 bits are available. +// There must be at least 4 bytes available. +func (b *bitReader) fillFast() { + if b.bitsRead < 32 { + return + } + // 2 bounds checks. + v := b.in[b.off-4:] + v = v[:4] + low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24) + b.value = (b.value << 32) | uint64(low) + b.bitsRead -= 32 + b.off -= 4 +} + +// fill() will make sure at least 32 bits are available. +func (b *bitReader) fill() { + if b.bitsRead < 32 { + return + } + if b.off > 4 { + v := b.in[b.off-4:] + v = v[:4] + low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24) + b.value = (b.value << 32) | uint64(low) + b.bitsRead -= 32 + b.off -= 4 + return + } + for b.off > 0 { + b.value = (b.value << 8) | uint64(b.in[b.off-1]) + b.bitsRead -= 8 + b.off-- + } +} + +// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read. +func (b *bitReader) fillFastStart() { + // Do single re-slice to avoid bounds checks. + b.value = binary.LittleEndian.Uint64(b.in[b.off-8:]) + b.bitsRead = 0 + b.off -= 8 +} + +// finished returns true if all bits have been read from the bit stream. +func (b *bitReader) finished() bool { + return b.bitsRead >= 64 && b.off == 0 +} + +// close the bitstream and returns an error if out-of-buffer reads occurred. +func (b *bitReader) close() error { + // Release reference. + b.in = nil + if b.bitsRead > 64 { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/vendor/github.com/klauspost/compress/fse/bitwriter.go b/vendor/github.com/klauspost/compress/fse/bitwriter.go new file mode 100644 index 0000000..d58b3fe --- /dev/null +++ b/vendor/github.com/klauspost/compress/fse/bitwriter.go @@ -0,0 +1,167 @@ +// Copyright 2018 Klaus Post. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// Based on work Copyright (c) 2013, Yann Collet, released under BSD License. + +package fse + +import "fmt" + +// bitWriter will write bits. +// First bit will be LSB of the first byte of output. +type bitWriter struct { + bitContainer uint64 + nBits uint8 + out []byte +} + +// bitMask16 is bitmasks. Has extra to avoid bounds check. +var bitMask16 = [32]uint16{ + 0, 1, 3, 7, 0xF, 0x1F, + 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF} /* up to 16 bits */ + +// addBits16NC will add up to 16 bits. +// It will not check if there is space for them, +// so the caller must ensure that it has flushed recently. +func (b *bitWriter) addBits16NC(value uint16, bits uint8) { + b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63) + b.nBits += bits +} + +// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated. +// It will not check if there is space for them, so the caller must ensure that it has flushed recently. +func (b *bitWriter) addBits16Clean(value uint16, bits uint8) { + b.bitContainer |= uint64(value) << (b.nBits & 63) + b.nBits += bits +} + +// addBits16ZeroNC will add up to 16 bits. +// It will not check if there is space for them, +// so the caller must ensure that it has flushed recently. +// This is fastest if bits can be zero. +func (b *bitWriter) addBits16ZeroNC(value uint16, bits uint8) { + if bits == 0 { + return + } + value <<= (16 - bits) & 15 + value >>= (16 - bits) & 15 + b.bitContainer |= uint64(value) << (b.nBits & 63) + b.nBits += bits +} + +// flush will flush all pending full bytes. +// There will be at least 56 bits available for writing when this has been called. +// Using flush32 is faster, but leaves less space for writing. +func (b *bitWriter) flush() { + v := b.nBits >> 3 + switch v { + case 0: + case 1: + b.out = append(b.out, + byte(b.bitContainer), + ) + case 2: + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + ) + case 3: + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + byte(b.bitContainer>>16), + ) + case 4: + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + byte(b.bitContainer>>16), + byte(b.bitContainer>>24), + ) + case 5: + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + byte(b.bitContainer>>16), + byte(b.bitContainer>>24), + byte(b.bitContainer>>32), + ) + case 6: + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + byte(b.bitContainer>>16), + byte(b.bitContainer>>24), + byte(b.bitContainer>>32), + byte(b.bitContainer>>40), + ) + case 7: + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + byte(b.bitContainer>>16), + byte(b.bitContainer>>24), + byte(b.bitContainer>>32), + byte(b.bitContainer>>40), + byte(b.bitContainer>>48), + ) + case 8: + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + byte(b.bitContainer>>16), + byte(b.bitContainer>>24), + byte(b.bitContainer>>32), + byte(b.bitContainer>>40), + byte(b.bitContainer>>48), + byte(b.bitContainer>>56), + ) + default: + panic(fmt.Errorf("bits (%d) > 64", b.nBits)) + } + b.bitContainer >>= v << 3 + b.nBits &= 7 +} + +// flush32 will flush out, so there are at least 32 bits available for writing. +func (b *bitWriter) flush32() { + if b.nBits < 32 { + return + } + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + byte(b.bitContainer>>16), + byte(b.bitContainer>>24)) + b.nBits -= 32 + b.bitContainer >>= 32 +} + +// flushAlign will flush remaining full bytes and align to next byte boundary. +func (b *bitWriter) flushAlign() { + nbBytes := (b.nBits + 7) >> 3 + for i := range nbBytes { + b.out = append(b.out, byte(b.bitContainer>>(i*8))) + } + b.nBits = 0 + b.bitContainer = 0 +} + +// close will write the alignment bit and write the final byte(s) +// to the output. +func (b *bitWriter) close() { + // End mark + b.addBits16Clean(1, 1) + // flush until next byte. + b.flushAlign() +} + +// reset and continue writing by appending to out. +func (b *bitWriter) reset(out []byte) { + b.bitContainer = 0 + b.nBits = 0 + b.out = out +} diff --git a/vendor/github.com/klauspost/compress/fse/bytereader.go b/vendor/github.com/klauspost/compress/fse/bytereader.go new file mode 100644 index 0000000..abade2d --- /dev/null +++ b/vendor/github.com/klauspost/compress/fse/bytereader.go @@ -0,0 +1,47 @@ +// Copyright 2018 Klaus Post. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// Based on work Copyright (c) 2013, Yann Collet, released under BSD License. + +package fse + +// byteReader provides a byte reader that reads +// little endian values from a byte stream. +// The input stream is manually advanced. +// The reader performs no bounds checks. +type byteReader struct { + b []byte + off int +} + +// init will initialize the reader and set the input. +func (b *byteReader) init(in []byte) { + b.b = in + b.off = 0 +} + +// advance the stream b n bytes. +func (b *byteReader) advance(n uint) { + b.off += int(n) +} + +// Uint32 returns a little endian uint32 starting at current offset. +func (b byteReader) Uint32() uint32 { + b2 := b.b[b.off:] + b2 = b2[:4] + v3 := uint32(b2[3]) + v2 := uint32(b2[2]) + v1 := uint32(b2[1]) + v0 := uint32(b2[0]) + return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24) +} + +// unread returns the unread portion of the input. +func (b byteReader) unread() []byte { + return b.b[b.off:] +} + +// remain will return the number of bytes remaining. +func (b byteReader) remain() int { + return len(b.b) - b.off +} diff --git a/vendor/github.com/klauspost/compress/fse/compress.go b/vendor/github.com/klauspost/compress/fse/compress.go new file mode 100644 index 0000000..8c8baa4 --- /dev/null +++ b/vendor/github.com/klauspost/compress/fse/compress.go @@ -0,0 +1,683 @@ +// Copyright 2018 Klaus Post. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// Based on work Copyright (c) 2013, Yann Collet, released under BSD License. + +package fse + +import ( + "errors" + "fmt" +) + +// Compress the input bytes. Input must be < 2GB. +// Provide a Scratch buffer to avoid memory allocations. +// Note that the output is also kept in the scratch buffer. +// If input is too hard to compress, ErrIncompressible is returned. +// If input is a single byte value repeated ErrUseRLE is returned. +func Compress(in []byte, s *Scratch) ([]byte, error) { + if len(in) <= 1 { + return nil, ErrIncompressible + } + if len(in) > (2<<30)-1 { + return nil, errors.New("input too big, must be < 2GB") + } + s, err := s.prepare(in) + if err != nil { + return nil, err + } + + // Create histogram, if none was provided. + maxCount := s.maxCount + if maxCount == 0 { + maxCount = s.countSimple(in) + } + // Reset for next run. + s.clearCount = true + s.maxCount = 0 + if maxCount == len(in) { + // One symbol, use RLE + return nil, ErrUseRLE + } + if maxCount == 1 || maxCount < (len(in)>>7) { + // Each symbol present maximum once or too well distributed. + return nil, ErrIncompressible + } + s.optimalTableLog() + err = s.normalizeCount() + if err != nil { + return nil, err + } + err = s.writeCount() + if err != nil { + return nil, err + } + + if false { + err = s.validateNorm() + if err != nil { + return nil, err + } + } + + err = s.buildCTable() + if err != nil { + return nil, err + } + err = s.compress(in) + if err != nil { + return nil, err + } + s.Out = s.bw.out + // Check if we compressed. + if len(s.Out) >= len(in) { + return nil, ErrIncompressible + } + return s.Out, nil +} + +// cState contains the compression state of a stream. +type cState struct { + bw *bitWriter + stateTable []uint16 + state uint16 +} + +// init will initialize the compression state to the first symbol of the stream. +func (c *cState) init(bw *bitWriter, ct *cTable, tableLog uint8, first symbolTransform) { + c.bw = bw + c.stateTable = ct.stateTable + + nbBitsOut := (first.deltaNbBits + (1 << 15)) >> 16 + im := int32((nbBitsOut << 16) - first.deltaNbBits) + lu := (im >> nbBitsOut) + first.deltaFindState + c.state = c.stateTable[lu] +} + +// encode the output symbol provided and write it to the bitstream. +func (c *cState) encode(symbolTT symbolTransform) { + nbBitsOut := (uint32(c.state) + symbolTT.deltaNbBits) >> 16 + dstState := int32(c.state>>(nbBitsOut&15)) + symbolTT.deltaFindState + c.bw.addBits16NC(c.state, uint8(nbBitsOut)) + c.state = c.stateTable[dstState] +} + +// encode the output symbol provided and write it to the bitstream. +func (c *cState) encodeZero(symbolTT symbolTransform) { + nbBitsOut := (uint32(c.state) + symbolTT.deltaNbBits) >> 16 + dstState := int32(c.state>>(nbBitsOut&15)) + symbolTT.deltaFindState + c.bw.addBits16ZeroNC(c.state, uint8(nbBitsOut)) + c.state = c.stateTable[dstState] +} + +// flush will write the tablelog to the output and flush the remaining full bytes. +func (c *cState) flush(tableLog uint8) { + c.bw.flush32() + c.bw.addBits16NC(c.state, tableLog) + c.bw.flush() +} + +// compress is the main compression loop that will encode the input from the last byte to the first. +func (s *Scratch) compress(src []byte) error { + if len(src) <= 2 { + return errors.New("compress: src too small") + } + tt := s.ct.symbolTT[:256] + s.bw.reset(s.Out) + + // Our two states each encodes every second byte. + // Last byte encoded (first byte decoded) will always be encoded by c1. + var c1, c2 cState + + // Encode so remaining size is divisible by 4. + ip := len(src) + if ip&1 == 1 { + c1.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-1]]) + c2.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-2]]) + c1.encodeZero(tt[src[ip-3]]) + ip -= 3 + } else { + c2.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-1]]) + c1.init(&s.bw, &s.ct, s.actualTableLog, tt[src[ip-2]]) + ip -= 2 + } + if ip&2 != 0 { + c2.encodeZero(tt[src[ip-1]]) + c1.encodeZero(tt[src[ip-2]]) + ip -= 2 + } + src = src[:ip] + + // Main compression loop. + switch { + case !s.zeroBits && s.actualTableLog <= 8: + // We can encode 4 symbols without requiring a flush. + // We do not need to check if any output is 0 bits. + for ; len(src) >= 4; src = src[:len(src)-4] { + s.bw.flush32() + v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1] + c2.encode(tt[v0]) + c1.encode(tt[v1]) + c2.encode(tt[v2]) + c1.encode(tt[v3]) + } + case !s.zeroBits: + // We do not need to check if any output is 0 bits. + for ; len(src) >= 4; src = src[:len(src)-4] { + s.bw.flush32() + v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1] + c2.encode(tt[v0]) + c1.encode(tt[v1]) + s.bw.flush32() + c2.encode(tt[v2]) + c1.encode(tt[v3]) + } + case s.actualTableLog <= 8: + // We can encode 4 symbols without requiring a flush + for ; len(src) >= 4; src = src[:len(src)-4] { + s.bw.flush32() + v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1] + c2.encodeZero(tt[v0]) + c1.encodeZero(tt[v1]) + c2.encodeZero(tt[v2]) + c1.encodeZero(tt[v3]) + } + default: + for ; len(src) >= 4; src = src[:len(src)-4] { + s.bw.flush32() + v3, v2, v1, v0 := src[len(src)-4], src[len(src)-3], src[len(src)-2], src[len(src)-1] + c2.encodeZero(tt[v0]) + c1.encodeZero(tt[v1]) + s.bw.flush32() + c2.encodeZero(tt[v2]) + c1.encodeZero(tt[v3]) + } + } + + // Flush final state. + // Used to initialize state when decoding. + c2.flush(s.actualTableLog) + c1.flush(s.actualTableLog) + + s.bw.close() + return nil +} + +// writeCount will write the normalized histogram count to header. +// This is read back by readNCount. +func (s *Scratch) writeCount() error { + var ( + tableLog = s.actualTableLog + tableSize = 1 << tableLog + previous0 bool + charnum uint16 + + maxHeaderSize = ((int(s.symbolLen)*int(tableLog) + 4 + 2) >> 3) + 3 + + // Write Table Size + bitStream = uint32(tableLog - minTablelog) + bitCount = uint(4) + remaining = int16(tableSize + 1) /* +1 for extra accuracy */ + threshold = int16(tableSize) + nbBits = uint(tableLog + 1) + ) + if cap(s.Out) < maxHeaderSize { + s.Out = make([]byte, 0, s.br.remain()+maxHeaderSize) + } + outP := uint(0) + out := s.Out[:maxHeaderSize] + + // stops at 1 + for remaining > 1 { + if previous0 { + start := charnum + for s.norm[charnum] == 0 { + charnum++ + } + for charnum >= start+24 { + start += 24 + bitStream += uint32(0xFFFF) << bitCount + out[outP] = byte(bitStream) + out[outP+1] = byte(bitStream >> 8) + outP += 2 + bitStream >>= 16 + } + for charnum >= start+3 { + start += 3 + bitStream += 3 << bitCount + bitCount += 2 + } + bitStream += uint32(charnum-start) << bitCount + bitCount += 2 + if bitCount > 16 { + out[outP] = byte(bitStream) + out[outP+1] = byte(bitStream >> 8) + outP += 2 + bitStream >>= 16 + bitCount -= 16 + } + } + + count := s.norm[charnum] + charnum++ + max := (2*threshold - 1) - remaining + if count < 0 { + remaining += count + } else { + remaining -= count + } + count++ // +1 for extra accuracy + if count >= threshold { + count += max // [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ + } + bitStream += uint32(count) << bitCount + bitCount += nbBits + if count < max { + bitCount-- + } + + previous0 = count == 1 + if remaining < 1 { + return errors.New("internal error: remaining<1") + } + for remaining < threshold { + nbBits-- + threshold >>= 1 + } + + if bitCount > 16 { + out[outP] = byte(bitStream) + out[outP+1] = byte(bitStream >> 8) + outP += 2 + bitStream >>= 16 + bitCount -= 16 + } + } + + out[outP] = byte(bitStream) + out[outP+1] = byte(bitStream >> 8) + outP += (bitCount + 7) / 8 + + if charnum > s.symbolLen { + return errors.New("internal error: charnum > s.symbolLen") + } + s.Out = out[:outP] + return nil +} + +// symbolTransform contains the state transform for a symbol. +type symbolTransform struct { + deltaFindState int32 + deltaNbBits uint32 +} + +// String prints values as a human readable string. +func (s symbolTransform) String() string { + return fmt.Sprintf("dnbits: %08x, fs:%d", s.deltaNbBits, s.deltaFindState) +} + +// cTable contains tables used for compression. +type cTable struct { + tableSymbol []byte + stateTable []uint16 + symbolTT []symbolTransform +} + +// allocCtable will allocate tables needed for compression. +// If existing tables a re big enough, they are simply re-used. +func (s *Scratch) allocCtable() { + tableSize := 1 << s.actualTableLog + // get tableSymbol that is big enough. + if cap(s.ct.tableSymbol) < tableSize { + s.ct.tableSymbol = make([]byte, tableSize) + } + s.ct.tableSymbol = s.ct.tableSymbol[:tableSize] + + ctSize := tableSize + if cap(s.ct.stateTable) < ctSize { + s.ct.stateTable = make([]uint16, ctSize) + } + s.ct.stateTable = s.ct.stateTable[:ctSize] + + if cap(s.ct.symbolTT) < 256 { + s.ct.symbolTT = make([]symbolTransform, 256) + } + s.ct.symbolTT = s.ct.symbolTT[:256] +} + +// buildCTable will populate the compression table so it is ready to be used. +func (s *Scratch) buildCTable() error { + tableSize := uint32(1 << s.actualTableLog) + highThreshold := tableSize - 1 + var cumul [maxSymbolValue + 2]int16 + + s.allocCtable() + tableSymbol := s.ct.tableSymbol[:tableSize] + // symbol start positions + { + cumul[0] = 0 + for ui, v := range s.norm[:s.symbolLen-1] { + u := byte(ui) // one less than reference + if v == -1 { + // Low proba symbol + cumul[u+1] = cumul[u] + 1 + tableSymbol[highThreshold] = u + highThreshold-- + } else { + cumul[u+1] = cumul[u] + v + } + } + // Encode last symbol separately to avoid overflowing u + u := int(s.symbolLen - 1) + v := s.norm[s.symbolLen-1] + if v == -1 { + // Low proba symbol + cumul[u+1] = cumul[u] + 1 + tableSymbol[highThreshold] = byte(u) + highThreshold-- + } else { + cumul[u+1] = cumul[u] + v + } + if uint32(cumul[s.symbolLen]) != tableSize { + return fmt.Errorf("internal error: expected cumul[s.symbolLen] (%d) == tableSize (%d)", cumul[s.symbolLen], tableSize) + } + cumul[s.symbolLen] = int16(tableSize) + 1 + } + // Spread symbols + s.zeroBits = false + { + step := tableStep(tableSize) + tableMask := tableSize - 1 + var position uint32 + // if any symbol > largeLimit, we may have 0 bits output. + largeLimit := int16(1 << (s.actualTableLog - 1)) + for ui, v := range s.norm[:s.symbolLen] { + symbol := byte(ui) + if v > largeLimit { + s.zeroBits = true + } + for range v { + tableSymbol[position] = symbol + position = (position + step) & tableMask + for position > highThreshold { + position = (position + step) & tableMask + } /* Low proba area */ + } + } + + // Check if we have gone through all positions + if position != 0 { + return errors.New("position!=0") + } + } + + // Build table + table := s.ct.stateTable + { + tsi := int(tableSize) + for u, v := range tableSymbol { + // TableU16 : sorted by symbol order; gives next state value + table[cumul[v]] = uint16(tsi + u) + cumul[v]++ + } + } + + // Build Symbol Transformation Table + { + total := int16(0) + symbolTT := s.ct.symbolTT[:s.symbolLen] + tableLog := s.actualTableLog + tl := (uint32(tableLog) << 16) - (1 << tableLog) + for i, v := range s.norm[:s.symbolLen] { + switch v { + case 0: + case -1, 1: + symbolTT[i].deltaNbBits = tl + symbolTT[i].deltaFindState = int32(total - 1) + total++ + default: + maxBitsOut := uint32(tableLog) - highBits(uint32(v-1)) + minStatePlus := uint32(v) << maxBitsOut + symbolTT[i].deltaNbBits = (maxBitsOut << 16) - minStatePlus + symbolTT[i].deltaFindState = int32(total - v) + total += v + } + } + if total != int16(tableSize) { + return fmt.Errorf("total mismatch %d (got) != %d (want)", total, tableSize) + } + } + return nil +} + +// countSimple will create a simple histogram in s.count. +// Returns the biggest count. +// Does not update s.clearCount. +func (s *Scratch) countSimple(in []byte) (max int) { + for _, v := range in { + s.count[v]++ + } + m, symlen := uint32(0), s.symbolLen + for i, v := range s.count[:] { + if v == 0 { + continue + } + if v > m { + m = v + } + symlen = uint16(i) + 1 + } + s.symbolLen = symlen + return int(m) +} + +// minTableLog provides the minimum logSize to safely represent a distribution. +func (s *Scratch) minTableLog() uint8 { + minBitsSrc := highBits(uint32(s.br.remain()-1)) + 1 + minBitsSymbols := highBits(uint32(s.symbolLen-1)) + 2 + if minBitsSrc < minBitsSymbols { + return uint8(minBitsSrc) + } + return uint8(minBitsSymbols) +} + +// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog +func (s *Scratch) optimalTableLog() { + tableLog := s.TableLog + minBits := s.minTableLog() + maxBitsSrc := uint8(highBits(uint32(s.br.remain()-1))) - 2 + if maxBitsSrc < tableLog { + // Accuracy can be reduced + tableLog = maxBitsSrc + } + if minBits > tableLog { + tableLog = minBits + } + // Need a minimum to safely represent all symbol values + if tableLog < minTablelog { + tableLog = minTablelog + } + if tableLog > maxTableLog { + tableLog = maxTableLog + } + s.actualTableLog = tableLog +} + +var rtbTable = [...]uint32{0, 473195, 504333, 520860, 550000, 700000, 750000, 830000} + +// normalizeCount will normalize the count of the symbols so +// the total is equal to the table size. +func (s *Scratch) normalizeCount() error { + var ( + tableLog = s.actualTableLog + scale = 62 - uint64(tableLog) + step = (1 << 62) / uint64(s.br.remain()) + vStep = uint64(1) << (scale - 20) + stillToDistribute = int16(1 << tableLog) + largest int + largestP int16 + lowThreshold = (uint32)(s.br.remain() >> tableLog) + ) + + for i, cnt := range s.count[:s.symbolLen] { + // already handled + // if (count[s] == s.length) return 0; /* rle special case */ + + if cnt == 0 { + s.norm[i] = 0 + continue + } + if cnt <= lowThreshold { + s.norm[i] = -1 + stillToDistribute-- + } else { + proba := (int16)((uint64(cnt) * step) >> scale) + if proba < 8 { + restToBeat := vStep * uint64(rtbTable[proba]) + v := uint64(cnt)*step - (uint64(proba) << scale) + if v > restToBeat { + proba++ + } + } + if proba > largestP { + largestP = proba + largest = i + } + s.norm[i] = proba + stillToDistribute -= proba + } + } + + if -stillToDistribute >= (s.norm[largest] >> 1) { + // corner case, need another normalization method + return s.normalizeCount2() + } + s.norm[largest] += stillToDistribute + return nil +} + +// Secondary normalization method. +// To be used when primary method fails. +func (s *Scratch) normalizeCount2() error { + const notYetAssigned = -2 + var ( + distributed uint32 + total = uint32(s.br.remain()) + tableLog = s.actualTableLog + lowThreshold = total >> tableLog + lowOne = (total * 3) >> (tableLog + 1) + ) + for i, cnt := range s.count[:s.symbolLen] { + if cnt == 0 { + s.norm[i] = 0 + continue + } + if cnt <= lowThreshold { + s.norm[i] = -1 + distributed++ + total -= cnt + continue + } + if cnt <= lowOne { + s.norm[i] = 1 + distributed++ + total -= cnt + continue + } + s.norm[i] = notYetAssigned + } + toDistribute := (1 << tableLog) - distributed + + if (total / toDistribute) > lowOne { + // risk of rounding to zero + lowOne = (total * 3) / (toDistribute * 2) + for i, cnt := range s.count[:s.symbolLen] { + if (s.norm[i] == notYetAssigned) && (cnt <= lowOne) { + s.norm[i] = 1 + distributed++ + total -= cnt + continue + } + } + toDistribute = (1 << tableLog) - distributed + } + if distributed == uint32(s.symbolLen)+1 { + // all values are pretty poor; + // probably incompressible data (should have already been detected); + // find max, then give all remaining points to max + var maxV int + var maxC uint32 + for i, cnt := range s.count[:s.symbolLen] { + if cnt > maxC { + maxV = i + maxC = cnt + } + } + s.norm[maxV] += int16(toDistribute) + return nil + } + + if total == 0 { + // all of the symbols were low enough for the lowOne or lowThreshold + for i := uint32(0); toDistribute > 0; i = (i + 1) % (uint32(s.symbolLen)) { + if s.norm[i] > 0 { + toDistribute-- + s.norm[i]++ + } + } + return nil + } + + var ( + vStepLog = 62 - uint64(tableLog) + mid = uint64((1 << (vStepLog - 1)) - 1) + rStep = (((1 << vStepLog) * uint64(toDistribute)) + mid) / uint64(total) // scale on remaining + tmpTotal = mid + ) + for i, cnt := range s.count[:s.symbolLen] { + if s.norm[i] == notYetAssigned { + var ( + end = tmpTotal + uint64(cnt)*rStep + sStart = uint32(tmpTotal >> vStepLog) + sEnd = uint32(end >> vStepLog) + weight = sEnd - sStart + ) + if weight < 1 { + return errors.New("weight < 1") + } + s.norm[i] = int16(weight) + tmpTotal = end + } + } + return nil +} + +// validateNorm validates the normalized histogram table. +func (s *Scratch) validateNorm() (err error) { + var total int + for _, v := range s.norm[:s.symbolLen] { + if v >= 0 { + total += int(v) + } else { + total -= int(v) + } + } + defer func() { + if err == nil { + return + } + fmt.Printf("selected TableLog: %d, Symbol length: %d\n", s.actualTableLog, s.symbolLen) + for i, v := range s.norm[:s.symbolLen] { + fmt.Printf("%3d: %5d -> %4d \n", i, s.count[i], v) + } + }() + if total != (1 << s.actualTableLog) { + return fmt.Errorf("warning: Total == %d != %d", total, 1< tablelogAbsoluteMax { + return errors.New("tableLog too large") + } + bitStream >>= 4 + bitCount := uint(4) + + s.actualTableLog = uint8(nbBits) + remaining := int32((1 << nbBits) + 1) + threshold := int32(1 << nbBits) + gotTotal := int32(0) + nbBits++ + + for remaining > 1 { + if previous0 { + n0 := charnum + for (bitStream & 0xFFFF) == 0xFFFF { + n0 += 24 + if b.off < iend-5 { + b.advance(2) + bitStream = b.Uint32() >> bitCount + } else { + bitStream >>= 16 + bitCount += 16 + } + } + for (bitStream & 3) == 3 { + n0 += 3 + bitStream >>= 2 + bitCount += 2 + } + n0 += uint16(bitStream & 3) + bitCount += 2 + if n0 > maxSymbolValue { + return errors.New("maxSymbolValue too small") + } + for charnum < n0 { + s.norm[charnum&0xff] = 0 + charnum++ + } + + if b.off <= iend-7 || b.off+int(bitCount>>3) <= iend-4 { + b.advance(bitCount >> 3) + bitCount &= 7 + bitStream = b.Uint32() >> bitCount + } else { + bitStream >>= 2 + } + } + + max := (2*(threshold) - 1) - (remaining) + var count int32 + + if (int32(bitStream) & (threshold - 1)) < max { + count = int32(bitStream) & (threshold - 1) + bitCount += nbBits - 1 + } else { + count = int32(bitStream) & (2*threshold - 1) + if count >= threshold { + count -= max + } + bitCount += nbBits + } + + count-- // extra accuracy + if count < 0 { + // -1 means +1 + remaining += count + gotTotal -= count + } else { + remaining -= count + gotTotal += count + } + s.norm[charnum&0xff] = int16(count) + charnum++ + previous0 = count == 0 + for remaining < threshold { + nbBits-- + threshold >>= 1 + } + if b.off <= iend-7 || b.off+int(bitCount>>3) <= iend-4 { + b.advance(bitCount >> 3) + bitCount &= 7 + } else { + bitCount -= (uint)(8 * (len(b.b) - 4 - b.off)) + b.off = len(b.b) - 4 + } + bitStream = b.Uint32() >> (bitCount & 31) + } + s.symbolLen = charnum + + if s.symbolLen <= 1 { + return fmt.Errorf("symbolLen (%d) too small", s.symbolLen) + } + if s.symbolLen > maxSymbolValue+1 { + return fmt.Errorf("symbolLen (%d) too big", s.symbolLen) + } + if remaining != 1 { + return fmt.Errorf("corruption detected (remaining %d != 1)", remaining) + } + if bitCount > 32 { + return fmt.Errorf("corruption detected (bitCount %d > 32)", bitCount) + } + if gotTotal != 1<> 3) + return nil +} + +// decSymbol contains information about a state entry, +// Including the state offset base, the output symbol and +// the number of bits to read for the low part of the destination state. +type decSymbol struct { + newState uint16 + symbol uint8 + nbBits uint8 +} + +// allocDtable will allocate decoding tables if they are not big enough. +func (s *Scratch) allocDtable() { + tableSize := 1 << s.actualTableLog + if cap(s.decTable) < tableSize { + s.decTable = make([]decSymbol, tableSize) + } + s.decTable = s.decTable[:tableSize] + + if cap(s.ct.tableSymbol) < 256 { + s.ct.tableSymbol = make([]byte, 256) + } + s.ct.tableSymbol = s.ct.tableSymbol[:256] + + if cap(s.ct.stateTable) < 256 { + s.ct.stateTable = make([]uint16, 256) + } + s.ct.stateTable = s.ct.stateTable[:256] +} + +// buildDtable will build the decoding table. +func (s *Scratch) buildDtable() error { + tableSize := uint32(1 << s.actualTableLog) + highThreshold := tableSize - 1 + s.allocDtable() + symbolNext := s.ct.stateTable[:256] + + // Init, lay down lowprob symbols + s.zeroBits = false + { + largeLimit := int16(1 << (s.actualTableLog - 1)) + for i, v := range s.norm[:s.symbolLen] { + if v == -1 { + s.decTable[highThreshold].symbol = uint8(i) + highThreshold-- + symbolNext[i] = 1 + } else { + if v >= largeLimit { + s.zeroBits = true + } + symbolNext[i] = uint16(v) + } + } + } + // Spread symbols + { + tableMask := tableSize - 1 + step := tableStep(tableSize) + position := uint32(0) + for ss, v := range s.norm[:s.symbolLen] { + for i := 0; i < int(v); i++ { + s.decTable[position].symbol = uint8(ss) + position = (position + step) & tableMask + for position > highThreshold { + // lowprob area + position = (position + step) & tableMask + } + } + } + if position != 0 { + // position must reach all cells once, otherwise normalizedCounter is incorrect + return errors.New("corrupted input (position != 0)") + } + } + + // Build Decoding table + { + tableSize := uint16(1 << s.actualTableLog) + for u, v := range s.decTable { + symbol := v.symbol + nextState := symbolNext[symbol] + symbolNext[symbol] = nextState + 1 + nBits := s.actualTableLog - byte(highBits(uint32(nextState))) + s.decTable[u].nbBits = nBits + newState := (nextState << nBits) - tableSize + if newState >= tableSize { + return fmt.Errorf("newState (%d) outside table size (%d)", newState, tableSize) + } + if newState == uint16(u) && nBits == 0 { + // Seems weird that this is possible with nbits > 0. + return fmt.Errorf("newState (%d) == oldState (%d) and no bits", newState, u) + } + s.decTable[u].newState = newState + } + } + return nil +} + +// decompress will decompress the bitstream. +// If the buffer is over-read an error is returned. +func (s *Scratch) decompress() error { + br := &s.bits + if err := br.init(s.br.unread()); err != nil { + return err + } + + var s1, s2 decoder + // Initialize and decode first state and symbol. + s1.init(br, s.decTable, s.actualTableLog) + s2.init(br, s.decTable, s.actualTableLog) + + // Use temp table to avoid bound checks/append penalty. + var tmp = s.ct.tableSymbol[:256] + var off uint8 + + // Main part + if !s.zeroBits { + for br.off >= 8 { + br.fillFast() + tmp[off+0] = s1.nextFast() + tmp[off+1] = s2.nextFast() + br.fillFast() + tmp[off+2] = s1.nextFast() + tmp[off+3] = s2.nextFast() + off += 4 + // When off is 0, we have overflowed and should write. + if off == 0 { + s.Out = append(s.Out, tmp...) + if len(s.Out) >= s.DecompressLimit { + return fmt.Errorf("output size (%d) > DecompressLimit (%d)", len(s.Out), s.DecompressLimit) + } + } + } + } else { + for br.off >= 8 { + br.fillFast() + tmp[off+0] = s1.next() + tmp[off+1] = s2.next() + br.fillFast() + tmp[off+2] = s1.next() + tmp[off+3] = s2.next() + off += 4 + if off == 0 { + s.Out = append(s.Out, tmp...) + // When off is 0, we have overflowed and should write. + if len(s.Out) >= s.DecompressLimit { + return fmt.Errorf("output size (%d) > DecompressLimit (%d)", len(s.Out), s.DecompressLimit) + } + } + } + } + s.Out = append(s.Out, tmp[:off]...) + + // Final bits, a bit more expensive check + for { + if s1.finished() { + s.Out = append(s.Out, s1.final(), s2.final()) + break + } + br.fill() + s.Out = append(s.Out, s1.next()) + if s2.finished() { + s.Out = append(s.Out, s2.final(), s1.final()) + break + } + s.Out = append(s.Out, s2.next()) + if len(s.Out) >= s.DecompressLimit { + return fmt.Errorf("output size (%d) > DecompressLimit (%d)", len(s.Out), s.DecompressLimit) + } + } + return br.close() +} + +// decoder keeps track of the current state and updates it from the bitstream. +type decoder struct { + state uint16 + br *bitReader + dt []decSymbol +} + +// init will initialize the decoder and read the first state from the stream. +func (d *decoder) init(in *bitReader, dt []decSymbol, tableLog uint8) { + d.dt = dt + d.br = in + d.state = in.getBits(tableLog) +} + +// next returns the next symbol and sets the next state. +// At least tablelog bits must be available in the bit reader. +func (d *decoder) next() uint8 { + n := &d.dt[d.state] + lowBits := d.br.getBits(n.nbBits) + d.state = n.newState + lowBits + return n.symbol +} + +// finished returns true if all bits have been read from the bitstream +// and the next state would require reading bits from the input. +func (d *decoder) finished() bool { + return d.br.finished() && d.dt[d.state].nbBits > 0 +} + +// final returns the current state symbol without decoding the next. +func (d *decoder) final() uint8 { + return d.dt[d.state].symbol +} + +// nextFast returns the next symbol and sets the next state. +// This can only be used if no symbols are 0 bits. +// At least tablelog bits must be available in the bit reader. +func (d *decoder) nextFast() uint8 { + n := d.dt[d.state] + lowBits := d.br.getBitsFast(n.nbBits) + d.state = n.newState + lowBits + return n.symbol +} diff --git a/vendor/github.com/klauspost/compress/fse/fse.go b/vendor/github.com/klauspost/compress/fse/fse.go new file mode 100644 index 0000000..535cbad --- /dev/null +++ b/vendor/github.com/klauspost/compress/fse/fse.go @@ -0,0 +1,144 @@ +// Copyright 2018 Klaus Post. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// Based on work Copyright (c) 2013, Yann Collet, released under BSD License. + +// Package fse provides Finite State Entropy encoding and decoding. +// +// Finite State Entropy encoding provides a fast near-optimal symbol encoding/decoding +// for byte blocks as implemented in zstd. +// +// See https://github.com/klauspost/compress/tree/master/fse for more information. +package fse + +import ( + "errors" + "fmt" + "math/bits" +) + +const ( + /*!MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + * Increasing memory usage improves compression ratio + * Reduced memory usage can improve speed, due to cache effect + * Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ + maxMemoryUsage = 14 + defaultMemoryUsage = 13 + + maxTableLog = maxMemoryUsage - 2 + maxTablesize = 1 << maxTableLog + defaultTablelog = defaultMemoryUsage - 2 + minTablelog = 5 + maxSymbolValue = 255 +) + +var ( + // ErrIncompressible is returned when input is judged to be too hard to compress. + ErrIncompressible = errors.New("input is not compressible") + + // ErrUseRLE is returned from the compressor when the input is a single byte value repeated. + ErrUseRLE = errors.New("input is single value repeated") +) + +// Scratch provides temporary storage for compression and decompression. +type Scratch struct { + // Private + count [maxSymbolValue + 1]uint32 + norm [maxSymbolValue + 1]int16 + br byteReader + bits bitReader + bw bitWriter + ct cTable // Compression tables. + decTable []decSymbol // Decompression table. + maxCount int // count of the most probable symbol + + // Per block parameters. + // These can be used to override compression parameters of the block. + // Do not touch, unless you know what you are doing. + + // Out is output buffer. + // If the scratch is re-used before the caller is done processing the output, + // set this field to nil. + // Otherwise the output buffer will be re-used for next Compression/Decompression step + // and allocation will be avoided. + Out []byte + + // DecompressLimit limits the maximum decoded size acceptable. + // If > 0 decompression will stop when approximately this many bytes + // has been decoded. + // If 0, maximum size will be 2GB. + DecompressLimit int + + symbolLen uint16 // Length of active part of the symbol table. + actualTableLog uint8 // Selected tablelog. + zeroBits bool // no bits has prob > 50%. + clearCount bool // clear count + + // MaxSymbolValue will override the maximum symbol value of the next block. + MaxSymbolValue uint8 + + // TableLog will attempt to override the tablelog for the next block. + TableLog uint8 +} + +// Histogram allows to populate the histogram and skip that step in the compression, +// It otherwise allows to inspect the histogram when compression is done. +// To indicate that you have populated the histogram call HistogramFinished +// with the value of the highest populated symbol, as well as the number of entries +// in the most populated entry. These are accepted at face value. +// The returned slice will always be length 256. +func (s *Scratch) Histogram() []uint32 { + return s.count[:] +} + +// HistogramFinished can be called to indicate that the histogram has been populated. +// maxSymbol is the index of the highest set symbol of the next data segment. +// maxCount is the number of entries in the most populated entry. +// These are accepted at face value. +func (s *Scratch) HistogramFinished(maxSymbol uint8, maxCount int) { + s.maxCount = maxCount + s.symbolLen = uint16(maxSymbol) + 1 + s.clearCount = maxCount != 0 +} + +// prepare will prepare and allocate scratch tables used for both compression and decompression. +func (s *Scratch) prepare(in []byte) (*Scratch, error) { + if s == nil { + s = &Scratch{} + } + if s.MaxSymbolValue == 0 { + s.MaxSymbolValue = 255 + } + if s.TableLog == 0 { + s.TableLog = defaultTablelog + } + if s.TableLog > maxTableLog { + return nil, fmt.Errorf("tableLog (%d) > maxTableLog (%d)", s.TableLog, maxTableLog) + } + if cap(s.Out) == 0 { + s.Out = make([]byte, 0, len(in)) + } + if s.clearCount && s.maxCount == 0 { + for i := range s.count { + s.count[i] = 0 + } + s.clearCount = false + } + s.br.init(in) + if s.DecompressLimit == 0 { + // Max size 2GB. + s.DecompressLimit = (2 << 30) - 1 + } + + return s, nil +} + +// tableStep returns the next table index. +func tableStep(tableSize uint32) uint32 { + return (tableSize >> 1) + (tableSize >> 3) + 3 +} + +func highBits(val uint32) (n uint32) { + return uint32(bits.Len32(val) - 1) +} diff --git a/vendor/github.com/klauspost/compress/gen.sh b/vendor/github.com/klauspost/compress/gen.sh new file mode 100644 index 0000000..aff9422 --- /dev/null +++ b/vendor/github.com/klauspost/compress/gen.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd s2/cmd/_s2sx/ || exit 1 +go generate . diff --git a/vendor/github.com/klauspost/compress/huff0/.gitignore b/vendor/github.com/klauspost/compress/huff0/.gitignore new file mode 100644 index 0000000..b3d2629 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/.gitignore @@ -0,0 +1 @@ +/huff0-fuzz.zip diff --git a/vendor/github.com/klauspost/compress/huff0/README.md b/vendor/github.com/klauspost/compress/huff0/README.md new file mode 100644 index 0000000..26d5101 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/README.md @@ -0,0 +1,89 @@ +# Huff0 entropy compression + +This package provides Huff0 encoding and decoding as used in zstd. + +[Huff0](https://github.com/Cyan4973/FiniteStateEntropy#new-generation-entropy-coders), +a Huffman codec designed for modern CPU, featuring OoO (Out of Order) operations on multiple ALU +(Arithmetic Logic Unit), achieving extremely fast compression and decompression speeds. + +This can be used for compressing input with a lot of similar input values to the smallest number of bytes. +This does not perform any multi-byte [dictionary coding](https://en.wikipedia.org/wiki/Dictionary_coder) as LZ coders, +but it can be used as a secondary step to compressors (like Snappy) that does not do entropy encoding. + +* [Godoc documentation](https://godoc.org/github.com/klauspost/compress/huff0) + +## News + +This is used as part of the [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression package. + +This ensures that most functionality is well tested. + +# Usage + +This package provides a low level interface that allows to compress single independent blocks. + +Each block is separate, and there is no built in integrity checks. +This means that the caller should keep track of block sizes and also do checksums if needed. + +Compressing a block is done via the [`Compress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress1X) and +[`Compress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Compress4X) functions. +You must provide input and will receive the output and maybe an error. + +These error values can be returned: + +| Error | Description | +|---------------------|-----------------------------------------------------------------------------| +| `` | Everything ok, output is returned | +| `ErrIncompressible` | Returned when input is judged to be too hard to compress | +| `ErrUseRLE` | Returned from the compressor when the input is a single byte value repeated | +| `ErrTooBig` | Returned if the input block exceeds the maximum allowed size (128 Kib) | +| `(error)` | An internal error occurred. | + + +As can be seen above some of there are errors that will be returned even under normal operation so it is important to handle these. + +To reduce allocations you can provide a [`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object +that can be re-used for successive calls. Both compression and decompression accepts a `Scratch` object, and the same +object can be used for both. + +Be aware, that when re-using a `Scratch` object that the *output* buffer is also re-used, so if you are still using this +you must set the `Out` field in the scratch to nil. The same buffer is used for compression and decompression output. + +The `Scratch` object will retain state that allows to re-use previous tables for encoding and decoding. + +## Tables and re-use + +Huff0 allows for reusing tables from the previous block to save space if that is expected to give better/faster results. + +The Scratch object allows you to set a [`ReusePolicy`](https://godoc.org/github.com/klauspost/compress/huff0#ReusePolicy) +that controls this behaviour. See the documentation for details. This can be altered between each block. + +Do however note that this information is *not* stored in the output block and it is up to the users of the package to +record whether [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable) should be called, +based on the boolean reported back from the CompressXX call. + +If you want to store the table separate from the data, you can access them as `OutData` and `OutTable` on the +[`Scratch`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch) object. + +## Decompressing + +The first part of decoding is to initialize the decoding table through [`ReadTable`](https://godoc.org/github.com/klauspost/compress/huff0#ReadTable). +This will initialize the decoding tables. +You can supply the complete block to `ReadTable` and it will return the data part of the block +which can be given to the decompressor. + +Decompressing is done by calling the [`Decompress1X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress1X) +or [`Decompress4X`](https://godoc.org/github.com/klauspost/compress/huff0#Scratch.Decompress4X) function. + +For concurrently decompressing content with a fixed table a stateless [`Decoder`](https://godoc.org/github.com/klauspost/compress/huff0#Decoder) can be requested which will remain correct as long as the scratch is unchanged. The capacity of the provided slice indicates the expected output size. + +You must provide the output from the compression stage, at exactly the size you got back. If you receive an error back +your input was likely corrupted. + +It is important to note that a successful decoding does *not* mean your output matches your original input. +There are no integrity checks, so relying on errors from the decompressor does not assure your data is valid. + +# Contributing + +Contributions are always welcome. Be aware that adding public functions will require good justification and breaking +changes will likely not be accepted. If in doubt open an issue before writing the PR. diff --git a/vendor/github.com/klauspost/compress/huff0/bitreader.go b/vendor/github.com/klauspost/compress/huff0/bitreader.go new file mode 100644 index 0000000..bfc7a52 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/bitreader.go @@ -0,0 +1,224 @@ +// Copyright 2018 Klaus Post. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// Based on work Copyright (c) 2013, Yann Collet, released under BSD License. + +package huff0 + +import ( + "errors" + "fmt" + "io" + + "github.com/klauspost/compress/internal/le" +) + +// bitReader reads a bitstream in reverse. +// The last set bit indicates the start of the stream and is used +// for aligning the input. +type bitReaderBytes struct { + in []byte + off uint // next byte to read is at in[off - 1] + value uint64 + bitsRead uint8 +} + +// init initializes and resets the bit reader. +func (b *bitReaderBytes) init(in []byte) error { + if len(in) < 1 { + return errors.New("corrupt stream: too short") + } + b.in = in + b.off = uint(len(in)) + // The highest bit of the last byte indicates where to start + v := in[len(in)-1] + if v == 0 { + return errors.New("corrupt stream, did not find end of stream") + } + b.bitsRead = 64 + b.value = 0 + if len(in) >= 8 { + b.fillFastStart() + } else { + b.fill() + b.fill() + } + b.advance(8 - uint8(highBit32(uint32(v)))) + return nil +} + +// peekByteFast requires that at least one byte is requested every time. +// There are no checks if the buffer is filled. +func (b *bitReaderBytes) peekByteFast() uint8 { + got := uint8(b.value >> 56) + return got +} + +func (b *bitReaderBytes) advance(n uint8) { + b.bitsRead += n + b.value <<= n & 63 +} + +// fillFast() will make sure at least 32 bits are available. +// There must be at least 4 bytes available. +func (b *bitReaderBytes) fillFast() { + if b.bitsRead < 32 { + return + } + + // 2 bounds checks. + low := le.Load32(b.in, b.off-4) + b.value |= uint64(low) << (b.bitsRead - 32) + b.bitsRead -= 32 + b.off -= 4 +} + +// fillFastStart() assumes the bitReaderBytes is empty and there is at least 8 bytes to read. +func (b *bitReaderBytes) fillFastStart() { + // Do single re-slice to avoid bounds checks. + b.value = le.Load64(b.in, b.off-8) + b.bitsRead = 0 + b.off -= 8 +} + +// fill() will make sure at least 32 bits are available. +func (b *bitReaderBytes) fill() { + if b.bitsRead < 32 { + return + } + if b.off >= 4 { + low := le.Load32(b.in, b.off-4) + b.value |= uint64(low) << (b.bitsRead - 32) + b.bitsRead -= 32 + b.off -= 4 + return + } + for b.off > 0 { + b.value |= uint64(b.in[b.off-1]) << (b.bitsRead - 8) + b.bitsRead -= 8 + b.off-- + } +} + +// finished returns true if all bits have been read from the bit stream. +func (b *bitReaderBytes) finished() bool { + return b.off == 0 && b.bitsRead >= 64 +} + +func (b *bitReaderBytes) remaining() uint { + return b.off*8 + uint(64-b.bitsRead) +} + +// close the bitstream and returns an error if out-of-buffer reads occurred. +func (b *bitReaderBytes) close() error { + // Release reference. + b.in = nil + if b.remaining() > 0 { + return fmt.Errorf("corrupt input: %d bits remain on stream", b.remaining()) + } + if b.bitsRead > 64 { + return io.ErrUnexpectedEOF + } + return nil +} + +// bitReaderShifted reads a bitstream in reverse. +// The last set bit indicates the start of the stream and is used +// for aligning the input. +type bitReaderShifted struct { + in []byte + off uint // next byte to read is at in[off - 1] + value uint64 + bitsRead uint8 +} + +// init initializes and resets the bit reader. +func (b *bitReaderShifted) init(in []byte) error { + if len(in) < 1 { + return errors.New("corrupt stream: too short") + } + b.in = in + b.off = uint(len(in)) + // The highest bit of the last byte indicates where to start + v := in[len(in)-1] + if v == 0 { + return errors.New("corrupt stream, did not find end of stream") + } + b.bitsRead = 64 + b.value = 0 + if len(in) >= 8 { + b.fillFastStart() + } else { + b.fill() + b.fill() + } + b.advance(8 - uint8(highBit32(uint32(v)))) + return nil +} + +// peekBitsFast requires that at least one bit is requested every time. +// There are no checks if the buffer is filled. +func (b *bitReaderShifted) peekBitsFast(n uint8) uint16 { + return uint16(b.value >> ((64 - n) & 63)) +} + +func (b *bitReaderShifted) advance(n uint8) { + b.bitsRead += n + b.value <<= n & 63 +} + +// fillFast() will make sure at least 32 bits are available. +// There must be at least 4 bytes available. +func (b *bitReaderShifted) fillFast() { + if b.bitsRead < 32 { + return + } + + low := le.Load32(b.in, b.off-4) + b.value |= uint64(low) << ((b.bitsRead - 32) & 63) + b.bitsRead -= 32 + b.off -= 4 +} + +// fillFastStart() assumes the bitReaderShifted is empty and there is at least 8 bytes to read. +func (b *bitReaderShifted) fillFastStart() { + b.value = le.Load64(b.in, b.off-8) + b.bitsRead = 0 + b.off -= 8 +} + +// fill() will make sure at least 32 bits are available. +func (b *bitReaderShifted) fill() { + if b.bitsRead < 32 { + return + } + if b.off > 4 { + low := le.Load32(b.in, b.off-4) + b.value |= uint64(low) << ((b.bitsRead - 32) & 63) + b.bitsRead -= 32 + b.off -= 4 + return + } + for b.off > 0 { + b.value |= uint64(b.in[b.off-1]) << ((b.bitsRead - 8) & 63) + b.bitsRead -= 8 + b.off-- + } +} + +func (b *bitReaderShifted) remaining() uint { + return b.off*8 + uint(64-b.bitsRead) +} + +// close the bitstream and returns an error if out-of-buffer reads occurred. +func (b *bitReaderShifted) close() error { + // Release reference. + b.in = nil + if b.remaining() > 0 { + return fmt.Errorf("corrupt input: %d bits remain on stream", b.remaining()) + } + if b.bitsRead > 64 { + return io.ErrUnexpectedEOF + } + return nil +} diff --git a/vendor/github.com/klauspost/compress/huff0/bitwriter.go b/vendor/github.com/klauspost/compress/huff0/bitwriter.go new file mode 100644 index 0000000..41db94c --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/bitwriter.go @@ -0,0 +1,102 @@ +// Copyright 2018 Klaus Post. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// Based on work Copyright (c) 2013, Yann Collet, released under BSD License. + +package huff0 + +// bitWriter will write bits. +// First bit will be LSB of the first byte of output. +type bitWriter struct { + bitContainer uint64 + nBits uint8 + out []byte +} + +// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated. +// It will not check if there is space for them, so the caller must ensure that it has flushed recently. +func (b *bitWriter) addBits16Clean(value uint16, bits uint8) { + b.bitContainer |= uint64(value) << (b.nBits & 63) + b.nBits += bits +} + +// encSymbol will add up to 16 bits. value may not contain more set bits than indicated. +// It will not check if there is space for them, so the caller must ensure that it has flushed recently. +func (b *bitWriter) encSymbol(ct cTable, symbol byte) { + enc := ct[symbol] + b.bitContainer |= uint64(enc.val) << (b.nBits & 63) + if false { + if enc.nBits == 0 { + panic("nbits 0") + } + } + b.nBits += enc.nBits +} + +// encTwoSymbols will add up to 32 bits. value may not contain more set bits than indicated. +// It will not check if there is space for them, so the caller must ensure that it has flushed recently. +func (b *bitWriter) encTwoSymbols(ct cTable, av, bv byte) { + encA := ct[av] + encB := ct[bv] + sh := b.nBits & 63 + combined := uint64(encA.val) | (uint64(encB.val) << (encA.nBits & 63)) + b.bitContainer |= combined << sh + if false { + if encA.nBits == 0 { + panic("nbitsA 0") + } + if encB.nBits == 0 { + panic("nbitsB 0") + } + } + b.nBits += encA.nBits + encB.nBits +} + +// encFourSymbols adds up to 32 bits from four symbols. +// It will not check if there is space for them, +// so the caller must ensure that b has been flushed recently. +func (b *bitWriter) encFourSymbols(encA, encB, encC, encD cTableEntry) { + bitsA := encA.nBits + bitsB := bitsA + encB.nBits + bitsC := bitsB + encC.nBits + bitsD := bitsC + encD.nBits + combined := uint64(encA.val) | + (uint64(encB.val) << (bitsA & 63)) | + (uint64(encC.val) << (bitsB & 63)) | + (uint64(encD.val) << (bitsC & 63)) + b.bitContainer |= combined << (b.nBits & 63) + b.nBits += bitsD +} + +// flush32 will flush out, so there are at least 32 bits available for writing. +func (b *bitWriter) flush32() { + if b.nBits < 32 { + return + } + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + byte(b.bitContainer>>16), + byte(b.bitContainer>>24)) + b.nBits -= 32 + b.bitContainer >>= 32 +} + +// flushAlign will flush remaining full bytes and align to next byte boundary. +func (b *bitWriter) flushAlign() { + nbBytes := (b.nBits + 7) >> 3 + for i := range nbBytes { + b.out = append(b.out, byte(b.bitContainer>>(i*8))) + } + b.nBits = 0 + b.bitContainer = 0 +} + +// close will write the alignment bit and write the final byte(s) +// to the output. +func (b *bitWriter) close() { + // End mark + b.addBits16Clean(1, 1) + // flush until next byte. + b.flushAlign() +} diff --git a/vendor/github.com/klauspost/compress/huff0/build_table.go b/vendor/github.com/klauspost/compress/huff0/build_table.go new file mode 100644 index 0000000..e3757c8 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/build_table.go @@ -0,0 +1,168 @@ +package huff0 + +import "errors" + +// BuildCTable builds a Huffman compression table from a precomputed symbol +// histogram and installs it as the previous (reuse) table on s. +// +// After this call: +// - EstimateSize/CanUseTable can probe the table against other histograms. +// - Compress1X/Compress4X with Reuse = ReusePolicyMust will encode without +// emitting a new table header. +// - TransferCTable can hand the table to a sibling Scratch. +// +// count[i] is the number of occurrences of symbol i. The histogram must have +// at least 2 distinct non-zero symbols; ErrUseRLE is returned for a single +// symbol and an error is returned for an empty histogram. +func (s *Scratch) BuildCTable(count *[256]uint32) error { + if s == nil { + return errors.New("huff0: BuildCTable on nil Scratch") + } + if count == nil { + return errors.New("huff0: nil count passed to BuildCTable") + } + var err error + s, err = s.prepare(nil) + if err != nil { + return err + } + s.count = *count + var total, maxCount int + var symLen uint16 + for i, v := range s.count { + total += int(v) + if int(v) > maxCount { + maxCount = int(v) + } + if v != 0 { + symLen = uint16(i) + 1 + } + } + if total == 0 { + return errors.New("huff0: empty histogram") + } + if symLen < 2 || maxCount == total { + return ErrUseRLE + } + // huff0's internal rank table assumes total ≤ BlockSizeMax (it uses + // highBit32(count+1) + 1 as a rank index into a fixed-size array). + // Histograms summed across multiple blocks can exceed that; scale the + // counts down preserving the distribution. Non-zero entries round up so + // rare symbols stay representable. + if total > BlockSizeMax { + shift := uint(0) + for total>>shift > BlockSizeMax { + shift++ + } + round := uint32(1<> shift + if scaled == 0 { + scaled = 1 + } + s.count[i] = scaled + newTotal += int(scaled) + if int(scaled) > newMax { + newMax = int(scaled) + } + } + total = newTotal + maxCount = newMax + if maxCount == total { + return ErrUseRLE + } + } + s.symbolLen = symLen + s.maxCount = maxCount + s.srcLen = total + if err := s.buildCTable(); err != nil { + return err + } + if cap(s.prevTable) < len(s.cTable) { + s.prevTable = make(cTable, 0, maxSymbolValue+1) + } + s.prevTable = s.prevTable[:len(s.cTable)] + copy(s.prevTable, s.cTable) + s.prevTableLog = s.actualTableLog + // Force the next Compress* to recount from real input. + s.clearCount = true + s.maxCount = 0 + return nil +} + +// EstimateSize returns an estimated compressed payload size in bytes for the +// supplied histogram using the table currently stored in prevTable. It returns +// -1 when the table cannot encode every non-zero symbol of hist (i.e. when +// CanUseTable would return false). The estimate excludes the table header. +func (s *Scratch) EstimateSize(hist *[256]uint32) int { + if s == nil || hist == nil || len(s.prevTable) == 0 { + return -1 + } + pt := s.prevTable + nbBits := uint32(7) + for i, v := range hist { + if v == 0 { + continue + } + if i >= len(pt) || pt[i].nBits == 0 { + return -1 + } + nbBits += uint32(pt[i].nBits) * v + } + return int(nbBits >> 3) +} + +// CanUseTable reports whether the table in prevTable can encode every +// non-zero symbol present in hist. +func (s *Scratch) CanUseTable(hist *[256]uint32) bool { + if s == nil || hist == nil || len(s.prevTable) == 0 { + return false + } + pt := s.prevTable + for i, v := range hist { + if v == 0 { + continue + } + if i >= len(pt) || pt[i].nBits == 0 { + return false + } + } + return true +} + +// AppendTable serializes the table currently stored in prevTable (e.g. as +// installed by BuildCTable or carried over from a previous Compress call) +// into a self-delimiting zstd-style header and appends it to dst. The +// returned slice can be parsed back by ReadTable. +func (s *Scratch) AppendTable(dst []byte) ([]byte, error) { + if s == nil || len(s.prevTable) == 0 { + return dst, errors.New("huff0: AppendTable with empty table") + } + // cTable.write reads s.actualTableLog, s.symbolLen, s.huffWeight, s.fse + // and writes into s.Out. Save/restore Out so we don't disturb in-flight + // compression buffers. + saveOut := s.Out + saveTL := s.actualTableLog + saveSL := s.symbolLen + if s.fse == nil { + // Lazily init in case AppendTable is called on a fresh Scratch. + if _, err := s.prepare(nil); err != nil { + return dst, err + } + saveOut = s.Out + } + s.Out = s.Out[:0] + s.actualTableLog = s.prevTableLog + s.symbolLen = uint16(len(s.prevTable)) + if err := s.prevTable.write(s); err != nil { + s.Out, s.actualTableLog, s.symbolLen = saveOut, saveTL, saveSL + return dst, err + } + dst = append(dst, s.Out...) + s.Out, s.actualTableLog, s.symbolLen = saveOut, saveTL, saveSL + return dst, nil +} diff --git a/vendor/github.com/klauspost/compress/huff0/compress.go b/vendor/github.com/klauspost/compress/huff0/compress.go new file mode 100644 index 0000000..a97cf1b --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/compress.go @@ -0,0 +1,742 @@ +package huff0 + +import ( + "fmt" + "math" + "runtime" + "sync" +) + +// Compress1X will compress the input. +// The output can be decoded using Decompress1X. +// Supply a Scratch object. The scratch object contains state about re-use, +// So when sharing across independent encodes, be sure to set the re-use policy. +func Compress1X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) { + s, err = s.prepare(in) + if err != nil { + return nil, false, err + } + return compress(in, s, s.compress1X) +} + +// Compress4X will compress the input. The input is split into 4 independent blocks +// and compressed similar to Compress1X. +// The output can be decoded using Decompress4X. +// Supply a Scratch object. The scratch object contains state about re-use, +// So when sharing across independent encodes, be sure to set the re-use policy. +func Compress4X(in []byte, s *Scratch) (out []byte, reUsed bool, err error) { + s, err = s.prepare(in) + if err != nil { + return nil, false, err + } + if false { + // TODO: compress4Xp only slightly faster. + const parallelThreshold = 8 << 10 + if len(in) < parallelThreshold || runtime.GOMAXPROCS(0) == 1 { + return compress(in, s, s.compress4X) + } + return compress(in, s, s.compress4Xp) + } + return compress(in, s, s.compress4X) +} + +func compress(in []byte, s *Scratch, compressor func(src []byte) ([]byte, error)) (out []byte, reUsed bool, err error) { + // Nuke previous table if we cannot reuse anyway. + if s.Reuse == ReusePolicyNone { + s.prevTable = s.prevTable[:0] + } + + // Create histogram, if none was provided. + maxCount := s.maxCount + var canReuse = false + if maxCount == 0 { + maxCount, canReuse = s.countSimple(in) + } else { + canReuse = s.canUseTable(s.prevTable) + } + + // We want the output size to be less than this: + wantSize := len(in) + if s.WantLogLess > 0 { + wantSize -= wantSize >> s.WantLogLess + } + + // Reset for next run. + s.clearCount = true + s.maxCount = 0 + if maxCount >= len(in) { + if maxCount > len(in) { + return nil, false, fmt.Errorf("maxCount (%d) > length (%d)", maxCount, len(in)) + } + if len(in) == 1 { + return nil, false, ErrIncompressible + } + // One symbol, use RLE + return nil, false, ErrUseRLE + } + if maxCount == 1 || maxCount < (len(in)>>7) { + // Each symbol present maximum once or too well distributed. + return nil, false, ErrIncompressible + } + if s.Reuse == ReusePolicyMust && !canReuse { + // We must reuse, but we can't. + return nil, false, ErrIncompressible + } + if (s.Reuse == ReusePolicyPrefer || s.Reuse == ReusePolicyMust) && canReuse { + keepTable := s.cTable + keepTL := s.actualTableLog + s.cTable = s.prevTable + s.actualTableLog = s.prevTableLog + s.Out, err = compressor(in) + s.cTable = keepTable + s.actualTableLog = keepTL + if err == nil && len(s.Out) < wantSize { + s.OutData = s.Out + return s.Out, true, nil + } + if s.Reuse == ReusePolicyMust { + return nil, false, ErrIncompressible + } + // Do not attempt to re-use later. + s.prevTable = s.prevTable[:0] + } + + // Calculate new table. + err = s.buildCTable() + if err != nil { + return nil, false, err + } + + if false && !s.canUseTable(s.cTable) { + panic("invalid table generated") + } + + if s.Reuse == ReusePolicyAllow && canReuse { + hSize := len(s.Out) + oldSize := s.prevTable.estimateSize(s.count[:s.symbolLen]) + newSize := s.cTable.estimateSize(s.count[:s.symbolLen]) + if oldSize <= hSize+newSize || hSize+12 >= wantSize { + // Retain cTable even if we re-use. + keepTable := s.cTable + keepTL := s.actualTableLog + + s.cTable = s.prevTable + s.actualTableLog = s.prevTableLog + s.Out, err = compressor(in) + + // Restore ctable. + s.cTable = keepTable + s.actualTableLog = keepTL + if err != nil { + return nil, false, err + } + if len(s.Out) >= wantSize { + return nil, false, ErrIncompressible + } + s.OutData = s.Out + return s.Out, true, nil + } + } + + // Use new table + err = s.cTable.write(s) + if err != nil { + s.OutTable = nil + return nil, false, err + } + s.OutTable = s.Out + + // Compress using new table + s.Out, err = compressor(in) + if err != nil { + s.OutTable = nil + return nil, false, err + } + if len(s.Out) >= wantSize { + s.OutTable = nil + return nil, false, ErrIncompressible + } + // Move current table into previous. + s.prevTable, s.prevTableLog, s.cTable = s.cTable, s.actualTableLog, s.prevTable[:0] + s.OutData = s.Out[len(s.OutTable):] + return s.Out, false, nil +} + +// EstimateSizes will estimate the data sizes +func EstimateSizes(in []byte, s *Scratch) (tableSz, dataSz, reuseSz int, err error) { + s, err = s.prepare(in) + if err != nil { + return 0, 0, 0, err + } + + // Create histogram, if none was provided. + tableSz, dataSz, reuseSz = -1, -1, -1 + maxCount := s.maxCount + var canReuse = false + if maxCount == 0 { + maxCount, canReuse = s.countSimple(in) + } else { + canReuse = s.canUseTable(s.prevTable) + } + + // We want the output size to be less than this: + wantSize := len(in) + if s.WantLogLess > 0 { + wantSize -= wantSize >> s.WantLogLess + } + + // Reset for next run. + s.clearCount = true + s.maxCount = 0 + if maxCount >= len(in) { + if maxCount > len(in) { + return 0, 0, 0, fmt.Errorf("maxCount (%d) > length (%d)", maxCount, len(in)) + } + if len(in) == 1 { + return 0, 0, 0, ErrIncompressible + } + // One symbol, use RLE + return 0, 0, 0, ErrUseRLE + } + if maxCount == 1 || maxCount < (len(in)>>7) { + // Each symbol present maximum once or too well distributed. + return 0, 0, 0, ErrIncompressible + } + + // Calculate new table. + err = s.buildCTable() + if err != nil { + return 0, 0, 0, err + } + + if false && !s.canUseTable(s.cTable) { + panic("invalid table generated") + } + + tableSz, err = s.cTable.estTableSize(s) + if err != nil { + return 0, 0, 0, err + } + if canReuse { + reuseSz = s.prevTable.estimateSize(s.count[:s.symbolLen]) + } + dataSz = s.cTable.estimateSize(s.count[:s.symbolLen]) + + // Restore + return tableSz, dataSz, reuseSz, nil +} + +func (s *Scratch) compress1X(src []byte) ([]byte, error) { + return s.compress1xDo(s.Out, src), nil +} + +func (s *Scratch) compress1xDo(dst, src []byte) []byte { + var bw = bitWriter{out: dst} + + // N is length divisible by 4. + n := len(src) + n -= n & 3 + cTable := s.cTable[:256] + + // Encode last bytes. + for i := len(src) & 3; i > 0; i-- { + bw.encSymbol(cTable, src[n+i-1]) + } + n -= 4 + if s.actualTableLog <= 8 { + for ; n >= 0; n -= 4 { + tmp := src[n : n+4] + // tmp should be len 4 + bw.flush32() + bw.encFourSymbols(cTable[tmp[3]], cTable[tmp[2]], cTable[tmp[1]], cTable[tmp[0]]) + } + } else { + for ; n >= 0; n -= 4 { + tmp := src[n : n+4] + // tmp should be len 4 + bw.flush32() + bw.encTwoSymbols(cTable, tmp[3], tmp[2]) + bw.flush32() + bw.encTwoSymbols(cTable, tmp[1], tmp[0]) + } + } + bw.close() + return bw.out +} + +var sixZeros [6]byte + +func (s *Scratch) compress4X(src []byte) ([]byte, error) { + if len(src) < 12 { + return nil, ErrIncompressible + } + segmentSize := (len(src) + 3) / 4 + + // Add placeholder for output length + offsetIdx := len(s.Out) + s.Out = append(s.Out, sixZeros[:]...) + + for i := range 4 { + toDo := src + if len(toDo) > segmentSize { + toDo = toDo[:segmentSize] + } + src = src[len(toDo):] + + idx := len(s.Out) + s.Out = s.compress1xDo(s.Out, toDo) + if len(s.Out)-idx > math.MaxUint16 { + // We cannot store the size in the jump table + return nil, ErrIncompressible + } + // Write compressed length as little endian before block. + if i < 3 { + // Last length is not written. + length := len(s.Out) - idx + s.Out[i*2+offsetIdx] = byte(length) + s.Out[i*2+offsetIdx+1] = byte(length >> 8) + } + } + + return s.Out, nil +} + +// compress4Xp will compress 4 streams using separate goroutines. +func (s *Scratch) compress4Xp(src []byte) ([]byte, error) { + if len(src) < 12 { + return nil, ErrIncompressible + } + // Add placeholder for output length + s.Out = s.Out[:6] + + segmentSize := (len(src) + 3) / 4 + var wg sync.WaitGroup + wg.Add(4) + for i := range 4 { + toDo := src + if len(toDo) > segmentSize { + toDo = toDo[:segmentSize] + } + src = src[len(toDo):] + + // Separate goroutine for each block. + go func(i int) { + s.tmpOut[i] = s.compress1xDo(s.tmpOut[i][:0], toDo) + wg.Done() + }(i) + } + wg.Wait() + for i := range 4 { + o := s.tmpOut[i] + if len(o) > math.MaxUint16 { + // We cannot store the size in the jump table + return nil, ErrIncompressible + } + // Write compressed length as little endian before block. + if i < 3 { + // Last length is not written. + s.Out[i*2] = byte(len(o)) + s.Out[i*2+1] = byte(len(o) >> 8) + } + + // Write output. + s.Out = append(s.Out, o...) + } + return s.Out, nil +} + +// countSimple will create a simple histogram in s.count. +// Returns the biggest count. +// Does not update s.clearCount. +func (s *Scratch) countSimple(in []byte) (max int, reuse bool) { + reuse = true + _ = s.count // Assert that s != nil to speed up the following loop. + for _, v := range in { + s.count[v]++ + } + m := uint32(0) + if len(s.prevTable) > 0 { + for i, v := range s.count[:] { + if v == 0 { + continue + } + if v > m { + m = v + } + s.symbolLen = uint16(i) + 1 + if i >= len(s.prevTable) { + reuse = false + } else if s.prevTable[i].nBits == 0 { + reuse = false + } + } + return int(m), reuse + } + for i, v := range s.count[:] { + if v == 0 { + continue + } + if v > m { + m = v + } + s.symbolLen = uint16(i) + 1 + } + return int(m), false +} + +func (s *Scratch) canUseTable(c cTable) bool { + if len(c) < int(s.symbolLen) { + return false + } + for i, v := range s.count[:s.symbolLen] { + if v != 0 && c[i].nBits == 0 { + return false + } + } + return true +} + +//lint:ignore U1000 used for debugging +func (s *Scratch) validateTable(c cTable) bool { + if len(c) < int(s.symbolLen) { + return false + } + for i, v := range s.count[:s.symbolLen] { + if v != 0 { + if c[i].nBits == 0 { + return false + } + if c[i].nBits > s.actualTableLog { + return false + } + } + } + return true +} + +// minTableLog provides the minimum logSize to safely represent a distribution. +func (s *Scratch) minTableLog() uint8 { + minBitsSrc := highBit32(uint32(s.srcLen)) + 1 + minBitsSymbols := highBit32(uint32(s.symbolLen-1)) + 2 + if minBitsSrc < minBitsSymbols { + return uint8(minBitsSrc) + } + return uint8(minBitsSymbols) +} + +// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog +func (s *Scratch) optimalTableLog() { + tableLog := s.TableLog + minBits := s.minTableLog() + maxBitsSrc := uint8(highBit32(uint32(s.srcLen-1))) - 1 + if maxBitsSrc < tableLog { + // Accuracy can be reduced + tableLog = maxBitsSrc + } + if minBits > tableLog { + tableLog = minBits + } + // Need a minimum to safely represent all symbol values + if tableLog < minTablelog { + tableLog = minTablelog + } + if tableLog > tableLogMax { + tableLog = tableLogMax + } + s.actualTableLog = tableLog +} + +type cTableEntry struct { + val uint16 + nBits uint8 + // We have 8 bits extra +} + +const huffNodesMask = huffNodesLen - 1 + +func (s *Scratch) buildCTable() error { + s.optimalTableLog() + s.huffSort() + if cap(s.cTable) < maxSymbolValue+1 { + s.cTable = make([]cTableEntry, s.symbolLen, maxSymbolValue+1) + } else { + s.cTable = s.cTable[:s.symbolLen] + for i := range s.cTable { + s.cTable[i] = cTableEntry{} + } + } + + var startNode = int16(s.symbolLen) + nonNullRank := s.symbolLen - 1 + + nodeNb := startNode + huffNode := s.nodes[1 : huffNodesLen+1] + + // This overlays the slice above, but allows "-1" index lookups. + // Different from reference implementation. + huffNode0 := s.nodes[0 : huffNodesLen+1] + + for huffNode[nonNullRank].count() == 0 { + nonNullRank-- + } + + lowS := int16(nonNullRank) + nodeRoot := nodeNb + lowS - 1 + lowN := nodeNb + huffNode[nodeNb].setCount(huffNode[lowS].count() + huffNode[lowS-1].count()) + huffNode[lowS].setParent(nodeNb) + huffNode[lowS-1].setParent(nodeNb) + nodeNb++ + lowS -= 2 + for n := nodeNb; n <= nodeRoot; n++ { + huffNode[n].setCount(1 << 30) + } + // fake entry, strong barrier + huffNode0[0].setCount(1 << 31) + + // create parents + for nodeNb <= nodeRoot { + var n1, n2 int16 + if huffNode0[lowS+1].count() < huffNode0[lowN+1].count() { + n1 = lowS + lowS-- + } else { + n1 = lowN + lowN++ + } + if huffNode0[lowS+1].count() < huffNode0[lowN+1].count() { + n2 = lowS + lowS-- + } else { + n2 = lowN + lowN++ + } + + huffNode[nodeNb].setCount(huffNode0[n1+1].count() + huffNode0[n2+1].count()) + huffNode0[n1+1].setParent(nodeNb) + huffNode0[n2+1].setParent(nodeNb) + nodeNb++ + } + + // distribute weights (unlimited tree height) + huffNode[nodeRoot].setNbBits(0) + for n := nodeRoot - 1; n >= startNode; n-- { + huffNode[n].setNbBits(huffNode[huffNode[n].parent()].nbBits() + 1) + } + for n := uint16(0); n <= nonNullRank; n++ { + huffNode[n].setNbBits(huffNode[huffNode[n].parent()].nbBits() + 1) + } + s.actualTableLog = s.setMaxHeight(int(nonNullRank)) + maxNbBits := s.actualTableLog + + // fill result into tree (val, nbBits) + if maxNbBits > tableLogMax { + return fmt.Errorf("internal error: maxNbBits (%d) > tableLogMax (%d)", maxNbBits, tableLogMax) + } + var nbPerRank [tableLogMax + 1]uint16 + var valPerRank [16]uint16 + for _, v := range huffNode[:nonNullRank+1] { + nbPerRank[v.nbBits()]++ + } + // determine stating value per rank + { + min := uint16(0) + for n := maxNbBits; n > 0; n-- { + // get starting value within each rank + valPerRank[n] = min + min += nbPerRank[n] + min >>= 1 + } + } + + // push nbBits per symbol, symbol order + for _, v := range huffNode[:nonNullRank+1] { + s.cTable[v.symbol()].nBits = v.nbBits() + } + + // assign value within rank, symbol order + t := s.cTable[:s.symbolLen] + for n, val := range t { + nbits := val.nBits & 15 + v := valPerRank[nbits] + t[n].val = v + valPerRank[nbits] = v + 1 + } + + return nil +} + +// huffSort will sort symbols, decreasing order. +func (s *Scratch) huffSort() { + type rankPos struct { + base uint32 + current uint32 + } + + // Clear nodes + nodes := s.nodes[:huffNodesLen+1] + s.nodes = nodes + nodes = nodes[1 : huffNodesLen+1] + + // Sort into buckets based on length of symbol count. + var rank [32]rankPos + for _, v := range s.count[:s.symbolLen] { + r := highBit32(v+1) & 31 + rank[r].base++ + } + // maxBitLength is log2(BlockSizeMax) + 1 + const maxBitLength = 18 + 1 + for n := maxBitLength; n > 0; n-- { + rank[n-1].base += rank[n].base + } + for n := range rank[:maxBitLength] { + rank[n].current = rank[n].base + } + for n, c := range s.count[:s.symbolLen] { + r := (highBit32(c+1) + 1) & 31 + pos := rank[r].current + rank[r].current++ + prev := nodes[(pos-1)&huffNodesMask] + for pos > rank[r].base && c > prev.count() { + nodes[pos&huffNodesMask] = prev + pos-- + prev = nodes[(pos-1)&huffNodesMask] + } + nodes[pos&huffNodesMask] = makeNodeElt(c, byte(n)) + } +} + +func (s *Scratch) setMaxHeight(lastNonNull int) uint8 { + maxNbBits := s.actualTableLog + huffNode := s.nodes[1 : huffNodesLen+1] + //huffNode = huffNode[: huffNodesLen] + + largestBits := huffNode[lastNonNull].nbBits() + + // early exit : no elt > maxNbBits + if largestBits <= maxNbBits { + return largestBits + } + totalCost := int(0) + baseCost := int(1) << (largestBits - maxNbBits) + n := uint32(lastNonNull) + + for huffNode[n].nbBits() > maxNbBits { + totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits())) + huffNode[n].setNbBits(maxNbBits) + n-- + } + // n stops at huffNode[n].nbBits <= maxNbBits + + for huffNode[n].nbBits() == maxNbBits { + n-- + } + // n end at index of smallest symbol using < maxNbBits + + // renorm totalCost + totalCost >>= largestBits - maxNbBits /* note : totalCost is necessarily a multiple of baseCost */ + + // repay normalized cost + { + const noSymbol = 0xF0F0F0F0 + var rankLast [tableLogMax + 2]uint32 + + for i := range rankLast[:] { + rankLast[i] = noSymbol + } + + // Get pos of last (smallest) symbol per rank + { + currentNbBits := maxNbBits + for pos := int(n); pos >= 0; pos-- { + if huffNode[pos].nbBits() >= currentNbBits { + continue + } + currentNbBits = huffNode[pos].nbBits() // < maxNbBits + rankLast[maxNbBits-currentNbBits] = uint32(pos) + } + } + + for totalCost > 0 { + nBitsToDecrease := uint8(highBit32(uint32(totalCost))) + 1 + + for ; nBitsToDecrease > 1; nBitsToDecrease-- { + highPos := rankLast[nBitsToDecrease] + lowPos := rankLast[nBitsToDecrease-1] + if highPos == noSymbol { + continue + } + if lowPos == noSymbol { + break + } + highTotal := huffNode[highPos].count() + lowTotal := 2 * huffNode[lowPos].count() + if highTotal <= lowTotal { + break + } + } + // only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) + // HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary + // FIXME: try to remove + for (nBitsToDecrease <= tableLogMax) && (rankLast[nBitsToDecrease] == noSymbol) { + nBitsToDecrease++ + } + totalCost -= 1 << (nBitsToDecrease - 1) + if rankLast[nBitsToDecrease-1] == noSymbol { + // this rank is no longer empty + rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease] + } + huffNode[rankLast[nBitsToDecrease]].setNbBits(1 + + huffNode[rankLast[nBitsToDecrease]].nbBits()) + if rankLast[nBitsToDecrease] == 0 { + /* special case, reached largest symbol */ + rankLast[nBitsToDecrease] = noSymbol + } else { + rankLast[nBitsToDecrease]-- + if huffNode[rankLast[nBitsToDecrease]].nbBits() != maxNbBits-nBitsToDecrease { + rankLast[nBitsToDecrease] = noSymbol /* this rank is now empty */ + } + } + } + + for totalCost < 0 { /* Sometimes, cost correction overshoot */ + if rankLast[1] == noSymbol { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */ + for huffNode[n].nbBits() == maxNbBits { + n-- + } + huffNode[n+1].setNbBits(huffNode[n+1].nbBits() - 1) + rankLast[1] = n + 1 + totalCost++ + continue + } + huffNode[rankLast[1]+1].setNbBits(huffNode[rankLast[1]+1].nbBits() - 1) + rankLast[1]++ + totalCost++ + } + } + return maxNbBits +} + +// A nodeElt is the fields +// +// count uint32 +// parent uint16 +// symbol byte +// nbBits uint8 +// +// in some order, all squashed into an integer so that the compiler +// always loads and stores entire nodeElts instead of separate fields. +type nodeElt uint64 + +func makeNodeElt(count uint32, symbol byte) nodeElt { + return nodeElt(count) | nodeElt(symbol)<<48 +} + +func (e *nodeElt) count() uint32 { return uint32(*e) } +func (e *nodeElt) parent() uint16 { return uint16(*e >> 32) } +func (e *nodeElt) symbol() byte { return byte(*e >> 48) } +func (e *nodeElt) nbBits() uint8 { return uint8(*e >> 56) } + +func (e *nodeElt) setCount(c uint32) { *e = (*e)&0xffffffff00000000 | nodeElt(c) } +func (e *nodeElt) setParent(p int16) { *e = (*e)&0xffff0000ffffffff | nodeElt(uint16(p))<<32 } +func (e *nodeElt) setNbBits(n uint8) { *e = (*e)&0x00ffffffffffffff | nodeElt(n)<<56 } diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go new file mode 100644 index 0000000..7d0efa8 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress.go @@ -0,0 +1,1161 @@ +package huff0 + +import ( + "errors" + "fmt" + "io" + "sync" + + "github.com/klauspost/compress/fse" +) + +type dTable struct { + single []dEntrySingle +} + +// single-symbols decoding +type dEntrySingle struct { + entry uint16 +} + +// Uses special code for all tables that are < 8 bits. +const use8BitTables = true + +// ReadTable will read a table from the input. +// The size of the input may be larger than the table definition. +// Any content remaining after the table definition will be returned. +// If no Scratch is provided a new one is allocated. +// The returned Scratch can be used for encoding or decoding input using this table. +func ReadTable(in []byte, s *Scratch) (s2 *Scratch, remain []byte, err error) { + s, err = s.prepare(nil) + if err != nil { + return s, nil, err + } + if len(in) <= 1 { + return s, nil, errors.New("input too small for table") + } + iSize := in[0] + in = in[1:] + if iSize >= 128 { + // Uncompressed + oSize := iSize - 127 + iSize = (oSize + 1) / 2 + if int(iSize) > len(in) { + return s, nil, errors.New("input too small for table") + } + for n := uint8(0); n < oSize; n += 2 { + v := in[n/2] + s.huffWeight[n] = v >> 4 + s.huffWeight[n+1] = v & 15 + } + s.symbolLen = uint16(oSize) + in = in[iSize:] + } else { + if len(in) < int(iSize) { + return s, nil, fmt.Errorf("input too small for table, want %d bytes, have %d", iSize, len(in)) + } + // FSE compressed weights + s.fse.DecompressLimit = 255 + hw := s.huffWeight[:] + s.fse.Out = hw + b, err := fse.Decompress(in[:iSize], s.fse) + s.fse.Out = nil + if err != nil { + return s, nil, fmt.Errorf("fse decompress returned: %w", err) + } + if len(b) > 255 { + return s, nil, errors.New("corrupt input: output table too large") + } + s.symbolLen = uint16(len(b)) + in = in[iSize:] + } + + // collect weight stats + var rankStats [16]uint32 + weightTotal := uint32(0) + for _, v := range s.huffWeight[:s.symbolLen] { + if v > tableLogMax { + return s, nil, errors.New("corrupt input: weight too large") + } + v2 := v & 15 + rankStats[v2]++ + // (1 << (v2-1)) is slower since the compiler cannot prove that v2 isn't 0. + weightTotal += (1 << v2) >> 1 + } + if weightTotal == 0 { + return s, nil, errors.New("corrupt input: weights zero") + } + + // get last non-null symbol weight (implied, total must be 2^n) + { + tableLog := highBit32(weightTotal) + 1 + if tableLog > tableLogMax { + return s, nil, errors.New("corrupt input: tableLog too big") + } + s.actualTableLog = uint8(tableLog) + // determine last weight + { + total := uint32(1) << tableLog + rest := total - weightTotal + verif := uint32(1) << highBit32(rest) + lastWeight := highBit32(rest) + 1 + if verif != rest { + // last value must be a clean power of 2 + return s, nil, errors.New("corrupt input: last value not power of two") + } + s.huffWeight[s.symbolLen] = uint8(lastWeight) + s.symbolLen++ + rankStats[lastWeight]++ + } + } + + if (rankStats[1] < 2) || (rankStats[1]&1 != 0) { + // by construction : at least 2 elts of rank 1, must be even + return s, nil, errors.New("corrupt input: min elt size, even check failed ") + } + + // TODO: Choose between single/double symbol decoding + + // Calculate starting value for each rank + { + var nextRankStart uint32 + for n := uint8(1); n < s.actualTableLog+1; n++ { + current := nextRankStart + nextRankStart += rankStats[n] << (n - 1) + rankStats[n] = current + } + } + + // fill DTable (always full size) + tSize := 1 << tableLogMax + if len(s.dt.single) != tSize { + s.dt.single = make([]dEntrySingle, tSize) + } + cTable := s.prevTable + if cap(cTable) < maxSymbolValue+1 { + cTable = make([]cTableEntry, 0, maxSymbolValue+1) + } + cTable = cTable[:maxSymbolValue+1] + s.prevTable = cTable[:s.symbolLen] + s.prevTableLog = s.actualTableLog + + for n, w := range s.huffWeight[:s.symbolLen] { + if w == 0 { + cTable[n] = cTableEntry{ + val: 0, + nBits: 0, + } + continue + } + length := (uint32(1) << w) >> 1 + d := dEntrySingle{ + entry: uint16(s.actualTableLog+1-w) | (uint16(n) << 8), + } + + rank := &rankStats[w] + cTable[n] = cTableEntry{ + val: uint16(*rank >> (w - 1)), + nBits: uint8(d.entry), + } + + single := s.dt.single[*rank : *rank+length] + for i := range single { + single[i] = d + } + *rank += length + } + + return s, in, nil +} + +// Decompress1X will decompress a 1X encoded stream. +// The length of the supplied input must match the end of a block exactly. +// Before this is called, the table must be initialized with ReadTable unless +// the encoder re-used the table. +// deprecated: Use the stateless Decoder() to get a concurrent version. +func (s *Scratch) Decompress1X(in []byte) (out []byte, err error) { + if cap(s.Out) < s.MaxDecodedSize { + s.Out = make([]byte, s.MaxDecodedSize) + } + s.Out = s.Out[:0:s.MaxDecodedSize] + s.Out, err = s.Decoder().Decompress1X(s.Out, in) + return s.Out, err +} + +// Decompress4X will decompress a 4X encoded stream. +// Before this is called, the table must be initialized with ReadTable unless +// the encoder re-used the table. +// The length of the supplied input must match the end of a block exactly. +// The destination size of the uncompressed data must be known and provided. +// deprecated: Use the stateless Decoder() to get a concurrent version. +func (s *Scratch) Decompress4X(in []byte, dstSize int) (out []byte, err error) { + if dstSize > s.MaxDecodedSize { + return nil, ErrMaxDecodedSizeExceeded + } + if cap(s.Out) < dstSize { + s.Out = make([]byte, s.MaxDecodedSize) + } + s.Out = s.Out[:0:dstSize] + s.Out, err = s.Decoder().Decompress4X(s.Out, in) + return s.Out, err +} + +// Decoder will return a stateless decoder that can be used by multiple +// decompressors concurrently. +// Before this is called, the table must be initialized with ReadTable. +// The Decoder is still linked to the scratch buffer so that cannot be reused. +// However, it is safe to discard the scratch. +func (s *Scratch) Decoder() *Decoder { + return &Decoder{ + dt: s.dt, + actualTableLog: s.actualTableLog, + bufs: &s.decPool, + } +} + +// Decoder provides stateless decoding. +type Decoder struct { + dt dTable + actualTableLog uint8 + bufs *sync.Pool +} + +func (d *Decoder) buffer() *[4][256]byte { + buf, ok := d.bufs.Get().(*[4][256]byte) + if ok { + return buf + } + return &[4][256]byte{} +} + +// decompress1X8Bit will decompress a 1X encoded stream with tablelog <= 8. +// The cap of the output buffer will be the maximum decompressed size. +// The length of the supplied input must match the end of a block exactly. +func (d *Decoder) decompress1X8Bit(dst, src []byte) ([]byte, error) { + if d.actualTableLog == 8 { + return d.decompress1X8BitExactly(dst, src) + } + var br bitReaderBytes + err := br.init(src) + if err != nil { + return dst, err + } + maxDecodedSize := cap(dst) + dst = dst[:0] + + // Avoid bounds check by always having full sized table. + dt := d.dt.single[:256] + + // Use temp table to avoid bound checks/append penalty. + bufs := d.buffer() + buf := &bufs[0] + var off uint8 + + switch d.actualTableLog { + case 8: + const shift = 0 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + d.bufs.Put(bufs) + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 7: + const shift = 8 - 7 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + d.bufs.Put(bufs) + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 6: + const shift = 8 - 6 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 5: + const shift = 8 - 5 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 4: + const shift = 8 - 4 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 3: + const shift = 8 - 3 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 2: + const shift = 8 - 2 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + case 1: + const shift = 8 - 1 + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>(56+shift))] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + default: + d.bufs.Put(bufs) + return nil, fmt.Errorf("invalid tablelog: %d", d.actualTableLog) + } + + if len(dst)+int(off) > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:off]...) + + // br < 4, so uint8 is fine + bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead)) + shift := (8 - d.actualTableLog) & 7 + + for bitsLeft > 0 { + if br.bitsRead >= 64-8 { + for br.off > 0 { + br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8) + br.bitsRead -= 8 + br.off-- + } + } + if len(dst) >= maxDecodedSize { + br.close() + d.bufs.Put(bufs) + return nil, ErrMaxDecodedSizeExceeded + } + v := dt[br.peekByteFast()>>shift] + nBits := uint8(v.entry) + br.advance(nBits) + bitsLeft -= int8(nBits) + dst = append(dst, uint8(v.entry>>8)) + } + d.bufs.Put(bufs) + return dst, br.close() +} + +// decompress1X8Bit will decompress a 1X encoded stream with tablelog <= 8. +// The cap of the output buffer will be the maximum decompressed size. +// The length of the supplied input must match the end of a block exactly. +func (d *Decoder) decompress1X8BitExactly(dst, src []byte) ([]byte, error) { + var br bitReaderBytes + err := br.init(src) + if err != nil { + return dst, err + } + maxDecodedSize := cap(dst) + dst = dst[:0] + + // Avoid bounds check by always having full sized table. + dt := d.dt.single[:256] + + // Use temp table to avoid bound checks/append penalty. + bufs := d.buffer() + buf := &bufs[0] + var off uint8 + + const shift = 56 + + //fmt.Printf("mask: %b, tl:%d\n", mask, d.actualTableLog) + for br.off >= 4 { + br.fillFast() + v := dt[uint8(br.value>>shift)] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>shift)] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>shift)] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[uint8(br.value>>shift)] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + + if len(dst)+int(off) > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:off]...) + + // br < 4, so uint8 is fine + bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead)) + for bitsLeft > 0 { + if br.bitsRead >= 64-8 { + for br.off > 0 { + br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8) + br.bitsRead -= 8 + br.off-- + } + } + if len(dst) >= maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + v := dt[br.peekByteFast()] + nBits := uint8(v.entry) + br.advance(nBits) + bitsLeft -= int8(nBits) + dst = append(dst, uint8(v.entry>>8)) + } + d.bufs.Put(bufs) + return dst, br.close() +} + +// Decompress4X will decompress a 4X encoded stream. +// The length of the supplied input must match the end of a block exactly. +// The *capacity* of the dst slice must match the destination size of +// the uncompressed data exactly. +func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) { + if d.actualTableLog == 8 { + return d.decompress4X8bitExactly(dst, src) + } + + var br [4]bitReaderBytes + start := 6 + for i := range 3 { + length := int(src[i*2]) | (int(src[i*2+1]) << 8) + if start+length >= len(src) { + return nil, errors.New("truncated input (or invalid offset)") + } + err := br[i].init(src[start : start+length]) + if err != nil { + return nil, err + } + start += length + } + err := br[3].init(src[start:]) + if err != nil { + return nil, err + } + + // destination, offset to match first output + dstSize := cap(dst) + dst = dst[:dstSize] + out := dst + dstEvery := (dstSize + 3) / 4 + + shift := (56 + (8 - d.actualTableLog)) & 63 + + const tlSize = 1 << 8 + single := d.dt.single[:tlSize] + + // Use temp table to avoid bound checks/append penalty. + buf := d.buffer() + var off uint8 + var decoded int + + // Decode 4 values from each decoder/loop. + const bufoff = 256 + for { + if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 { + break + } + + { + // Interleave 2 decodes. + const stream = 0 + const stream2 = 1 + br1 := &br[stream] + br2 := &br[stream2] + br1.fillFast() + br2.fillFast() + + v := single[uint8(br1.value>>shift)].entry + v2 := single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off] = uint8(v >> 8) + buf[stream2][off] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+1] = uint8(v >> 8) + buf[stream2][off+1] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+2] = uint8(v >> 8) + buf[stream2][off+2] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+3] = uint8(v >> 8) + buf[stream2][off+3] = uint8(v2 >> 8) + } + + { + const stream = 2 + const stream2 = 3 + br1 := &br[stream] + br2 := &br[stream2] + br1.fillFast() + br2.fillFast() + + v := single[uint8(br1.value>>shift)].entry + v2 := single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off] = uint8(v >> 8) + buf[stream2][off] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+1] = uint8(v >> 8) + buf[stream2][off+1] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+2] = uint8(v >> 8) + buf[stream2][off+2] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+3] = uint8(v >> 8) + buf[stream2][off+3] = uint8(v2 >> 8) + } + + off += 4 + + if off == 0 { + if bufoff > dstEvery { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 1") + } + // There must at least be 3 buffers left. + if len(out)-bufoff < dstEvery*3 { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 2") + } + //copy(out, buf[0][:]) + //copy(out[dstEvery:], buf[1][:]) + //copy(out[dstEvery*2:], buf[2][:]) + *(*[bufoff]byte)(out) = buf[0] + *(*[bufoff]byte)(out[dstEvery:]) = buf[1] + *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2] + *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3] + out = out[bufoff:] + decoded += bufoff * 4 + } + } + if off > 0 { + ioff := int(off) + if len(out) < dstEvery*3+ioff { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 3") + } + copy(out, buf[0][:off]) + copy(out[dstEvery:], buf[1][:off]) + copy(out[dstEvery*2:], buf[2][:off]) + copy(out[dstEvery*3:], buf[3][:off]) + decoded += int(off) * 4 + out = out[off:] + } + + // Decode remaining. + // Decode remaining. + remainBytes := dstEvery - (decoded / 4) + for i := range br { + offset := dstEvery * i + endsAt := min(offset+remainBytes, len(out)) + br := &br[i] + bitsLeft := br.remaining() + for bitsLeft > 0 { + if br.finished() { + d.bufs.Put(buf) + return nil, io.ErrUnexpectedEOF + } + if br.bitsRead >= 56 { + if br.off >= 4 { + v := br.in[br.off-4:] + v = v[:4] + low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24) + br.value |= uint64(low) << (br.bitsRead - 32) + br.bitsRead -= 32 + br.off -= 4 + } else { + for br.off > 0 { + br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8) + br.bitsRead -= 8 + br.off-- + } + } + } + // end inline... + if offset >= endsAt { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 4") + } + + // Read value and increment offset. + v := single[uint8(br.value>>shift)].entry + nBits := uint8(v) + br.advance(nBits) + bitsLeft -= uint(nBits) + out[offset] = uint8(v >> 8) + offset++ + } + if offset != endsAt { + d.bufs.Put(buf) + return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt) + } + decoded += offset - dstEvery*i + err = br.close() + if err != nil { + d.bufs.Put(buf) + return nil, err + } + } + d.bufs.Put(buf) + if dstSize != decoded { + return nil, errors.New("corruption detected: short output block") + } + return dst, nil +} + +// Decompress4X will decompress a 4X encoded stream. +// The length of the supplied input must match the end of a block exactly. +// The *capacity* of the dst slice must match the destination size of +// the uncompressed data exactly. +func (d *Decoder) decompress4X8bitExactly(dst, src []byte) ([]byte, error) { + var br [4]bitReaderBytes + start := 6 + for i := range 3 { + length := int(src[i*2]) | (int(src[i*2+1]) << 8) + if start+length >= len(src) { + return nil, errors.New("truncated input (or invalid offset)") + } + err := br[i].init(src[start : start+length]) + if err != nil { + return nil, err + } + start += length + } + err := br[3].init(src[start:]) + if err != nil { + return nil, err + } + + // destination, offset to match first output + dstSize := cap(dst) + dst = dst[:dstSize] + out := dst + dstEvery := (dstSize + 3) / 4 + + const shift = 56 + const tlSize = 1 << 8 + single := d.dt.single[:tlSize] + + // Use temp table to avoid bound checks/append penalty. + buf := d.buffer() + var off uint8 + var decoded int + + // Decode 4 values from each decoder/loop. + const bufoff = 256 + for { + if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 { + break + } + + { + // Interleave 2 decodes. + const stream = 0 + const stream2 = 1 + br1 := &br[stream] + br2 := &br[stream2] + br1.fillFast() + br2.fillFast() + + v := single[uint8(br1.value>>shift)].entry + v2 := single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off] = uint8(v >> 8) + buf[stream2][off] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+1] = uint8(v >> 8) + buf[stream2][off+1] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+2] = uint8(v >> 8) + buf[stream2][off+2] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+3] = uint8(v >> 8) + buf[stream2][off+3] = uint8(v2 >> 8) + } + + { + const stream = 2 + const stream2 = 3 + br1 := &br[stream] + br2 := &br[stream2] + br1.fillFast() + br2.fillFast() + + v := single[uint8(br1.value>>shift)].entry + v2 := single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off] = uint8(v >> 8) + buf[stream2][off] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+1] = uint8(v >> 8) + buf[stream2][off+1] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+2] = uint8(v >> 8) + buf[stream2][off+2] = uint8(v2 >> 8) + + v = single[uint8(br1.value>>shift)].entry + v2 = single[uint8(br2.value>>shift)].entry + br1.bitsRead += uint8(v) + br1.value <<= v & 63 + br2.bitsRead += uint8(v2) + br2.value <<= v2 & 63 + buf[stream][off+3] = uint8(v >> 8) + buf[stream2][off+3] = uint8(v2 >> 8) + } + + off += 4 + + if off == 0 { + if bufoff > dstEvery { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 1") + } + // There must at least be 3 buffers left. + if len(out)-bufoff < dstEvery*3 { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 2") + } + + //copy(out, buf[0][:]) + //copy(out[dstEvery:], buf[1][:]) + //copy(out[dstEvery*2:], buf[2][:]) + // copy(out[dstEvery*3:], buf[3][:]) + *(*[bufoff]byte)(out) = buf[0] + *(*[bufoff]byte)(out[dstEvery:]) = buf[1] + *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2] + *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3] + out = out[bufoff:] + decoded += bufoff * 4 + } + } + if off > 0 { + ioff := int(off) + if len(out) < dstEvery*3+ioff { + return nil, errors.New("corruption detected: stream overrun 3") + } + copy(out, buf[0][:off]) + copy(out[dstEvery:], buf[1][:off]) + copy(out[dstEvery*2:], buf[2][:off]) + copy(out[dstEvery*3:], buf[3][:off]) + decoded += int(off) * 4 + out = out[off:] + } + + // Decode remaining. + remainBytes := dstEvery - (decoded / 4) + for i := range br { + offset := dstEvery * i + endsAt := min(offset+remainBytes, len(out)) + br := &br[i] + bitsLeft := br.remaining() + for bitsLeft > 0 { + if br.finished() { + d.bufs.Put(buf) + return nil, io.ErrUnexpectedEOF + } + if br.bitsRead >= 56 { + if br.off >= 4 { + v := br.in[br.off-4:] + v = v[:4] + low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24) + br.value |= uint64(low) << (br.bitsRead - 32) + br.bitsRead -= 32 + br.off -= 4 + } else { + for br.off > 0 { + br.value |= uint64(br.in[br.off-1]) << (br.bitsRead - 8) + br.bitsRead -= 8 + br.off-- + } + } + } + // end inline... + if offset >= endsAt { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 4") + } + + // Read value and increment offset. + v := single[br.peekByteFast()].entry + nBits := uint8(v) + br.advance(nBits) + bitsLeft -= uint(nBits) + out[offset] = uint8(v >> 8) + offset++ + } + if offset != endsAt { + d.bufs.Put(buf) + return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt) + } + + decoded += offset - dstEvery*i + err = br.close() + if err != nil { + d.bufs.Put(buf) + return nil, err + } + } + d.bufs.Put(buf) + if dstSize != decoded { + return nil, errors.New("corruption detected: short output block") + } + return dst, nil +} + +// matches will compare a decoding table to a coding table. +// Errors are written to the writer. +// Nothing will be written if table is ok. +func (s *Scratch) matches(ct cTable, w io.Writer) { + if s == nil || len(s.dt.single) == 0 { + return + } + dt := s.dt.single[:1<>8) == byte(sym) { + fmt.Fprintf(w, "symbol %x has decoder, but no encoder\n", sym) + errs++ + break + } + } + if errs == 0 { + broken-- + } + continue + } + // Unused bits in input + ub := tablelog - enc.nBits + top := enc.val << ub + // decoder looks at top bits. + dec := dt[top] + if uint8(dec.entry) != enc.nBits { + fmt.Fprintf(w, "symbol 0x%x bit size mismatch (enc: %d, dec:%d).\n", sym, enc.nBits, uint8(dec.entry)) + errs++ + } + if uint8(dec.entry>>8) != uint8(sym) { + fmt.Fprintf(w, "symbol 0x%x decoder output mismatch (enc: %d, dec:%d).\n", sym, sym, uint8(dec.entry>>8)) + errs++ + } + if errs > 0 { + fmt.Fprintf(w, "%d errors in base, stopping\n", errs) + continue + } + // Ensure that all combinations are covered. + for i := uint16(0); i < (1 << ub); i++ { + vval := top | i + dec := dt[vval] + if uint8(dec.entry) != enc.nBits { + fmt.Fprintf(w, "symbol 0x%x bit size mismatch (enc: %d, dec:%d).\n", vval, enc.nBits, uint8(dec.entry)) + errs++ + } + if uint8(dec.entry>>8) != uint8(sym) { + fmt.Fprintf(w, "symbol 0x%x decoder output mismatch (enc: %d, dec:%d).\n", vval, sym, uint8(dec.entry>>8)) + errs++ + } + if errs > 20 { + fmt.Fprintf(w, "%d errors, stopping\n", errs) + break + } + } + if errs == 0 { + ok++ + broken-- + } + } + if broken > 0 { + fmt.Fprintf(w, "%d broken, %d ok\n", broken, ok) + } +} diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go new file mode 100644 index 0000000..7035d65 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.go @@ -0,0 +1,49 @@ +//go:build amd64 && !appengine && !noasm && gc + +// amd64 stubs and dispatch for the asm loops used by decompress_asm.go. +package huff0 + +import ( + "github.com/klauspost/compress/internal/cpuinfo" +) + +// decompress4x_main_loop_amd64 is an x86 assembler implementation +// of Decompress4X when tablelog > 8. +// +//go:noescape +func decompress4x_main_loop_amd64(ctx *decompress4xContext) + +// decompress4x_8b_main_loop_amd64 is an x86 assembler implementation +// of Decompress4X when tablelog <= 8 which decodes 4 entries +// per loop. +// +//go:noescape +func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext) + +// decompress1x_main_loop_amd64 is an x86 assembler implementation +// of Decompress1X when tablelog > 8. +// +//go:noescape +func decompress1x_main_loop_amd64(ctx *decompress1xContext) + +// decompress1x_main_loop_bmi2 is an x86 with BMI2 assembler implementation +// of Decompress1X when tablelog > 8. +// +//go:noescape +func decompress1x_main_loop_bmi2(ctx *decompress1xContext) + +func decompress4x_main_loop_asm(ctx *decompress4xContext) { + decompress4x_main_loop_amd64(ctx) +} + +func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) { + decompress4x_8b_main_loop_amd64(ctx) +} + +func decompress1x_main_loop_asm(ctx *decompress1xContext) { + if cpuinfo.HasBMI2() { + decompress1x_main_loop_bmi2(ctx) + } else { + decompress1x_main_loop_amd64(ctx) + } +} diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s new file mode 100644 index 0000000..c5d4a71 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress_amd64.s @@ -0,0 +1,830 @@ +// Code generated by command: go run gen.go -out ../decompress.s -arch amd64,arm64 -pkg=huff0. DO NOT EDIT. + +//go:build !appengine && !noasm && gc + +// func decompress4x_main_loop_amd64(ctx *decompress4xContext) +TEXT ·decompress4x_main_loop_amd64(SB), $0-8 + // Preload values + MOVQ ctx+0(FP), AX + MOVBQZX 8(AX), DI + MOVQ 16(AX), BX + MOVQ 48(AX), SI + MOVQ 24(AX), R8 + MOVQ 32(AX), R9 + MOVQ (AX), R10 + + // Main loop +main_loop: + XORL DX, DX + CMPQ BX, SI + SETGE DL + + // br0.fillFast32() + MOVQ 32(R10), R11 + MOVBQZX 40(R10), R12 + CMPQ R12, $0x20 + JBE skip_fill0 + MOVQ 24(R10), AX + SUBQ $0x20, R12 + SUBQ $0x04, AX + MOVQ (R10), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + MOVL (AX)(R13*1), R13 + MOVQ R12, CX + SHLQ CL, R13 + MOVQ AX, 24(R10) + ORQ R13, R11 + + // exhausted += (br0.off < 4) + CMPQ AX, $0x04 + ADCB $+0, DL + +skip_fill0: + // val0 := br0.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v0 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br0.advance(uint8(v0.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + + // val1 := br0.peekTopBits(peekBits) + MOVQ DI, CX + MOVQ R11, R13 + SHRQ CL, R13 + + // v1 := table[val1&mask] + MOVW (R9)(R13*2), CX + + // br0.advance(uint8(v1.entry)) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + MOVW AX, (BX) + + // update the bitreader structure + MOVQ R11, 32(R10) + MOVB R12, 40(R10) + + // br1.fillFast32() + MOVQ 80(R10), R11 + MOVBQZX 88(R10), R12 + CMPQ R12, $0x20 + JBE skip_fill1 + MOVQ 72(R10), AX + SUBQ $0x20, R12 + SUBQ $0x04, AX + MOVQ 48(R10), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + MOVL (AX)(R13*1), R13 + MOVQ R12, CX + SHLQ CL, R13 + MOVQ AX, 72(R10) + ORQ R13, R11 + + // exhausted += (br1.off < 4) + CMPQ AX, $0x04 + ADCB $+0, DL + +skip_fill1: + // val0 := br1.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v0 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br1.advance(uint8(v0.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + + // val1 := br1.peekTopBits(peekBits) + MOVQ DI, CX + MOVQ R11, R13 + SHRQ CL, R13 + + // v1 := table[val1&mask] + MOVW (R9)(R13*2), CX + + // br1.advance(uint8(v1.entry)) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + MOVW AX, (BX)(R8*1) + + // update the bitreader structure + MOVQ R11, 80(R10) + MOVB R12, 88(R10) + + // br2.fillFast32() + MOVQ 128(R10), R11 + MOVBQZX 136(R10), R12 + CMPQ R12, $0x20 + JBE skip_fill2 + MOVQ 120(R10), AX + SUBQ $0x20, R12 + SUBQ $0x04, AX + MOVQ 96(R10), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + MOVL (AX)(R13*1), R13 + MOVQ R12, CX + SHLQ CL, R13 + MOVQ AX, 120(R10) + ORQ R13, R11 + + // exhausted += (br2.off < 4) + CMPQ AX, $0x04 + ADCB $+0, DL + +skip_fill2: + // val0 := br2.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v0 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br2.advance(uint8(v0.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + + // val1 := br2.peekTopBits(peekBits) + MOVQ DI, CX + MOVQ R11, R13 + SHRQ CL, R13 + + // v1 := table[val1&mask] + MOVW (R9)(R13*2), CX + + // br2.advance(uint8(v1.entry)) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + MOVW AX, (BX)(R8*2) + + // update the bitreader structure + MOVQ R11, 128(R10) + MOVB R12, 136(R10) + + // br3.fillFast32() + MOVQ 176(R10), R11 + MOVBQZX 184(R10), R12 + CMPQ R12, $0x20 + JBE skip_fill3 + MOVQ 168(R10), AX + SUBQ $0x20, R12 + SUBQ $0x04, AX + MOVQ 144(R10), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + MOVL (AX)(R13*1), R13 + MOVQ R12, CX + SHLQ CL, R13 + MOVQ AX, 168(R10) + ORQ R13, R11 + + // exhausted += (br3.off < 4) + CMPQ AX, $0x04 + ADCB $+0, DL + +skip_fill3: + // val0 := br3.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v0 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br3.advance(uint8(v0.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + + // val1 := br3.peekTopBits(peekBits) + MOVQ DI, CX + MOVQ R11, R13 + SHRQ CL, R13 + + // v1 := table[val1&mask] + MOVW (R9)(R13*2), CX + + // br3.advance(uint8(v1.entry)) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + LEAQ (R8)(R8*2), CX + MOVW AX, (BX)(CX*1) + + // update the bitreader structure + MOVQ R11, 176(R10) + MOVB R12, 184(R10) + ADDQ $0x02, BX + TESTB DL, DL + JZ main_loop + MOVQ ctx+0(FP), AX + SUBQ 16(AX), BX + SHLQ $0x02, BX + MOVQ BX, 40(AX) + RET + +// func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext) +TEXT ·decompress4x_8b_main_loop_amd64(SB), $0-8 + // Preload values + MOVQ ctx+0(FP), CX + MOVBQZX 8(CX), DI + MOVQ 16(CX), BX + MOVQ 48(CX), SI + MOVQ 24(CX), R8 + MOVQ 32(CX), R9 + MOVQ (CX), R10 + + // Main loop +main_loop: + XORL DX, DX + CMPQ BX, SI + SETGE DL + + // br0.fillFast32() + MOVQ 32(R10), R11 + MOVBQZX 40(R10), R12 + CMPQ R12, $0x20 + JBE skip_fill0 + MOVQ 24(R10), R13 + SUBQ $0x20, R12 + SUBQ $0x04, R13 + MOVQ (R10), R14 + + // b.value |= uint64(low) << (b.bitsRead & 63) + MOVL (R13)(R14*1), R14 + MOVQ R12, CX + SHLQ CL, R14 + MOVQ R13, 24(R10) + ORQ R14, R11 + + // exhausted += (br0.off < 4) + CMPQ R13, $0x04 + ADCB $+0, DL + +skip_fill0: + // val0 := br0.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v0 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br0.advance(uint8(v0.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + + // val1 := br0.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v1 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br0.advance(uint8(v1.entry) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + BSWAPL AX + + // val2 := br0.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v2 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br0.advance(uint8(v2.entry) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + + // val3 := br0.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v3 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br0.advance(uint8(v3.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + BSWAPL AX + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + MOVL AX, (BX) + + // update the bitreader structure + MOVQ R11, 32(R10) + MOVB R12, 40(R10) + + // br1.fillFast32() + MOVQ 80(R10), R11 + MOVBQZX 88(R10), R12 + CMPQ R12, $0x20 + JBE skip_fill1 + MOVQ 72(R10), R13 + SUBQ $0x20, R12 + SUBQ $0x04, R13 + MOVQ 48(R10), R14 + + // b.value |= uint64(low) << (b.bitsRead & 63) + MOVL (R13)(R14*1), R14 + MOVQ R12, CX + SHLQ CL, R14 + MOVQ R13, 72(R10) + ORQ R14, R11 + + // exhausted += (br1.off < 4) + CMPQ R13, $0x04 + ADCB $+0, DL + +skip_fill1: + // val0 := br1.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v0 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br1.advance(uint8(v0.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + + // val1 := br1.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v1 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br1.advance(uint8(v1.entry) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + BSWAPL AX + + // val2 := br1.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v2 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br1.advance(uint8(v2.entry) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + + // val3 := br1.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v3 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br1.advance(uint8(v3.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + BSWAPL AX + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + MOVL AX, (BX)(R8*1) + + // update the bitreader structure + MOVQ R11, 80(R10) + MOVB R12, 88(R10) + + // br2.fillFast32() + MOVQ 128(R10), R11 + MOVBQZX 136(R10), R12 + CMPQ R12, $0x20 + JBE skip_fill2 + MOVQ 120(R10), R13 + SUBQ $0x20, R12 + SUBQ $0x04, R13 + MOVQ 96(R10), R14 + + // b.value |= uint64(low) << (b.bitsRead & 63) + MOVL (R13)(R14*1), R14 + MOVQ R12, CX + SHLQ CL, R14 + MOVQ R13, 120(R10) + ORQ R14, R11 + + // exhausted += (br2.off < 4) + CMPQ R13, $0x04 + ADCB $+0, DL + +skip_fill2: + // val0 := br2.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v0 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br2.advance(uint8(v0.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + + // val1 := br2.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v1 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br2.advance(uint8(v1.entry) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + BSWAPL AX + + // val2 := br2.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v2 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br2.advance(uint8(v2.entry) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + + // val3 := br2.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v3 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br2.advance(uint8(v3.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + BSWAPL AX + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + MOVL AX, (BX)(R8*2) + + // update the bitreader structure + MOVQ R11, 128(R10) + MOVB R12, 136(R10) + + // br3.fillFast32() + MOVQ 176(R10), R11 + MOVBQZX 184(R10), R12 + CMPQ R12, $0x20 + JBE skip_fill3 + MOVQ 168(R10), R13 + SUBQ $0x20, R12 + SUBQ $0x04, R13 + MOVQ 144(R10), R14 + + // b.value |= uint64(low) << (b.bitsRead & 63) + MOVL (R13)(R14*1), R14 + MOVQ R12, CX + SHLQ CL, R14 + MOVQ R13, 168(R10) + ORQ R14, R11 + + // exhausted += (br3.off < 4) + CMPQ R13, $0x04 + ADCB $+0, DL + +skip_fill3: + // val0 := br3.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v0 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br3.advance(uint8(v0.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + + // val1 := br3.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v1 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br3.advance(uint8(v1.entry) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + BSWAPL AX + + // val2 := br3.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v2 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br3.advance(uint8(v2.entry) + MOVB CH, AH + SHLQ CL, R11 + ADDB CL, R12 + + // val3 := br3.peekTopBits(peekBits) + MOVQ R11, R13 + MOVQ DI, CX + SHRQ CL, R13 + + // v3 := table[val0&mask] + MOVW (R9)(R13*2), CX + + // br3.advance(uint8(v3.entry) + MOVB CH, AL + SHLQ CL, R11 + ADDB CL, R12 + BSWAPL AX + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + LEAQ (R8)(R8*2), CX + MOVL AX, (BX)(CX*1) + + // update the bitreader structure + MOVQ R11, 176(R10) + MOVB R12, 184(R10) + ADDQ $0x04, BX + TESTB DL, DL + JZ main_loop + MOVQ ctx+0(FP), AX + SUBQ 16(AX), BX + SHLQ $0x02, BX + MOVQ BX, 40(AX) + RET + +// func decompress1x_main_loop_amd64(ctx *decompress1xContext) +TEXT ·decompress1x_main_loop_amd64(SB), $0-8 + MOVQ ctx+0(FP), CX + MOVQ 16(CX), DX + MOVQ 24(CX), BX + CMPQ BX, $0x04 + JB error_max_decoded_size_exceeded + LEAQ (DX)(BX*1), BX + MOVQ (CX), SI + MOVQ (SI), R8 + MOVQ 24(SI), R9 + MOVQ 32(SI), R10 + MOVBQZX 40(SI), R11 + MOVQ 32(CX), SI + MOVBQZX 8(CX), DI + JMP loop_condition + +main_loop: + // Check if we have room for 4 bytes in the output buffer + LEAQ 4(DX), CX + CMPQ CX, BX + JGE error_max_decoded_size_exceeded + + // Decode 4 values + CMPQ R11, $0x20 + JL bitReader_fillFast_1_end + SUBQ $0x20, R11 + SUBQ $0x04, R9 + MOVL (R8)(R9*1), R12 + MOVQ R11, CX + SHLQ CL, R12 + ORQ R12, R10 + +bitReader_fillFast_1_end: + MOVQ DI, CX + MOVQ R10, R12 + SHRQ CL, R12 + MOVW (SI)(R12*2), CX + MOVB CH, AL + MOVBQZX CL, CX + ADDQ CX, R11 + SHLQ CL, R10 + MOVQ DI, CX + MOVQ R10, R12 + SHRQ CL, R12 + MOVW (SI)(R12*2), CX + MOVB CH, AH + MOVBQZX CL, CX + ADDQ CX, R11 + SHLQ CL, R10 + BSWAPL AX + CMPQ R11, $0x20 + JL bitReader_fillFast_2_end + SUBQ $0x20, R11 + SUBQ $0x04, R9 + MOVL (R8)(R9*1), R12 + MOVQ R11, CX + SHLQ CL, R12 + ORQ R12, R10 + +bitReader_fillFast_2_end: + MOVQ DI, CX + MOVQ R10, R12 + SHRQ CL, R12 + MOVW (SI)(R12*2), CX + MOVB CH, AH + MOVBQZX CL, CX + ADDQ CX, R11 + SHLQ CL, R10 + MOVQ DI, CX + MOVQ R10, R12 + SHRQ CL, R12 + MOVW (SI)(R12*2), CX + MOVB CH, AL + MOVBQZX CL, CX + ADDQ CX, R11 + SHLQ CL, R10 + BSWAPL AX + + // Store the decoded values + MOVL AX, (DX) + ADDQ $0x04, DX + +loop_condition: + CMPQ R9, $0x08 + JGE main_loop + + // Update ctx structure + MOVQ ctx+0(FP), AX + SUBQ 16(AX), DX + MOVQ DX, 40(AX) + MOVQ (AX), AX + MOVQ R9, 24(AX) + MOVQ R10, 32(AX) + MOVB R11, 40(AX) + RET + + // Report error +error_max_decoded_size_exceeded: + MOVQ ctx+0(FP), AX + MOVQ $-1, CX + MOVQ CX, 40(AX) + RET + +// func decompress1x_main_loop_bmi2(ctx *decompress1xContext) +// Requires: BMI2 +TEXT ·decompress1x_main_loop_bmi2(SB), $0-8 + MOVQ ctx+0(FP), CX + MOVQ 16(CX), DX + MOVQ 24(CX), BX + CMPQ BX, $0x04 + JB error_max_decoded_size_exceeded + LEAQ (DX)(BX*1), BX + MOVQ (CX), SI + MOVQ (SI), R8 + MOVQ 24(SI), R9 + MOVQ 32(SI), R10 + MOVBQZX 40(SI), R11 + MOVQ 32(CX), SI + MOVBQZX 8(CX), DI + JMP loop_condition + +main_loop: + // Check if we have room for 4 bytes in the output buffer + LEAQ 4(DX), CX + CMPQ CX, BX + JGE error_max_decoded_size_exceeded + + // Decode 4 values + CMPQ R11, $0x20 + JL bitReader_fillFast_1_end + SUBQ $0x20, R11 + SUBQ $0x04, R9 + MOVL (R8)(R9*1), CX + SHLXQ R11, CX, CX + ORQ CX, R10 + +bitReader_fillFast_1_end: + SHRXQ DI, R10, CX + MOVW (SI)(CX*2), CX + MOVB CH, AL + MOVBQZX CL, CX + ADDQ CX, R11 + SHLXQ CX, R10, R10 + SHRXQ DI, R10, CX + MOVW (SI)(CX*2), CX + MOVB CH, AH + MOVBQZX CL, CX + ADDQ CX, R11 + SHLXQ CX, R10, R10 + BSWAPL AX + CMPQ R11, $0x20 + JL bitReader_fillFast_2_end + SUBQ $0x20, R11 + SUBQ $0x04, R9 + MOVL (R8)(R9*1), CX + SHLXQ R11, CX, CX + ORQ CX, R10 + +bitReader_fillFast_2_end: + SHRXQ DI, R10, CX + MOVW (SI)(CX*2), CX + MOVB CH, AH + MOVBQZX CL, CX + ADDQ CX, R11 + SHLXQ CX, R10, R10 + SHRXQ DI, R10, CX + MOVW (SI)(CX*2), CX + MOVB CH, AL + MOVBQZX CL, CX + ADDQ CX, R11 + SHLXQ CX, R10, R10 + BSWAPL AX + + // Store the decoded values + MOVL AX, (DX) + ADDQ $0x04, DX + +loop_condition: + CMPQ R9, $0x08 + JGE main_loop + + // Update ctx structure + MOVQ ctx+0(FP), AX + SUBQ 16(AX), DX + MOVQ DX, 40(AX) + MOVQ (AX), AX + MOVQ R9, 24(AX) + MOVQ R10, 32(AX) + MOVB R11, 40(AX) + RET + + // Report error +error_max_decoded_size_exceeded: + MOVQ ctx+0(FP), AX + MOVQ $-1, CX + MOVQ CX, 40(AX) + RET diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_arm64.go b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.go new file mode 100644 index 0000000..8ba3c81 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.go @@ -0,0 +1,37 @@ +//go:build arm64 && !appengine && !noasm && gc + +// arm64 stubs and dispatch for the asm loops used by decompress_asm.go. +// The asm (decompress_arm64.s) is generated by the avo arm64 lowering +// printer from the same source as the amd64 asm; see _generate/gen.go. +package huff0 + +// decompress4x_main_loop_arm64 is an arm64 assembler implementation +// of Decompress4X when tablelog > 8. +// +//go:noescape +func decompress4x_main_loop_arm64(ctx *decompress4xContext) + +// decompress4x_8b_main_loop_arm64 is an arm64 assembler implementation +// of Decompress4X when tablelog <= 8 which decodes 4 entries +// per loop. +// +//go:noescape +func decompress4x_8b_main_loop_arm64(ctx *decompress4xContext) + +// decompress1x_main_loop_arm64 is an arm64 assembler implementation +// of Decompress1X when tablelog > 8. +// +//go:noescape +func decompress1x_main_loop_arm64(ctx *decompress1xContext) + +func decompress4x_main_loop_asm(ctx *decompress4xContext) { + decompress4x_main_loop_arm64(ctx) +} + +func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) { + decompress4x_8b_main_loop_arm64(ctx) +} + +func decompress1x_main_loop_asm(ctx *decompress1xContext) { + decompress1x_main_loop_arm64(ctx) +} diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s new file mode 100644 index 0000000..e160127 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress_arm64.s @@ -0,0 +1,851 @@ +// Code generated by command: go run gen.go -out ../decompress.s -arch amd64,arm64 -pkg=huff0. DO NOT EDIT. +// EXPERIMENTAL arm64 output lowered from an amd64 avo program. + +//go:build arm64 && !appengine && !noasm && gc + +// func decompress4x_main_loop_amd64(ctx *decompress4xContext) +TEXT ·decompress4x_main_loop_arm64(SB), $0-8 + // Preload values + MOVD ctx+0(FP), R0 + MOVBU 8(R0), R6 + MOVD 16(R0), R3 + MOVD 48(R0), R5 + MOVD 24(R0), R7 + MOVD 32(R0), R8 + MOVD (R0), R9 + + // Main loop +main_loop: + MOVD $0, R2 + CMP R5, R3 + CSET GE, R16 + BFI $0, R16, $8, R2 + + // br0.fillFast32() + MOVD 32(R9), R10 + MOVBU 40(R9), R11 + CMP $0x20, R11 + BLS skip_fill0 + MOVD 24(R9), R0 + SUB $0x20, R11, R11 + SUB $0x04, R0, R0 + MOVD (R9), R12 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R12, R0, R15 + MOVWU (R15), R12 + MOVD R11, R1 + LSL R1, R12, R12 + MOVD R0, 24(R9) + ORR R12, R10, R10 + + // exhausted += (br0.off < 4) + CMP $0x04, R0 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill0: + // val0 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br0.peekTopBits(peekBits) + MOVD R6, R1 + MOVD R10, R12 + LSR R1, R12, R12 + + // v1 := table[val1&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v1.entry)) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + MOVH R0, (R3) + + // update the bitreader structure + MOVD R10, 32(R9) + MOVB R11, 40(R9) + + // br1.fillFast32() + MOVD 80(R9), R10 + MOVBU 88(R9), R11 + CMP $0x20, R11 + BLS skip_fill1 + MOVD 72(R9), R0 + SUB $0x20, R11, R11 + SUB $0x04, R0, R0 + MOVD 48(R9), R12 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R12, R0, R15 + MOVWU (R15), R12 + MOVD R11, R1 + LSL R1, R12, R12 + MOVD R0, 72(R9) + ORR R12, R10, R10 + + // exhausted += (br1.off < 4) + CMP $0x04, R0 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill1: + // val0 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br1.peekTopBits(peekBits) + MOVD R6, R1 + MOVD R10, R12 + LSR R1, R12, R12 + + // v1 := table[val1&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v1.entry)) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + ADD R7, R3, R15 + MOVH R0, (R15) + + // update the bitreader structure + MOVD R10, 80(R9) + MOVB R11, 88(R9) + + // br2.fillFast32() + MOVD 128(R9), R10 + MOVBU 136(R9), R11 + CMP $0x20, R11 + BLS skip_fill2 + MOVD 120(R9), R0 + SUB $0x20, R11, R11 + SUB $0x04, R0, R0 + MOVD 96(R9), R12 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R12, R0, R15 + MOVWU (R15), R12 + MOVD R11, R1 + LSL R1, R12, R12 + MOVD R0, 120(R9) + ORR R12, R10, R10 + + // exhausted += (br2.off < 4) + CMP $0x04, R0 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill2: + // val0 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br2.peekTopBits(peekBits) + MOVD R6, R1 + MOVD R10, R12 + LSR R1, R12, R12 + + // v1 := table[val1&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v1.entry)) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + ADD R7<<1, R3, R15 + MOVH R0, (R15) + + // update the bitreader structure + MOVD R10, 128(R9) + MOVB R11, 136(R9) + + // br3.fillFast32() + MOVD 176(R9), R10 + MOVBU 184(R9), R11 + CMP $0x20, R11 + BLS skip_fill3 + MOVD 168(R9), R0 + SUB $0x20, R11, R11 + SUB $0x04, R0, R0 + MOVD 144(R9), R12 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R12, R0, R15 + MOVWU (R15), R12 + MOVD R11, R1 + LSL R1, R12, R12 + MOVD R0, 168(R9) + ORR R12, R10, R10 + + // exhausted += (br3.off < 4) + CMP $0x04, R0 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill3: + // val0 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br3.peekTopBits(peekBits) + MOVD R6, R1 + MOVD R10, R12 + LSR R1, R12, R12 + + // v1 := table[val1&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v1.entry)) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // these two writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + ADD R7<<1, R7, R1 + ADD R1, R3, R15 + MOVH R0, (R15) + + // update the bitreader structure + MOVD R10, 176(R9) + MOVB R11, 184(R9) + ADD $0x02, R3, R3 + AND $0xff, R2, R15 + AND $0xff, R2, R16 + TST R16, R15 + BEQ main_loop + MOVD ctx+0(FP), R0 + MOVD 16(R0), R16 + SUB R16, R3, R3 + LSL $0x02, R3, R3 + MOVD R3, 40(R0) + RET + +// func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext) +TEXT ·decompress4x_8b_main_loop_arm64(SB), $0-8 + // Preload values + MOVD ctx+0(FP), R1 + MOVBU 8(R1), R6 + MOVD 16(R1), R3 + MOVD 48(R1), R5 + MOVD 24(R1), R7 + MOVD 32(R1), R8 + MOVD (R1), R9 + + // Main loop +main_loop: + MOVD $0, R2 + CMP R5, R3 + CSET GE, R16 + BFI $0, R16, $8, R2 + + // br0.fillFast32() + MOVD 32(R9), R10 + MOVBU 40(R9), R11 + CMP $0x20, R11 + BLS skip_fill0 + MOVD 24(R9), R12 + SUB $0x20, R11, R11 + SUB $0x04, R12, R12 + MOVD (R9), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R13, R12, R15 + MOVWU (R15), R13 + MOVD R11, R1 + LSL R1, R13, R13 + MOVD R12, 24(R9) + ORR R13, R10, R10 + + // exhausted += (br0.off < 4) + CMP $0x04, R12 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill0: + // val0 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v1 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v1.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // val2 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v2 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v2.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val3 := br0.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v3 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br0.advance(uint8(v3.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + MOVW R0, (R3) + + // update the bitreader structure + MOVD R10, 32(R9) + MOVB R11, 40(R9) + + // br1.fillFast32() + MOVD 80(R9), R10 + MOVBU 88(R9), R11 + CMP $0x20, R11 + BLS skip_fill1 + MOVD 72(R9), R12 + SUB $0x20, R11, R11 + SUB $0x04, R12, R12 + MOVD 48(R9), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R13, R12, R15 + MOVWU (R15), R13 + MOVD R11, R1 + LSL R1, R13, R13 + MOVD R12, 72(R9) + ORR R13, R10, R10 + + // exhausted += (br1.off < 4) + CMP $0x04, R12 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill1: + // val0 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v1 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v1.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // val2 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v2 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v2.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val3 := br1.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v3 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br1.advance(uint8(v3.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + ADD R7, R3, R15 + MOVW R0, (R15) + + // update the bitreader structure + MOVD R10, 80(R9) + MOVB R11, 88(R9) + + // br2.fillFast32() + MOVD 128(R9), R10 + MOVBU 136(R9), R11 + CMP $0x20, R11 + BLS skip_fill2 + MOVD 120(R9), R12 + SUB $0x20, R11, R11 + SUB $0x04, R12, R12 + MOVD 96(R9), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R13, R12, R15 + MOVWU (R15), R13 + MOVD R11, R1 + LSL R1, R13, R13 + MOVD R12, 120(R9) + ORR R13, R10, R10 + + // exhausted += (br2.off < 4) + CMP $0x04, R12 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill2: + // val0 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v1 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v1.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // val2 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v2 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v2.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val3 := br2.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v3 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br2.advance(uint8(v3.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + ADD R7<<1, R3, R15 + MOVW R0, (R15) + + // update the bitreader structure + MOVD R10, 128(R9) + MOVB R11, 136(R9) + + // br3.fillFast32() + MOVD 176(R9), R10 + MOVBU 184(R9), R11 + CMP $0x20, R11 + BLS skip_fill3 + MOVD 168(R9), R12 + SUB $0x20, R11, R11 + SUB $0x04, R12, R12 + MOVD 144(R9), R13 + + // b.value |= uint64(low) << (b.bitsRead & 63) + ADD R13, R12, R15 + MOVWU (R15), R13 + MOVD R11, R1 + LSL R1, R13, R13 + MOVD R12, 168(R9) + ORR R13, R10, R10 + + // exhausted += (br3.off < 4) + CMP $0x04, R12 + CSINC HS, R2, R2, R16 + BFI $0, R16, $8, R2 + +skip_fill3: + // val0 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v0 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v0.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val1 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v1 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v1.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // val2 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v2 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v2.entry) + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + + // val3 := br3.peekTopBits(peekBits) + MOVD R10, R12 + MOVD R6, R1 + LSR R1, R12, R12 + + // v3 := table[val0&mask] + ADD R12<<1, R8, R15 + MOVHU (R15), R1 + + // br3.advance(uint8(v3.entry) + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + LSL R1, R10, R10 + ADD R1, R11, R15 + BFI $0, R15, $8, R11 + REVW R0, R0 + + // these four writes get coalesced + // out[id * dstEvery + 0] = uint8(v0.entry >> 8) + // out[id * dstEvery + 1] = uint8(v1.entry >> 8) + // out[id * dstEvery + 3] = uint8(v2.entry >> 8) + // out[id * dstEvery + 4] = uint8(v3.entry >> 8) + ADD R7<<1, R7, R1 + ADD R1, R3, R15 + MOVW R0, (R15) + + // update the bitreader structure + MOVD R10, 176(R9) + MOVB R11, 184(R9) + ADD $0x04, R3, R3 + AND $0xff, R2, R15 + AND $0xff, R2, R16 + TST R16, R15 + BEQ main_loop + MOVD ctx+0(FP), R0 + MOVD 16(R0), R16 + SUB R16, R3, R3 + LSL $0x02, R3, R3 + MOVD R3, 40(R0) + RET + +// func decompress1x_main_loop_amd64(ctx *decompress1xContext) +TEXT ·decompress1x_main_loop_arm64(SB), $0-8 + MOVD ctx+0(FP), R1 + MOVD 16(R1), R2 + MOVD 24(R1), R3 + CMP $0x04, R3 + BLO error_max_decoded_size_exceeded + ADD R3, R2, R3 + MOVD (R1), R5 + MOVD (R5), R7 + MOVD 24(R5), R8 + MOVD 32(R5), R9 + MOVBU 40(R5), R10 + MOVD 32(R1), R5 + MOVBU 8(R1), R6 + JMP loop_condition + +main_loop: + // Check if we have room for 4 bytes in the output buffer + ADD $4, R2, R1 + CMP R3, R1 + BGE error_max_decoded_size_exceeded + + // Decode 4 values + CMP $0x20, R10 + BLT bitReader_fillFast_1_end + SUB $0x20, R10, R10 + SUB $0x04, R8, R8 + ADD R8, R7, R15 + MOVWU (R15), R11 + MOVD R10, R1 + LSL R1, R11, R11 + ORR R11, R9, R9 + +bitReader_fillFast_1_end: + MOVD R6, R1 + MOVD R9, R11 + LSR R1, R11, R11 + ADD R11<<1, R5, R15 + MOVHU (R15), R1 + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + MOVBU R1, R1 + ADD R1, R10, R10 + LSL R1, R9, R9 + MOVD R6, R1 + MOVD R9, R11 + LSR R1, R11, R11 + ADD R11<<1, R5, R15 + MOVHU (R15), R1 + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + MOVBU R1, R1 + ADD R1, R10, R10 + LSL R1, R9, R9 + REVW R0, R0 + CMP $0x20, R10 + BLT bitReader_fillFast_2_end + SUB $0x20, R10, R10 + SUB $0x04, R8, R8 + ADD R8, R7, R15 + MOVWU (R15), R11 + MOVD R10, R1 + LSL R1, R11, R11 + ORR R11, R9, R9 + +bitReader_fillFast_2_end: + MOVD R6, R1 + MOVD R9, R11 + LSR R1, R11, R11 + ADD R11<<1, R5, R15 + MOVHU (R15), R1 + UBFX $8, R1, $8, R16 + BFI $8, R16, $8, R0 + MOVBU R1, R1 + ADD R1, R10, R10 + LSL R1, R9, R9 + MOVD R6, R1 + MOVD R9, R11 + LSR R1, R11, R11 + ADD R11<<1, R5, R15 + MOVHU (R15), R1 + UBFX $8, R1, $8, R16 + BFI $0, R16, $8, R0 + MOVBU R1, R1 + ADD R1, R10, R10 + LSL R1, R9, R9 + REVW R0, R0 + + // Store the decoded values + MOVW R0, (R2) + ADD $0x04, R2, R2 + +loop_condition: + CMP $0x08, R8 + BGE main_loop + + // Update ctx structure + MOVD ctx+0(FP), R0 + MOVD 16(R0), R16 + SUB R16, R2, R2 + MOVD R2, 40(R0) + MOVD (R0), R0 + MOVD R8, 24(R0) + MOVD R9, 32(R0) + MOVB R10, 40(R0) + RET + + // Report error +error_max_decoded_size_exceeded: + MOVD ctx+0(FP), R0 + MOVD $-1, R1 + MOVD R1, 40(R0) + RET + +// skipped decompress1x_main_loop_bmi2 (generic twin preferred on arm64) diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_asm.go b/vendor/github.com/klauspost/compress/huff0/decompress_asm.go new file mode 100644 index 0000000..4854dd4 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress_asm.go @@ -0,0 +1,193 @@ +//go:build (amd64 || arm64) && !appengine && !noasm && gc + +// This file contains the specialisation of Decoder.Decompress4X +// and Decoder.Decompress1X that use an asm implementation of their main loops. +// The asm function stubs and any per-arch dispatch live in decompress_amd64.go +// and decompress_arm64.go. +package huff0 + +import ( + "errors" + "fmt" +) + +// fallback8BitSize is the size where using Go version is faster. +const fallback8BitSize = 800 + +type decompress4xContext struct { + pbr *[4]bitReaderShifted + peekBits uint8 + out *byte + dstEvery int + tbl *dEntrySingle + decoded int + limit *byte +} + +// Decompress4X will decompress a 4X encoded stream. +// The length of the supplied input must match the end of a block exactly. +// The *capacity* of the dst slice must match the destination size of +// the uncompressed data exactly. +func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) { + if len(d.dt.single) == 0 { + return nil, errors.New("no table loaded") + } + if len(src) < 6+(4*1) { + return nil, errors.New("input too small") + } + + use8BitTables := d.actualTableLog <= 8 + if cap(dst) < fallback8BitSize && use8BitTables { + return d.decompress4X8bit(dst, src) + } + + var br [4]bitReaderShifted + // Decode "jump table" + start := 6 + for i := range 3 { + length := int(src[i*2]) | (int(src[i*2+1]) << 8) + if start+length >= len(src) { + return nil, errors.New("truncated input (or invalid offset)") + } + err := br[i].init(src[start : start+length]) + if err != nil { + return nil, err + } + start += length + } + err := br[3].init(src[start:]) + if err != nil { + return nil, err + } + + // destination, offset to match first output + dstSize := cap(dst) + dst = dst[:dstSize] + out := dst + dstEvery := (dstSize + 3) / 4 + + const tlSize = 1 << tableLogMax + const tlMask = tlSize - 1 + single := d.dt.single[:tlSize] + + var decoded int + + if len(out) > 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) { + ctx := decompress4xContext{ + pbr: &br, + peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast() + out: &out[0], + dstEvery: dstEvery, + tbl: &single[0], + limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last. + } + if use8BitTables { + decompress4x_8b_main_loop_asm(&ctx) + } else { + decompress4x_main_loop_asm(&ctx) + } + + decoded = ctx.decoded + out = out[decoded/4:] + } + + // Decode remaining. + remainBytes := dstEvery - (decoded / 4) + for i := range br { + offset := dstEvery * i + endsAt := min(offset+remainBytes, len(out)) + br := &br[i] + bitsLeft := br.remaining() + for bitsLeft > 0 { + br.fill() + if offset >= endsAt { + return nil, errors.New("corruption detected: stream overrun 4") + } + + // Read value and increment offset. + val := br.peekBitsFast(d.actualTableLog) + v := single[val&tlMask].entry + nBits := uint8(v) + br.advance(nBits) + bitsLeft -= uint(nBits) + out[offset] = uint8(v >> 8) + offset++ + } + if offset != endsAt { + return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt) + } + decoded += offset - dstEvery*i + err = br.close() + if err != nil { + return nil, err + } + } + if dstSize != decoded { + return nil, errors.New("corruption detected: short output block") + } + return dst, nil +} + +type decompress1xContext struct { + pbr *bitReaderShifted + peekBits uint8 + out *byte + outCap int + tbl *dEntrySingle + decoded int +} + +// Error reported by asm implementations +const error_max_decoded_size_exeeded = -1 + +// Decompress1X will decompress a 1X encoded stream. +// The cap of the output buffer will be the maximum decompressed size. +// The length of the supplied input must match the end of a block exactly. +func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) { + if len(d.dt.single) == 0 { + return nil, errors.New("no table loaded") + } + var br bitReaderShifted + err := br.init(src) + if err != nil { + return dst, err + } + maxDecodedSize := cap(dst) + dst = dst[:maxDecodedSize] + + const tlSize = 1 << tableLogMax + const tlMask = tlSize - 1 + + if maxDecodedSize >= 4 { + ctx := decompress1xContext{ + pbr: &br, + out: &dst[0], + outCap: maxDecodedSize, + peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast() + tbl: &d.dt.single[0], + } + + decompress1x_main_loop_asm(&ctx) + if ctx.decoded == error_max_decoded_size_exeeded { + return nil, ErrMaxDecodedSizeExceeded + } + + dst = dst[:ctx.decoded] + } + + // br < 8, so uint8 is fine + bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead + for bitsLeft > 0 { + br.fill() + if len(dst) >= maxDecodedSize { + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask] + nBits := uint8(v.entry) + br.advance(nBits) + bitsLeft -= nBits + dst = append(dst, uint8(v.entry>>8)) + } + return dst, br.close() +} diff --git a/vendor/github.com/klauspost/compress/huff0/decompress_generic.go b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go new file mode 100644 index 0000000..e1bca5c --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/decompress_generic.go @@ -0,0 +1,298 @@ +//go:build (!amd64 && !arm64) || appengine || !gc || noasm + +// This file contains a generic implementation of Decoder.Decompress4X. +package huff0 + +import ( + "errors" + "fmt" +) + +// Decompress4X will decompress a 4X encoded stream. +// The length of the supplied input must match the end of a block exactly. +// The *capacity* of the dst slice must match the destination size of +// the uncompressed data exactly. +func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) { + if len(d.dt.single) == 0 { + return nil, errors.New("no table loaded") + } + if len(src) < 6+(4*1) { + return nil, errors.New("input too small") + } + if use8BitTables && d.actualTableLog <= 8 { + return d.decompress4X8bit(dst, src) + } + + var br [4]bitReaderShifted + // Decode "jump table" + start := 6 + for i := 0; i < 3; i++ { + length := int(src[i*2]) | (int(src[i*2+1]) << 8) + if start+length >= len(src) { + return nil, errors.New("truncated input (or invalid offset)") + } + err := br[i].init(src[start : start+length]) + if err != nil { + return nil, err + } + start += length + } + err := br[3].init(src[start:]) + if err != nil { + return nil, err + } + + // destination, offset to match first output + dstSize := cap(dst) + dst = dst[:dstSize] + out := dst + dstEvery := (dstSize + 3) / 4 + + const tlSize = 1 << tableLogMax + const tlMask = tlSize - 1 + single := d.dt.single[:tlSize] + + // Use temp table to avoid bound checks/append penalty. + buf := d.buffer() + var off uint8 + var decoded int + + // Decode 2 values from each decoder/loop. + const bufoff = 256 + for { + if br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4 { + break + } + + { + const stream = 0 + const stream2 = 1 + br[stream].fillFast() + br[stream2].fillFast() + + val := br[stream].peekBitsFast(d.actualTableLog) + val2 := br[stream2].peekBitsFast(d.actualTableLog) + v := single[val&tlMask] + v2 := single[val2&tlMask] + br[stream].advance(uint8(v.entry)) + br[stream2].advance(uint8(v2.entry)) + buf[stream][off] = uint8(v.entry >> 8) + buf[stream2][off] = uint8(v2.entry >> 8) + + val = br[stream].peekBitsFast(d.actualTableLog) + val2 = br[stream2].peekBitsFast(d.actualTableLog) + v = single[val&tlMask] + v2 = single[val2&tlMask] + br[stream].advance(uint8(v.entry)) + br[stream2].advance(uint8(v2.entry)) + buf[stream][off+1] = uint8(v.entry >> 8) + buf[stream2][off+1] = uint8(v2.entry >> 8) + } + + { + const stream = 2 + const stream2 = 3 + br[stream].fillFast() + br[stream2].fillFast() + + val := br[stream].peekBitsFast(d.actualTableLog) + val2 := br[stream2].peekBitsFast(d.actualTableLog) + v := single[val&tlMask] + v2 := single[val2&tlMask] + br[stream].advance(uint8(v.entry)) + br[stream2].advance(uint8(v2.entry)) + buf[stream][off] = uint8(v.entry >> 8) + buf[stream2][off] = uint8(v2.entry >> 8) + + val = br[stream].peekBitsFast(d.actualTableLog) + val2 = br[stream2].peekBitsFast(d.actualTableLog) + v = single[val&tlMask] + v2 = single[val2&tlMask] + br[stream].advance(uint8(v.entry)) + br[stream2].advance(uint8(v2.entry)) + buf[stream][off+1] = uint8(v.entry >> 8) + buf[stream2][off+1] = uint8(v2.entry >> 8) + } + + off += 2 + + if off == 0 { + if bufoff > dstEvery { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 1") + } + // There must at least be 3 buffers left. + if len(out)-bufoff < dstEvery*3 { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 2") + } + //copy(out, buf[0][:]) + //copy(out[dstEvery:], buf[1][:]) + //copy(out[dstEvery*2:], buf[2][:]) + //copy(out[dstEvery*3:], buf[3][:]) + *(*[bufoff]byte)(out) = buf[0] + *(*[bufoff]byte)(out[dstEvery:]) = buf[1] + *(*[bufoff]byte)(out[dstEvery*2:]) = buf[2] + *(*[bufoff]byte)(out[dstEvery*3:]) = buf[3] + out = out[bufoff:] + decoded += bufoff * 4 + } + } + if off > 0 { + ioff := int(off) + if len(out) < dstEvery*3+ioff { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 3") + } + copy(out, buf[0][:off]) + copy(out[dstEvery:], buf[1][:off]) + copy(out[dstEvery*2:], buf[2][:off]) + copy(out[dstEvery*3:], buf[3][:off]) + decoded += int(off) * 4 + out = out[off:] + } + + // Decode remaining. + remainBytes := dstEvery - (decoded / 4) + for i := range br { + offset := dstEvery * i + endsAt := offset + remainBytes + if endsAt > len(out) { + endsAt = len(out) + } + br := &br[i] + bitsLeft := br.remaining() + for bitsLeft > 0 { + br.fill() + if offset >= endsAt { + d.bufs.Put(buf) + return nil, errors.New("corruption detected: stream overrun 4") + } + + // Read value and increment offset. + val := br.peekBitsFast(d.actualTableLog) + v := single[val&tlMask].entry + nBits := uint8(v) + br.advance(nBits) + bitsLeft -= uint(nBits) + out[offset] = uint8(v >> 8) + offset++ + } + if offset != endsAt { + d.bufs.Put(buf) + return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt) + } + decoded += offset - dstEvery*i + err = br.close() + if err != nil { + return nil, err + } + } + d.bufs.Put(buf) + if dstSize != decoded { + return nil, errors.New("corruption detected: short output block") + } + return dst, nil +} + +// Decompress1X will decompress a 1X encoded stream. +// The cap of the output buffer will be the maximum decompressed size. +// The length of the supplied input must match the end of a block exactly. +func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) { + if len(d.dt.single) == 0 { + return nil, errors.New("no table loaded") + } + if use8BitTables && d.actualTableLog <= 8 { + return d.decompress1X8Bit(dst, src) + } + var br bitReaderShifted + err := br.init(src) + if err != nil { + return dst, err + } + maxDecodedSize := cap(dst) + dst = dst[:0] + + // Avoid bounds check by always having full sized table. + const tlSize = 1 << tableLogMax + const tlMask = tlSize - 1 + dt := d.dt.single[:tlSize] + + // Use temp table to avoid bound checks/append penalty. + bufs := d.buffer() + buf := &bufs[0] + var off uint8 + + for br.off >= 8 { + br.fillFast() + v := dt[br.peekBitsFast(d.actualTableLog)&tlMask] + br.advance(uint8(v.entry)) + buf[off+0] = uint8(v.entry >> 8) + + v = dt[br.peekBitsFast(d.actualTableLog)&tlMask] + br.advance(uint8(v.entry)) + buf[off+1] = uint8(v.entry >> 8) + + // Refill + br.fillFast() + + v = dt[br.peekBitsFast(d.actualTableLog)&tlMask] + br.advance(uint8(v.entry)) + buf[off+2] = uint8(v.entry >> 8) + + v = dt[br.peekBitsFast(d.actualTableLog)&tlMask] + br.advance(uint8(v.entry)) + buf[off+3] = uint8(v.entry >> 8) + + off += 4 + if off == 0 { + if len(dst)+256 > maxDecodedSize { + br.close() + d.bufs.Put(bufs) + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:]...) + } + } + + if len(dst)+int(off) > maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + dst = append(dst, buf[:off]...) + + // br < 8, so uint8 is fine + bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead + for bitsLeft > 0 { + br.fill() + if false && br.bitsRead >= 32 { + if br.off >= 4 { + v := br.in[br.off-4:] + v = v[:4] + low := (uint32(v[0])) | (uint32(v[1]) << 8) | (uint32(v[2]) << 16) | (uint32(v[3]) << 24) + br.value = (br.value << 32) | uint64(low) + br.bitsRead -= 32 + br.off -= 4 + } else { + for br.off > 0 { + br.value = (br.value << 8) | uint64(br.in[br.off-1]) + br.bitsRead -= 8 + br.off-- + } + } + } + if len(dst) >= maxDecodedSize { + d.bufs.Put(bufs) + br.close() + return nil, ErrMaxDecodedSizeExceeded + } + v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask] + nBits := uint8(v.entry) + br.advance(nBits) + bitsLeft -= nBits + dst = append(dst, uint8(v.entry>>8)) + } + d.bufs.Put(bufs) + return dst, br.close() +} diff --git a/vendor/github.com/klauspost/compress/huff0/huff0.go b/vendor/github.com/klauspost/compress/huff0/huff0.go new file mode 100644 index 0000000..67d9e05 --- /dev/null +++ b/vendor/github.com/klauspost/compress/huff0/huff0.go @@ -0,0 +1,337 @@ +// Package huff0 provides fast huffman encoding as used in zstd. +// +// See README.md at https://github.com/klauspost/compress/tree/master/huff0 for details. +package huff0 + +import ( + "errors" + "fmt" + "math" + "math/bits" + "sync" + + "github.com/klauspost/compress/fse" +) + +const ( + maxSymbolValue = 255 + + // zstandard limits tablelog to 11, see: + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#huffman-tree-description + tableLogMax = 11 + tableLogDefault = 11 + minTablelog = 5 + huffNodesLen = 512 + + // BlockSizeMax is maximum input size for a single block uncompressed. + BlockSizeMax = 1<<18 - 1 +) + +var ( + // ErrIncompressible is returned when input is judged to be too hard to compress. + ErrIncompressible = errors.New("input is not compressible") + + // ErrUseRLE is returned from the compressor when the input is a single byte value repeated. + ErrUseRLE = errors.New("input is single value repeated") + + // ErrTooBig is return if input is too large for a single block. + ErrTooBig = errors.New("input too big") + + // ErrMaxDecodedSizeExceeded is return if input is too large for a single block. + ErrMaxDecodedSizeExceeded = errors.New("maximum output size exceeded") +) + +type ReusePolicy uint8 + +const ( + // ReusePolicyAllow will allow reuse if it produces smaller output. + ReusePolicyAllow ReusePolicy = iota + + // ReusePolicyPrefer will re-use aggressively if possible. + // This will not check if a new table will produce smaller output, + // except if the current table is impossible to use or + // compressed output is bigger than input. + ReusePolicyPrefer + + // ReusePolicyNone will disable re-use of tables. + // This is slightly faster than ReusePolicyAllow but may produce larger output. + ReusePolicyNone + + // ReusePolicyMust must allow reuse and produce smaller output. + ReusePolicyMust +) + +type Scratch struct { + count [maxSymbolValue + 1]uint32 + + // Per block parameters. + // These can be used to override compression parameters of the block. + // Do not touch, unless you know what you are doing. + + // Out is output buffer. + // If the scratch is re-used before the caller is done processing the output, + // set this field to nil. + // Otherwise the output buffer will be re-used for next Compression/Decompression step + // and allocation will be avoided. + Out []byte + + // OutTable will contain the table data only, if a new table has been generated. + // Slice of the returned data. + OutTable []byte + + // OutData will contain the compressed data. + // Slice of the returned data. + OutData []byte + + // MaxDecodedSize will set the maximum allowed output size. + // This value will automatically be set to BlockSizeMax if not set. + // Decoders will return ErrMaxDecodedSizeExceeded is this limit is exceeded. + MaxDecodedSize int + + srcLen int + + // MaxSymbolValue will override the maximum symbol value of the next block. + MaxSymbolValue uint8 + + // TableLog will attempt to override the tablelog for the next block. + // Must be <= 11 and >= 5. + TableLog uint8 + + // Reuse will specify the reuse policy + Reuse ReusePolicy + + // WantLogLess allows to specify a log 2 reduction that should at least be achieved, + // otherwise the block will be returned as incompressible. + // The reduction should then at least be (input size >> WantLogLess) + // If WantLogLess == 0 any improvement will do. + WantLogLess uint8 + + symbolLen uint16 // Length of active part of the symbol table. + maxCount int // count of the most probable symbol + clearCount bool // clear count + actualTableLog uint8 // Selected tablelog. + prevTableLog uint8 // Tablelog for previous table + prevTable cTable // Table used for previous compression. + cTable cTable // compression table + dt dTable // decompression table + nodes []nodeElt + tmpOut [4][]byte + fse *fse.Scratch + decPool sync.Pool // *[4][256]byte buffers. + huffWeight [maxSymbolValue + 1]byte +} + +// TransferCTable will transfer the previously used compression table. +func (s *Scratch) TransferCTable(src *Scratch) { + if cap(s.prevTable) < len(src.prevTable) { + s.prevTable = make(cTable, 0, maxSymbolValue+1) + } + s.prevTable = s.prevTable[:len(src.prevTable)] + copy(s.prevTable, src.prevTable) + s.prevTableLog = src.prevTableLog +} + +func (s *Scratch) prepare(in []byte) (*Scratch, error) { + if len(in) > BlockSizeMax { + return nil, ErrTooBig + } + if s == nil { + s = &Scratch{} + } + if s.MaxSymbolValue == 0 { + s.MaxSymbolValue = maxSymbolValue + } + if s.TableLog == 0 { + s.TableLog = tableLogDefault + } + if s.TableLog > tableLogMax || s.TableLog < minTablelog { + return nil, fmt.Errorf(" invalid tableLog %d (%d -> %d)", s.TableLog, minTablelog, tableLogMax) + } + if s.MaxDecodedSize <= 0 || s.MaxDecodedSize > BlockSizeMax { + s.MaxDecodedSize = BlockSizeMax + } + if s.clearCount && s.maxCount == 0 { + for i := range s.count { + s.count[i] = 0 + } + s.clearCount = false + } + if cap(s.Out) == 0 { + s.Out = make([]byte, 0, len(in)) + } + s.Out = s.Out[:0] + + s.OutTable = nil + s.OutData = nil + if cap(s.nodes) < huffNodesLen+1 { + s.nodes = make([]nodeElt, 0, huffNodesLen+1) + } + s.nodes = s.nodes[:0] + if s.fse == nil { + s.fse = &fse.Scratch{} + } + s.srcLen = len(in) + + return s, nil +} + +type cTable []cTableEntry + +func (c cTable) write(s *Scratch) error { + var ( + // precomputed conversion table + bitsToWeight [tableLogMax + 1]byte + huffLog = s.actualTableLog + // last weight is not saved. + maxSymbolValue = uint8(s.symbolLen - 1) + huffWeight = s.huffWeight[:256] + ) + const ( + maxFSETableLog = 6 + ) + // convert to weight + bitsToWeight[0] = 0 + for n := uint8(1); n < huffLog+1; n++ { + bitsToWeight[n] = huffLog + 1 - n + } + + // Acquire histogram for FSE. + hist := s.fse.Histogram() + hist = hist[:256] + for i := range hist[:16] { + hist[i] = 0 + } + for n := range maxSymbolValue { + v := bitsToWeight[c[n].nBits] & 15 + huffWeight[n] = v + hist[v]++ + } + + // FSE compress if feasible. + if maxSymbolValue >= 2 { + huffMaxCnt := uint32(0) + huffMax := uint8(0) + for i, v := range hist[:16] { + if v == 0 { + continue + } + huffMax = byte(i) + if v > huffMaxCnt { + huffMaxCnt = v + } + } + s.fse.HistogramFinished(huffMax, int(huffMaxCnt)) + s.fse.TableLog = maxFSETableLog + b, err := fse.Compress(huffWeight[:maxSymbolValue], s.fse) + if err == nil && len(b) < int(s.symbolLen>>1) { + s.Out = append(s.Out, uint8(len(b))) + s.Out = append(s.Out, b...) + return nil + } + // Unable to compress (RLE/uncompressible) + } + // write raw values as 4-bits (max : 15) + if maxSymbolValue > (256 - 128) { + // should not happen : likely means source cannot be compressed + return ErrIncompressible + } + op := s.Out + // special case, pack weights 4 bits/weight. + op = append(op, 128|(maxSymbolValue-1)) + // be sure it doesn't cause msan issue in final combination + huffWeight[maxSymbolValue] = 0 + for n := uint16(0); n < uint16(maxSymbolValue); n += 2 { + op = append(op, (huffWeight[n]<<4)|huffWeight[n+1]) + } + s.Out = op + return nil +} + +func (c cTable) estTableSize(s *Scratch) (sz int, err error) { + var ( + // precomputed conversion table + bitsToWeight [tableLogMax + 1]byte + huffLog = s.actualTableLog + // last weight is not saved. + maxSymbolValue = uint8(s.symbolLen - 1) + huffWeight = s.huffWeight[:256] + ) + const ( + maxFSETableLog = 6 + ) + // convert to weight + bitsToWeight[0] = 0 + for n := uint8(1); n < huffLog+1; n++ { + bitsToWeight[n] = huffLog + 1 - n + } + + // Acquire histogram for FSE. + hist := s.fse.Histogram() + hist = hist[:256] + for i := range hist[:16] { + hist[i] = 0 + } + for n := range maxSymbolValue { + v := bitsToWeight[c[n].nBits] & 15 + huffWeight[n] = v + hist[v]++ + } + + // FSE compress if feasible. + if maxSymbolValue >= 2 { + huffMaxCnt := uint32(0) + huffMax := uint8(0) + for i, v := range hist[:16] { + if v == 0 { + continue + } + huffMax = byte(i) + if v > huffMaxCnt { + huffMaxCnt = v + } + } + s.fse.HistogramFinished(huffMax, int(huffMaxCnt)) + s.fse.TableLog = maxFSETableLog + b, err := fse.Compress(huffWeight[:maxSymbolValue], s.fse) + if err == nil && len(b) < int(s.symbolLen>>1) { + sz += 1 + len(b) + return sz, nil + } + // Unable to compress (RLE/uncompressible) + } + // write raw values as 4-bits (max : 15) + if maxSymbolValue > (256 - 128) { + // should not happen : likely means source cannot be compressed + return 0, ErrIncompressible + } + // special case, pack weights 4 bits/weight. + sz += 1 + int(maxSymbolValue/2) + return sz, nil +} + +// estimateSize returns the estimated size in bytes of the input represented in the +// histogram supplied. +func (c cTable) estimateSize(hist []uint32) int { + nbBits := uint32(7) + for i, v := range c[:len(hist)] { + nbBits += uint32(v.nBits) * hist[i] + } + return int(nbBits >> 3) +} + +// minSize returns the minimum possible size considering the shannon limit. +func (s *Scratch) minSize(total int) int { + nbBits := float64(7) + fTotal := float64(total) + for _, v := range s.count[:s.symbolLen] { + n := float64(v) + if n > 0 { + nbBits += math.Log2(fTotal/n) * n + } + } + return int(nbBits) >> 3 +} + +func highBit32(val uint32) (n uint32) { + return uint32(bits.Len32(val) - 1) +} diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go new file mode 100644 index 0000000..3954c51 --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo.go @@ -0,0 +1,34 @@ +// Package cpuinfo gives runtime info about the current CPU. +// +// This is a very limited module meant for use internally +// in this project. For more versatile solution check +// https://github.com/klauspost/cpuid. +package cpuinfo + +// HasBMI1 checks whether an x86 CPU supports the BMI1 extension. +func HasBMI1() bool { + return hasBMI1 +} + +// HasBMI2 checks whether an x86 CPU supports the BMI2 extension. +func HasBMI2() bool { + return hasBMI2 +} + +// DisableBMI2 will disable BMI2, for testing purposes. +// Call returned function to restore previous state. +func DisableBMI2() func() { + old := hasBMI2 + hasBMI2 = false + return func() { + hasBMI2 = old + } +} + +// HasBMI checks whether an x86 CPU supports both BMI1 and BMI2 extensions. +func HasBMI() bool { + return HasBMI1() && HasBMI2() +} + +var hasBMI1 bool +var hasBMI2 bool diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go new file mode 100644 index 0000000..b97f905 --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.go @@ -0,0 +1,10 @@ +//go:build amd64 && !appengine && !noasm && gc + +package cpuinfo + +// go:noescape +func x86extensions() (bmi1, bmi2 bool) + +func init() { + hasBMI1, hasBMI2 = x86extensions() +} diff --git a/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s new file mode 100644 index 0000000..4465fbe --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/cpuinfo/cpuinfo_amd64.s @@ -0,0 +1,36 @@ +// +build !appengine +// +build gc +// +build !noasm + +#include "textflag.h" +#include "funcdata.h" +#include "go_asm.h" + +TEXT ·x86extensions(SB), NOSPLIT, $0 + // 1. determine max EAX value + XORQ AX, AX + CPUID + + CMPQ AX, $7 + JB unsupported + + // 2. EAX = 7, ECX = 0 --- see Table 3-8 "Information Returned by CPUID Instruction" + MOVQ $7, AX + MOVQ $0, CX + CPUID + + BTQ $3, BX // bit 3 = BMI1 + SETCS AL + + BTQ $8, BX // bit 8 = BMI2 + SETCS AH + + MOVB AL, bmi1+0(FP) + MOVB AH, bmi2+1(FP) + RET + +unsupported: + XORQ AX, AX + MOVB AL, bmi1+0(FP) + MOVB AL, bmi2+1(FP) + RET diff --git a/vendor/github.com/klauspost/compress/internal/le/le.go b/vendor/github.com/klauspost/compress/internal/le/le.go new file mode 100644 index 0000000..e54909e --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/le/le.go @@ -0,0 +1,5 @@ +package le + +type Indexer interface { + int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 +} diff --git a/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go b/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go new file mode 100644 index 0000000..4f2a0d8 --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/le/unsafe_disabled.go @@ -0,0 +1,42 @@ +//go:build !(amd64 || arm64 || ppc64le || riscv64) || nounsafe || purego || appengine + +package le + +import ( + "encoding/binary" +) + +// Load8 will load from b at index i. +func Load8[I Indexer](b []byte, i I) byte { + return b[i] +} + +// Load16 will load from b at index i. +func Load16[I Indexer](b []byte, i I) uint16 { + return binary.LittleEndian.Uint16(b[i:]) +} + +// Load32 will load from b at index i. +func Load32[I Indexer](b []byte, i I) uint32 { + return binary.LittleEndian.Uint32(b[i:]) +} + +// Load64 will load from b at index i. +func Load64[I Indexer](b []byte, i I) uint64 { + return binary.LittleEndian.Uint64(b[i:]) +} + +// Store16 will store v at b. +func Store16(b []byte, v uint16) { + binary.LittleEndian.PutUint16(b, v) +} + +// Store32 will store v at b. +func Store32(b []byte, v uint32) { + binary.LittleEndian.PutUint32(b, v) +} + +// Store64 will store v at b. +func Store64[I Indexer](b []byte, i I, v uint64) { + binary.LittleEndian.PutUint64(b[i:], v) +} diff --git a/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go b/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go new file mode 100644 index 0000000..218a38b --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/le/unsafe_enabled.go @@ -0,0 +1,52 @@ +// We enable 64 bit LE platforms: + +//go:build (amd64 || arm64 || ppc64le || riscv64) && !nounsafe && !purego && !appengine + +package le + +import ( + "unsafe" +) + +// Load8 will load from b at index i. +func Load8[I Indexer](b []byte, i I) byte { + //return binary.LittleEndian.Uint16(b[i:]) + //return *(*uint16)(unsafe.Pointer(&b[i])) + return *(*byte)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i)) +} + +// Load16 will load from b at index i. +func Load16[I Indexer](b []byte, i I) uint16 { + //return binary.LittleEndian.Uint16(b[i:]) + //return *(*uint16)(unsafe.Pointer(&b[i])) + return *(*uint16)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i)) +} + +// Load32 will load from b at index i. +func Load32[I Indexer](b []byte, i I) uint32 { + //return binary.LittleEndian.Uint32(b[i:]) + //return *(*uint32)(unsafe.Pointer(&b[i])) + return *(*uint32)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i)) +} + +// Load64 will load from b at index i. +func Load64[I Indexer](b []byte, i I) uint64 { + //return binary.LittleEndian.Uint64(b[i:]) + //return *(*uint64)(unsafe.Pointer(&b[i])) + return *(*uint64)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i)) +} + +// Store16 will store v at b. +func Store16(b []byte, v uint16) { + *(*uint16)(unsafe.Pointer(unsafe.SliceData(b))) = v +} + +// Store32 will store v at b. +func Store32(b []byte, v uint32) { + *(*uint32)(unsafe.Pointer(unsafe.SliceData(b))) = v +} + +// Store64 will store v at b[i:]. +func Store64[I Indexer](b []byte, i I, v uint64) { + *(*uint64)(unsafe.Add(unsafe.Pointer(unsafe.SliceData(b)), i)) = v +} diff --git a/vendor/github.com/klauspost/compress/internal/snapref/LICENSE b/vendor/github.com/klauspost/compress/internal/snapref/LICENSE new file mode 100644 index 0000000..6050c10 --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/snapref/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 The Snappy-Go Authors. 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. + * Neither the name of Google Inc. nor the names of its +contributors may 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 +OWNER 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/klauspost/compress/internal/snapref/decode.go b/vendor/github.com/klauspost/compress/internal/snapref/decode.go new file mode 100644 index 0000000..584b757 --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/snapref/decode.go @@ -0,0 +1,264 @@ +// Copyright 2011 The Snappy-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 snapref + +import ( + "encoding/binary" + "errors" + "io" +) + +var ( + // ErrCorrupt reports that the input is invalid. + ErrCorrupt = errors.New("snappy: corrupt input") + // ErrTooLarge reports that the uncompressed length is too large. + ErrTooLarge = errors.New("snappy: decoded block is too large") + // ErrUnsupported reports that the input isn't supported. + ErrUnsupported = errors.New("snappy: unsupported input") + + errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length") +) + +// DecodedLen returns the length of the decoded block. +func DecodedLen(src []byte) (int, error) { + v, _, err := decodedLen(src) + return v, err +} + +// decodedLen returns the length of the decoded block and the number of bytes +// that the length header occupied. +func decodedLen(src []byte) (blockLen, headerLen int, err error) { + v, n := binary.Uvarint(src) + if n <= 0 || n > 5 || v > 0xffffffff { + return 0, 0, ErrCorrupt + } + + const wordSize = 32 << (^uint(0) >> 32 & 1) + if wordSize == 32 && v > 0x7fffffff { + return 0, 0, ErrTooLarge + } + return int(v), n, nil +} + +const ( + decodeErrCodeCorrupt = 1 + decodeErrCodeUnsupportedLiteralLength = 2 +) + +// Decode returns the decoded form of src. The returned slice may be a sub- +// slice of dst if dst was large enough to hold the entire decoded block. +// Otherwise, a newly allocated slice will be returned. +// +// The dst and src must not overlap. It is valid to pass a nil dst. +// +// Decode handles the Snappy block format, not the Snappy stream format. +func Decode(dst, src []byte) ([]byte, error) { + dLen, s, err := decodedLen(src) + if err != nil { + return nil, err + } + if dLen <= len(dst) { + dst = dst[:dLen] + } else { + dst = make([]byte, dLen) + } + switch decode(dst, src[s:]) { + case 0: + return dst, nil + case decodeErrCodeUnsupportedLiteralLength: + return nil, errUnsupportedLiteralLength + } + return nil, ErrCorrupt +} + +// NewReader returns a new Reader that decompresses from r, using the framing +// format described at +// https://github.com/google/snappy/blob/master/framing_format.txt +func NewReader(r io.Reader) *Reader { + return &Reader{ + r: r, + decoded: make([]byte, maxBlockSize), + buf: make([]byte, maxEncodedLenOfMaxBlockSize+checksumSize), + } +} + +// Reader is an io.Reader that can read Snappy-compressed bytes. +// +// Reader handles the Snappy stream format, not the Snappy block format. +type Reader struct { + r io.Reader + err error + decoded []byte + buf []byte + // decoded[i:j] contains decoded bytes that have not yet been passed on. + i, j int + readHeader bool +} + +// Reset discards any buffered data, resets all state, and switches the Snappy +// reader to read from r. This permits reusing a Reader rather than allocating +// a new one. +func (r *Reader) Reset(reader io.Reader) { + r.r = reader + r.err = nil + r.i = 0 + r.j = 0 + r.readHeader = false +} + +func (r *Reader) readFull(p []byte, allowEOF bool) (ok bool) { + if _, r.err = io.ReadFull(r.r, p); r.err != nil { + if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) { + r.err = ErrCorrupt + } + return false + } + return true +} + +func (r *Reader) fill() error { + for r.i >= r.j { + if !r.readFull(r.buf[:4], true) { + return r.err + } + chunkType := r.buf[0] + if !r.readHeader { + if chunkType != chunkTypeStreamIdentifier { + r.err = ErrCorrupt + return r.err + } + r.readHeader = true + } + chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16 + if chunkLen > len(r.buf) { + r.err = ErrUnsupported + return r.err + } + + // The chunk types are specified at + // https://github.com/google/snappy/blob/master/framing_format.txt + switch chunkType { + case chunkTypeCompressedData: + // Section 4.2. Compressed data (chunk type 0x00). + if chunkLen < checksumSize { + r.err = ErrCorrupt + return r.err + } + buf := r.buf[:chunkLen] + if !r.readFull(buf, false) { + return r.err + } + checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 + buf = buf[checksumSize:] + + n, err := DecodedLen(buf) + if err != nil { + r.err = err + return r.err + } + if n > len(r.decoded) { + r.err = ErrCorrupt + return r.err + } + if _, err := Decode(r.decoded, buf); err != nil { + r.err = err + return r.err + } + if crc(r.decoded[:n]) != checksum { + r.err = ErrCorrupt + return r.err + } + r.i, r.j = 0, n + continue + + case chunkTypeUncompressedData: + // Section 4.3. Uncompressed data (chunk type 0x01). + if chunkLen < checksumSize { + r.err = ErrCorrupt + return r.err + } + buf := r.buf[:checksumSize] + if !r.readFull(buf, false) { + return r.err + } + checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 + // Read directly into r.decoded instead of via r.buf. + n := chunkLen - checksumSize + if n > len(r.decoded) { + r.err = ErrCorrupt + return r.err + } + if !r.readFull(r.decoded[:n], false) { + return r.err + } + if crc(r.decoded[:n]) != checksum { + r.err = ErrCorrupt + return r.err + } + r.i, r.j = 0, n + continue + + case chunkTypeStreamIdentifier: + // Section 4.1. Stream identifier (chunk type 0xff). + if chunkLen != len(magicBody) { + r.err = ErrCorrupt + return r.err + } + if !r.readFull(r.buf[:len(magicBody)], false) { + return r.err + } + for i := range len(magicBody) { + if r.buf[i] != magicBody[i] { + r.err = ErrCorrupt + return r.err + } + } + continue + } + + if chunkType <= 0x7f { + // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f). + r.err = ErrUnsupported + return r.err + } + // Section 4.4 Padding (chunk type 0xfe). + // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd). + if !r.readFull(r.buf[:chunkLen], false) { + return r.err + } + } + + return nil +} + +// Read satisfies the io.Reader interface. +func (r *Reader) Read(p []byte) (int, error) { + if r.err != nil { + return 0, r.err + } + + if err := r.fill(); err != nil { + return 0, err + } + + n := copy(p, r.decoded[r.i:r.j]) + r.i += n + return n, nil +} + +// ReadByte satisfies the io.ByteReader interface. +func (r *Reader) ReadByte() (byte, error) { + if r.err != nil { + return 0, r.err + } + + if err := r.fill(); err != nil { + return 0, err + } + + c := r.decoded[r.i] + r.i++ + return c, nil +} diff --git a/vendor/github.com/klauspost/compress/internal/snapref/decode_other.go b/vendor/github.com/klauspost/compress/internal/snapref/decode_other.go new file mode 100644 index 0000000..77395a6 --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/snapref/decode_other.go @@ -0,0 +1,113 @@ +// Copyright 2016 The Snappy-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 snapref + +// decode writes the decoding of src to dst. It assumes that the varint-encoded +// length of the decompressed bytes has already been read, and that len(dst) +// equals that length. +// +// It returns 0 on success or a decodeErrCodeXxx error code on failure. +func decode(dst, src []byte) int { + var d, s, offset, length int + for s < len(src) { + switch src[s] & 0x03 { + case tagLiteral: + x := uint32(src[s] >> 2) + switch { + case x < 60: + s++ + case x == 60: + s += 2 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + x = uint32(src[s-1]) + case x == 61: + s += 3 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + x = uint32(src[s-2]) | uint32(src[s-1])<<8 + case x == 62: + s += 4 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16 + case x == 63: + s += 5 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24 + } + length = int(x) + 1 + if length <= 0 { + return decodeErrCodeUnsupportedLiteralLength + } + if length > len(dst)-d || length > len(src)-s { + return decodeErrCodeCorrupt + } + copy(dst[d:], src[s:s+length]) + d += length + s += length + continue + + case tagCopy1: + s += 2 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + length = 4 + int(src[s-2])>>2&0x7 + offset = int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1])) + + case tagCopy2: + s += 3 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + length = 1 + int(src[s-3])>>2 + offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8) + + case tagCopy4: + s += 5 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + return decodeErrCodeCorrupt + } + length = 1 + int(src[s-5])>>2 + offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24) + } + + if offset <= 0 || d < offset || length > len(dst)-d { + return decodeErrCodeCorrupt + } + // Copy from an earlier sub-slice of dst to a later sub-slice. + // If no overlap, use the built-in copy: + if offset >= length { + copy(dst[d:d+length], dst[d-offset:]) + d += length + continue + } + + // Unlike the built-in copy function, this byte-by-byte copy always runs + // forwards, even if the slices overlap. Conceptually, this is: + // + // d += forwardCopy(dst[d:d+length], dst[d-offset:]) + // + // We align the slices into a and b and show the compiler they are the same size. + // This allows the loop to run without bounds checks. + a := dst[d : d+length] + b := dst[d-offset:] + b = b[:len(a)] + for i := range a { + a[i] = b[i] + } + d += length + } + if d != len(dst) { + return decodeErrCodeCorrupt + } + return 0 +} diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode.go b/vendor/github.com/klauspost/compress/internal/snapref/encode.go new file mode 100644 index 0000000..860a994 --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/snapref/encode.go @@ -0,0 +1,291 @@ +// Copyright 2011 The Snappy-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 snapref + +import ( + "encoding/binary" + "errors" + "io" +) + +// Encode returns the encoded form of src. The returned slice may be a sub- +// slice of dst if dst was large enough to hold the entire encoded block. +// Otherwise, a newly allocated slice will be returned. +// +// The dst and src must not overlap. It is valid to pass a nil dst. +// +// Encode handles the Snappy block format, not the Snappy stream format. +func Encode(dst, src []byte) []byte { + if n := MaxEncodedLen(len(src)); n < 0 { + panic(ErrTooLarge) + } else if cap(dst) < n { + dst = make([]byte, n) + } else { + dst = dst[:n] + } + + // The block starts with the varint-encoded length of the decompressed bytes. + d := binary.PutUvarint(dst, uint64(len(src))) + + for len(src) > 0 { + p := src + src = nil + if len(p) > maxBlockSize { + p, src = p[:maxBlockSize], p[maxBlockSize:] + } + if len(p) < minNonLiteralBlockSize { + d += emitLiteral(dst[d:], p) + } else { + d += encodeBlock(dst[d:], p) + } + } + return dst[:d] +} + +// inputMargin is the minimum number of extra input bytes to keep, inside +// encodeBlock's inner loop. On some architectures, this margin lets us +// implement a fast path for emitLiteral, where the copy of short (<= 16 byte) +// literals can be implemented as a single load to and store from a 16-byte +// register. That literal's actual length can be as short as 1 byte, so this +// can copy up to 15 bytes too much, but that's OK as subsequent iterations of +// the encoding loop will fix up the copy overrun, and this inputMargin ensures +// that we don't overrun the dst and src buffers. +const inputMargin = 16 - 1 + +// minNonLiteralBlockSize is the minimum size of the input to encodeBlock that +// could be encoded with a copy tag. This is the minimum with respect to the +// algorithm used by encodeBlock, not a minimum enforced by the file format. +// +// The encoded output must start with at least a 1 byte literal, as there are +// no previous bytes to copy. A minimal (1 byte) copy after that, generated +// from an emitCopy call in encodeBlock's main loop, would require at least +// another inputMargin bytes, for the reason above: we want any emitLiteral +// calls inside encodeBlock's main loop to use the fast path if possible, which +// requires being able to overrun by inputMargin bytes. Thus, +// minNonLiteralBlockSize equals 1 + 1 + inputMargin. +// +// The C++ code doesn't use this exact threshold, but it could, as discussed at +// https://groups.google.com/d/topic/snappy-compression/oGbhsdIJSJ8/discussion +// The difference between Go (2+inputMargin) and C++ (inputMargin) is purely an +// optimization. It should not affect the encoded form. This is tested by +// TestSameEncodingAsCppShortCopies. +const minNonLiteralBlockSize = 1 + 1 + inputMargin + +// MaxEncodedLen returns the maximum length of a snappy block, given its +// uncompressed length. +// +// It will return a negative value if srcLen is too large to encode. +func MaxEncodedLen(srcLen int) int { + n := uint64(srcLen) + if n > 0xffffffff { + return -1 + } + // Compressed data can be defined as: + // compressed := item* literal* + // item := literal* copy + // + // The trailing literal sequence has a space blowup of at most 62/60 + // since a literal of length 60 needs one tag byte + one extra byte + // for length information. + // + // Item blowup is trickier to measure. Suppose the "copy" op copies + // 4 bytes of data. Because of a special check in the encoding code, + // we produce a 4-byte copy only if the offset is < 65536. Therefore + // the copy op takes 3 bytes to encode, and this type of item leads + // to at most the 62/60 blowup for representing literals. + // + // Suppose the "copy" op copies 5 bytes of data. If the offset is big + // enough, it will take 5 bytes to encode the copy op. Therefore the + // worst case here is a one-byte literal followed by a five-byte copy. + // That is, 6 bytes of input turn into 7 bytes of "compressed" data. + // + // This last factor dominates the blowup, so the final estimate is: + n = 32 + n + n/6 + if n > 0xffffffff { + return -1 + } + return int(n) +} + +var errClosed = errors.New("snappy: Writer is closed") + +// NewWriter returns a new Writer that compresses to w. +// +// The Writer returned does not buffer writes. There is no need to Flush or +// Close such a Writer. +// +// Deprecated: the Writer returned is not suitable for many small writes, only +// for few large writes. Use NewBufferedWriter instead, which is efficient +// regardless of the frequency and shape of the writes, and remember to Close +// that Writer when done. +func NewWriter(w io.Writer) *Writer { + return &Writer{ + w: w, + obuf: make([]byte, obufLen), + } +} + +// NewBufferedWriter returns a new Writer that compresses to w, using the +// framing format described at +// https://github.com/google/snappy/blob/master/framing_format.txt +// +// The Writer returned buffers writes. Users must call Close to guarantee all +// data has been forwarded to the underlying io.Writer. They may also call +// Flush zero or more times before calling Close. +func NewBufferedWriter(w io.Writer) *Writer { + return &Writer{ + w: w, + ibuf: make([]byte, 0, maxBlockSize), + obuf: make([]byte, obufLen), + } +} + +// Writer is an io.Writer that can write Snappy-compressed bytes. +// +// Writer handles the Snappy stream format, not the Snappy block format. +type Writer struct { + w io.Writer + err error + + // ibuf is a buffer for the incoming (uncompressed) bytes. + // + // Its use is optional. For backwards compatibility, Writers created by the + // NewWriter function have ibuf == nil, do not buffer incoming bytes, and + // therefore do not need to be Flush'ed or Close'd. + ibuf []byte + + // obuf is a buffer for the outgoing (compressed) bytes. + obuf []byte + + // wroteStreamHeader is whether we have written the stream header. + wroteStreamHeader bool +} + +// Reset discards the writer's state and switches the Snappy writer to write to +// w. This permits reusing a Writer rather than allocating a new one. +func (w *Writer) Reset(writer io.Writer) { + w.w = writer + w.err = nil + if w.ibuf != nil { + w.ibuf = w.ibuf[:0] + } + w.wroteStreamHeader = false +} + +// Write satisfies the io.Writer interface. +func (w *Writer) Write(p []byte) (nRet int, errRet error) { + if w.ibuf == nil { + // Do not buffer incoming bytes. This does not perform or compress well + // if the caller of Writer.Write writes many small slices. This + // behavior is therefore deprecated, but still supported for backwards + // compatibility with code that doesn't explicitly Flush or Close. + return w.write(p) + } + + // The remainder of this method is based on bufio.Writer.Write from the + // standard library. + + for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil { + var n int + if len(w.ibuf) == 0 { + // Large write, empty buffer. + // Write directly from p to avoid copy. + n, _ = w.write(p) + } else { + n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p) + w.ibuf = w.ibuf[:len(w.ibuf)+n] + w.Flush() + } + nRet += n + p = p[n:] + } + if w.err != nil { + return nRet, w.err + } + n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p) + w.ibuf = w.ibuf[:len(w.ibuf)+n] + nRet += n + return nRet, nil +} + +func (w *Writer) write(p []byte) (nRet int, errRet error) { + if w.err != nil { + return 0, w.err + } + for len(p) > 0 { + obufStart := len(magicChunk) + if !w.wroteStreamHeader { + w.wroteStreamHeader = true + copy(w.obuf, magicChunk) + obufStart = 0 + } + + var uncompressed []byte + if len(p) > maxBlockSize { + uncompressed, p = p[:maxBlockSize], p[maxBlockSize:] + } else { + uncompressed, p = p, nil + } + checksum := crc(uncompressed) + + // Compress the buffer, discarding the result if the improvement + // isn't at least 12.5%. + compressed := Encode(w.obuf[obufHeaderLen:], uncompressed) + chunkType := uint8(chunkTypeCompressedData) + chunkLen := 4 + len(compressed) + obufEnd := obufHeaderLen + len(compressed) + if len(compressed) >= len(uncompressed)-len(uncompressed)/8 { + chunkType = chunkTypeUncompressedData + chunkLen = 4 + len(uncompressed) + obufEnd = obufHeaderLen + } + + // Fill in the per-chunk header that comes before the body. + w.obuf[len(magicChunk)+0] = chunkType + w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0) + w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8) + w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16) + w.obuf[len(magicChunk)+4] = uint8(checksum >> 0) + w.obuf[len(magicChunk)+5] = uint8(checksum >> 8) + w.obuf[len(magicChunk)+6] = uint8(checksum >> 16) + w.obuf[len(magicChunk)+7] = uint8(checksum >> 24) + + if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil { + w.err = err + return nRet, err + } + if chunkType == chunkTypeUncompressedData { + if _, err := w.w.Write(uncompressed); err != nil { + w.err = err + return nRet, err + } + } + nRet += len(uncompressed) + } + return nRet, nil +} + +// Flush flushes the Writer to its underlying io.Writer. +func (w *Writer) Flush() error { + if w.err != nil { + return w.err + } + if len(w.ibuf) == 0 { + return nil + } + w.write(w.ibuf) + w.ibuf = w.ibuf[:0] + return w.err +} + +// Close calls Flush and then closes the Writer. +func (w *Writer) Close() error { + w.Flush() + ret := w.err + if w.err == nil { + w.err = errClosed + } + return ret +} diff --git a/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go new file mode 100644 index 0000000..2754bac --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/snapref/encode_other.go @@ -0,0 +1,250 @@ +// Copyright 2016 The Snappy-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 snapref + +func load32(b []byte, i int) uint32 { + b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line. + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func load64(b []byte, i int) uint64 { + b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line. + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +// emitLiteral writes a literal chunk and returns the number of bytes written. +// +// It assumes that: +// +// dst is long enough to hold the encoded bytes +// 1 <= len(lit) && len(lit) <= 65536 +func emitLiteral(dst, lit []byte) int { + i, n := 0, uint(len(lit)-1) + switch { + case n < 60: + dst[0] = uint8(n)<<2 | tagLiteral + i = 1 + case n < 1<<8: + dst[0] = 60<<2 | tagLiteral + dst[1] = uint8(n) + i = 2 + default: + dst[0] = 61<<2 | tagLiteral + dst[1] = uint8(n) + dst[2] = uint8(n >> 8) + i = 3 + } + return i + copy(dst[i:], lit) +} + +// emitCopy writes a copy chunk and returns the number of bytes written. +// +// It assumes that: +// +// dst is long enough to hold the encoded bytes +// 1 <= offset && offset <= 65535 +// 4 <= length && length <= 65535 +func emitCopy(dst []byte, offset, length int) int { + i := 0 + // The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The + // threshold for this loop is a little higher (at 68 = 64 + 4), and the + // length emitted down below is a little lower (at 60 = 64 - 4), because + // it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed + // by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as + // a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as + // 3+3 bytes). The magic 4 in the 64±4 is because the minimum length for a + // tagCopy1 op is 4 bytes, which is why a length 3 copy has to be an + // encodes-as-3-bytes tagCopy2 instead of an encodes-as-2-bytes tagCopy1. + for length >= 68 { + // Emit a length 64 copy, encoded as 3 bytes. + dst[i+0] = 63<<2 | tagCopy2 + dst[i+1] = uint8(offset) + dst[i+2] = uint8(offset >> 8) + i += 3 + length -= 64 + } + if length > 64 { + // Emit a length 60 copy, encoded as 3 bytes. + dst[i+0] = 59<<2 | tagCopy2 + dst[i+1] = uint8(offset) + dst[i+2] = uint8(offset >> 8) + i += 3 + length -= 60 + } + if length >= 12 || offset >= 2048 { + // Emit the remaining copy, encoded as 3 bytes. + dst[i+0] = uint8(length-1)<<2 | tagCopy2 + dst[i+1] = uint8(offset) + dst[i+2] = uint8(offset >> 8) + return i + 3 + } + // Emit the remaining copy, encoded as 2 bytes. + dst[i+0] = uint8(offset>>8)<<5 | uint8(length-4)<<2 | tagCopy1 + dst[i+1] = uint8(offset) + return i + 2 +} + +func hash(u, shift uint32) uint32 { + return (u * 0x1e35a7bd) >> shift +} + +// EncodeBlockInto exposes encodeBlock but checks dst size. +func EncodeBlockInto(dst, src []byte) (d int) { + if MaxEncodedLen(len(src)) > len(dst) { + return 0 + } + + // encodeBlock breaks on too big blocks, so split. + for len(src) > 0 { + p := src + src = nil + if len(p) > maxBlockSize { + p, src = p[:maxBlockSize], p[maxBlockSize:] + } + if len(p) < minNonLiteralBlockSize { + d += emitLiteral(dst[d:], p) + } else { + d += encodeBlock(dst[d:], p) + } + } + return d +} + +// encodeBlock encodes a non-empty src to a guaranteed-large-enough dst. It +// assumes that the varint-encoded length of the decompressed bytes has already +// been written. +// +// It also assumes that: +// +// len(dst) >= MaxEncodedLen(len(src)) && +// minNonLiteralBlockSize <= len(src) && len(src) <= maxBlockSize +func encodeBlock(dst, src []byte) (d int) { + // Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive. + // The table element type is uint16, as s < sLimit and sLimit < len(src) + // and len(src) <= maxBlockSize and maxBlockSize == 65536. + const ( + maxTableSize = 1 << 14 + // tableMask is redundant, but helps the compiler eliminate bounds + // checks. + tableMask = maxTableSize - 1 + ) + shift := uint32(32 - 8) + for tableSize := 1 << 8; tableSize < maxTableSize && tableSize < len(src); tableSize *= 2 { + shift-- + } + // In Go, all array elements are zero-initialized, so there is no advantage + // to a smaller tableSize per se. However, it matches the C++ algorithm, + // and in the asm versions of this code, we can get away with zeroing only + // the first tableSize elements. + var table [maxTableSize]uint16 + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := len(src) - inputMargin + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := 0 + + // The encoded form must start with a literal, as there are no previous + // bytes to copy, so we start looking for hash matches at s == 1. + s := 1 + nextHash := hash(load32(src, s), shift) + + for { + // Copied from the C++ snappy implementation: + // + // Heuristic match skipping: If 32 bytes are scanned with no matches + // found, start looking only at every other byte. If 32 more bytes are + // scanned (or skipped), look at every third byte, etc.. When a match + // is found, immediately go back to looking at every byte. This is a + // small loss (~5% performance, ~0.1% density) for compressible data + // due to more bookkeeping, but for non-compressible data (such as + // JPEG) it's a huge win since the compressor quickly "realizes" the + // data is incompressible and doesn't bother looking for matches + // everywhere. + // + // The "skip" variable keeps track of how many bytes there are since + // the last match; dividing it by 32 (ie. right-shifting by five) gives + // the number of bytes to move ahead for each iteration. + skip := 32 + + nextS := s + candidate := 0 + for { + s = nextS + bytesBetweenHashLookups := skip >> 5 + nextS = s + bytesBetweenHashLookups + skip += bytesBetweenHashLookups + if nextS > sLimit { + goto emitRemainder + } + candidate = int(table[nextHash&tableMask]) + table[nextHash&tableMask] = uint16(s) + nextHash = hash(load32(src, nextS), shift) + if load32(src, s) == load32(src, candidate) { + break + } + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + d += emitLiteral(dst[d:], src[nextEmit:s]) + + // Call emitCopy, and then see if another emitCopy could be our next + // move. Repeat until we find no match for the input immediately after + // what was consumed by the last emitCopy call. + // + // If we exit this loop normally then we need to call emitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can + // exit this loop via goto if we get close to exhausting the input. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + base := s + + // Extend the 4-byte match as long as possible. + // + // This is an inlined version of: + // s = extendMatch(src, candidate+4, s+4) + s += 4 + for i := candidate + 4; s < len(src) && src[i] == src[s]; i, s = i+1, s+1 { + } + + d += emitCopy(dst[d:], base-candidate, s-base) + nextEmit = s + if s >= sLimit { + goto emitRemainder + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-1 and at s. If + // another emitCopy is not our next move, also calculate nextHash + // at s+1. At least on GOARCH=amd64, these three hash calculations + // are faster as one load64 call (with some shifts) instead of + // three load32 calls. + x := load64(src, s-1) + prevHash := hash(uint32(x>>0), shift) + table[prevHash&tableMask] = uint16(s - 1) + currHash := hash(uint32(x>>8), shift) + candidate = int(table[currHash&tableMask]) + table[currHash&tableMask] = uint16(s) + if uint32(x>>8) != load32(src, candidate) { + nextHash = hash(uint32(x>>16), shift) + s++ + break + } + } + } + +emitRemainder: + if nextEmit < len(src) { + d += emitLiteral(dst[d:], src[nextEmit:]) + } + return d +} diff --git a/vendor/github.com/klauspost/compress/internal/snapref/snappy.go b/vendor/github.com/klauspost/compress/internal/snapref/snappy.go new file mode 100644 index 0000000..34d01f4 --- /dev/null +++ b/vendor/github.com/klauspost/compress/internal/snapref/snappy.go @@ -0,0 +1,98 @@ +// Copyright 2011 The Snappy-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 snapref implements the Snappy compression format. It aims for very +// high speeds and reasonable compression. +// +// There are actually two Snappy formats: block and stream. They are related, +// but different: trying to decompress block-compressed data as a Snappy stream +// will fail, and vice versa. The block format is the Decode and Encode +// functions and the stream format is the Reader and Writer types. +// +// The block format, the more common case, is used when the complete size (the +// number of bytes) of the original data is known upfront, at the time +// compression starts. The stream format, also known as the framing format, is +// for when that isn't always true. +// +// The canonical, C++ implementation is at https://github.com/google/snappy and +// it only implements the block format. +package snapref + +import ( + "hash/crc32" +) + +/* +Each encoded block begins with the varint-encoded length of the decoded data, +followed by a sequence of chunks. Chunks begin and end on byte boundaries. The +first byte of each chunk is broken into its 2 least and 6 most significant bits +called l and m: l ranges in [0, 4) and m ranges in [0, 64). l is the chunk tag. +Zero means a literal tag. All other values mean a copy tag. + +For literal tags: + - If m < 60, the next 1 + m bytes are literal bytes. + - Otherwise, let n be the little-endian unsigned integer denoted by the next + m - 59 bytes. The next 1 + n bytes after that are literal bytes. + +For copy tags, length bytes are copied from offset bytes ago, in the style of +Lempel-Ziv compression algorithms. In particular: + - For l == 1, the offset ranges in [0, 1<<11) and the length in [4, 12). + The length is 4 + the low 3 bits of m. The high 3 bits of m form bits 8-10 + of the offset. The next byte is bits 0-7 of the offset. + - For l == 2, the offset ranges in [0, 1<<16) and the length in [1, 65). + The length is 1 + m. The offset is the little-endian unsigned integer + denoted by the next 2 bytes. + - For l == 3, this tag is a legacy format that is no longer issued by most + encoders. Nonetheless, the offset ranges in [0, 1<<32) and the length in + [1, 65). The length is 1 + m. The offset is the little-endian unsigned + integer denoted by the next 4 bytes. +*/ +const ( + tagLiteral = 0x00 + tagCopy1 = 0x01 + tagCopy2 = 0x02 + tagCopy4 = 0x03 +) + +const ( + checksumSize = 4 + chunkHeaderSize = 4 + magicChunk = "\xff\x06\x00\x00" + magicBody + magicBody = "sNaPpY" + + // maxBlockSize is the maximum size of the input to encodeBlock. It is not + // part of the wire format per se, but some parts of the encoder assume + // that an offset fits into a uint16. + // + // Also, for the framing format (Writer type instead of Encode function), + // https://github.com/google/snappy/blob/master/framing_format.txt says + // that "the uncompressed data in a chunk must be no longer than 65536 + // bytes". + maxBlockSize = 65536 + + // maxEncodedLenOfMaxBlockSize equals MaxEncodedLen(maxBlockSize), but is + // hard coded to be a const instead of a variable, so that obufLen can also + // be a const. Their equivalence is confirmed by + // TestMaxEncodedLenOfMaxBlockSize. + maxEncodedLenOfMaxBlockSize = 76490 + + obufHeaderLen = len(magicChunk) + checksumSize + chunkHeaderSize + obufLen = obufHeaderLen + maxEncodedLenOfMaxBlockSize +) + +const ( + chunkTypeCompressedData = 0x00 + chunkTypeUncompressedData = 0x01 + chunkTypePadding = 0xfe + chunkTypeStreamIdentifier = 0xff +) + +var crcTable = crc32.MakeTable(crc32.Castagnoli) + +// crc implements the checksum specified in section 3 of +// https://github.com/google/snappy/blob/master/framing_format.txt +func crc(b []byte) uint32 { + c := crc32.Update(0, crcTable, b) + return uint32(c>>15|c<<17) + 0xa282ead8 +} diff --git a/vendor/github.com/klauspost/compress/s2sx.mod b/vendor/github.com/klauspost/compress/s2sx.mod new file mode 100644 index 0000000..81bda5e --- /dev/null +++ b/vendor/github.com/klauspost/compress/s2sx.mod @@ -0,0 +1,3 @@ +module github.com/klauspost/compress + +go 1.22 diff --git a/vendor/github.com/klauspost/compress/s2sx.sum b/vendor/github.com/klauspost/compress/s2sx.sum new file mode 100644 index 0000000..e69de29 diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md new file mode 100644 index 0000000..a5aeeae --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/README.md @@ -0,0 +1,474 @@ +# zstd + +[Zstandard](https://facebook.github.io/zstd/) is a real-time compression algorithm, providing high compression ratios. +It offers a very wide range of compression / speed trade-off, while being backed by a very fast decoder. +A high performance compression algorithm is implemented. For now focused on speed. + +This package provides [compression](#Compressor) to and [decompression](#Decompressor) of Zstandard content. + +This package is pure Go. Use `noasm` and `nounsafe` to disable relevant features. + +The `zstd` package is provided as open source software using a Go standard license. + +Currently the package is heavily optimized for 64 bit processors and will be significantly slower on 32 bit processors. + +For seekable zstd streams, see [this excellent package](https://github.com/SaveTheRbtz/zstd-seekable-format-go). + +## Installation + +Install using `go get -u github.com/klauspost/compress`. The package is located in `github.com/klauspost/compress/zstd`. + +[![Go Reference](https://pkg.go.dev/badge/github.com/klauspost/compress/zstd.svg)](https://pkg.go.dev/github.com/klauspost/compress/zstd) + +## Compressor + +### Status: + +STABLE - there may always be subtle bugs, a wide variety of content has been tested and the library is actively +used by several projects. This library is being [fuzz-tested](https://github.com/klauspost/compress-fuzz) for all updates. + +There may still be specific combinations of data types/size/settings that could lead to edge cases, +so as always, testing is recommended. + +For now, a high speed (fastest) and medium-fast (default) compressor has been implemented. + +* The "Fastest" compression ratio is roughly equivalent to zstd level 1. +* The "Default" compression ratio is roughly equivalent to zstd level 3 (default). +* The "Better" compression ratio is roughly equivalent to zstd level 7. +* The "Best" compression ratio is roughly equivalent to zstd level 11. + +In terms of speed, it is typically 2x as fast as the stdlib deflate/gzip in its fastest mode. +The compression ratio compared to stdlib is around level 3, but usually 3x as fast. + + +### Usage + +An Encoder can be used for either compressing a stream via the +`io.WriteCloser` interface supported by the Encoder or as multiple independent +tasks via the `EncodeAll` function. +Smaller encodes are encouraged to use the EncodeAll function. +Use `NewWriter` to create a new instance that can be used for both. + +To create a writer with default options, do like this: + +```Go +// Compress input to output. +func Compress(in io.Reader, out io.Writer) error { + enc, err := zstd.NewWriter(out) + if err != nil { + return err + } + _, err = io.Copy(enc, in) + if err != nil { + enc.Close() + return err + } + return enc.Close() +} +``` + +Now you can encode by writing data to `enc`. The output will be finished writing when `Close()` is called. +Even if your encode fails, you should still call `Close()` to release any resources that may be held up. + +The above is fine for big encodes. However, whenever possible try to *reuse* the writer. + +To reuse the encoder, you can use the `Reset(io.Writer)` function to change to another output. +This will allow the encoder to reuse all resources and avoid wasteful allocations. + +By default, stream encoding has 'light' concurrency, meaning up to 2 goroutines can be working on part +of a stream. This is independent of the `WithEncoderConcurrency(n)`, but that is likely to change +in the future. So if you want to limit concurrency for future updates, specify the concurrency +you would like. + +If you would like stream encoding to be done without spawning async goroutines, use `WithEncoderConcurrency(1)` +which will compress input as each block is completed, blocking on writes until each has completed. + +#### Parallel Stream Compression + +For maximum throughput on large streams, use `WithConcurrentBlocks(true)` together with +`WithEncoderConcurrency(n)` where n is the number of CPU cores you want to use. +This splits the input into large sections (jobs) that are compressed simultaneously by multiple goroutines, +similar to how the C zstd library does multithreaded compression. + +```Go +enc, err := zstd.NewWriter(out, + zstd.WithEncoderLevel(zstd.SpeedDefault), + zstd.WithEncoderConcurrency(runtime.GOMAXPROCS(0)), + zstd.WithConcurrentBlocks(true), +) +``` + +Each non-first job receives an overlap prefix from the previous job for match context, +so compression ratio is only marginally affected. Output is flushed in order, +producing a valid single-frame zstd stream. + +Benchmark on 1.8GB GOB stream (AMD Ryzen 9 9950X): + +| Level | 1 thread | 4 threads | 16 threads | 1T ratio | 16T ratio | +|---------|:----------:|:------------------:|:-------------------:|:--------:|:---------:| +| fastest | 783 MB/s | 2950 MB/s (3.8×) | 6939 MB/s (8.9×) | 12.24% | 12.26% | +| default | 728 MB/s | 2533 MB/s (3.5×) | 5340 MB/s (7.3×) | 10.67% | 10.68% | +| better | 434 MB/s | 1105 MB/s (2.5×) | 2206 MB/s (5.1×) | 9.14% | 9.21% | +| best | 129 MB/s | 367 MB/s (2.8×) | 884 MB/s (6.8×) | 8.48% | 8.63% | + +Notes: +* Not compatible with dictionary encoding. +* `Flush()` dispatches the current partial job, so latency-sensitive callers can force output. +* `EncodeAll` is unaffected — it uses its own concurrency via the encoder pool. + +You can specify your desired compression level using `WithEncoderLevel()` option. Currently only pre-defined +compression settings can be specified. + +#### Future Compatibility Guarantees + +This will be an evolving project. When using this package it is important to note that both the compression efficiency and speed may change. + +The goal will be to keep the default efficiency at the default zstd (level 3). +However the encoding should never be assumed to remain the same, +and you should not use hashes of compressed output for similarity checks. + +The Encoder can be assumed to produce the same output from the exact same code version. +However, the may be modes in the future that break this, +although they will not be enabled without an explicit option. + +This encoder is not designed to (and will probably never) output the exact same bitstream as the reference encoder. + +Also note, that the cgo decompressor currently does not [report all errors on invalid input](https://github.com/DataDog/zstd/issues/59), +[omits error checks](https://github.com/DataDog/zstd/issues/61), [ignores checksums](https://github.com/DataDog/zstd/issues/43) +and seems to ignore concatenated streams, even though [it is part of the spec](https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frames). + +#### Blocks + +For compressing small blocks, the returned encoder has a function called `EncodeAll(src, dst []byte) []byte`. + +`EncodeAll` will encode all input in src and append it to dst. +This function can be called concurrently. +Each call will only run on a same goroutine as the caller. + +Encoded blocks can be concatenated and the result will be the combined input stream. +Data compressed with EncodeAll can be decoded with the Decoder, using either a stream or `DecodeAll`. + +Especially when encoding blocks you should take special care to reuse the encoder. +This will effectively make it run without allocations after a warmup period. +To make it run completely without allocations, supply a destination buffer with space for all content. + +```Go +import "github.com/klauspost/compress/zstd" + +// Create a writer that caches compressors. +// For this operation type we supply a nil Reader. +var encoder, _ = zstd.NewWriter(nil) + +// Compress a buffer. +// If you have a destination buffer, the allocation in the call can also be eliminated. +func Compress(src []byte) []byte { + return encoder.EncodeAll(src, make([]byte, 0, len(src))) +} +``` + +You can control the maximum number of concurrent encodes using the `WithEncoderConcurrency(n)` +option when creating the writer. + +Using the Encoder for both a stream and individual blocks concurrently is safe. + +### Performance + +I have collected some speed examples to compare speed and compression against other compressors. + +* `file` is the input file. +* `out` is the compressor used. `zskp` is this package. `zstd` is the Datadog cgo library. `gzstd/gzkp` is gzip standard and this library. +* `level` is the compression level used. For `zskp` level 1 is "fastest", level 2 is "default"; 3 is "better", 4 is "best". +* `insize`/`outsize` is the input/output size. +* `millis` is the number of milliseconds used for compression. +* `mb/s` is megabytes (2^20 bytes) per second. + +``` +Silesia Corpus: +http://sun.aei.polsl.pl/~sdeor/corpus/silesia.zip + +This package: +file out level insize outsize millis mb/s +silesia.tar zskp 1 211947520 73821326 634 318.47 +silesia.tar zskp 2 211947520 67655404 1508 133.96 +silesia.tar zskp 3 211947520 64746933 3000 67.37 +silesia.tar zskp 4 211947520 60073508 16926 11.94 + +cgo zstd: +silesia.tar zstd 1 211947520 73605392 543 371.56 +silesia.tar zstd 3 211947520 66793289 864 233.68 +silesia.tar zstd 6 211947520 62916450 1913 105.66 +silesia.tar zstd 9 211947520 60212393 5063 39.92 + +gzip, stdlib/this package: +silesia.tar gzstd 1 211947520 80007735 1498 134.87 +silesia.tar gzkp 1 211947520 80088272 1009 200.31 + +GOB stream of binary data. Highly compressible. +https://files.klauspost.com/compress/gob-stream.7z + +file out level insize outsize millis mb/s +gob-stream zskp 1 1911399616 233948096 3230 564.34 +gob-stream zskp 2 1911399616 203997694 4997 364.73 +gob-stream zskp 3 1911399616 173526523 13435 135.68 +gob-stream zskp 4 1911399616 162195235 47559 38.33 + +gob-stream zstd 1 1911399616 249810424 2637 691.26 +gob-stream zstd 3 1911399616 208192146 3490 522.31 +gob-stream zstd 6 1911399616 193632038 6687 272.56 +gob-stream zstd 9 1911399616 177620386 16175 112.70 + +gob-stream gzstd 1 1911399616 357382013 9046 201.49 +gob-stream gzkp 1 1911399616 359136669 4885 373.08 + +The test data for the Large Text Compression Benchmark is the first +10^9 bytes of the English Wikipedia dump on Mar. 3, 2006. +http://mattmahoney.net/dc/textdata.html + +file out level insize outsize millis mb/s +enwik9 zskp 1 1000000000 343833605 3687 258.64 +enwik9 zskp 2 1000000000 317001237 7672 124.29 +enwik9 zskp 3 1000000000 291915823 15923 59.89 +enwik9 zskp 4 1000000000 261710291 77697 12.27 + +enwik9 zstd 1 1000000000 358072021 3110 306.65 +enwik9 zstd 3 1000000000 313734672 4784 199.35 +enwik9 zstd 6 1000000000 295138875 10290 92.68 +enwik9 zstd 9 1000000000 278348700 28549 33.40 + +enwik9 gzstd 1 1000000000 382578136 8608 110.78 +enwik9 gzkp 1 1000000000 382781160 5628 169.45 + +Highly compressible JSON file. +https://files.klauspost.com/compress/github-june-2days-2019.json.zst + +file out level insize outsize millis mb/s +github-june-2days-2019.json zskp 1 6273951764 697439532 9789 611.17 +github-june-2days-2019.json zskp 2 6273951764 610876538 18553 322.49 +github-june-2days-2019.json zskp 3 6273951764 517662858 44186 135.41 +github-june-2days-2019.json zskp 4 6273951764 464617114 165373 36.18 + +github-june-2days-2019.json zstd 1 6273951764 766284037 8450 708.00 +github-june-2days-2019.json zstd 3 6273951764 661889476 10927 547.57 +github-june-2days-2019.json zstd 6 6273951764 642756859 22996 260.18 +github-june-2days-2019.json zstd 9 6273951764 601974523 52413 114.16 + +github-june-2days-2019.json gzstd 1 6273951764 1164397768 26793 223.32 +github-june-2days-2019.json gzkp 1 6273951764 1120631856 17693 338.16 + +VM Image, Linux mint with a few installed applications: +https://files.klauspost.com/compress/rawstudio-mint14.7z + +file out level insize outsize millis mb/s +rawstudio-mint14.tar zskp 1 8558382592 3718400221 18206 448.29 +rawstudio-mint14.tar zskp 2 8558382592 3326118337 37074 220.15 +rawstudio-mint14.tar zskp 3 8558382592 3163842361 87306 93.49 +rawstudio-mint14.tar zskp 4 8558382592 2970480650 783862 10.41 + +rawstudio-mint14.tar zstd 1 8558382592 3609250104 17136 476.27 +rawstudio-mint14.tar zstd 3 8558382592 3341679997 29262 278.92 +rawstudio-mint14.tar zstd 6 8558382592 3235846406 77904 104.77 +rawstudio-mint14.tar zstd 9 8558382592 3160778861 140946 57.91 + +rawstudio-mint14.tar gzstd 1 8558382592 3926234992 51345 158.96 +rawstudio-mint14.tar gzkp 1 8558382592 3960117298 36722 222.26 + +CSV data: +https://files.klauspost.com/compress/nyc-taxi-data-10M.csv.zst + +file out level insize outsize millis mb/s +nyc-taxi-data-10M.csv zskp 1 3325605752 641319332 9462 335.17 +nyc-taxi-data-10M.csv zskp 2 3325605752 588976126 17570 180.50 +nyc-taxi-data-10M.csv zskp 3 3325605752 529329260 32432 97.79 +nyc-taxi-data-10M.csv zskp 4 3325605752 474949772 138025 22.98 + +nyc-taxi-data-10M.csv zstd 1 3325605752 687399637 8233 385.18 +nyc-taxi-data-10M.csv zstd 3 3325605752 598514411 10065 315.07 +nyc-taxi-data-10M.csv zstd 6 3325605752 570522953 20038 158.27 +nyc-taxi-data-10M.csv zstd 9 3325605752 517554797 64565 49.12 + +nyc-taxi-data-10M.csv gzstd 1 3325605752 928654908 21270 149.11 +nyc-taxi-data-10M.csv gzkp 1 3325605752 922273214 13929 227.68 +``` + +## Decompressor + +Status: STABLE - there may still be subtle bugs, but a wide variety of content has been tested. + +This library is being continuously [fuzz-tested](https://github.com/klauspost/compress-fuzz), +kindly supplied by [fuzzit.dev](https://fuzzit.dev/). +The main purpose of the fuzz testing is to ensure that it is not possible to crash the decoder, +or run it past its limits with ANY input provided. + +### Usage + +The package has been designed for two main usages, big streams of data and smaller in-memory buffers. +There are two main usages of the package for these. Both of them are accessed by creating a `Decoder`. + +For streaming use a simple setup could look like this: + +```Go +import "github.com/klauspost/compress/zstd" + +func Decompress(in io.Reader, out io.Writer) error { + d, err := zstd.NewReader(in) + if err != nil { + return err + } + defer d.Close() + + // Copy content... + _, err = io.Copy(out, d) + return err +} +``` + +It is important to use the "Close" function when you no longer need the Reader to stop running goroutines, +when running with default settings. +Goroutines will exit once an error has been returned, including `io.EOF` at the end of a stream. + +Streams are decoded concurrently in 4 asynchronous stages to give the best possible throughput. +However, if you prefer synchronous decompression, use `WithDecoderConcurrency(1)` which will decompress data +as it is being requested only. + +For decoding buffers, it could look something like this: + +```Go +import "github.com/klauspost/compress/zstd" + +// Create a reader that caches decompressors. +// For this operation type we supply a nil Reader. +var decoder, _ = zstd.NewReader(nil, zstd.WithDecoderConcurrency(0)) + +// Decompress a buffer. We don't supply a destination buffer, +// so it will be allocated by the decoder. +func Decompress(src []byte) ([]byte, error) { + return decoder.DecodeAll(src, nil) +} +``` + +Both of these cases should provide the functionality needed. +The decoder can be used for *concurrent* decompression of multiple buffers. +By default 4 decompressors will be created. + +It will only allow a certain number of concurrent operations to run. +To tweak that yourself use the `WithDecoderConcurrency(n)` option when creating the decoder. +It is possible to use `WithDecoderConcurrency(0)` to create GOMAXPROCS decoders. + +### Dictionaries + +Data compressed with [dictionaries](https://github.com/facebook/zstd#the-case-for-small-data-compression) can be decompressed. + +Dictionaries are added individually to Decoders. +Dictionaries are generated by the `zstd --train` command and contains an initial state for the decoder. +To add a dictionary use the `WithDecoderDicts(dicts ...[]byte)` option with the dictionary data. +Several dictionaries can be added at once. + +The dictionary will be used automatically for the data that specifies them. +A re-used Decoder will still contain the dictionaries registered. + +When registering multiple dictionaries with the same ID, the last one will be used. + +It is possible to use dictionaries when compressing data. + +To enable a dictionary use `WithEncoderDict(dict []byte)`. Here only one dictionary will be used +and it will likely be used even if it doesn't improve compression. + +The used dictionary must be used to decompress the content. + +For any real gains, the dictionary should be built with similar data. +If an unsuitable dictionary is used the output may be slightly larger than using no dictionary. +Use the [zstd commandline tool](https://github.com/facebook/zstd/releases) to build a dictionary from sample data. +For information see [zstd dictionary information](https://github.com/facebook/zstd#the-case-for-small-data-compression). + +For now there is a fixed startup performance penalty for compressing content with dictionaries. +This will likely be improved over time. Just be aware to test performance when implementing. + +### Allocation-less operation + +The decoder has been designed to operate without allocations after a warmup. + +This means that you should *store* the decoder for best performance. +To re-use a stream decoder, use the `Reset(r io.Reader) error` to switch to another stream. +A decoder can safely be re-used even if the previous stream failed. + +To release the resources, you must call the `Close()` function on a decoder. +After this it can *no longer be reused*, but all running goroutines will be stopped. +So you *must* use this if you will no longer need the Reader. + +For decompressing smaller buffers a single decoder can be used. +When decoding buffers, you can supply a destination slice with length 0 and your expected capacity. +In this case no unneeded allocations should be made. + +### Concurrency + +The buffer decoder does everything on the same goroutine and does nothing concurrently. +It can however decode several buffers concurrently. Use `WithDecoderConcurrency(n)` to limit that. + +The stream decoder will create goroutines that: + +1) Reads input and splits the input into blocks. +2) Decompression of literals. +3) Decompression of sequences. +4) Reconstruction of output stream. + +So effectively this also means the decoder will "read ahead" and prepare data to always be available for output. + +The concurrency level will, for streams, determine how many blocks ahead the compression will start. + +Since "blocks" are quite dependent on the output of the previous block stream decoding will only have limited concurrency. + +In practice this means that concurrency is often limited to utilizing about 3 cores effectively. + +### Benchmarks + +The first two are streaming decodes and the last are smaller inputs. + +Running on AMD Ryzen 9 3950X 16-Core Processor. AMD64 assembly used. + +``` +BenchmarkDecoderSilesia-32 5 206878840 ns/op 1024.50 MB/s 49808 B/op 43 allocs/op +BenchmarkDecoderEnwik9-32 1 1271809000 ns/op 786.28 MB/s 72048 B/op 52 allocs/op + +Concurrent blocks, performance: + +BenchmarkDecoder_DecodeAllParallel/kppkn.gtb.zst-32 67356 17857 ns/op 10321.96 MB/s 22.48 pct 102 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/geo.protodata.zst-32 266656 4421 ns/op 26823.21 MB/s 11.89 pct 19 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/plrabn12.txt.zst-32 20992 56842 ns/op 8477.17 MB/s 39.90 pct 754 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/lcet10.txt.zst-32 27456 43932 ns/op 9714.01 MB/s 33.27 pct 524 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/asyoulik.txt.zst-32 78432 15047 ns/op 8319.15 MB/s 40.34 pct 66 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/alice29.txt.zst-32 65800 18436 ns/op 8249.63 MB/s 37.75 pct 88 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/html_x_4.zst-32 102993 11523 ns/op 35546.09 MB/s 3.637 pct 143 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/paper-100k.pdf.zst-32 1000000 1070 ns/op 95720.98 MB/s 80.53 pct 3 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/fireworks.jpeg.zst-32 749802 1752 ns/op 70272.35 MB/s 100.0 pct 5 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/urls.10K.zst-32 22640 52934 ns/op 13263.37 MB/s 26.25 pct 1014 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/html.zst-32 226412 5232 ns/op 19572.27 MB/s 14.49 pct 20 B/op 0 allocs/op +BenchmarkDecoder_DecodeAllParallel/comp-data.bin.zst-32 923041 1276 ns/op 3194.71 MB/s 31.26 pct 0 B/op 0 allocs/op +``` + +This reflects the performance around May 2022, but this may be out of date. + +## Zstd inside ZIP files + +It is possible to use zstandard to compress individual files inside zip archives. +While this isn't widely supported it can be useful for internal files. + +To support the compression and decompression of these files you must register a compressor and decompressor. + +It is highly recommended registering the (de)compressors on individual zip Reader/Writer and NOT +use the global registration functions. The main reason for this is that 2 registrations from +different packages will result in a panic. + +It is a good idea to only have a single compressor and decompressor, since they can be used for multiple zip +files concurrently, and using a single instance will allow reusing some resources. + +See [this example](https://pkg.go.dev/github.com/klauspost/compress/zstd#example-ZipCompressor) for +how to compress and decompress files inside zip archives. + +# Contributions + +Contributions are always welcome. +For new features/fixes, remember to add tests and for performance enhancements include benchmarks. + +For general feedback and experience reports, feel free to open an issue or write me on [Twitter](https://twitter.com/sh0dan). + +This package includes the excellent [`github.com/cespare/xxhash`](https://github.com/cespare/xxhash) package Copyright (c) 2016 Caleb Spare. diff --git a/vendor/github.com/klauspost/compress/zstd/bitreader.go b/vendor/github.com/klauspost/compress/zstd/bitreader.go new file mode 100644 index 0000000..d41e3e1 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/bitreader.go @@ -0,0 +1,135 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "errors" + "fmt" + "io" + "math/bits" + + "github.com/klauspost/compress/internal/le" +) + +// bitReader reads a bitstream in reverse. +// The last set bit indicates the start of the stream and is used +// for aligning the input. +type bitReader struct { + in []byte + value uint64 // Maybe use [16]byte, but shifting is awkward. + cursor int // offset where next read should end + bitsRead uint8 +} + +// init initializes and resets the bit reader. +func (b *bitReader) init(in []byte) error { + if len(in) < 1 { + return errors.New("corrupt stream: too short") + } + b.in = in + // The highest bit of the last byte indicates where to start + v := in[len(in)-1] + if v == 0 { + return errors.New("corrupt stream, did not find end of stream") + } + b.cursor = len(in) + b.bitsRead = 64 + b.value = 0 + if len(in) >= 8 { + b.fillFastStart() + } else { + b.fill() + b.fill() + } + b.bitsRead += 8 - uint8(highBits(uint32(v))) + return nil +} + +// getBits will return n bits. n can be 0. +func (b *bitReader) getBits(n uint8) int { + if n == 0 /*|| b.bitsRead >= 64 */ { + return 0 + } + return int(b.get32BitsFast(n)) +} + +// get32BitsFast requires that at least one bit is requested every time. +// There are no checks if the buffer is filled. +func (b *bitReader) get32BitsFast(n uint8) uint32 { + const regMask = 64 - 1 + v := uint32((b.value << (b.bitsRead & regMask)) >> ((regMask + 1 - n) & regMask)) + b.bitsRead += n + return v +} + +// fillFast() will make sure at least 32 bits are available. +// There must be at least 4 bytes available. +func (b *bitReader) fillFast() { + if b.bitsRead < 32 { + return + } + b.cursor -= 4 + b.value = (b.value << 32) | uint64(le.Load32(b.in, b.cursor)) + b.bitsRead -= 32 +} + +// fillFastStart() assumes the bitreader is empty and there is at least 8 bytes to read. +func (b *bitReader) fillFastStart() { + b.cursor -= 8 + b.value = le.Load64(b.in, b.cursor) + b.bitsRead = 0 +} + +// fill() will make sure at least 32 bits are available. +func (b *bitReader) fill() { + if b.bitsRead < 32 { + return + } + if b.cursor >= 4 { + b.cursor -= 4 + b.value = (b.value << 32) | uint64(le.Load32(b.in, b.cursor)) + b.bitsRead -= 32 + return + } + + b.bitsRead -= uint8(8 * b.cursor) + for b.cursor > 0 { + b.cursor -= 1 + b.value = (b.value << 8) | uint64(b.in[b.cursor]) + } +} + +// finished returns true if all bits have been read from the bit stream. +func (b *bitReader) finished() bool { + return b.cursor == 0 && b.bitsRead >= 64 +} + +// overread returns true if more bits have been requested than is on the stream. +func (b *bitReader) overread() bool { + return b.bitsRead > 64 +} + +// remain returns the number of bits remaining. +func (b *bitReader) remain() uint { + return 8*uint(b.cursor) + 64 - uint(b.bitsRead) +} + +// close the bitstream and returns an error if out-of-buffer reads occurred. +func (b *bitReader) close() error { + // Release reference. + b.in = nil + b.cursor = 0 + if !b.finished() { + return fmt.Errorf("%d extra bits on block, should be 0", b.remain()) + } + if b.bitsRead > 64 { + return io.ErrUnexpectedEOF + } + return nil +} + +func highBits(val uint32) (n uint32) { + return uint32(bits.Len32(val) - 1) +} diff --git a/vendor/github.com/klauspost/compress/zstd/bitwriter.go b/vendor/github.com/klauspost/compress/zstd/bitwriter.go new file mode 100644 index 0000000..b22b297 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/bitwriter.go @@ -0,0 +1,112 @@ +// Copyright 2018 Klaus Post. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// Based on work Copyright (c) 2013, Yann Collet, released under BSD License. + +package zstd + +// bitWriter will write bits. +// First bit will be LSB of the first byte of output. +type bitWriter struct { + bitContainer uint64 + nBits uint8 + out []byte +} + +// bitMask16 is bitmasks. Has extra to avoid bounds check. +var bitMask16 = [32]uint16{ + 0, 1, 3, 7, 0xF, 0x1F, + 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF} /* up to 16 bits */ + +var bitMask32 = [32]uint32{ + 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, + 0x1ffff, 0x3ffff, 0x7FFFF, 0xfFFFF, 0x1fFFFF, 0x3fFFFF, 0x7fFFFF, 0xffFFFF, + 0x1ffFFFF, 0x3ffFFFF, 0x7ffFFFF, 0xfffFFFF, 0x1fffFFFF, 0x3fffFFFF, 0x7fffFFFF, +} // up to 32 bits + +// addBits16NC will add up to 16 bits. +// It will not check if there is space for them, +// so the caller must ensure that it has flushed recently. +func (b *bitWriter) addBits16NC(value uint16, bits uint8) { + b.bitContainer |= uint64(value&bitMask16[bits&31]) << (b.nBits & 63) + b.nBits += bits +} + +// addBits32NC will add up to 31 bits. +// It will not check if there is space for them, +// so the caller must ensure that it has flushed recently. +func (b *bitWriter) addBits32NC(value uint32, bits uint8) { + b.bitContainer |= uint64(value&bitMask32[bits&31]) << (b.nBits & 63) + b.nBits += bits +} + +// addBits64NC will add up to 64 bits. +// There must be space for 32 bits. +func (b *bitWriter) addBits64NC(value uint64, bits uint8) { + if bits <= 31 { + b.addBits32Clean(uint32(value), bits) + return + } + b.addBits32Clean(uint32(value), 32) + b.flush32() + b.addBits32Clean(uint32(value>>32), bits-32) +} + +// addBits32Clean will add up to 32 bits. +// It will not check if there is space for them. +// The input must not contain more bits than specified. +func (b *bitWriter) addBits32Clean(value uint32, bits uint8) { + b.bitContainer |= uint64(value) << (b.nBits & 63) + b.nBits += bits +} + +// addBits16Clean will add up to 16 bits. value may not contain more set bits than indicated. +// It will not check if there is space for them, so the caller must ensure that it has flushed recently. +func (b *bitWriter) addBits16Clean(value uint16, bits uint8) { + b.bitContainer |= uint64(value) << (b.nBits & 63) + b.nBits += bits +} + +// flush32 will flush out, so there are at least 32 bits available for writing. +func (b *bitWriter) flush32() { + if b.nBits < 32 { + return + } + b.out = append(b.out, + byte(b.bitContainer), + byte(b.bitContainer>>8), + byte(b.bitContainer>>16), + byte(b.bitContainer>>24)) + b.nBits -= 32 + b.bitContainer >>= 32 +} + +// flushAlign will flush remaining full bytes and align to next byte boundary. +func (b *bitWriter) flushAlign() { + nbBytes := (b.nBits + 7) >> 3 + for i := range nbBytes { + b.out = append(b.out, byte(b.bitContainer>>(i*8))) + } + b.nBits = 0 + b.bitContainer = 0 +} + +// close will write the alignment bit and write the final byte(s) +// to the output. +func (b *bitWriter) close() { + // End mark + b.addBits16Clean(1, 1) + // flush until next byte. + b.flushAlign() +} + +// reset and continue writing by appending to out. +func (b *bitWriter) reset(out []byte) { + b.bitContainer = 0 + b.nBits = 0 + b.out = out +} diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go new file mode 100644 index 0000000..51f9da0 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go @@ -0,0 +1,709 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "errors" + "fmt" + "hash/crc32" + "io" + "sync" + + "github.com/klauspost/compress/huff0" + "github.com/klauspost/compress/zstd/internal/xxhash" +) + +type blockType uint8 + +//go:generate stringer -type=blockType,literalsBlockType,seqCompMode,tableIndex + +const ( + blockTypeRaw blockType = iota + blockTypeRLE + blockTypeCompressed + blockTypeReserved +) + +type literalsBlockType uint8 + +const ( + literalsBlockRaw literalsBlockType = iota + literalsBlockRLE + literalsBlockCompressed + literalsBlockTreeless +) + +const ( + // maxCompressedBlockSize is the biggest allowed compressed block size (128KB) + maxCompressedBlockSize = 128 << 10 + + compressedBlockOverAlloc = 16 + maxCompressedBlockSizeAlloc = 128<<10 + compressedBlockOverAlloc + + // Maximum possible block size (all Raw+Uncompressed). + maxBlockSize = (1 << 21) - 1 + + maxMatchLen = 131074 + maxSequences = 0x7f00 + 0xffff + + // We support slightly less than the reference decoder to be able to + // use ints on 32 bit archs. + maxOffsetBits = 30 +) + +var ( + huffDecoderPool = sync.Pool{New: func() any { + return &huff0.Scratch{} + }} + + fseDecoderPool = sync.Pool{New: func() any { + return &fseDecoder{} + }} +) + +type blockDec struct { + // Raw source data of the block. + data []byte + dataStorage []byte + + // Destination of the decoded data. + dst []byte + + // Buffer for literals data. + literalBuf []byte + + // Window size of the block. + WindowSize uint64 + + err error + + // Check against this crc, if hasCRC is true. + checkCRC uint32 + hasCRC bool + + // Frame to use for singlethreaded decoding. + // Should not be used by the decoder itself since parent may be another frame. + localFrame *frameDec + + sequence []seqVals + + async struct { + newHist *history + literals []byte + seqData []byte + seqSize int // Size of uncompressed sequences + fcs uint64 + } + + // Block is RLE, this is the size. + RLESize uint32 + + Type blockType + + // Is this the last block of a frame? + Last bool + + // Use less memory + lowMem bool +} + +func (b *blockDec) String() string { + if b == nil { + return "" + } + return fmt.Sprintf("Steam Size: %d, Type: %v, Last: %t, Window: %d", len(b.data), b.Type, b.Last, b.WindowSize) +} + +func newBlockDec(lowMem bool) *blockDec { + b := blockDec{ + lowMem: lowMem, + } + return &b +} + +// reset will reset the block. +// Input must be a start of a block and will be at the end of the block when returned. +func (b *blockDec) reset(br byteBuffer, windowSize uint64) error { + b.WindowSize = windowSize + tmp, err := br.readSmall(3) + if err != nil { + println("Reading block header:", err) + return err + } + bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16) + b.Last = bh&1 != 0 + b.Type = blockType((bh >> 1) & 3) + // find size. + cSize := int(bh >> 3) + maxSize := maxCompressedBlockSizeAlloc + switch b.Type { + case blockTypeReserved: + return ErrReservedBlockType + case blockTypeRLE: + if cSize > maxCompressedBlockSize || cSize > int(b.WindowSize) { + if debugDecoder { + printf("rle block too big: csize:%d block: %+v\n", uint64(cSize), b) + } + return ErrWindowSizeExceeded + } + b.RLESize = uint32(cSize) + if b.lowMem { + maxSize = cSize + } + cSize = 1 + case blockTypeCompressed: + if debugDecoder { + println("Data size on stream:", cSize) + } + b.RLESize = 0 + maxSize = maxCompressedBlockSizeAlloc + if windowSize < maxCompressedBlockSize && b.lowMem { + maxSize = int(windowSize) + compressedBlockOverAlloc + } + if cSize > maxCompressedBlockSize || uint64(cSize) > b.WindowSize { + if debugDecoder { + printf("compressed block too big: csize:%d block: %+v\n", uint64(cSize), b) + } + return ErrCompressedSizeTooBig + } + // Empty compressed blocks must at least be 2 bytes + // for Literals_Block_Type and one for Sequences_Section_Header. + if cSize < 2 { + return ErrBlockTooSmall + } + case blockTypeRaw: + if cSize > maxCompressedBlockSize || cSize > int(b.WindowSize) { + if debugDecoder { + printf("rle block too big: csize:%d block: %+v\n", uint64(cSize), b) + } + return ErrWindowSizeExceeded + } + + b.RLESize = 0 + // We do not need a destination for raw blocks. + maxSize = -1 + default: + panic("Invalid block type") + } + + // Read block data. + if _, ok := br.(*byteBuf); !ok && cap(b.dataStorage) < cSize { + // byteBuf doesn't need a destination buffer. + if b.lowMem || cSize > maxCompressedBlockSize { + b.dataStorage = make([]byte, 0, cSize+compressedBlockOverAlloc) + } else { + b.dataStorage = make([]byte, 0, maxCompressedBlockSizeAlloc) + } + } + b.data, err = br.readBig(cSize, b.dataStorage) + if err != nil { + if debugDecoder { + println("Reading block:", err, "(", cSize, ")", len(b.data)) + printf("%T", br) + } + return err + } + if cap(b.dst) <= maxSize { + b.dst = make([]byte, 0, maxSize+1) + } + return nil +} + +// sendEOF will make the decoder send EOF on this frame. +func (b *blockDec) sendErr(err error) { + b.Last = true + b.Type = blockTypeReserved + b.err = err +} + +// Close will release resources. +// Closed blockDec cannot be reset. +func (b *blockDec) Close() { +} + +// decodeBuf +func (b *blockDec) decodeBuf(hist *history) error { + switch b.Type { + case blockTypeRLE: + if cap(b.dst) < int(b.RLESize) { + if b.lowMem { + b.dst = make([]byte, b.RLESize) + } else { + b.dst = make([]byte, maxCompressedBlockSize) + } + } + b.dst = b.dst[:b.RLESize] + v := b.data[0] + for i := range b.dst { + b.dst[i] = v + } + hist.appendKeep(b.dst) + return nil + case blockTypeRaw: + hist.appendKeep(b.data) + return nil + case blockTypeCompressed: + saved := b.dst + // Append directly to history + if hist.ignoreBuffer == 0 { + b.dst = hist.b + hist.b = nil + } else { + b.dst = b.dst[:0] + } + err := b.decodeCompressed(hist) + if debugDecoder { + println("Decompressed to total", len(b.dst), "bytes, hash:", xxhash.Sum64(b.dst), "error:", err) + } + if hist.ignoreBuffer == 0 { + hist.b = b.dst + b.dst = saved + } else { + hist.appendKeep(b.dst) + } + return err + case blockTypeReserved: + // Used for returning errors. + return b.err + default: + panic("Invalid block type") + } +} + +func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err error) { + // There must be at least one byte for Literals_Block_Type and one for Sequences_Section_Header + if len(in) < 2 { + return in, ErrBlockTooSmall + } + + litType := literalsBlockType(in[0] & 3) + var litRegenSize int + var litCompSize int + sizeFormat := (in[0] >> 2) & 3 + var fourStreams bool + var literals []byte + switch litType { + case literalsBlockRaw, literalsBlockRLE: + switch sizeFormat { + case 0, 2: + // Regenerated_Size uses 5 bits (0-31). Literals_Section_Header uses 1 byte. + litRegenSize = int(in[0] >> 3) + in = in[1:] + case 1: + // Regenerated_Size uses 12 bits (0-4095). Literals_Section_Header uses 2 bytes. + litRegenSize = int(in[0]>>4) + (int(in[1]) << 4) + in = in[2:] + case 3: + // Regenerated_Size uses 20 bits (0-1048575). Literals_Section_Header uses 3 bytes. + if len(in) < 3 { + println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in)) + return in, ErrBlockTooSmall + } + litRegenSize = int(in[0]>>4) + (int(in[1]) << 4) + (int(in[2]) << 12) + in = in[3:] + } + case literalsBlockCompressed, literalsBlockTreeless: + switch sizeFormat { + case 0, 1: + // Both Regenerated_Size and Compressed_Size use 10 bits (0-1023). + if len(in) < 3 { + println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in)) + return in, ErrBlockTooSmall + } + n := uint64(in[0]>>4) + (uint64(in[1]) << 4) + (uint64(in[2]) << 12) + litRegenSize = int(n & 1023) + litCompSize = int(n >> 10) + fourStreams = sizeFormat == 1 + in = in[3:] + case 2: + fourStreams = true + if len(in) < 4 { + println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in)) + return in, ErrBlockTooSmall + } + n := uint64(in[0]>>4) + (uint64(in[1]) << 4) + (uint64(in[2]) << 12) + (uint64(in[3]) << 20) + litRegenSize = int(n & 16383) + litCompSize = int(n >> 14) + in = in[4:] + case 3: + fourStreams = true + if len(in) < 5 { + println("too small: litType:", litType, " sizeFormat", sizeFormat, len(in)) + return in, ErrBlockTooSmall + } + n := uint64(in[0]>>4) + (uint64(in[1]) << 4) + (uint64(in[2]) << 12) + (uint64(in[3]) << 20) + (uint64(in[4]) << 28) + litRegenSize = int(n & 262143) + litCompSize = int(n >> 18) + in = in[5:] + } + } + if debugDecoder { + println("literals type:", litType, "litRegenSize:", litRegenSize, "litCompSize:", litCompSize, "sizeFormat:", sizeFormat, "4X:", fourStreams) + } + if litRegenSize > int(b.WindowSize) || litRegenSize > maxCompressedBlockSize { + return in, ErrWindowSizeExceeded + } + + switch litType { + case literalsBlockRaw: + if len(in) < litRegenSize { + println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", litRegenSize) + return in, ErrBlockTooSmall + } + literals = in[:litRegenSize] + in = in[litRegenSize:] + //printf("Found %d uncompressed literals\n", litRegenSize) + case literalsBlockRLE: + if len(in) < 1 { + println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", 1) + return in, ErrBlockTooSmall + } + if cap(b.literalBuf) < litRegenSize { + if b.lowMem { + b.literalBuf = make([]byte, litRegenSize, litRegenSize+compressedBlockOverAlloc) + } else { + b.literalBuf = make([]byte, litRegenSize, maxCompressedBlockSize+compressedBlockOverAlloc) + } + } + literals = b.literalBuf[:litRegenSize] + v := in[0] + for i := range literals { + literals[i] = v + } + in = in[1:] + if debugDecoder { + printf("Found %d RLE compressed literals\n", litRegenSize) + } + case literalsBlockTreeless: + if len(in) < litCompSize { + println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", litCompSize) + return in, ErrBlockTooSmall + } + // Store compressed literals, so we defer decoding until we get history. + literals = in[:litCompSize] + in = in[litCompSize:] + if debugDecoder { + printf("Found %d compressed literals\n", litCompSize) + } + huff := hist.huffTree + if huff == nil { + return in, errors.New("literal block was treeless, but no history was defined") + } + // Ensure we have space to store it. + if cap(b.literalBuf) < litRegenSize { + if b.lowMem { + b.literalBuf = make([]byte, 0, litRegenSize+compressedBlockOverAlloc) + } else { + b.literalBuf = make([]byte, 0, maxCompressedBlockSize+compressedBlockOverAlloc) + } + } + var err error + // Decoder.Decompress* uses cap(dst) for the size limit. Do not write + // MaxDecodedSize on hist.huffTree: with a trained dictionary that + // pointer aliases the shared dict.litEnc and concurrent DecodeAll races. + if fourStreams { + literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals) + } else { + literals, err = huff.Decoder().Decompress1X(b.literalBuf[:0:litRegenSize], literals) + } + // Make sure we don't leak our literals buffer + if err != nil { + println("decompressing literals:", err) + return in, err + } + if len(literals) != litRegenSize { + return in, fmt.Errorf("literal output size mismatch want %d, got %d", litRegenSize, len(literals)) + } + + case literalsBlockCompressed: + if len(in) < litCompSize { + println("too small: litType:", litType, " sizeFormat", sizeFormat, "remain:", len(in), "want:", litCompSize) + return in, ErrBlockTooSmall + } + literals = in[:litCompSize] + in = in[litCompSize:] + // Ensure we have space to store it. + if cap(b.literalBuf) < litRegenSize { + if b.lowMem { + b.literalBuf = make([]byte, 0, litRegenSize+compressedBlockOverAlloc) + } else { + b.literalBuf = make([]byte, 0, maxCompressedBlockSize+compressedBlockOverAlloc) + } + } + huff := hist.huffTree + if huff == nil || (hist.dict != nil && huff == hist.dict.litEnc) { + huff = huffDecoderPool.Get().(*huff0.Scratch) + if huff == nil { + huff = &huff0.Scratch{} + } + } + var err error + if debugDecoder { + println("huff table input:", len(literals), "CRC:", crc32.ChecksumIEEE(literals)) + } + huff, literals, err = huff0.ReadTable(literals, huff) + if err != nil { + println("reading huffman table:", err) + return in, err + } + hist.huffTree = huff + huff.MaxDecodedSize = litRegenSize + // Use our out buffer. + if fourStreams { + literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals) + } else { + literals, err = huff.Decoder().Decompress1X(b.literalBuf[:0:litRegenSize], literals) + } + if err != nil { + println("decoding compressed literals:", err) + return in, err + } + // Make sure we don't leak our literals buffer + if len(literals) != litRegenSize { + return in, fmt.Errorf("literal output size mismatch want %d, got %d", litRegenSize, len(literals)) + } + // Re-cap to get extra size. + literals = b.literalBuf[:len(literals)] + if debugDecoder { + printf("Decompressed %d literals into %d bytes\n", litCompSize, litRegenSize) + } + } + hist.decoders.literals = literals + return in, nil +} + +// decodeCompressed will start decompressing a block. +func (b *blockDec) decodeCompressed(hist *history) error { + in := b.data + in, err := b.decodeLiterals(in, hist) + if err != nil { + return err + } + err = b.prepareSequences(in, hist) + if err != nil { + return err + } + if hist.decoders.nSeqs == 0 { + b.dst = append(b.dst, hist.decoders.literals...) + return nil + } + before := len(hist.decoders.out) + err = hist.decoders.decodeSync(hist.b[hist.ignoreBuffer:]) + if err != nil { + return err + } + if hist.decoders.maxSyncLen > 0 { + hist.decoders.maxSyncLen += uint64(before) + hist.decoders.maxSyncLen -= uint64(len(hist.decoders.out)) + } + b.dst = hist.decoders.out + hist.recentOffsets = hist.decoders.prevOffset + return nil +} + +func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) { + if debugDecoder { + printf("prepareSequences: %d byte(s) input\n", len(in)) + } + // Decode Sequences + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#sequences-section + if len(in) < 1 { + return ErrBlockTooSmall + } + var nSeqs int + seqHeader := in[0] + switch { + case seqHeader < 128: + nSeqs = int(seqHeader) + in = in[1:] + case seqHeader < 255: + if len(in) < 2 { + return ErrBlockTooSmall + } + nSeqs = int(seqHeader-128)<<8 | int(in[1]) + in = in[2:] + case seqHeader == 255: + if len(in) < 3 { + return ErrBlockTooSmall + } + nSeqs = 0x7f00 + int(in[1]) + (int(in[2]) << 8) + in = in[3:] + } + if nSeqs == 0 && len(in) != 0 { + // When no sequences, there should not be any more data... + if debugDecoder { + printf("prepareSequences: 0 sequences, but %d byte(s) left on stream\n", len(in)) + } + return ErrUnexpectedBlockSize + } + + var seqs = &hist.decoders + seqs.nSeqs = nSeqs + if nSeqs > 0 { + if len(in) < 1 { + return ErrBlockTooSmall + } + br := byteReader{b: in, off: 0} + compMode := br.Uint8() + br.advance(1) + if debugDecoder { + printf("Compression modes: 0b%b", compMode) + } + if compMode&3 != 0 { + return errors.New("corrupt block: reserved bits not zero") + } + for i := range uint(3) { + mode := seqCompMode((compMode >> (6 - i*2)) & 3) + if debugDecoder { + println("Table", tableIndex(i), "is", mode) + } + var seq *sequenceDec + switch tableIndex(i) { + case tableLiteralLengths: + seq = &seqs.litLengths + case tableOffsets: + seq = &seqs.offsets + case tableMatchLengths: + seq = &seqs.matchLengths + default: + panic("unknown table") + } + switch mode { + case compModePredefined: + if seq.fse != nil && !seq.fse.preDefined { + fseDecoderPool.Put(seq.fse) + } + seq.fse = &fsePredef[i] + case compModeRLE: + if br.remain() < 1 { + return ErrBlockTooSmall + } + v := br.Uint8() + br.advance(1) + if seq.fse == nil || seq.fse.preDefined { + seq.fse = fseDecoderPool.Get().(*fseDecoder) + } + symb, err := decSymbolValue(v, symbolTableX[i]) + if err != nil { + printf("RLE Transform table (%v) error: %v", tableIndex(i), err) + return err + } + seq.fse.setRLE(symb) + if debugDecoder { + printf("RLE set to 0x%x, code: %v", symb, v) + } + case compModeFSE: + if debugDecoder { + println("Reading table for", tableIndex(i)) + } + if seq.fse == nil || seq.fse.preDefined { + seq.fse = fseDecoderPool.Get().(*fseDecoder) + } + err := seq.fse.readNCount(&br, uint16(maxTableSymbol[i])) + if err != nil { + println("Read table error:", err) + return err + } + err = seq.fse.transform(symbolTableX[i]) + if err != nil { + println("Transform table error:", err) + return err + } + if debugDecoder { + println("Read table ok", "symbolLen:", seq.fse.symbolLen) + } + case compModeRepeat: + seq.repeat = true + } + if br.overread() { + return io.ErrUnexpectedEOF + } + } + in = br.unread() + } + if debugDecoder { + println("Literals:", len(seqs.literals), "hash:", xxhash.Sum64(seqs.literals), "and", seqs.nSeqs, "sequences.") + } + + if nSeqs == 0 { + if len(b.sequence) > 0 { + b.sequence = b.sequence[:0] + } + return nil + } + br := seqs.br + if br == nil { + br = &bitReader{} + } + if err := br.init(in); err != nil { + return err + } + + if err := seqs.initialize(br, hist, b.dst); err != nil { + println("initializing sequences:", err) + return err + } + + return nil +} + +func (b *blockDec) decodeSequences(hist *history) error { + if cap(b.sequence) < hist.decoders.nSeqs { + if b.lowMem { + b.sequence = make([]seqVals, 0, hist.decoders.nSeqs) + } else { + b.sequence = make([]seqVals, 0, 0x7F00+0xffff) + } + } + b.sequence = b.sequence[:hist.decoders.nSeqs] + if hist.decoders.nSeqs == 0 { + hist.decoders.seqSize = len(hist.decoders.literals) + return nil + } + hist.decoders.windowSize = hist.windowSize + hist.decoders.prevOffset = hist.recentOffsets + + err := hist.decoders.decode(b.sequence) + hist.recentOffsets = hist.decoders.prevOffset + return err +} + +func (b *blockDec) executeSequences(hist *history) error { + hbytes := hist.b + if len(hbytes) > hist.windowSize { + hbytes = hbytes[len(hbytes)-hist.windowSize:] + } + hist.decoders.windowSize = hist.windowSize + hist.decoders.out = b.dst[:0] + err := hist.decoders.execute(b.sequence, hbytes) + if err != nil { + return err + } + return b.updateHistory(hist) +} + +func (b *blockDec) updateHistory(hist *history) error { + if len(b.data) > maxCompressedBlockSize { + return fmt.Errorf("compressed block size too large (%d)", len(b.data)) + } + // Set output and release references. + b.dst = hist.decoders.out + hist.recentOffsets = hist.decoders.prevOffset + + if b.Last { + // if last block we don't care about history. + println("Last block, no history returned") + hist.b = hist.b[:0] + return nil + } else { + hist.append(b.dst) + if debugDecoder { + println("Finished block with ", len(b.sequence), "sequences. Added", len(b.dst), "to history, now length", len(hist.b)) + } + } + hist.decoders.out, hist.decoders.literals = nil, nil + + return nil +} diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go new file mode 100644 index 0000000..0e33aea --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go @@ -0,0 +1,893 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "errors" + "fmt" + "math" + "math/bits" + "slices" + + "github.com/klauspost/compress/huff0" +) + +type blockEnc struct { + size int + literals []byte + sequences []seq + coders seqCoders + litEnc *huff0.Scratch + dictLitEnc *huff0.Scratch + wr bitWriter + + extraLits int + output []byte + recentOffsets [3]uint32 + prevRecentOffsets [3]uint32 + + last bool + lowMem bool +} + +// init should be used once the block has been created. +// If called more than once, the effect is the same as calling reset. +func (b *blockEnc) init() { + if b.lowMem { + // 1K literals + if cap(b.literals) < 1<<10 { + b.literals = make([]byte, 0, 1<<10) + } + const defSeqs = 20 + if cap(b.sequences) < defSeqs { + b.sequences = make([]seq, 0, defSeqs) + } + // 1K + if cap(b.output) < 1<<10 { + b.output = make([]byte, 0, 1<<10) + } + } else { + if cap(b.literals) < maxCompressedBlockSize { + b.literals = make([]byte, 0, maxCompressedBlockSize) + } + const defSeqs = 2000 + if cap(b.sequences) < defSeqs { + b.sequences = make([]seq, 0, defSeqs) + } + if cap(b.output) < maxCompressedBlockSize { + b.output = make([]byte, 0, maxCompressedBlockSize) + } + } + + if b.coders.mlEnc == nil { + b.coders.mlEnc = &fseEncoder{} + b.coders.mlPrev = &fseEncoder{} + b.coders.ofEnc = &fseEncoder{} + b.coders.ofPrev = &fseEncoder{} + b.coders.llEnc = &fseEncoder{} + b.coders.llPrev = &fseEncoder{} + } + b.litEnc = &huff0.Scratch{WantLogLess: 4} + b.reset(nil) +} + +// initNewEncode can be used to reset offsets and encoders to the initial state. +func (b *blockEnc) initNewEncode() { + b.recentOffsets = [3]uint32{1, 4, 8} + b.litEnc.Reuse = huff0.ReusePolicyNone + b.coders.setPrev(nil, nil, nil) + b.dictLitEnc = nil +} + +// reset will reset the block for a new encode, but in the same stream, +// meaning that state will be carried over, but the block content is reset. +// If a previous block is provided, the recent offsets are carried over. +func (b *blockEnc) reset(prev *blockEnc) { + b.extraLits = 0 + b.literals = b.literals[:0] + b.size = 0 + b.sequences = b.sequences[:0] + b.output = b.output[:0] + b.last = false + if prev != nil { + b.recentOffsets = prev.prevRecentOffsets + } + b.dictLitEnc = nil +} + +// reset will reset the block for a new encode, but in the same stream, +// meaning that state will be carried over, but the block content is reset. +// If a previous block is provided, the recent offsets are carried over. +func (b *blockEnc) swapEncoders(prev *blockEnc) { + b.coders.swap(&prev.coders) + b.litEnc, prev.litEnc = prev.litEnc, b.litEnc +} + +// blockHeader contains the information for a block header. +type blockHeader uint32 + +// setLast sets the 'last' indicator on a block. +func (h *blockHeader) setLast(b bool) { + if b { + *h = *h | 1 + } else { + const mask = (1 << 24) - 2 + *h = *h & mask + } +} + +// setSize will store the compressed size of a block. +func (h *blockHeader) setSize(v uint32) { + const mask = 7 + *h = (*h)&mask | blockHeader(v<<3) +} + +// setType sets the block type. +func (h *blockHeader) setType(t blockType) { + const mask = 1 | (((1 << 24) - 1) ^ 7) + *h = (*h & mask) | blockHeader(t<<1) +} + +// appendTo will append the block header to a slice. +func (h blockHeader) appendTo(b []byte) []byte { + return append(b, uint8(h), uint8(h>>8), uint8(h>>16)) +} + +// String returns a string representation of the block. +func (h blockHeader) String() string { + return fmt.Sprintf("Type: %d, Size: %d, Last:%t", (h>>1)&3, h>>3, h&1 == 1) +} + +// literalsHeader contains literals header information. +type literalsHeader uint64 + +// setType can be used to set the type of literal block. +func (h *literalsHeader) setType(t literalsBlockType) { + const mask = math.MaxUint64 - 3 + *h = (*h & mask) | literalsHeader(t) +} + +// setSize can be used to set a single size, for uncompressed and RLE content. +func (h *literalsHeader) setSize(regenLen int) { + inBits := bits.Len32(uint32(regenLen)) + // Only retain 2 bits + const mask = 3 + lh := uint64(*h & mask) + switch { + case inBits < 5: + lh |= (uint64(regenLen) << 3) | (1 << 60) + if debugEncoder { + got := int(lh>>3) & 0xff + if got != regenLen { + panic(fmt.Sprint("litRegenSize = ", regenLen, "(want) != ", got, "(got)")) + } + } + case inBits < 12: + lh |= (1 << 2) | (uint64(regenLen) << 4) | (2 << 60) + case inBits < 20: + lh |= (3 << 2) | (uint64(regenLen) << 4) | (3 << 60) + default: + panic(fmt.Errorf("internal error: block too big (%d)", regenLen)) + } + *h = literalsHeader(lh) +} + +// setSizes will set the size of a compressed literals section and the input length. +func (h *literalsHeader) setSizes(compLen, inLen int, single bool) { + compBits, inBits := bits.Len32(uint32(compLen)), bits.Len32(uint32(inLen)) + // Only retain 2 bits + const mask = 3 + lh := uint64(*h & mask) + switch { + case compBits <= 10 && inBits <= 10: + if !single { + lh |= 1 << 2 + } + lh |= (uint64(inLen) << 4) | (uint64(compLen) << (10 + 4)) | (3 << 60) + if debugEncoder { + const mmask = (1 << 24) - 1 + n := (lh >> 4) & mmask + if int(n&1023) != inLen { + panic(fmt.Sprint("regensize:", int(n&1023), "!=", inLen, inBits)) + } + if int(n>>10) != compLen { + panic(fmt.Sprint("compsize:", int(n>>10), "!=", compLen, compBits)) + } + } + case compBits <= 14 && inBits <= 14: + lh |= (2 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (14 + 4)) | (4 << 60) + if single { + panic("single stream used with more than 10 bits length.") + } + case compBits <= 18 && inBits <= 18: + lh |= (3 << 2) | (uint64(inLen) << 4) | (uint64(compLen) << (18 + 4)) | (5 << 60) + if single { + panic("single stream used with more than 10 bits length.") + } + default: + panic("internal error: block too big") + } + *h = literalsHeader(lh) +} + +// appendTo will append the literals header to a byte slice. +func (h literalsHeader) appendTo(b []byte) []byte { + size := uint8(h >> 60) + switch size { + case 1: + b = append(b, uint8(h)) + case 2: + b = append(b, uint8(h), uint8(h>>8)) + case 3: + b = append(b, uint8(h), uint8(h>>8), uint8(h>>16)) + case 4: + b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24)) + case 5: + b = append(b, uint8(h), uint8(h>>8), uint8(h>>16), uint8(h>>24), uint8(h>>32)) + default: + panic(fmt.Errorf("internal error: literalsHeader has invalid size (%d)", size)) + } + return b +} + +// size returns the output size with currently set values. +func (h literalsHeader) size() int { + return int(h >> 60) +} + +func (h literalsHeader) String() string { + return fmt.Sprintf("Type: %d, SizeFormat: %d, Size: 0x%d, Bytes:%d", literalsBlockType(h&3), (h>>2)&3, h&((1<<60)-1)>>4, h>>60) +} + +// pushOffsets will push the recent offsets to the backup store. +func (b *blockEnc) pushOffsets() { + b.prevRecentOffsets = b.recentOffsets +} + +// pushOffsets will push the recent offsets to the backup store. +func (b *blockEnc) popOffsets() { + b.recentOffsets = b.prevRecentOffsets +} + +// matchOffset will adjust recent offsets and return the adjusted one, +// if it matches a previous offset. +func (b *blockEnc) matchOffset(offset, lits uint32) uint32 { + // Check if offset is one of the recent offsets. + // Adjusts the output offset accordingly. + // Gives a tiny bit of compression, typically around 1%. + if true { + if lits > 0 { + switch offset { + case b.recentOffsets[0]: + offset = 1 + case b.recentOffsets[1]: + b.recentOffsets[1] = b.recentOffsets[0] + b.recentOffsets[0] = offset + offset = 2 + case b.recentOffsets[2]: + b.recentOffsets[2] = b.recentOffsets[1] + b.recentOffsets[1] = b.recentOffsets[0] + b.recentOffsets[0] = offset + offset = 3 + default: + b.recentOffsets[2] = b.recentOffsets[1] + b.recentOffsets[1] = b.recentOffsets[0] + b.recentOffsets[0] = offset + offset += 3 + } + } else { + switch offset { + case b.recentOffsets[1]: + b.recentOffsets[1] = b.recentOffsets[0] + b.recentOffsets[0] = offset + offset = 1 + case b.recentOffsets[2]: + b.recentOffsets[2] = b.recentOffsets[1] + b.recentOffsets[1] = b.recentOffsets[0] + b.recentOffsets[0] = offset + offset = 2 + case b.recentOffsets[0] - 1: + b.recentOffsets[2] = b.recentOffsets[1] + b.recentOffsets[1] = b.recentOffsets[0] + b.recentOffsets[0] = offset + offset = 3 + default: + b.recentOffsets[2] = b.recentOffsets[1] + b.recentOffsets[1] = b.recentOffsets[0] + b.recentOffsets[0] = offset + offset += 3 + } + } + } else { + offset += 3 + } + return offset +} + +// encodeRaw can be used to set the output to a raw representation of supplied bytes. +func (b *blockEnc) encodeRaw(a []byte) { + var bh blockHeader + bh.setLast(b.last) + bh.setSize(uint32(len(a))) + bh.setType(blockTypeRaw) + b.output = bh.appendTo(b.output[:0]) + b.output = append(b.output, a...) + if debugEncoder { + println("Adding RAW block, length", len(a), "last:", b.last) + } +} + +// encodeRaw can be used to set the output to a raw representation of supplied bytes. +func (b *blockEnc) encodeRawTo(dst, src []byte) []byte { + var bh blockHeader + bh.setLast(b.last) + bh.setSize(uint32(len(src))) + bh.setType(blockTypeRaw) + dst = bh.appendTo(dst) + dst = append(dst, src...) + if debugEncoder { + println("Adding RAW block, length", len(src), "last:", b.last) + } + return dst +} + +// encodeLits can be used if the block is only litLen. +func (b *blockEnc) encodeLits(lits []byte, raw bool) error { + var bh blockHeader + bh.setLast(b.last) + bh.setSize(uint32(len(lits))) + + // Don't compress extremely small blocks + if len(lits) < 8 || (len(lits) < 32 && b.dictLitEnc == nil) || raw { + if debugEncoder { + println("Adding RAW block, length", len(lits), "last:", b.last) + } + bh.setType(blockTypeRaw) + b.output = bh.appendTo(b.output) + b.output = append(b.output, lits...) + return nil + } + + var ( + out []byte + reUsed, single bool + err error + ) + if b.dictLitEnc != nil { + b.litEnc.TransferCTable(b.dictLitEnc) + b.litEnc.Reuse = huff0.ReusePolicyAllow + b.dictLitEnc = nil + } + if len(lits) >= 1024 { + // Use 4 Streams. + out, reUsed, err = huff0.Compress4X(lits, b.litEnc) + } else if len(lits) > 16 { + // Use 1 stream + single = true + out, reUsed, err = huff0.Compress1X(lits, b.litEnc) + } else { + err = huff0.ErrIncompressible + } + if err == nil && len(out)+5 > len(lits) { + // If we are close, we may still be worse or equal to raw. + var lh literalsHeader + lh.setSizes(len(out), len(lits), single) + if len(out)+lh.size() >= len(lits) { + err = huff0.ErrIncompressible + } + } + switch err { + case huff0.ErrIncompressible: + if debugEncoder { + println("Adding RAW block, length", len(lits), "last:", b.last) + } + bh.setType(blockTypeRaw) + b.output = bh.appendTo(b.output) + b.output = append(b.output, lits...) + return nil + case huff0.ErrUseRLE: + if debugEncoder { + println("Adding RLE block, length", len(lits)) + } + bh.setType(blockTypeRLE) + b.output = bh.appendTo(b.output) + b.output = append(b.output, lits[0]) + return nil + case nil: + default: + return err + } + // Compressed... + // Now, allow reuse + b.litEnc.Reuse = huff0.ReusePolicyAllow + bh.setType(blockTypeCompressed) + var lh literalsHeader + if reUsed { + if debugEncoder { + println("Reused tree, compressed to", len(out)) + } + lh.setType(literalsBlockTreeless) + } else { + if debugEncoder { + println("New tree, compressed to", len(out), "tree size:", len(b.litEnc.OutTable)) + } + lh.setType(literalsBlockCompressed) + } + // Set sizes + lh.setSizes(len(out), len(lits), single) + bh.setSize(uint32(len(out) + lh.size() + 1)) + + // Write block headers. + b.output = bh.appendTo(b.output) + b.output = lh.appendTo(b.output) + // Add compressed data. + b.output = append(b.output, out...) + // No sequences. + b.output = append(b.output, 0) + return nil +} + +// encodeRLE will encode an RLE block. +func (b *blockEnc) encodeRLE(val byte, length uint32) { + var bh blockHeader + bh.setLast(b.last) + bh.setSize(length) + bh.setType(blockTypeRLE) + b.output = bh.appendTo(b.output) + b.output = append(b.output, val) +} + +// fuzzFseEncoder can be used to fuzz the FSE encoder. +func fuzzFseEncoder(data []byte) int { + if len(data) > maxSequences || len(data) < 2 { + return 0 + } + enc := fseEncoder{} + hist := enc.Histogram() + maxSym := uint8(0) + for i, v := range data { + v = v & 63 + data[i] = v + hist[v]++ + if v > maxSym { + maxSym = v + } + } + if maxSym == 0 { + // All 0 + return 0 + } + cnt := int(slices.Max(hist[:maxSym])) + if cnt == len(data) { + // RLE + return 0 + } + enc.HistogramFinished(maxSym, cnt) + err := enc.normalizeCount(len(data)) + if err != nil { + return 0 + } + _, err = enc.writeCount(nil) + if err != nil { + panic(err) + } + return 1 +} + +// encode will encode the block and append the output in b.output. +// Previous offset codes must be pushed if more blocks are expected. +func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error { + if len(b.sequences) == 0 { + return b.encodeLits(b.literals, rawAllLits) + } + if len(b.sequences) == 1 && len(org) > 0 && len(b.literals) <= 1 { + // Check common RLE cases. + seq := b.sequences[0] + if seq.litLen == uint32(len(b.literals)) && seq.offset-3 == 1 { + // Offset == 1 and 0 or 1 literals. + b.encodeRLE(org[0], b.sequences[0].matchLen+zstdMinMatch+seq.litLen) + return nil + } + } + + // We want some difference to at least account for the headers. + saved := b.size - len(b.literals) - (b.size >> 6) + if saved < 16 { + if org == nil { + return errIncompressible + } + b.popOffsets() + return b.encodeLits(org, rawAllLits) + } + + var bh blockHeader + var lh literalsHeader + bh.setLast(b.last) + bh.setType(blockTypeCompressed) + // Store offset of the block header. Needed when we know the size. + bhOffset := len(b.output) + b.output = bh.appendTo(b.output) + + var ( + out []byte + reUsed, single bool + err error + ) + if b.dictLitEnc != nil { + b.litEnc.TransferCTable(b.dictLitEnc) + b.litEnc.Reuse = huff0.ReusePolicyAllow + b.dictLitEnc = nil + } + if len(b.literals) >= 1024 && !raw { + // Use 4 Streams. + out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc) + } else if len(b.literals) > 16 && !raw { + // Use 1 stream + single = true + out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc) + } else { + err = huff0.ErrIncompressible + } + + if err == nil && len(out)+5 > len(b.literals) { + // If we are close, we may still be worse or equal to raw. + var lh literalsHeader + lh.setSize(len(b.literals)) + szRaw := lh.size() + lh.setSizes(len(out), len(b.literals), single) + szComp := lh.size() + if len(out)+szComp >= len(b.literals)+szRaw { + err = huff0.ErrIncompressible + } + } + switch err { + case huff0.ErrIncompressible: + lh.setType(literalsBlockRaw) + lh.setSize(len(b.literals)) + b.output = lh.appendTo(b.output) + b.output = append(b.output, b.literals...) + if debugEncoder { + println("Adding literals RAW, length", len(b.literals)) + } + case huff0.ErrUseRLE: + lh.setType(literalsBlockRLE) + lh.setSize(len(b.literals)) + b.output = lh.appendTo(b.output) + b.output = append(b.output, b.literals[0]) + if debugEncoder { + println("Adding literals RLE") + } + case nil: + // Compressed litLen... + if reUsed { + if debugEncoder { + println("reused tree") + } + lh.setType(literalsBlockTreeless) + } else { + if debugEncoder { + println("new tree, size:", len(b.litEnc.OutTable)) + } + lh.setType(literalsBlockCompressed) + if debugEncoder { + _, _, err := huff0.ReadTable(out, nil) + if err != nil { + panic(err) + } + } + } + lh.setSizes(len(out), len(b.literals), single) + if debugEncoder { + printf("Compressed %d literals to %d bytes", len(b.literals), len(out)) + println("Adding literal header:", lh) + } + b.output = lh.appendTo(b.output) + b.output = append(b.output, out...) + b.litEnc.Reuse = huff0.ReusePolicyAllow + if debugEncoder { + println("Adding literals compressed") + } + default: + if debugEncoder { + println("Adding literals ERROR:", err) + } + return err + } + // Sequence compression + + // Write the number of sequences + switch { + case len(b.sequences) < 128: + b.output = append(b.output, uint8(len(b.sequences))) + case len(b.sequences) < 0x7f00: // TODO: this could be wrong + n := len(b.sequences) + b.output = append(b.output, 128+uint8(n>>8), uint8(n)) + default: + n := len(b.sequences) - 0x7f00 + b.output = append(b.output, 255, uint8(n), uint8(n>>8)) + } + if debugEncoder { + println("Encoding", len(b.sequences), "sequences") + } + b.genCodes() + llEnc := b.coders.llEnc + ofEnc := b.coders.ofEnc + mlEnc := b.coders.mlEnc + err = llEnc.normalizeCount(len(b.sequences)) + if err != nil { + return err + } + err = ofEnc.normalizeCount(len(b.sequences)) + if err != nil { + return err + } + err = mlEnc.normalizeCount(len(b.sequences)) + if err != nil { + return err + } + + // Choose the best compression mode for each type. + // Will evaluate the new vs predefined and previous. + chooseComp := func(cur, prev, preDef *fseEncoder) (*fseEncoder, seqCompMode) { + // See if predefined/previous is better + hist := cur.count[:cur.symbolLen] + nSize := cur.approxSize(hist) + cur.maxHeaderSize() + predefSize := preDef.approxSize(hist) + prevSize := prev.approxSize(hist) + + // Add a small penalty for new encoders. + // Don't bother with extremely small (<2 byte gains). + nSize = nSize + (nSize+2*8*16)>>4 + switch { + case predefSize <= prevSize && predefSize <= nSize || forcePreDef: + if debugEncoder { + println("Using predefined", predefSize>>3, "<=", nSize>>3) + } + return preDef, compModePredefined + case prevSize <= nSize: + if debugEncoder { + println("Using previous", prevSize>>3, "<=", nSize>>3) + } + return prev, compModeRepeat + default: + if debugEncoder { + println("Using new, predef", predefSize>>3, ". previous:", prevSize>>3, ">", nSize>>3, "header max:", cur.maxHeaderSize()>>3, "bytes") + println("tl:", cur.actualTableLog, "symbolLen:", cur.symbolLen, "norm:", cur.norm[:cur.symbolLen], "hist", cur.count[:cur.symbolLen]) + } + return cur, compModeFSE + } + } + + // Write compression mode + var mode uint8 + if llEnc.useRLE { + mode |= uint8(compModeRLE) << 6 + llEnc.setRLE(b.sequences[0].llCode) + if debugEncoder { + println("llEnc.useRLE") + } + } else { + var m seqCompMode + llEnc, m = chooseComp(llEnc, b.coders.llPrev, &fsePredefEnc[tableLiteralLengths]) + mode |= uint8(m) << 6 + } + if ofEnc.useRLE { + mode |= uint8(compModeRLE) << 4 + ofEnc.setRLE(b.sequences[0].ofCode) + if debugEncoder { + println("ofEnc.useRLE") + } + } else { + var m seqCompMode + ofEnc, m = chooseComp(ofEnc, b.coders.ofPrev, &fsePredefEnc[tableOffsets]) + mode |= uint8(m) << 4 + } + + if mlEnc.useRLE { + mode |= uint8(compModeRLE) << 2 + mlEnc.setRLE(b.sequences[0].mlCode) + if debugEncoder { + println("mlEnc.useRLE, code: ", b.sequences[0].mlCode, "value", b.sequences[0].matchLen) + } + } else { + var m seqCompMode + mlEnc, m = chooseComp(mlEnc, b.coders.mlPrev, &fsePredefEnc[tableMatchLengths]) + mode |= uint8(m) << 2 + } + b.output = append(b.output, mode) + if debugEncoder { + printf("Compression modes: 0b%b", mode) + } + b.output, err = llEnc.writeCount(b.output) + if err != nil { + return err + } + start := len(b.output) + b.output, err = ofEnc.writeCount(b.output) + if err != nil { + return err + } + if false { + println("block:", b.output[start:], "tablelog", ofEnc.actualTableLog, "maxcount:", ofEnc.maxCount) + fmt.Printf("selected TableLog: %d, Symbol length: %d\n", ofEnc.actualTableLog, ofEnc.symbolLen) + for i, v := range ofEnc.norm[:ofEnc.symbolLen] { + fmt.Printf("%3d: %5d -> %4d \n", i, ofEnc.count[i], v) + } + } + b.output, err = mlEnc.writeCount(b.output) + if err != nil { + return err + } + + // Maybe in block? + wr := &b.wr + wr.reset(b.output) + + var ll, of, ml cState + + // Current sequence + seq := len(b.sequences) - 1 + s := b.sequences[seq] + llEnc.setBits(llBitsTable[:]) + mlEnc.setBits(mlBitsTable[:]) + ofEnc.setBits(nil) + + llTT, ofTT, mlTT := llEnc.ct.symbolTT[:256], ofEnc.ct.symbolTT[:256], mlEnc.ct.symbolTT[:256] + + // We have 3 bounds checks here (and in the loop). + // Since we are iterating backwards it is kinda hard to avoid. + llB, ofB, mlB := llTT[s.llCode], ofTT[s.ofCode], mlTT[s.mlCode] + ll.init(wr, &llEnc.ct, llB) + of.init(wr, &ofEnc.ct, ofB) + wr.flush32() + ml.init(wr, &mlEnc.ct, mlB) + + // Each of these lookups also generates a bounds check. + wr.addBits32NC(s.litLen, llB.outBits) + wr.addBits32NC(s.matchLen, mlB.outBits) + wr.flush32() + wr.addBits32NC(s.offset, ofB.outBits) + if debugSequences { + println("Encoded seq", seq, s, "codes:", s.llCode, s.mlCode, s.ofCode, "states:", ll.state, ml.state, of.state, "bits:", llB, mlB, ofB) + } + seq-- + // Store sequences in reverse... + for seq >= 0 { + s = b.sequences[seq] + + ofB := ofTT[s.ofCode] + wr.flush32() // tablelog max is below 8 for each, so it will fill max 24 bits. + //of.encode(ofB) + nbBitsOut := (uint32(of.state) + ofB.deltaNbBits) >> 16 + dstState := int32(of.state>>(nbBitsOut&15)) + int32(ofB.deltaFindState) + wr.addBits16NC(of.state, uint8(nbBitsOut)) + of.state = of.stateTable[dstState] + + // Accumulate extra bits. + outBits := ofB.outBits & 31 + extraBits := uint64(s.offset & bitMask32[outBits]) + extraBitsN := outBits + + mlB := mlTT[s.mlCode] + //ml.encode(mlB) + nbBitsOut = (uint32(ml.state) + mlB.deltaNbBits) >> 16 + dstState = int32(ml.state>>(nbBitsOut&15)) + int32(mlB.deltaFindState) + wr.addBits16NC(ml.state, uint8(nbBitsOut)) + ml.state = ml.stateTable[dstState] + + outBits = mlB.outBits & 31 + extraBits = extraBits<> 16 + dstState = int32(ll.state>>(nbBitsOut&15)) + int32(llB.deltaFindState) + wr.addBits16NC(ll.state, uint8(nbBitsOut)) + ll.state = ll.stateTable[dstState] + + outBits = llB.outBits & 31 + extraBits = extraBits<= b.size { + // Discard and encode as raw block. + b.output = b.encodeRawTo(b.output[:bhOffset], org) + b.popOffsets() + b.litEnc.Reuse = huff0.ReusePolicyNone + return nil + } + + // Size is output minus block header. + bh.setSize(uint32(len(b.output)-bhOffset) - 3) + if debugEncoder { + println("Rewriting block header", bh) + } + _ = bh.appendTo(b.output[bhOffset:bhOffset]) + b.coders.setPrev(llEnc, mlEnc, ofEnc) + return nil +} + +var errIncompressible = errors.New("incompressible") + +func (b *blockEnc) genCodes() { + if len(b.sequences) == 0 { + // nothing to do + return + } + if len(b.sequences) > math.MaxUint16 { + panic("can only encode up to 64K sequences") + } + // No bounds checks after here: + llH := b.coders.llEnc.Histogram() + ofH := b.coders.ofEnc.Histogram() + mlH := b.coders.mlEnc.Histogram() + for i := range llH { + llH[i] = 0 + } + for i := range ofH { + ofH[i] = 0 + } + for i := range mlH { + mlH[i] = 0 + } + + var llMax, ofMax, mlMax uint8 + for i := range b.sequences { + seq := &b.sequences[i] + v := llCode(seq.litLen) + seq.llCode = v + llH[v]++ + if v > llMax { + llMax = v + } + + v = ofCode(seq.offset) + seq.ofCode = v + ofH[v]++ + if v > ofMax { + ofMax = v + } + + v = mlCode(seq.matchLen) + seq.mlCode = v + mlH[v]++ + if v > mlMax { + mlMax = v + if debugAsserts && mlMax > maxMatchLengthSymbol { + panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d), matchlen: %d", mlMax, seq.matchLen)) + } + } + } + if debugAsserts && mlMax > maxMatchLengthSymbol { + panic(fmt.Errorf("mlMax > maxMatchLengthSymbol (%d)", mlMax)) + } + if debugAsserts && ofMax > maxOffsetBits { + panic(fmt.Errorf("ofMax > maxOffsetBits (%d)", ofMax)) + } + if debugAsserts && llMax > maxLiteralLengthSymbol { + panic(fmt.Errorf("llMax > maxLiteralLengthSymbol (%d)", llMax)) + } + + b.coders.mlEnc.HistogramFinished(mlMax, int(slices.Max(mlH[:mlMax+1]))) + b.coders.ofEnc.HistogramFinished(ofMax, int(slices.Max(ofH[:ofMax+1]))) + b.coders.llEnc.HistogramFinished(llMax, int(slices.Max(llH[:llMax+1]))) +} diff --git a/vendor/github.com/klauspost/compress/zstd/blocktype_string.go b/vendor/github.com/klauspost/compress/zstd/blocktype_string.go new file mode 100644 index 0000000..01a01e4 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/blocktype_string.go @@ -0,0 +1,85 @@ +// Code generated by "stringer -type=blockType,literalsBlockType,seqCompMode,tableIndex"; DO NOT EDIT. + +package zstd + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[blockTypeRaw-0] + _ = x[blockTypeRLE-1] + _ = x[blockTypeCompressed-2] + _ = x[blockTypeReserved-3] +} + +const _blockType_name = "blockTypeRawblockTypeRLEblockTypeCompressedblockTypeReserved" + +var _blockType_index = [...]uint8{0, 12, 24, 43, 60} + +func (i blockType) String() string { + if i >= blockType(len(_blockType_index)-1) { + return "blockType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _blockType_name[_blockType_index[i]:_blockType_index[i+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[literalsBlockRaw-0] + _ = x[literalsBlockRLE-1] + _ = x[literalsBlockCompressed-2] + _ = x[literalsBlockTreeless-3] +} + +const _literalsBlockType_name = "literalsBlockRawliteralsBlockRLEliteralsBlockCompressedliteralsBlockTreeless" + +var _literalsBlockType_index = [...]uint8{0, 16, 32, 55, 76} + +func (i literalsBlockType) String() string { + if i >= literalsBlockType(len(_literalsBlockType_index)-1) { + return "literalsBlockType(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _literalsBlockType_name[_literalsBlockType_index[i]:_literalsBlockType_index[i+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[compModePredefined-0] + _ = x[compModeRLE-1] + _ = x[compModeFSE-2] + _ = x[compModeRepeat-3] +} + +const _seqCompMode_name = "compModePredefinedcompModeRLEcompModeFSEcompModeRepeat" + +var _seqCompMode_index = [...]uint8{0, 18, 29, 40, 54} + +func (i seqCompMode) String() string { + if i >= seqCompMode(len(_seqCompMode_index)-1) { + return "seqCompMode(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _seqCompMode_name[_seqCompMode_index[i]:_seqCompMode_index[i+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[tableLiteralLengths-0] + _ = x[tableOffsets-1] + _ = x[tableMatchLengths-2] +} + +const _tableIndex_name = "tableLiteralLengthstableOffsetstableMatchLengths" + +var _tableIndex_index = [...]uint8{0, 19, 31, 48} + +func (i tableIndex) String() string { + if i >= tableIndex(len(_tableIndex_index)-1) { + return "tableIndex(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _tableIndex_name[_tableIndex_index[i]:_tableIndex_index[i+1]] +} diff --git a/vendor/github.com/klauspost/compress/zstd/bytebuf.go b/vendor/github.com/klauspost/compress/zstd/bytebuf.go new file mode 100644 index 0000000..55a3885 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/bytebuf.go @@ -0,0 +1,131 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "fmt" + "io" +) + +type byteBuffer interface { + // Read up to 8 bytes. + // Returns io.ErrUnexpectedEOF if this cannot be satisfied. + readSmall(n int) ([]byte, error) + + // Read >8 bytes. + // MAY use the destination slice. + readBig(n int, dst []byte) ([]byte, error) + + // Read a single byte. + readByte() (byte, error) + + // Skip n bytes. + skipN(n int64) error +} + +// in-memory buffer +type byteBuf []byte + +func (b *byteBuf) readSmall(n int) ([]byte, error) { + if debugAsserts && n > 8 { + panic(fmt.Errorf("small read > 8 (%d). use readBig", n)) + } + bb := *b + if len(bb) < n { + return nil, io.ErrUnexpectedEOF + } + r := bb[:n] + *b = bb[n:] + return r, nil +} + +func (b *byteBuf) readBig(n int, dst []byte) ([]byte, error) { + bb := *b + if len(bb) < n { + return nil, io.ErrUnexpectedEOF + } + r := bb[:n] + *b = bb[n:] + return r, nil +} + +func (b *byteBuf) readByte() (byte, error) { + bb := *b + if len(bb) < 1 { + return 0, io.ErrUnexpectedEOF + } + r := bb[0] + *b = bb[1:] + return r, nil +} + +func (b *byteBuf) skipN(n int64) error { + bb := *b + if n < 0 { + return fmt.Errorf("negative skip (%d) requested", n) + } + if int64(len(bb)) < n { + return io.ErrUnexpectedEOF + } + *b = bb[n:] + return nil +} + +// wrapper around a reader. +type readerWrapper struct { + r io.Reader + tmp [8]byte +} + +func (r *readerWrapper) readSmall(n int) ([]byte, error) { + if debugAsserts && n > 8 { + panic(fmt.Errorf("small read > 8 (%d). use readBig", n)) + } + n2, err := io.ReadFull(r.r, r.tmp[:n]) + // We only really care about the actual bytes read. + if err != nil { + if err == io.EOF { + return nil, io.ErrUnexpectedEOF + } + if debugDecoder { + println("readSmall: got", n2, "want", n, "err", err) + } + return nil, err + } + return r.tmp[:n], nil +} + +func (r *readerWrapper) readBig(n int, dst []byte) ([]byte, error) { + if cap(dst) < n { + dst = make([]byte, n) + } + n2, err := io.ReadFull(r.r, dst[:n]) + if err == io.EOF && n > 0 { + err = io.ErrUnexpectedEOF + } + return dst[:n2], err +} + +func (r *readerWrapper) readByte() (byte, error) { + n2, err := io.ReadFull(r.r, r.tmp[:1]) + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return 0, err + } + if n2 != 1 { + return 0, io.ErrUnexpectedEOF + } + return r.tmp[0], nil +} + +func (r *readerWrapper) skipN(n int64) error { + n2, err := io.CopyN(io.Discard, r.r, n) + if n2 != n { + err = io.ErrUnexpectedEOF + } + return err +} diff --git a/vendor/github.com/klauspost/compress/zstd/bytereader.go b/vendor/github.com/klauspost/compress/zstd/bytereader.go new file mode 100644 index 0000000..0e59a24 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/bytereader.go @@ -0,0 +1,82 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +// byteReader provides a byte reader that reads +// little endian values from a byte stream. +// The input stream is manually advanced. +// The reader performs no bounds checks. +type byteReader struct { + b []byte + off int +} + +// advance the stream b n bytes. +func (b *byteReader) advance(n uint) { + b.off += int(n) +} + +// overread returns whether we have advanced too far. +func (b *byteReader) overread() bool { + return b.off > len(b.b) +} + +// Int32 returns a little endian int32 starting at current offset. +func (b byteReader) Int32() int32 { + b2 := b.b[b.off:] + b2 = b2[:4] + v3 := int32(b2[3]) + v2 := int32(b2[2]) + v1 := int32(b2[1]) + v0 := int32(b2[0]) + return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24) +} + +// Uint8 returns the next byte +func (b *byteReader) Uint8() uint8 { + v := b.b[b.off] + return v +} + +// Uint32 returns a little endian uint32 starting at current offset. +func (b byteReader) Uint32() uint32 { + if r := b.remain(); r < 4 { + // Very rare + v := uint32(0) + for i := 1; i <= r; i++ { + v = (v << 8) | uint32(b.b[len(b.b)-i]) + } + return v + } + b2 := b.b[b.off:] + b2 = b2[:4] + v3 := uint32(b2[3]) + v2 := uint32(b2[2]) + v1 := uint32(b2[1]) + v0 := uint32(b2[0]) + return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24) +} + +// Uint32NC returns a little endian uint32 starting at current offset. +// The caller must be sure if there are at least 4 bytes left. +func (b byteReader) Uint32NC() uint32 { + b2 := b.b[b.off:] + b2 = b2[:4] + v3 := uint32(b2[3]) + v2 := uint32(b2[2]) + v1 := uint32(b2[1]) + v0 := uint32(b2[0]) + return v0 | (v1 << 8) | (v2 << 16) | (v3 << 24) +} + +// unread returns the unread portion of the input. +func (b byteReader) unread() []byte { + return b.b[b.off:] +} + +// remain will return the number of bytes remaining. +func (b byteReader) remain() int { + return len(b.b) - b.off +} diff --git a/vendor/github.com/klauspost/compress/zstd/decodeheader.go b/vendor/github.com/klauspost/compress/zstd/decodeheader.go new file mode 100644 index 0000000..6a5a298 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/decodeheader.go @@ -0,0 +1,261 @@ +// Copyright 2020+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. + +package zstd + +import ( + "encoding/binary" + "errors" + "io" +) + +// HeaderMaxSize is the maximum size of a Frame and Block Header. +// If less is sent to Header.Decode it *may* still contain enough information. +const HeaderMaxSize = 14 + 3 + +// Header contains information about the first frame and block within that. +type Header struct { + // SingleSegment specifies whether the data is to be decompressed into a + // single contiguous memory segment. + // It implies that WindowSize is invalid and that FrameContentSize is valid. + SingleSegment bool + + // WindowSize is the window of data to keep while decoding. + // Will only be set if SingleSegment is false. + WindowSize uint64 + + // Dictionary ID. + // If 0, no dictionary. + DictionaryID uint32 + + // HasFCS specifies whether FrameContentSize has a valid value. + HasFCS bool + + // FrameContentSize is the expected uncompressed size of the entire frame. + FrameContentSize uint64 + + // Skippable will be true if the frame is meant to be skipped. + // This implies that FirstBlock.OK is false. + Skippable bool + + // SkippableID is the user-specific ID for the skippable frame. + // Valid values are between 0 to 15, inclusive. + SkippableID int + + // SkippableSize is the length of the user data to skip following + // the header. + SkippableSize uint32 + + // HeaderSize is the raw size of the frame header. + // + // For normal frames, it includes the size of the magic number and + // the size of the header (per section 3.1.1.1). + // It does not include the size for any data blocks (section 3.1.1.2) nor + // the size for the trailing content checksum. + // + // For skippable frames, this counts the size of the magic number + // along with the size of the size field of the payload. + // It does not include the size of the skippable payload itself. + // The total frame size is the HeaderSize plus the SkippableSize. + HeaderSize int + + // First block information. + FirstBlock struct { + // OK will be set if first block could be decoded. + OK bool + + // Is this the last block of a frame? + Last bool + + // Is the data compressed? + // If true CompressedSize will be populated. + // Unfortunately DecompressedSize cannot be determined + // without decoding the blocks. + Compressed bool + + // DecompressedSize is the expected decompressed size of the block. + // Will be 0 if it cannot be determined. + DecompressedSize int + + // CompressedSize of the data in the block. + // Does not include the block header. + // Will be equal to DecompressedSize if not Compressed. + CompressedSize int + } + + // If set there is a checksum present for the block content. + // The checksum field at the end is always 4 bytes long. + HasCheckSum bool +} + +// Decode the header from the beginning of the stream. +// This will decode the frame header and the first block header if enough bytes are provided. +// It is recommended to provide at least HeaderMaxSize bytes. +// If the frame header cannot be read an error will be returned. +// If there isn't enough input, io.ErrUnexpectedEOF is returned. +// The FirstBlock.OK will indicate if enough information was available to decode the first block header. +func (h *Header) Decode(in []byte) error { + _, err := h.DecodeAndStrip(in) + return err +} + +// DecodeAndStrip will decode the header from the beginning of the stream +// and on success return the remaining bytes. +// This will decode the frame header and the first block header if enough bytes are provided. +// It is recommended to provide at least HeaderMaxSize bytes. +// If the frame header cannot be read an error will be returned. +// If there isn't enough input, io.ErrUnexpectedEOF is returned. +// The FirstBlock.OK will indicate if enough information was available to decode the first block header. +func (h *Header) DecodeAndStrip(in []byte) (remain []byte, err error) { + *h = Header{} + if len(in) < 4 { + return nil, io.ErrUnexpectedEOF + } + h.HeaderSize += 4 + b, in := in[:4], in[4:] + if string(b) != frameMagic { + if string(b[1:4]) != skippableFrameMagic || b[0]&0xf0 != 0x50 { + return nil, ErrMagicMismatch + } + if len(in) < 4 { + return nil, io.ErrUnexpectedEOF + } + h.HeaderSize += 4 + h.Skippable = true + h.SkippableID = int(b[0] & 0xf) + h.SkippableSize = binary.LittleEndian.Uint32(in) + return in[4:], nil + } + + // Read Window_Descriptor + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor + if len(in) < 1 { + return nil, io.ErrUnexpectedEOF + } + fhd, in := in[0], in[1:] + h.HeaderSize++ + h.SingleSegment = fhd&(1<<5) != 0 + h.HasCheckSum = fhd&(1<<2) != 0 + if fhd&(1<<3) != 0 { + return nil, errors.New("reserved bit set on frame header") + } + + if !h.SingleSegment { + if len(in) < 1 { + return nil, io.ErrUnexpectedEOF + } + var wd byte + wd, in = in[0], in[1:] + h.HeaderSize++ + windowLog := 10 + (wd >> 3) + windowBase := uint64(1) << windowLog + windowAdd := (windowBase / 8) * uint64(wd&0x7) + h.WindowSize = windowBase + windowAdd + } + + // Read Dictionary_ID + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id + if size := fhd & 3; size != 0 { + if size == 3 { + size = 4 + } + if len(in) < int(size) { + return nil, io.ErrUnexpectedEOF + } + b, in = in[:size], in[size:] + h.HeaderSize += int(size) + switch len(b) { + case 1: + h.DictionaryID = uint32(b[0]) + case 2: + h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8) + case 4: + h.DictionaryID = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24) + } + } + + // Read Frame_Content_Size + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_size + var fcsSize int + v := fhd >> 6 + switch v { + case 0: + if h.SingleSegment { + fcsSize = 1 + } + default: + fcsSize = 1 << v + } + + if fcsSize > 0 { + h.HasFCS = true + if len(in) < fcsSize { + return nil, io.ErrUnexpectedEOF + } + b, in = in[:fcsSize], in[fcsSize:] + h.HeaderSize += int(fcsSize) + switch len(b) { + case 1: + h.FrameContentSize = uint64(b[0]) + case 2: + // When FCS_Field_Size is 2, the offset of 256 is added. + h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256 + case 4: + h.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24) + case 8: + d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24) + d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24) + h.FrameContentSize = uint64(d1) | (uint64(d2) << 32) + } + } + + // Frame Header done, we will not fail from now on. + if len(in) < 3 { + return in, nil + } + tmp := in[:3] + bh := uint32(tmp[0]) | (uint32(tmp[1]) << 8) | (uint32(tmp[2]) << 16) + h.FirstBlock.Last = bh&1 != 0 + blockType := blockType((bh >> 1) & 3) + // find size. + cSize := int(bh >> 3) + switch blockType { + case blockTypeReserved: + return in, nil + case blockTypeRLE: + h.FirstBlock.Compressed = true + h.FirstBlock.DecompressedSize = cSize + h.FirstBlock.CompressedSize = 1 + case blockTypeCompressed: + h.FirstBlock.Compressed = true + h.FirstBlock.CompressedSize = cSize + case blockTypeRaw: + h.FirstBlock.DecompressedSize = cSize + h.FirstBlock.CompressedSize = cSize + default: + panic("Invalid block type") + } + + h.FirstBlock.OK = true + return in, nil +} + +// AppendTo will append the encoded header to the dst slice. +// There is no error checking performed on the header values. +func (h *Header) AppendTo(dst []byte) ([]byte, error) { + if h.Skippable { + magic := [4]byte{0x50, 0x2a, 0x4d, 0x18} + magic[0] |= byte(h.SkippableID & 0xf) + dst = append(dst, magic[:]...) + f := h.SkippableSize + return append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24)), nil + } + f := frameHeader{ + ContentSize: h.FrameContentSize, + WindowSize: uint32(h.WindowSize), + SingleSegment: h.SingleSegment, + Checksum: h.HasCheckSum, + DictID: h.DictionaryID, + } + return f.appendTo(dst), nil +} diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go new file mode 100644 index 0000000..c7e500f --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/decoder.go @@ -0,0 +1,957 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "context" + "encoding/binary" + "io" + "sync" + + "github.com/klauspost/compress/zstd/internal/xxhash" +) + +// Decoder provides decoding of zstandard streams. +// The decoder has been designed to operate without allocations after a warmup. +// This means that you should store the decoder for best performance. +// To re-use a stream decoder, use the Reset(r io.Reader) error to switch to another stream. +// A decoder can safely be re-used even if the previous stream failed. +// To release the resources, you must call the Close() function on a decoder. +type Decoder struct { + o decoderOptions + + // Unreferenced decoders, ready for use. + decoders chan *blockDec + + // Current read position used for Reader functionality. + current decoderState + + // sync stream decoding + syncStream struct { + decodedFrame uint64 + br readerWrapper + enabled bool + inFrame bool + dstBuf []byte + } + + frame *frameDec + + // streamWg is the waitgroup for all streams + streamWg sync.WaitGroup +} + +// decoderState is used for maintaining state when the decoder +// is used for streaming. +type decoderState struct { + // current block being written to stream. + decodeOutput + + // output in order to be written to stream. + output chan decodeOutput + + // cancel remaining output. + cancel context.CancelFunc + + // crc of current frame + crc *xxhash.Digest + + flushed bool +} + +var ( + // Check the interfaces we want to support. + _ = io.WriterTo(&Decoder{}) + _ = io.Reader(&Decoder{}) +) + +// NewReader creates a new decoder. +// A nil Reader can be provided in which case Reset can be used to start a decode. +// +// A Decoder can be used in two modes: +// +// 1) As a stream, or +// 2) For stateless decoding using DecodeAll. +// +// Only a single stream can be decoded concurrently, but the same decoder +// can run multiple concurrent stateless decodes. It is even possible to +// use stateless decodes while a stream is being decoded. +// +// The Reset function can be used to initiate a new stream, which will considerably +// reduce the allocations normally caused by NewReader. +func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) { + initPredefined() + var d Decoder + d.o.setDefault() + for _, o := range opts { + err := o(&d.o) + if err != nil { + return nil, err + } + } + d.current.crc = xxhash.New() + d.current.flushed = true + + if r == nil { + d.current.err = ErrDecoderNilInput + } + + // Initialize dict map if needed. + if d.o.dicts == nil { + d.o.dicts = make(map[uint32]*dict) + } + + // Create decoders + d.decoders = make(chan *blockDec, d.o.concurrent) + for i := 0; i < d.o.concurrent; i++ { + dec := newBlockDec(d.o.lowMem) + dec.localFrame = newFrameDec(d.o) + d.decoders <- dec + } + + if r == nil { + return &d, nil + } + return &d, d.Reset(r) +} + +// Read bytes from the decompressed stream into p. +// Returns the number of bytes read and any error that occurred. +// When the stream is done, io.EOF will be returned. +func (d *Decoder) Read(p []byte) (int, error) { + var n int + for { + if len(d.current.b) > 0 { + filled := copy(p, d.current.b) + p = p[filled:] + d.current.b = d.current.b[filled:] + n += filled + } + if len(p) == 0 { + break + } + if len(d.current.b) == 0 { + // We have an error and no more data + if d.current.err != nil { + break + } + if !d.nextBlock(n == 0) { + return n, d.current.err + } + } + } + if len(d.current.b) > 0 { + if debugDecoder { + println("returning", n, "still bytes left:", len(d.current.b)) + } + // Only return error at end of block + return n, nil + } + if d.current.err != nil { + d.drainOutput() + } + if debugDecoder { + println("returning", n, d.current.err, len(d.decoders)) + } + return n, d.current.err +} + +// Reset will reset the decoder the supplied stream after the current has finished processing. +// Note that this functionality cannot be used after Close has been called. +// Reset can be called with a nil reader to release references to the previous reader. +// After being called with a nil reader, no other operations than Reset or DecodeAll or Close +// should be used. +func (d *Decoder) Reset(r io.Reader) error { + if d.current.err == ErrDecoderClosed { + return d.current.err + } + + d.drainOutput() + + d.syncStream.br.r = nil + if r == nil { + d.current.err = ErrDecoderNilInput + if len(d.current.b) > 0 { + d.current.b = d.current.b[:0] + } + d.current.flushed = true + return nil + } + + // If bytes buffer and < 5MB, do sync decoding anyway. + if bb, ok := r.(byter); ok && bb.Len() < d.o.decodeBufsBelow && !d.o.limitToCap { + bb2 := bb + if debugDecoder { + println("*bytes.Buffer detected, doing sync decode, len:", bb.Len()) + } + b := bb2.Bytes() + var dst []byte + if cap(d.syncStream.dstBuf) > 0 { + dst = d.syncStream.dstBuf[:0] + } + + dst, err := d.DecodeAll(b, dst) + if err == nil { + err = io.EOF + } + // Save output buffer + d.syncStream.dstBuf = dst + d.current.b = dst + d.current.err = err + d.current.flushed = true + if debugDecoder { + println("sync decode to", len(dst), "bytes, err:", err) + } + return nil + } + // Remove current block. + d.stashDecoder() + d.current.decodeOutput = decodeOutput{} + d.current.err = nil + d.current.flushed = false + d.current.d = nil + d.syncStream.dstBuf = nil + + // Ensure no-one else is still running... + d.streamWg.Wait() + if d.frame == nil { + d.frame = newFrameDec(d.o) + } + + if d.o.concurrent == 1 { + return d.startSyncDecoder(r) + } + + d.current.output = make(chan decodeOutput, d.o.concurrent) + ctx, cancel := context.WithCancel(context.Background()) + d.current.cancel = cancel + d.streamWg.Add(1) + go d.startStreamDecoder(ctx, r, d.current.output) + + return nil +} + +// ResetWithOptions will reset the decoder and apply the given options +// for the next stream or DecodeAll operation. +// Options are applied on top of the existing options. +// Some options cannot be changed on reset and will return an error. +func (d *Decoder) ResetWithOptions(r io.Reader, opts ...DOption) error { + d.o.resetOpt = true + defer func() { d.o.resetOpt = false }() + for _, o := range opts { + if err := o(&d.o); err != nil { + return err + } + } + return d.Reset(r) +} + +// drainOutput will drain the output until errEndOfStream is sent. +func (d *Decoder) drainOutput() { + if d.current.cancel != nil { + if debugDecoder { + println("cancelling current") + } + d.current.cancel() + d.current.cancel = nil + } + if d.current.d != nil { + if debugDecoder { + printf("re-adding current decoder %p, decoders: %d", d.current.d, len(d.decoders)) + } + d.decoders <- d.current.d + d.current.d = nil + d.current.b = nil + } + if d.current.output == nil || d.current.flushed { + println("current already flushed") + return + } + for v := range d.current.output { + if v.d != nil { + if debugDecoder { + printf("re-adding decoder %p", v.d) + } + d.decoders <- v.d + } + } + d.current.output = nil + d.current.flushed = true +} + +// WriteTo writes data to w until there's no more data to write or when an error occurs. +// The return value n is the number of bytes written. +// Any error encountered during the write is also returned. +func (d *Decoder) WriteTo(w io.Writer) (int64, error) { + var n int64 + for { + if len(d.current.b) > 0 { + n2, err2 := w.Write(d.current.b) + n += int64(n2) + if err2 != nil && (d.current.err == nil || d.current.err == io.EOF) { + d.current.err = err2 + } else if n2 != len(d.current.b) { + d.current.err = io.ErrShortWrite + } + } + if d.current.err != nil { + break + } + d.nextBlock(true) + } + err := d.current.err + if err != nil { + d.drainOutput() + } + if err == io.EOF { + err = nil + } + return n, err +} + +// DecodeAll allows stateless decoding of a blob of bytes. +// Output will be appended to dst, so if the destination size is known +// you can pre-allocate the destination slice to avoid allocations. +// DecodeAll can be used concurrently. +// The Decoder concurrency limits will be respected. +func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) { + if d.decoders == nil { + return dst, ErrDecoderClosed + } + + // Grab a block decoder and frame decoder. + block := <-d.decoders + frame := block.localFrame + initialSize := len(dst) + defer func() { + if debugDecoder { + printf("re-adding decoder: %p", block) + } + frame.rawInput = nil + frame.bBuf = nil + if frame.history.decoders.br != nil { + frame.history.decoders.br.in = nil + frame.history.decoders.br.cursor = 0 + } + d.decoders <- block + }() + frame.bBuf = input + + for { + frame.history.reset() + err := frame.reset(&frame.bBuf) + if err != nil { + if err == io.EOF { + if debugDecoder { + println("frame reset return EOF") + } + return dst, nil + } + return dst, err + } + if err = d.setDict(frame); err != nil { + return nil, err + } + if frame.WindowSize > d.o.maxWindowSize { + if debugDecoder { + println("window size exceeded:", frame.WindowSize, ">", d.o.maxWindowSize) + } + return dst, ErrWindowSizeExceeded + } + if frame.FrameContentSize != fcsUnknown { + if frame.FrameContentSize > d.o.maxDecodedSize-uint64(len(dst)-initialSize) { + if debugDecoder { + println("decoder size exceeded; fcs:", frame.FrameContentSize, "> mcs:", d.o.maxDecodedSize-uint64(len(dst)-initialSize), "len:", len(dst)) + } + return dst, ErrDecoderSizeExceeded + } + if d.o.limitToCap && frame.FrameContentSize > uint64(cap(dst)-len(dst)) { + if debugDecoder { + println("decoder size exceeded; fcs:", frame.FrameContentSize, "> (cap-len)", cap(dst)-len(dst)) + } + return dst, ErrDecoderSizeExceeded + } + if cap(dst)-len(dst) < int(frame.FrameContentSize) { + dst2 := make([]byte, len(dst), len(dst)+int(frame.FrameContentSize)+compressedBlockOverAlloc) + copy(dst2, dst) + dst = dst2 + } + } + + if cap(dst) == 0 && !d.o.limitToCap { + // Allocate len(input) * 2 by default if nothing is provided + // and we didn't get frame content size. + size := min( + // Cap to 1 MB. + len(input)*2, 1<<20) + if uint64(size) > d.o.maxDecodedSize { + size = int(d.o.maxDecodedSize) + } + dst = make([]byte, 0, size) + } + + dst, err = frame.runDecoder(dst, block) + if err != nil { + return dst, err + } + if uint64(len(dst)-initialSize) > d.o.maxDecodedSize { + return dst, ErrDecoderSizeExceeded + } + if len(frame.bBuf) == 0 { + if debugDecoder { + println("frame dbuf empty") + } + break + } + } + return dst, nil +} + +// nextBlock returns the next block. +// If an error occurs d.err will be set. +// Optionally the function can block for new output. +// If non-blocking mode is used the returned boolean will be false +// if no data was available without blocking. +func (d *Decoder) nextBlock(blocking bool) (ok bool) { + if d.current.err != nil { + // Keep error state. + return false + } + d.current.b = d.current.b[:0] + + // SYNC: + if d.syncStream.enabled { + if !blocking { + return false + } + ok = d.nextBlockSync() + if !ok { + d.stashDecoder() + } + return ok + } + + //ASYNC: + d.stashDecoder() + if blocking { + d.current.decodeOutput, ok = <-d.current.output + } else { + select { + case d.current.decodeOutput, ok = <-d.current.output: + default: + return false + } + } + if !ok { + // This should not happen, so signal error state... + d.current.err = io.ErrUnexpectedEOF + return false + } + next := d.current.decodeOutput + if next.d != nil && next.d.async.newHist != nil { + d.current.crc.Reset() + } + if debugDecoder { + var tmp [4]byte + binary.LittleEndian.PutUint32(tmp[:], uint32(xxhash.Sum64(next.b))) + println("got", len(d.current.b), "bytes, error:", d.current.err, "data crc:", tmp) + } + + if d.o.ignoreChecksum { + return true + } + + if len(next.b) > 0 { + d.current.crc.Write(next.b) + } + if next.err == nil && next.d != nil && next.d.hasCRC { + got := uint32(d.current.crc.Sum64()) + if got != next.d.checkCRC { + if debugDecoder { + printf("CRC Check Failed: %08x (got) != %08x (on stream)\n", got, next.d.checkCRC) + } + d.current.err = ErrCRCMismatch + } else { + if debugDecoder { + printf("CRC ok %08x\n", got) + } + } + } + + return true +} + +func (d *Decoder) nextBlockSync() (ok bool) { + if d.current.d == nil { + d.current.d = <-d.decoders + } + for len(d.current.b) == 0 { + if !d.syncStream.inFrame { + d.frame.history.reset() + d.current.err = d.frame.reset(&d.syncStream.br) + if d.current.err == nil { + d.current.err = d.setDict(d.frame) + } + if d.current.err != nil { + return false + } + if d.frame.WindowSize > d.o.maxDecodedSize || d.frame.WindowSize > d.o.maxWindowSize { + d.current.err = ErrDecoderSizeExceeded + return false + } + + d.syncStream.decodedFrame = 0 + d.syncStream.inFrame = true + } + d.current.err = d.frame.next(d.current.d) + if d.current.err != nil { + return false + } + d.frame.history.ensureBlock() + if debugDecoder { + println("History trimmed:", len(d.frame.history.b), "decoded already:", d.syncStream.decodedFrame) + } + histBefore := len(d.frame.history.b) + d.current.err = d.current.d.decodeBuf(&d.frame.history) + + if d.current.err != nil { + println("error after:", d.current.err) + return false + } + d.current.b = d.frame.history.b[histBefore:] + if debugDecoder { + println("history after:", len(d.frame.history.b)) + } + + // Check frame size (before CRC) + d.syncStream.decodedFrame += uint64(len(d.current.b)) + if d.syncStream.decodedFrame > d.frame.FrameContentSize { + if debugDecoder { + printf("DecodedFrame (%d) > FrameContentSize (%d)\n", d.syncStream.decodedFrame, d.frame.FrameContentSize) + } + d.current.err = ErrFrameSizeExceeded + return false + } + + // Check FCS + if d.current.d.Last && d.frame.FrameContentSize != fcsUnknown && d.syncStream.decodedFrame != d.frame.FrameContentSize { + if debugDecoder { + printf("DecodedFrame (%d) != FrameContentSize (%d)\n", d.syncStream.decodedFrame, d.frame.FrameContentSize) + } + d.current.err = ErrFrameSizeMismatch + return false + } + + // Update/Check CRC + if d.frame.HasCheckSum { + if !d.o.ignoreChecksum { + d.frame.crc.Write(d.current.b) + } + if d.current.d.Last { + if !d.o.ignoreChecksum { + d.current.err = d.frame.checkCRC() + } else { + d.current.err = d.frame.consumeCRC() + } + if d.current.err != nil { + println("CRC error:", d.current.err) + return false + } + } + } + d.syncStream.inFrame = !d.current.d.Last + } + return true +} + +func (d *Decoder) stashDecoder() { + if d.current.d != nil { + if debugDecoder { + printf("re-adding current decoder %p", d.current.d) + } + d.decoders <- d.current.d + d.current.d = nil + } +} + +// Close will release all resources. +// It is NOT possible to reuse the decoder after this. +func (d *Decoder) Close() { + if d.current.err == ErrDecoderClosed { + return + } + d.drainOutput() + if d.current.cancel != nil { + d.current.cancel() + d.streamWg.Wait() + d.current.cancel = nil + } + if d.decoders != nil { + close(d.decoders) + for dec := range d.decoders { + dec.Close() + } + d.decoders = nil + } + if d.current.d != nil { + d.current.d.Close() + d.current.d = nil + } + d.current.err = ErrDecoderClosed +} + +// IOReadCloser returns the decoder as an io.ReadCloser for convenience. +// Any changes to the decoder will be reflected, so the returned ReadCloser +// can be reused along with the decoder. +// io.WriterTo is also supported by the returned ReadCloser. +func (d *Decoder) IOReadCloser() io.ReadCloser { + return closeWrapper{d: d} +} + +// closeWrapper wraps a function call as a closer. +type closeWrapper struct { + d *Decoder +} + +// WriteTo forwards WriteTo calls to the decoder. +func (c closeWrapper) WriteTo(w io.Writer) (n int64, err error) { + return c.d.WriteTo(w) +} + +// Read forwards read calls to the decoder. +func (c closeWrapper) Read(p []byte) (n int, err error) { + return c.d.Read(p) +} + +// Close closes the decoder. +func (c closeWrapper) Close() error { + c.d.Close() + return nil +} + +type decodeOutput struct { + d *blockDec + b []byte + err error +} + +func (d *Decoder) startSyncDecoder(r io.Reader) error { + d.frame.history.reset() + d.syncStream.br = readerWrapper{r: r} + d.syncStream.inFrame = false + d.syncStream.enabled = true + d.syncStream.decodedFrame = 0 + return nil +} + +// Create Decoder: +// ASYNC: +// Spawn 3 go routines. +// 0: Read frames and decode block literals. +// 1: Decode sequences. +// 2: Execute sequences, send to output. +func (d *Decoder) startStreamDecoder(ctx context.Context, r io.Reader, output chan decodeOutput) { + defer d.streamWg.Done() + br := readerWrapper{r: r} + + var seqDecode = make(chan *blockDec, d.o.concurrent) + var seqExecute = make(chan *blockDec, d.o.concurrent) + + // Async 1: Decode sequences... + go func() { + var hist history + var hasErr bool + + for block := range seqDecode { + if hasErr { + if block != nil { + seqExecute <- block + } + continue + } + if block.async.newHist != nil { + if debugDecoder { + println("Async 1: new history, recent:", block.async.newHist.recentOffsets) + } + hist.reset() + hist.decoders = block.async.newHist.decoders + hist.recentOffsets = block.async.newHist.recentOffsets + hist.windowSize = block.async.newHist.windowSize + if block.async.newHist.dict != nil { + hist.setDict(block.async.newHist.dict) + } + } + if block.err != nil || block.Type != blockTypeCompressed { + hasErr = block.err != nil + seqExecute <- block + continue + } + + hist.decoders.literals = block.async.literals + block.err = block.prepareSequences(block.async.seqData, &hist) + if debugDecoder && block.err != nil { + println("prepareSequences returned:", block.err) + } + hasErr = block.err != nil + if block.err == nil { + block.err = block.decodeSequences(&hist) + if debugDecoder && block.err != nil { + println("decodeSequences returned:", block.err) + } + hasErr = block.err != nil + // block.async.sequence = hist.decoders.seq[:hist.decoders.nSeqs] + block.async.seqSize = hist.decoders.seqSize + } + seqExecute <- block + } + close(seqExecute) + hist.reset() + }() + + var wg sync.WaitGroup + wg.Add(1) + + // Async 3: Execute sequences... + frameHistCache := d.frame.history.b + go func() { + var hist history + var decodedFrame uint64 + var fcs uint64 + var hasErr bool + for block := range seqExecute { + out := decodeOutput{err: block.err, d: block} + if block.err != nil || hasErr { + hasErr = true + output <- out + continue + } + if block.async.newHist != nil { + if debugDecoder { + println("Async 2: new history") + } + hist.reset() + hist.windowSize = block.async.newHist.windowSize + hist.allocFrameBuffer = block.async.newHist.allocFrameBuffer + if block.async.newHist.dict != nil { + hist.setDict(block.async.newHist.dict) + } + + if cap(hist.b) < hist.allocFrameBuffer { + if cap(frameHistCache) >= hist.allocFrameBuffer { + hist.b = frameHistCache + } else { + hist.b = make([]byte, 0, hist.allocFrameBuffer) + println("Alloc history sized", hist.allocFrameBuffer) + } + } + hist.b = hist.b[:0] + fcs = block.async.fcs + decodedFrame = 0 + } + do := decodeOutput{err: block.err, d: block} + switch block.Type { + case blockTypeRLE: + if debugDecoder { + println("add rle block length:", block.RLESize) + } + + if cap(block.dst) < int(block.RLESize) { + if block.lowMem { + block.dst = make([]byte, block.RLESize) + } else { + block.dst = make([]byte, maxCompressedBlockSize) + } + } + block.dst = block.dst[:block.RLESize] + v := block.data[0] + for i := range block.dst { + block.dst[i] = v + } + hist.append(block.dst) + do.b = block.dst + case blockTypeRaw: + if debugDecoder { + println("add raw block length:", len(block.data)) + } + hist.append(block.data) + do.b = block.data + case blockTypeCompressed: + if debugDecoder { + println("execute with history length:", len(hist.b), "window:", hist.windowSize) + } + hist.decoders.seqSize = block.async.seqSize + hist.decoders.literals = block.async.literals + do.err = block.executeSequences(&hist) + hasErr = do.err != nil + if debugDecoder && hasErr { + println("executeSequences returned:", do.err) + } + do.b = block.dst + } + if !hasErr { + decodedFrame += uint64(len(do.b)) + if decodedFrame > fcs { + println("fcs exceeded", block.Last, fcs, decodedFrame) + do.err = ErrFrameSizeExceeded + hasErr = true + } else if block.Last && fcs != fcsUnknown && decodedFrame != fcs { + do.err = ErrFrameSizeMismatch + hasErr = true + } else { + if debugDecoder { + println("fcs ok", block.Last, fcs, decodedFrame) + } + } + } + output <- do + } + close(output) + frameHistCache = hist.b + wg.Done() + if debugDecoder { + println("decoder goroutines finished") + } + hist.reset() + }() + + var hist history +decodeStream: + for { + var hasErr bool + hist.reset() + decodeBlock := func(block *blockDec) { + if hasErr { + if block != nil { + seqDecode <- block + } + return + } + if block.err != nil || block.Type != blockTypeCompressed { + hasErr = block.err != nil + seqDecode <- block + return + } + + remain, err := block.decodeLiterals(block.data, &hist) + block.err = err + hasErr = block.err != nil + if err == nil { + block.async.literals = hist.decoders.literals + block.async.seqData = remain + } else if debugDecoder { + println("decodeLiterals error:", err) + } + seqDecode <- block + } + frame := d.frame + if debugDecoder { + println("New frame...") + } + var historySent bool + frame.history.reset() + err := frame.reset(&br) + if debugDecoder && err != nil { + println("Frame decoder returned", err) + } + if err == nil { + err = d.setDict(frame) + } + if err == nil && d.frame.WindowSize > d.o.maxWindowSize { + if debugDecoder { + println("decoder size exceeded, fws:", d.frame.WindowSize, "> mws:", d.o.maxWindowSize) + } + + err = ErrDecoderSizeExceeded + } + if err != nil { + select { + case <-ctx.Done(): + case dec := <-d.decoders: + dec.sendErr(err) + decodeBlock(dec) + } + break decodeStream + } + + // Go through all blocks of the frame. + for { + var dec *blockDec + select { + case <-ctx.Done(): + break decodeStream + case dec = <-d.decoders: + // Once we have a decoder, we MUST return it. + } + err := frame.next(dec) + if !historySent { + h := frame.history + if debugDecoder { + println("Alloc History:", h.allocFrameBuffer) + } + hist.reset() + if h.dict != nil { + hist.setDict(h.dict) + } + dec.async.newHist = &h + dec.async.fcs = frame.FrameContentSize + historySent = true + } else { + dec.async.newHist = nil + } + if debugDecoder && err != nil { + println("next block returned error:", err) + } + dec.err = err + dec.hasCRC = false + if dec.Last && frame.HasCheckSum && err == nil { + crc, err := frame.rawInput.readSmall(4) + if len(crc) < 4 { + if err == nil { + err = io.ErrUnexpectedEOF + + } + println("CRC missing?", err) + dec.err = err + } else { + dec.checkCRC = binary.LittleEndian.Uint32(crc) + dec.hasCRC = true + if debugDecoder { + printf("found crc to check: %08x\n", dec.checkCRC) + } + } + } + err = dec.err + last := dec.Last + decodeBlock(dec) + if err != nil { + break decodeStream + } + if last { + break + } + } + } + close(seqDecode) + wg.Wait() + hist.reset() + d.frame.history.b = frameHistCache +} + +func (d *Decoder) setDict(frame *frameDec) (err error) { + dict, ok := d.o.dicts[frame.DictionaryID] + if ok { + if debugDecoder { + println("setting dict", frame.DictionaryID) + } + frame.history.setDict(dict) + } else if frame.DictionaryID != 0 { + // A zero or missing dictionary id is ambiguous: + // either dictionary zero, or no dictionary. In particular, + // zstd --patch-from uses this id for the source file, + // so only return an error if the dictionary id is not zero. + err = ErrUnknownDictionary + } + return err +} diff --git a/vendor/github.com/klauspost/compress/zstd/decoder_options.go b/vendor/github.com/klauspost/compress/zstd/decoder_options.go new file mode 100644 index 0000000..537627a --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/decoder_options.go @@ -0,0 +1,213 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "errors" + "fmt" + "math/bits" + "runtime" +) + +// DOption is an option for creating a decoder. +type DOption func(*decoderOptions) error + +// options retains accumulated state of multiple options. +type decoderOptions struct { + lowMem bool + concurrent int + maxDecodedSize uint64 + maxWindowSize uint64 + dicts map[uint32]*dict + ignoreChecksum bool + limitToCap bool + decodeBufsBelow int + resetOpt bool +} + +func (o *decoderOptions) setDefault() { + *o = decoderOptions{ + // use less ram: true for now, but may change. + lowMem: true, + concurrent: runtime.GOMAXPROCS(0), + maxWindowSize: MaxWindowSize, + decodeBufsBelow: 128 << 10, + } + if o.concurrent > 4 { + o.concurrent = 4 + } + o.maxDecodedSize = 64 << 30 +} + +// WithDecoderLowmem will set whether to use a lower amount of memory, +// but possibly have to allocate more while running. +// Cannot be changed with ResetWithOptions. +func WithDecoderLowmem(b bool) DOption { + return func(o *decoderOptions) error { + if o.resetOpt && b != o.lowMem { + return errors.New("WithDecoderLowmem cannot be changed on Reset") + } + o.lowMem = b + return nil + } +} + +// WithDecoderConcurrency sets the number of created decoders. +// When decoding block with DecodeAll, this will limit the number +// of possible concurrently running decodes. +// When decoding streams, this will limit the number of +// inflight blocks. +// When decoding streams and setting maximum to 1, +// no async decoding will be done. +// The value supplied must be at least 0. +// When a value of 0 is provided GOMAXPROCS will be used. +// By default this will be set to 4 or GOMAXPROCS, whatever is lower. +// Cannot be changed with ResetWithOptions. +func WithDecoderConcurrency(n int) DOption { + return func(o *decoderOptions) error { + if n < 0 { + return errors.New("concurrency must be at least 0") + } + newVal := n + if n == 0 { + newVal = runtime.GOMAXPROCS(0) + } + if o.resetOpt && newVal != o.concurrent { + return errors.New("WithDecoderConcurrency cannot be changed on Reset") + } + o.concurrent = newVal + return nil + } +} + +// WithDecoderMaxMemory allows to set a maximum decoded size for in-memory +// non-streaming operations or maximum window size for streaming operations. +// This can be used to control memory usage of potentially hostile content. +// Maximum is 1 << 63 bytes. Default is 64GiB. +// Can be changed with ResetWithOptions. +func WithDecoderMaxMemory(n uint64) DOption { + return func(o *decoderOptions) error { + if n == 0 { + return errors.New("WithDecoderMaxMemory must be at least 1") + } + if n > 1<<63 { + return errors.New("WithDecoderMaxmemory must be less than 1 << 63") + } + o.maxDecodedSize = n + return nil + } +} + +// WithDecoderDicts allows to register one or more dictionaries for the decoder. +// +// Each slice in dict must be in the [dictionary format] produced by +// "zstd --train" from the Zstandard reference implementation. +// +// If several dictionaries with the same ID are provided, the last one will be used. +// Can be changed with ResetWithOptions. +// +// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format +func WithDecoderDicts(dicts ...[]byte) DOption { + return func(o *decoderOptions) error { + if o.dicts == nil { + o.dicts = make(map[uint32]*dict) + } + for _, b := range dicts { + d, err := loadDict(b) + if err != nil { + return err + } + o.dicts[d.id] = d + } + return nil + } +} + +// WithDecoderDictRaw registers a dictionary that may be used by the decoder. +// The slice content can be arbitrary data. +// Can be changed with ResetWithOptions. +func WithDecoderDictRaw(id uint32, content []byte) DOption { + return func(o *decoderOptions) error { + if bits.UintSize > 32 && uint(len(content)) > dictMaxLength { + return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content)) + } + if o.dicts == nil { + o.dicts = make(map[uint32]*dict) + } + o.dicts[id] = &dict{id: id, content: content, offsets: [3]int{1, 4, 8}} + return nil + } +} + +// WithDecoderMaxWindow allows to set a maximum window size for decodes. +// This allows rejecting packets that will cause big memory usage. +// The Decoder will likely allocate more memory based on the WithDecoderLowmem setting. +// If WithDecoderMaxMemory is set to a lower value, that will be used. +// Default is 512MB, Maximum is ~3.75 TB as per zstandard spec. +// Can be changed with ResetWithOptions. +func WithDecoderMaxWindow(size uint64) DOption { + return func(o *decoderOptions) error { + if size < MinWindowSize { + return errors.New("WithMaxWindowSize must be at least 1KB, 1024 bytes") + } + if size > (1<<41)+7*(1<<38) { + return errors.New("WithMaxWindowSize must be less than (1<<41) + 7*(1<<38) ~ 3.75TB") + } + o.maxWindowSize = size + return nil + } +} + +// WithDecodeAllCapLimit will limit DecodeAll to decoding cap(dst)-len(dst) bytes, +// or any size set in WithDecoderMaxMemory. +// This can be used to limit decoding to a specific maximum output size. +// Disabled by default. +// Can be changed with ResetWithOptions. +func WithDecodeAllCapLimit(b bool) DOption { + return func(o *decoderOptions) error { + o.limitToCap = b + return nil + } +} + +// WithDecodeBuffersBelow will fully decode readers that have a +// `Bytes() []byte` and `Len() int` interface similar to bytes.Buffer. +// This typically uses less allocations but will have the full decompressed object in memory. +// Note that DecodeAllCapLimit will disable this, as well as giving a size of 0 or less. +// Default is 128KiB. +// Cannot be changed with ResetWithOptions. +func WithDecodeBuffersBelow(size int) DOption { + return func(o *decoderOptions) error { + if o.resetOpt && size != o.decodeBufsBelow { + return errors.New("WithDecodeBuffersBelow cannot be changed on Reset") + } + o.decodeBufsBelow = size + return nil + } +} + +// IgnoreChecksum allows to forcibly ignore checksum checking. +// Can be changed with ResetWithOptions. +func IgnoreChecksum(b bool) DOption { + return func(o *decoderOptions) error { + o.ignoreChecksum = b + return nil + } +} + +// WithDecoderDictDelete removes dictionaries by ID. +// If no ids are passed, all dictionaries are deleted. +// Should be used with ResetWithOptions. +func WithDecoderDictDelete(ids ...uint32) DOption { + return func(o *decoderOptions) error { + if len(ids) == 0 { + clear(o.dicts) + } + for _, id := range ids { + delete(o.dicts, id) + } + return nil + } +} diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go new file mode 100644 index 0000000..67f40e7 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/dict.go @@ -0,0 +1,603 @@ +package zstd + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "math" + "sort" + + "github.com/klauspost/compress/huff0" +) + +type dict struct { + id uint32 + + litEnc *huff0.Scratch + llDec, ofDec, mlDec sequenceDec + offsets [3]int + content []byte +} + +const dictMagic = "\x37\xa4\x30\xec" + +// Maximum dictionary size for the reference implementation (1.5.3) is 2 GiB. +const dictMaxLength = 1 << 31 + +// ID returns the dictionary id or 0 if d is nil. +func (d *dict) ID() uint32 { + if d == nil { + return 0 + } + return d.id +} + +// ContentSize returns the dictionary content size or 0 if d is nil. +func (d *dict) ContentSize() int { + if d == nil { + return 0 + } + return len(d.content) +} + +// Content returns the dictionary content. +func (d *dict) Content() []byte { + if d == nil { + return nil + } + return d.content +} + +// Offsets returns the initial offsets. +func (d *dict) Offsets() [3]int { + if d == nil { + return [3]int{} + } + return d.offsets +} + +// LitEncoder returns the literal encoder. +func (d *dict) LitEncoder() *huff0.Scratch { + if d == nil { + return nil + } + return d.litEnc +} + +// Load a dictionary as described in +// https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format +func loadDict(b []byte) (*dict, error) { + // Check static field size. + if len(b) <= 8+(3*4) { + return nil, io.ErrUnexpectedEOF + } + d := dict{ + llDec: sequenceDec{fse: &fseDecoder{}}, + ofDec: sequenceDec{fse: &fseDecoder{}}, + mlDec: sequenceDec{fse: &fseDecoder{}}, + } + if string(b[:4]) != dictMagic { + return nil, ErrMagicMismatch + } + d.id = binary.LittleEndian.Uint32(b[4:8]) + if d.id == 0 { + return nil, errors.New("dictionaries cannot have ID 0") + } + + // Read literal table + var err error + d.litEnc, b, err = huff0.ReadTable(b[8:], nil) + if err != nil { + return nil, fmt.Errorf("loading literal table: %w", err) + } + d.litEnc.Reuse = huff0.ReusePolicyMust + + br := byteReader{ + b: b, + off: 0, + } + readDec := func(i tableIndex, dec *fseDecoder) error { + if err := dec.readNCount(&br, uint16(maxTableSymbol[i])); err != nil { + return err + } + if br.overread() { + return io.ErrUnexpectedEOF + } + err = dec.transform(symbolTableX[i]) + if err != nil { + println("Transform table error:", err) + return err + } + if debugDecoder || debugEncoder { + println("Read table ok", "symbolLen:", dec.symbolLen) + } + // Set decoders as predefined so they aren't reused. + dec.preDefined = true + return nil + } + + if err := readDec(tableOffsets, d.ofDec.fse); err != nil { + return nil, err + } + if err := readDec(tableMatchLengths, d.mlDec.fse); err != nil { + return nil, err + } + if err := readDec(tableLiteralLengths, d.llDec.fse); err != nil { + return nil, err + } + if br.remain() < 12 { + return nil, io.ErrUnexpectedEOF + } + + d.offsets[0] = int(br.Uint32()) + br.advance(4) + d.offsets[1] = int(br.Uint32()) + br.advance(4) + d.offsets[2] = int(br.Uint32()) + br.advance(4) + if d.offsets[0] <= 0 || d.offsets[1] <= 0 || d.offsets[2] <= 0 { + return nil, errors.New("invalid offset in dictionary") + } + d.content = make([]byte, br.remain()) + copy(d.content, br.unread()) + if d.offsets[0] > len(d.content) || d.offsets[1] > len(d.content) || d.offsets[2] > len(d.content) { + return nil, fmt.Errorf("initial offset bigger than dictionary content size %d, offsets: %v", len(d.content), d.offsets) + } + + return &d, nil +} + +// InspectDictionary loads a zstd dictionary and provides functions to inspect the content. +func InspectDictionary(b []byte) (interface { + ID() uint32 + ContentSize() int + Content() []byte + Offsets() [3]int + LitEncoder() *huff0.Scratch +}, error) { + initPredefined() + d, err := loadDict(b) + return d, err +} + +type BuildDictOptions struct { + // Dictionary ID. + ID uint32 + + // Content to use to create dictionary tables. + Contents [][]byte + + // History to use for all blocks. + History []byte + + // Offsets to use. + Offsets [3]int + + // CompatV155 will make the dictionary compatible with Zstd v1.5.5 and earlier. + // See https://github.com/facebook/zstd/issues/3724 + CompatV155 bool + + // Use the specified encoder level. + // The dictionary will be built using the specified encoder level, + // which will reflect speed and make the dictionary tailored for that level. + // If not set SpeedBestCompression will be used. + Level EncoderLevel + + // DebugOut will write stats and other details here if set. + DebugOut io.Writer +} + +func BuildDict(o BuildDictOptions) ([]byte, error) { + initPredefined() + hist := o.History + contents := o.Contents + debug := o.DebugOut != nil + println := func(args ...any) { + if o.DebugOut != nil { + fmt.Fprintln(o.DebugOut, args...) + } + } + printf := func(s string, args ...any) { + if o.DebugOut != nil { + fmt.Fprintf(o.DebugOut, s, args...) + } + } + print := func(args ...any) { + if o.DebugOut != nil { + fmt.Fprint(o.DebugOut, args...) + } + } + + if int64(len(hist)) > dictMaxLength { + return nil, fmt.Errorf("dictionary of size %d > %d", len(hist), int64(dictMaxLength)) + } + if len(hist) < 8 { + return nil, fmt.Errorf("dictionary of size %d < %d", len(hist), 8) + } + if len(contents) == 0 { + return nil, errors.New("no content provided") + } + d := dict{ + id: o.ID, + litEnc: nil, + llDec: sequenceDec{}, + ofDec: sequenceDec{}, + mlDec: sequenceDec{}, + offsets: o.Offsets, + content: hist, + } + block := blockEnc{lowMem: false} + block.init() + var enc encoder + if o.Level != 0 { + eOpts := encoderOptions{ + level: o.Level, + blockSize: maxMatchLen, + windowSize: maxMatchLen, + dict: &d, + lowMem: false, + } + enc = eOpts.encoder() + } else { + o.Level = SpeedBestCompression + enc = encoder(&bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(maxMatchLen), bufferReset: math.MaxInt32 - int32(maxMatchLen*2), lowMem: false}}) + } + var ( + remain [256]int + ll [256]int + ml [256]int + of [256]int + ) + addValues := func(dst *[256]int, src []byte) { + for _, v := range src { + dst[v]++ + } + } + addHist := func(dst *[256]int, src *[256]uint32) { + for i, v := range src { + dst[i] += int(v) + } + } + seqs := 0 + nUsed := 0 + litTotal := 0 + newOffsets := make(map[uint32]int, 1000) + for _, b := range contents { + block.reset(nil) + if len(b) < 8 { + continue + } + nUsed++ + enc.Reset(&d, true) + enc.Encode(&block, b) + addValues(&remain, block.literals) + litTotal += len(block.literals) + if len(block.sequences) == 0 { + continue + } + seqs += len(block.sequences) + block.genCodes() + addHist(&ll, block.coders.llEnc.Histogram()) + addHist(&ml, block.coders.mlEnc.Histogram()) + addHist(&of, block.coders.ofEnc.Histogram()) + for i, seq := range block.sequences { + if i > 3 { + break + } + offset := seq.offset + if offset == 0 { + continue + } + if int(offset) >= len(o.History) { + continue + } + if offset > 3 { + newOffsets[offset-3]++ + } else { + // Repeat codes reference the training Offsets. Skip unset + // (zero) entries so they are not ranked as real offsets. + prev := o.Offsets[offset-1] + if prev > 0 { + newOffsets[uint32(prev)]++ + } + } + } + } + // Find most used offsets. + var sortedOffsets []uint32 + for k := range newOffsets { + if k == 0 { + continue + } + sortedOffsets = append(sortedOffsets, k) + } + sort.Slice(sortedOffsets, func(i, j int) bool { + a, b := sortedOffsets[i], sortedOffsets[j] + ca, cb := newOffsets[a], newOffsets[b] + if ca == cb { + // Prefer the longer offset + return a > b + } + return ca > cb + }) + if debug { + print("Offsets:") + for i, v := range sortedOffsets { + if i > 20 { + break + } + printf("[%d: %d],", v, newOffsets[v]) + } + println("") + } + // Dictionary recent-offsets must be three positive values within the + // history. Ranked matches may be fewer (or empty when only unset + // repeat codes were seen), so fill remaining slots with defaults. + used := make(map[int]bool, 3) + var finalOffsets [3]int + nOff := 0 + for _, v := range sortedOffsets { + iv := int(v) + if iv <= 0 || iv > len(hist) || used[iv] { + continue + } + finalOffsets[nOff] = iv + used[iv] = true + nOff++ + if nOff == 3 { + break + } + } + for _, def := range []int{1, 4, 8} { + if nOff == 3 { + break + } + if def <= len(hist) && !used[def] { + finalOffsets[nOff] = def + used[def] = true + nOff++ + } + } + for def := 1; nOff < 3 && def <= len(hist); def++ { + if !used[def] { + finalOffsets[nOff] = def + used[def] = true + nOff++ + } + } + if nOff < 3 { + return nil, fmt.Errorf("could not determine 3 valid dictionary offsets (history size %d)", len(hist)) + } + o.Offsets = finalOffsets + if debug { + println("New repeat offsets", o.Offsets) + } + + if nUsed == 0 || seqs == 0 { + return nil, fmt.Errorf("%d blocks, %d sequences found", nUsed, seqs) + } + if litTotal == 0 { + return nil, errors.New("0 literals found") + } + if debug { + println("Sequences:", seqs, "Blocks:", nUsed, "Literals:", litTotal) + } + if seqs/nUsed < 512 { + // Use 512 as minimum. + nUsed = seqs / 512 + if nUsed == 0 { + nUsed = 1 + } + } + copyHist := func(dst *fseEncoder, src *[256]int) ([]byte, error) { + hist := dst.Histogram() + var maxSym uint8 + var maxCount int + var fakeLength int + for i, v := range src { + if v > 0 { + v = v / nUsed + if v == 0 { + v = 1 + } + } + if v > maxCount { + maxCount = v + } + if v != 0 { + maxSym = uint8(i) + } + fakeLength += v + hist[i] = uint32(v) + } + + // Ensure we aren't trying to represent RLE. + if maxCount == fakeLength { + for i := range hist { + if uint8(i) == maxSym { + fakeLength++ + maxSym++ + hist[i+1] = 1 + if maxSym > 1 { + break + } + } + if hist[0] == 0 { + fakeLength++ + hist[i] = 1 + if maxSym > 1 { + break + } + } + } + } + + dst.HistogramFinished(maxSym, maxCount) + dst.reUsed = false + dst.useRLE = false + err := dst.normalizeCount(fakeLength) + if err != nil { + return nil, err + } + if debug { + println("RAW:", dst.count[:maxSym+1], "NORM:", dst.norm[:maxSym+1], "LEN:", fakeLength) + } + return dst.writeCount(nil) + } + if debug { + print("Literal lengths: ") + } + llTable, err := copyHist(block.coders.llEnc, &ll) + if err != nil { + return nil, err + } + if debug { + print("Match lengths: ") + } + mlTable, err := copyHist(block.coders.mlEnc, &ml) + if err != nil { + return nil, err + } + if debug { + print("Offsets: ") + } + ofTable, err := copyHist(block.coders.ofEnc, &of) + if err != nil { + return nil, err + } + + // Literal table + avgSize := min(litTotal, huff0.BlockSizeMax/2) + huffBuff := make([]byte, 0, avgSize) + // Target size + div := max(litTotal/avgSize, 1) + if debug { + println("Huffman weights:") + } + for i, n := range remain[:] { + if n > 0 { + n = n / div + // Allow all entries to be represented. + if n == 0 { + n = 1 + } + huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...) + if debug { + printf("[%d: %d], ", i, n) + } + } + } + if o.CompatV155 && remain[255]/div == 0 { + huffBuff = append(huffBuff, 255) + } + scratch := &huff0.Scratch{TableLog: 11} + for tries := range 255 { + scratch = &huff0.Scratch{TableLog: 11} + _, _, err = huff0.Compress1X(huffBuff, scratch) + if err == nil { + break + } + if debug { + printf("Try %d: Huffman error: %v\n", tries+1, err) + } + huffBuff = huffBuff[:0] + if tries == 250 { + if debug { + println("Huffman: Bailing out with predefined table") + } + + // Bail out.... Just generate something + huffBuff = append(huffBuff, bytes.Repeat([]byte{255}, 10000)...) + for i := range 128 { + huffBuff = append(huffBuff, byte(i)) + } + continue + } + if errors.Is(err, huff0.ErrIncompressible) { + // Try truncating least common. + for i, n := range remain[:] { + if n > 0 { + n = n / (div * (i + 1)) + if n > 0 { + huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...) + } + } + } + if o.CompatV155 && len(huffBuff) > 0 && huffBuff[len(huffBuff)-1] != 255 { + huffBuff = append(huffBuff, 255) + } + if len(huffBuff) == 0 { + huffBuff = append(huffBuff, 0, 255) + } + } + if errors.Is(err, huff0.ErrUseRLE) { + for i, n := range remain[:] { + n = n / (div * (i + 1)) + // Allow all entries to be represented. + if n == 0 { + n = 1 + } + huffBuff = append(huffBuff, bytes.Repeat([]byte{byte(i)}, n)...) + } + } + } + + var out bytes.Buffer + out.Write([]byte(dictMagic)) + out.Write(binary.LittleEndian.AppendUint32(nil, o.ID)) + out.Write(scratch.OutTable) + if debug { + println("huff table:", len(scratch.OutTable), "bytes") + println("of table:", len(ofTable), "bytes") + println("ml table:", len(mlTable), "bytes") + println("ll table:", len(llTable), "bytes") + } + out.Write(ofTable) + out.Write(mlTable) + out.Write(llTable) + out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[0]))) + out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[1]))) + out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[2]))) + out.Write(hist) + if _, err := loadDict(out.Bytes()); err != nil { + return nil, fmt.Errorf("built dictionary failed validation: %w", err) + } + if debug { + i, err := InspectDictionary(out.Bytes()) + if err != nil { + panic(err) + } + println("ID:", i.ID()) + println("Content size:", i.ContentSize()) + println("Encoder:", i.LitEncoder() != nil) + println("Offsets:", i.Offsets()) + var totalSize int + for _, b := range contents { + totalSize += len(b) + } + + encWith := func(opts ...EOption) int { + enc, err := NewWriter(nil, opts...) + if err != nil { + panic(err) + } + defer enc.Close() + var dst []byte + var totalSize int + for _, b := range contents { + dst = enc.EncodeAll(b, dst[:0]) + totalSize += len(dst) + } + return totalSize + } + plain := encWith(WithEncoderLevel(o.Level)) + withDict := encWith(WithEncoderLevel(o.Level), WithEncoderDict(out.Bytes())) + println("Input size:", totalSize) + println("Plain Compressed:", plain) + println("Dict Compressed:", withDict) + println("Saved:", plain-withDict, (plain-withDict)/len(contents), "bytes per input (rounded down)") + } + return out.Bytes(), nil +} diff --git a/vendor/github.com/klauspost/compress/zstd/enc_base.go b/vendor/github.com/klauspost/compress/zstd/enc_base.go new file mode 100644 index 0000000..c4fea57 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/enc_base.go @@ -0,0 +1,199 @@ +package zstd + +import ( + "fmt" + "math/bits" + + "github.com/klauspost/compress/zstd/internal/xxhash" +) + +const ( + dictShardBits = 7 +) + +type fastBase struct { + // cur is the offset at the start of hist + cur int32 + // maximum offset. Should be at least 2x block size. + maxMatchOff int32 + bufferReset int32 + hist []byte + crc *xxhash.Digest + tmp [8]byte + blk *blockEnc + lastDict *dict + lowMem bool +} + +// CRC returns the underlying CRC writer. +func (e *fastBase) CRC() *xxhash.Digest { + return e.crc +} + +// AppendCRC will append the CRC to the destination slice and return it. +func (e *fastBase) AppendCRC(dst []byte) []byte { + crc := e.crc.Sum(e.tmp[:0]) + dst = append(dst, crc[7], crc[6], crc[5], crc[4]) + return dst +} + +// WindowSize returns the window size of the encoder, +// or a window size small enough to contain the input size, if > 0. +func (e *fastBase) WindowSize(size int64) int32 { + if size > 0 && size < int64(e.maxMatchOff) { + b := max( + // Keep minimum window. + int32(1)< e.bufferReset { + panic(fmt.Sprintf("ecur (%d) > buffer reset (%d)", e.cur, e.bufferReset)) + } + // check if we have space already + if len(e.hist)+len(src) > cap(e.hist) { + if cap(e.hist) == 0 { + e.ensureHist(len(src)) + } else { + if cap(e.hist) < int(e.maxMatchOff+maxCompressedBlockSize) { + panic(fmt.Errorf("unexpected buffer cap %d, want at least %d with window %d", cap(e.hist), e.maxMatchOff+maxCompressedBlockSize, e.maxMatchOff)) + } + // Move down + offset := int32(len(e.hist)) - e.maxMatchOff + copy(e.hist[0:e.maxMatchOff], e.hist[offset:]) + e.cur += offset + e.hist = e.hist[:e.maxMatchOff] + } + } + s := int32(len(e.hist)) + e.hist = append(e.hist, src...) + return s +} + +// ensureHist will ensure that history can keep at least this many bytes. +func (e *fastBase) ensureHist(n int) { + if cap(e.hist) >= n { + return + } + l := e.maxMatchOff + if (e.lowMem && e.maxMatchOff > maxCompressedBlockSize) || e.maxMatchOff <= maxCompressedBlockSize { + l += maxCompressedBlockSize + } else { + l += e.maxMatchOff + } + // Make it at least 1MB. + if l < 1<<20 && !e.lowMem { + l = 1 << 20 + } + // Make it at least the requested size. + if l < int32(n) { + l = int32(n) + } + e.hist = make([]byte, 0, l) +} + +// useBlock will replace the block with the provided one, +// but transfer recent offsets from the previous. +func (e *fastBase) UseBlock(enc *blockEnc) { + enc.reset(e.blk) + e.blk = enc +} + +func (e *fastBase) matchlen(s, t int32, src []byte) int32 { + if debugAsserts { + if s < 0 { + err := fmt.Sprintf("s (%d) < 0", s) + panic(err) + } + if t < 0 { + err := fmt.Sprintf("t (%d) < 0", t) + panic(err) + } + if s-t > e.maxMatchOff { + err := fmt.Sprintf("s (%d) - t (%d) > maxMatchOff (%d)", s, t, e.maxMatchOff) + panic(err) + } + if len(src)-int(s) > maxCompressedBlockSize { + panic(fmt.Sprintf("len(src)-s (%d) > maxCompressedBlockSize (%d)", len(src)-int(s), maxCompressedBlockSize)) + } + } + return int32(matchLen(src[s:], src[t:])) +} + +// resetBasePrefix resets the encoder state and loads prefix as initial history. +// This is used for parallel job encoding where non-first jobs need overlap context. +// Rep offsets are set to defaults [1,4,8] (invalidated, matching C behavior). +func (e *fastBase) resetBasePrefix(prefix []byte) { + if e.blk == nil { + e.blk = &blockEnc{lowMem: e.lowMem} + e.blk.init() + } else { + e.blk.reset(nil) + } + e.blk.initNewEncode() + if e.crc == nil { + e.crc = xxhash.New() + } else { + e.crc.Reset() + } + e.blk.dictLitEnc = nil + e.ensureHist(len(prefix) + maxCompressedBlockSize) + // Bump cur so old table entries fall outside the window. + // When cur >= bufferReset, leave it; the first Encode call + // will shift/clear tables, preserving valid prefix entries. + if e.cur < e.bufferReset { + e.cur += e.maxMatchOff + int32(len(e.hist)) + } + e.hist = e.hist[:0] + e.hist = append(e.hist, prefix...) +} + +// Reset the encoding table. +func (e *fastBase) resetBase(d *dict, singleBlock bool) { + if e.blk == nil { + e.blk = &blockEnc{lowMem: e.lowMem} + e.blk.init() + } else { + e.blk.reset(nil) + } + e.blk.initNewEncode() + if e.crc == nil { + e.crc = xxhash.New() + } else { + e.crc.Reset() + } + e.blk.dictLitEnc = nil + if d != nil { + low := e.lowMem + if singleBlock { + e.lowMem = true + } + e.ensureHist(d.ContentSize() + maxCompressedBlockSize) + e.lowMem = low + } + + // We offset current position so everything will be out of reach. + // If above reset line, history will be purged. + if e.cur < e.bufferReset { + e.cur += e.maxMatchOff + int32(len(e.hist)) + } + e.hist = e.hist[:0] + if d != nil { + // Set offsets (currently not used) + for i, off := range d.offsets { + e.blk.recentOffsets[i] = uint32(off) + e.blk.prevRecentOffsets[i] = e.blk.recentOffsets[i] + } + // Transfer litenc. + e.blk.dictLitEnc = d.litEnc + e.hist = append(e.hist, d.content...) + } +} diff --git a/vendor/github.com/klauspost/compress/zstd/enc_best.go b/vendor/github.com/klauspost/compress/zstd/enc_best.go new file mode 100644 index 0000000..c71382d --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/enc_best.go @@ -0,0 +1,568 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "bytes" + "fmt" + + "github.com/klauspost/compress" +) + +const ( + bestLongTableBits = 22 // Bits used in the long match table + bestLongTableSize = 1 << bestLongTableBits // Size of the table + bestLongLen = 8 // Bytes used for table hash + + // Note: Increasing the short table bits or making the hash shorter + // can actually lead to compression degradation since it will 'steal' more from the + // long match table and match offsets are quite big. + // This greatly depends on the type of input. + bestShortTableBits = 18 // Bits used in the short match table + bestShortTableSize = 1 << bestShortTableBits // Size of the table + bestShortLen = 4 // Bytes used for table hash + +) + +type match struct { + offset int32 + s int32 + length int32 + rep int32 + est int32 +} + +const highScore = maxMatchLen * 8 + +// estBits will estimate output bits from predefined tables. +func (m *match) estBits(bitsPerByte int32) { + mlc := mlCode(uint32(m.length - zstdMinMatch)) + var ofc uint8 + if m.rep < 0 { + ofc = ofCode(uint32(m.s-m.offset) + 3) + } else { + ofc = ofCode(uint32(m.rep) & 3) + } + // Cost, excluding + ofTT, mlTT := fsePredefEnc[tableOffsets].ct.symbolTT[ofc], fsePredefEnc[tableMatchLengths].ct.symbolTT[mlc] + + // Add cost of match encoding... + m.est = int32(ofTT.outBits + mlTT.outBits) + m.est += int32(ofTT.deltaNbBits>>16 + mlTT.deltaNbBits>>16) + // Subtract savings compared to literal encoding... + m.est -= (m.length * bitsPerByte) >> 10 + if m.est > 0 { + // Unlikely gain.. + m.length = 0 + m.est = highScore + } +} + +// bestFastEncoder uses 2 tables, one for short matches (5 bytes) and one for long matches. +// The long match table contains the previous entry with the same hash, +// effectively making it a "chain" of length 2. +// When we find a long match we choose between the two values and select the longest. +// When we find a short match, after checking the long, we check if we can find a long at n+1 +// and that it is longer (lazy matching). +type bestFastEncoder struct { + fastBase + table [bestShortTableSize]prevEntry + longTable [bestLongTableSize]prevEntry + dictTable []prevEntry + dictLongTable []prevEntry +} + +// Encode improves compression... +func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) { + const ( + // Input margin is the number of bytes we read (8) + // and the maximum we will read ahead (2) + inputMargin = 8 + 4 + minNonLiteralBlockSize = 16 + ) + + // Protect against e.cur wraparound. + for e.cur >= e.bufferReset-int32(len(e.hist)) { + if len(e.hist) == 0 { + e.table = [bestShortTableSize]prevEntry{} + e.longTable = [bestLongTableSize]prevEntry{} + e.cur = e.maxMatchOff + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff + for i := range e.table[:] { + v := e.table[i].offset + v2 := e.table[i].prev + if v < minOff { + v = 0 + v2 = 0 + } else { + v = v - e.cur + e.maxMatchOff + if v2 < minOff { + v2 = 0 + } else { + v2 = v2 - e.cur + e.maxMatchOff + } + } + e.table[i] = prevEntry{ + offset: v, + prev: v2, + } + } + for i := range e.longTable[:] { + v := e.longTable[i].offset + v2 := e.longTable[i].prev + if v < minOff { + v = 0 + v2 = 0 + } else { + v = v - e.cur + e.maxMatchOff + if v2 < minOff { + v2 = 0 + } else { + v2 = v2 - e.cur + e.maxMatchOff + } + } + e.longTable[i] = prevEntry{ + offset: v, + prev: v2, + } + } + e.cur = e.maxMatchOff + break + } + + // Add block to history + s := e.addBlock(src) + blk.size = len(src) + + // Check RLE first + if len(src) > zstdMinMatch { + ml := matchLen(src[1:], src) + if ml == len(src)-1 { + blk.literals = append(blk.literals, src[0]) + blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3}) + return + } + } + + if len(src) < minNonLiteralBlockSize { + blk.extraLits = len(src) + blk.literals = blk.literals[:len(src)] + copy(blk.literals, src) + return + } + + // Use this to estimate literal cost. + // Scaled by 10 bits. + bitsPerByte := max( + // Huffman can never go < 1 bit/byte + int32((compress.ShannonEntropyBits(src)*1024)/len(src)), 1024) + + // Override src + src = e.hist + sLimit := int32(len(src)) - inputMargin + const kSearchStrength = 10 + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := s + + // Relative offsets + offset1 := int32(blk.recentOffsets[0]) + offset2 := int32(blk.recentOffsets[1]) + offset3 := int32(blk.recentOffsets[2]) + + addLiterals := func(s *seq, until int32) { + if until == nextEmit { + return + } + blk.literals = append(blk.literals, src[nextEmit:until]...) + s.litLen = uint32(until - nextEmit) + } + + if debugEncoder { + println("recent offsets:", blk.recentOffsets) + } + +encodeLoop: + for { + // We allow the encoder to optionally turn off repeat offsets across blocks + canRepeat := len(blk.sequences) > 2 + + if debugAsserts && canRepeat && offset1 == 0 { + panic("offset0 was 0") + } + + const goodEnough = 250 + + cv := load6432(src, s) + + nextHashL := hashLen(cv, bestLongTableBits, bestLongLen) + nextHashS := hashLen(cv, bestShortTableBits, bestShortLen) + candidateL := e.longTable[nextHashL] + candidateS := e.table[nextHashS] + + // Set m to a match at offset if it looks like that will improve compression. + improve := func(m *match, offset int32, s int32, first uint32, rep int32) { + delta := s - offset + if delta >= e.maxMatchOff || delta <= 0 || load3232(src, offset) != first { + return + } + // Try to quick reject if we already have a long match. + if m.length > 16 { + left := len(src) - int(m.s+m.length) + // If we are too close to the end, keep as is. + if left <= 0 { + return + } + checkLen := m.length - (s - m.s) - 8 + if left > 2 && checkLen > 4 { + // Check 4 bytes, 4 bytes from the end of the current match. + a := load3232(src, offset+checkLen) + b := load3232(src, s+checkLen) + if a != b { + return + } + } + } + l := 4 + e.matchlen(s+4, offset+4, src) + if m.rep <= 0 { + // Extend candidate match backwards as far as possible. + // Do not extend repeats as we can assume they are optimal + // and offsets change if s == nextEmit. + tMin := max(s-e.maxMatchOff, 0) + for offset > tMin && s > nextEmit && src[offset-1] == src[s-1] && l < maxMatchLength { + s-- + offset-- + l++ + } + } + if debugAsserts { + if offset >= s { + panic(fmt.Sprintf("offset: %d - s:%d - rep: %d - cur :%d - max: %d", offset, s, rep, e.cur, e.maxMatchOff)) + } + if !bytes.Equal(src[s:s+l], src[offset:offset+l]) { + panic(fmt.Sprintf("second match mismatch: %v != %v, first: %08x", src[s:s+4], src[offset:offset+4], first)) + } + } + cand := match{offset: offset, s: s, length: l, rep: rep} + cand.estBits(bitsPerByte) + if m.est >= highScore || cand.est-m.est+(cand.s-m.s)*bitsPerByte>>10 < 0 { + *m = cand + } + } + + best := match{s: s, est: highScore} + improve(&best, candidateL.offset-e.cur, s, uint32(cv), -1) + improve(&best, candidateL.prev-e.cur, s, uint32(cv), -1) + improve(&best, candidateS.offset-e.cur, s, uint32(cv), -1) + improve(&best, candidateS.prev-e.cur, s, uint32(cv), -1) + + if canRepeat && best.length < goodEnough { + if s == nextEmit { + // Check repeats straight after a match. + improve(&best, s-offset2, s, uint32(cv), 1|4) + improve(&best, s-offset3, s, uint32(cv), 2|4) + if offset1 > 1 { + improve(&best, s-(offset1-1), s, uint32(cv), 3|4) + } + } + + // If either no match or a non-repeat match, check at + 1 + if best.rep <= 0 { + cv32 := uint32(cv >> 8) + spp := s + 1 + improve(&best, spp-offset1, spp, cv32, 1) + improve(&best, spp-offset2, spp, cv32, 2) + improve(&best, spp-offset3, spp, cv32, 3) + if best.rep < 0 { + cv32 = uint32(cv >> 24) + spp += 2 + improve(&best, spp-offset1, spp, cv32, 1) + improve(&best, spp-offset2, spp, cv32, 2) + improve(&best, spp-offset3, spp, cv32, 3) + } + } + } + // Load next and check... + e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: candidateL.offset} + e.table[nextHashS] = prevEntry{offset: s + e.cur, prev: candidateS.offset} + index0 := s + 1 + + // Look far ahead, unless we have a really long match already... + if best.length < goodEnough { + // No match found, move forward on input, no need to check forward... + if best.length < 4 { + s += 1 + (s-nextEmit)>>(kSearchStrength-1) + if s >= sLimit { + break encodeLoop + } + continue + } + + candidateS = e.table[hashLen(cv>>8, bestShortTableBits, bestShortLen)] + cv = load6432(src, s+1) + cv2 := load6432(src, s+2) + candidateL = e.longTable[hashLen(cv, bestLongTableBits, bestLongLen)] + candidateL2 := e.longTable[hashLen(cv2, bestLongTableBits, bestLongLen)] + + // Short at s+1 + improve(&best, candidateS.offset-e.cur, s+1, uint32(cv), -1) + // Long at s+1, s+2 + improve(&best, candidateL.offset-e.cur, s+1, uint32(cv), -1) + improve(&best, candidateL.prev-e.cur, s+1, uint32(cv), -1) + improve(&best, candidateL2.offset-e.cur, s+2, uint32(cv2), -1) + improve(&best, candidateL2.prev-e.cur, s+2, uint32(cv2), -1) + if false { + // Short at s+3. + // Too often worse... + improve(&best, e.table[hashLen(cv2>>8, bestShortTableBits, bestShortLen)].offset-e.cur, s+3, uint32(cv2>>8), -1) + } + + // Start check at a fixed offset to allow for a few mismatches. + // For this compression level 2 yields the best results. + // We cannot do this if we have already indexed this position. + const skipBeginning = 2 + if best.s > s-skipBeginning { + // See if we can find a better match by checking where the current best ends. + // Use that offset to see if we can find a better full match. + if sAt := best.s + best.length; sAt < sLimit { + nextHashL := hashLen(load6432(src, sAt), bestLongTableBits, bestLongLen) + candidateEnd := e.longTable[nextHashL] + + if off := candidateEnd.offset - e.cur - best.length + skipBeginning; off >= 0 { + improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1) + if off := candidateEnd.prev - e.cur - best.length + skipBeginning; off >= 0 { + improve(&best, off, best.s+skipBeginning, load3232(src, best.s+skipBeginning), -1) + } + } + } + } + } + + if debugAsserts { + if best.offset >= best.s { + panic(fmt.Sprintf("best.offset > s: %d >= %d", best.offset, best.s)) + } + if best.s < nextEmit { + panic(fmt.Sprintf("s %d < nextEmit %d", best.s, nextEmit)) + } + if best.offset < s-e.maxMatchOff { + panic(fmt.Sprintf("best.offset < s-e.maxMatchOff: %d < %d", best.offset, s-e.maxMatchOff)) + } + if !bytes.Equal(src[best.s:best.s+best.length], src[best.offset:best.offset+best.length]) { + panic(fmt.Sprintf("match mismatch: %v != %v", src[best.s:best.s+best.length], src[best.offset:best.offset+best.length])) + } + } + + // We have a match, we can store the forward value + s = best.s + if best.rep > 0 { + var seq seq + seq.matchLen = uint32(best.length - zstdMinMatch) + addLiterals(&seq, best.s) + + // Repeat. If bit 4 is set, this is a non-lit repeat. + seq.offset = uint32(best.rep & 3) + if debugSequences { + println("repeat sequence", seq, "next s:", best.s, "off:", best.s-best.offset) + } + blk.sequences = append(blk.sequences, seq) + + // Index old s + 1 -> s - 1 + s = best.s + best.length + nextEmit = s + + // Index skipped... + end := min(s, sLimit+4) + off := index0 + e.cur + for index0 < end { + cv0 := load6432(src, index0) + h0 := hashLen(cv0, bestLongTableBits, bestLongLen) + h1 := hashLen(cv0, bestShortTableBits, bestShortLen) + e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} + e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset} + off++ + index0++ + } + + switch best.rep { + case 2, 4 | 1: + offset1, offset2 = offset2, offset1 + case 3, 4 | 2: + offset1, offset2, offset3 = offset3, offset1, offset2 + case 4 | 3: + offset1, offset2, offset3 = offset1-1, offset1, offset2 + } + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, best.length) + } + break encodeLoop + } + continue + } + + // A 4-byte match has been found. Update recent offsets. + // We'll later see if more than 4 bytes. + t := best.offset + offset1, offset2, offset3 = s-t, offset1, offset2 + + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + + if debugAsserts && int(offset1) > len(src) { + panic("invalid offset") + } + + // Write our sequence + var seq seq + l := best.length + seq.litLen = uint32(s - nextEmit) + seq.matchLen = uint32(l - zstdMinMatch) + if seq.litLen > 0 { + blk.literals = append(blk.literals, src[nextEmit:s]...) + } + seq.offset = uint32(s-t) + 3 + s += l + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + nextEmit = s + + // Index old s + 1 -> s - 1 or sLimit + end := min(s, sLimit-4) + + off := index0 + e.cur + for index0 < end { + cv0 := load6432(src, index0) + h0 := hashLen(cv0, bestLongTableBits, bestLongLen) + h1 := hashLen(cv0, bestShortTableBits, bestShortLen) + e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} + e.table[h1] = prevEntry{offset: off, prev: e.table[h1].offset} + index0++ + off++ + } + if s >= sLimit { + break encodeLoop + } + } + + if int(nextEmit) < len(src) { + blk.literals = append(blk.literals, src[nextEmit:]...) + blk.extraLits = len(src) - int(nextEmit) + } + blk.recentOffsets[0] = uint32(offset1) + blk.recentOffsets[1] = uint32(offset2) + blk.recentOffsets[2] = uint32(offset3) + if debugEncoder { + println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits) + } +} + +// EncodeNoHist will encode a block with no history and no following blocks. +// Most notable difference is that src will not be copied for history and +// we do not need to check for max match length. +func (e *bestFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) { + e.ensureHist(len(src)) + e.Encode(blk, src) +} + +// Reset will reset and set a dictionary if not nil +func (e *bestFastEncoder) Reset(d *dict, singleBlock bool) { + e.resetBase(d, singleBlock) + if d == nil { + return + } + dictChanged := d != e.lastDict + // Init or copy dict table + if len(e.dictTable) != len(e.table) || dictChanged { + if len(e.dictTable) != len(e.table) { + e.dictTable = make([]prevEntry, len(e.table)) + } else { + clear(e.dictTable) + } + end := int32(len(d.content)) - 8 + e.maxMatchOff + for i := e.maxMatchOff; i < end; i += 4 { + const hashLog = bestShortTableBits + + cv := load6432(d.content, i-e.maxMatchOff) + nextHash := hashLen(cv, hashLog, bestShortLen) // 0 -> 4 + nextHash1 := hashLen(cv>>8, hashLog, bestShortLen) // 1 -> 5 + nextHash2 := hashLen(cv>>16, hashLog, bestShortLen) // 2 -> 6 + nextHash3 := hashLen(cv>>24, hashLog, bestShortLen) // 3 -> 7 + e.dictTable[nextHash] = prevEntry{ + prev: e.dictTable[nextHash].offset, + offset: i, + } + e.dictTable[nextHash1] = prevEntry{ + prev: e.dictTable[nextHash1].offset, + offset: i + 1, + } + e.dictTable[nextHash2] = prevEntry{ + prev: e.dictTable[nextHash2].offset, + offset: i + 2, + } + e.dictTable[nextHash3] = prevEntry{ + prev: e.dictTable[nextHash3].offset, + offset: i + 3, + } + } + } + + // Init or copy dict long table + if len(e.dictLongTable) != len(e.longTable) || dictChanged { + if len(e.dictLongTable) != len(e.longTable) { + e.dictLongTable = make([]prevEntry, len(e.longTable)) + } else { + clear(e.dictLongTable) + } + if len(d.content) >= 8 { + cv := load6432(d.content, 0) + h := hashLen(cv, bestLongTableBits, bestLongLen) + e.dictLongTable[h] = prevEntry{ + offset: e.maxMatchOff, + prev: e.dictLongTable[h].offset, + } + + end := int32(len(d.content)) - 8 + e.maxMatchOff + off := 8 // First to read + for i := e.maxMatchOff + 1; i < end; i++ { + cv = cv>>8 | (uint64(d.content[off]) << 56) + h := hashLen(cv, bestLongTableBits, bestLongLen) + e.dictLongTable[h] = prevEntry{ + offset: i, + prev: e.dictLongTable[h].offset, + } + off++ + } + } + } + e.lastDict = d + // Reset table to initial state + copy(e.longTable[:], e.dictLongTable) + + e.cur = e.maxMatchOff + // Reset table to initial state + copy(e.table[:], e.dictTable) +} + +func (e *bestFastEncoder) ResetPrefix(prefix []byte) { + e.resetBasePrefix(prefix) + if len(prefix) < 8 { + return + } + end := e.cur + int32(len(prefix)) - 8 + for i := e.cur; i < end; i++ { + cv := load6432(prefix, i-e.cur) + h := hashLen(cv, bestLongTableBits, bestLongLen) + e.longTable[h] = prevEntry{offset: i, prev: e.longTable[h].offset} + h0 := hashLen(cv, bestShortTableBits, bestShortLen) + e.table[h0] = prevEntry{offset: i, prev: e.table[h0].offset} + } +} diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go new file mode 100644 index 0000000..523d57f --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go @@ -0,0 +1,1256 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import "fmt" + +const ( + betterLongTableBits = 19 // Bits used in the long match table + betterLongTableSize = 1 << betterLongTableBits // Size of the table + betterLongLen = 8 // Bytes used for table hash + + // Note: Increasing the short table bits or making the hash shorter + // can actually lead to compression degradation since it will 'steal' more from the + // long match table and match offsets are quite big. + // This greatly depends on the type of input. + betterShortTableBits = 13 // Bits used in the short match table + betterShortTableSize = 1 << betterShortTableBits // Size of the table + betterShortLen = 5 // Bytes used for table hash + + betterLongTableShardCnt = 1 << (betterLongTableBits - dictShardBits) // Number of shards in the table + betterLongTableShardSize = betterLongTableSize / betterLongTableShardCnt // Size of an individual shard + + betterShortTableShardCnt = 1 << (betterShortTableBits - dictShardBits) // Number of shards in the table + betterShortTableShardSize = betterShortTableSize / betterShortTableShardCnt // Size of an individual shard +) + +type prevEntry struct { + offset int32 + prev int32 +} + +// betterFastEncoder uses 2 tables, one for short matches (5 bytes) and one for long matches. +// The long match table contains the previous entry with the same hash, +// effectively making it a "chain" of length 2. +// When we find a long match we choose between the two values and select the longest. +// When we find a short match, after checking the long, we check if we can find a long at n+1 +// and that it is longer (lazy matching). +type betterFastEncoder struct { + fastBase + table [betterShortTableSize]tableEntry + longTable [betterLongTableSize]prevEntry +} + +type betterFastEncoderDict struct { + betterFastEncoder + dictTable []tableEntry + dictLongTable []prevEntry + shortTableShardDirty [betterShortTableShardCnt]bool + longTableShardDirty [betterLongTableShardCnt]bool + allDirty bool +} + +// Encode improves compression... +func (e *betterFastEncoder) Encode(blk *blockEnc, src []byte) { + const ( + // Input margin is the number of bytes we read (8) + // and the maximum we will read ahead (2) + inputMargin = 8 + 2 + minNonLiteralBlockSize = 16 + ) + + // Protect against e.cur wraparound. + for e.cur >= e.bufferReset-int32(len(e.hist)) { + if len(e.hist) == 0 { + e.table = [betterShortTableSize]tableEntry{} + e.longTable = [betterLongTableSize]prevEntry{} + e.cur = e.maxMatchOff + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff + for i := range e.table[:] { + v := e.table[i].offset + if v < minOff { + v = 0 + } else { + v = v - e.cur + e.maxMatchOff + } + e.table[i].offset = v + } + for i := range e.longTable[:] { + v := e.longTable[i].offset + v2 := e.longTable[i].prev + if v < minOff { + v = 0 + v2 = 0 + } else { + v = v - e.cur + e.maxMatchOff + if v2 < minOff { + v2 = 0 + } else { + v2 = v2 - e.cur + e.maxMatchOff + } + } + e.longTable[i] = prevEntry{ + offset: v, + prev: v2, + } + } + e.cur = e.maxMatchOff + break + } + // Add block to history + s := e.addBlock(src) + blk.size = len(src) + + // Check RLE first + if len(src) > zstdMinMatch { + ml := matchLen(src[1:], src) + if ml == len(src)-1 { + blk.literals = append(blk.literals, src[0]) + blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3}) + return + } + } + + if len(src) < minNonLiteralBlockSize { + blk.extraLits = len(src) + blk.literals = blk.literals[:len(src)] + copy(blk.literals, src) + return + } + + // Override src + src = e.hist + sLimit := int32(len(src)) - inputMargin + // stepSize is the number of bytes to skip on every main loop iteration. + // It should be >= 1. + const stepSize = 1 + + const kSearchStrength = 9 + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := s + cv := load6432(src, s) + + // Relative offsets + offset1 := int32(blk.recentOffsets[0]) + offset2 := int32(blk.recentOffsets[1]) + + addLiterals := func(s *seq, until int32) { + if until == nextEmit { + return + } + blk.literals = append(blk.literals, src[nextEmit:until]...) + s.litLen = uint32(until - nextEmit) + } + if debugEncoder { + println("recent offsets:", blk.recentOffsets) + } + +encodeLoop: + for { + var t int32 + // We allow the encoder to optionally turn off repeat offsets across blocks + canRepeat := len(blk.sequences) > 2 + var matched, index0 int32 + + for { + if debugAsserts && canRepeat && offset1 == 0 { + panic("offset0 was 0") + } + + nextHashL := hashLen(cv, betterLongTableBits, betterLongLen) + nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) + candidateL := e.longTable[nextHashL] + candidateS := e.table[nextHashS] + + const repOff = 1 + repIndex := s - offset1 + repOff + off := s + e.cur + e.longTable[nextHashL] = prevEntry{offset: off, prev: candidateL.offset} + e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)} + index0 = s + 1 + + if canRepeat { + if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { + // Consider history as well. + var seq seq + length := 4 + e.matchlen(s+4+repOff, repIndex+4, src) + + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + repOff + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + tMin := max(s-e.maxMatchOff, 0) + for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 0 + seq.offset = 1 + if debugSequences { + println("repeat sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Index match start+1 (long) -> s - 1 + index0 := s + repOff + s += length + repOff + + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + // Index skipped... + for index0 < s-1 { + cv0 := load6432(src, index0) + cv1 := cv0 >> 8 + h0 := hashLen(cv0, betterLongTableBits, betterLongLen) + off := index0 + e.cur + e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} + e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)} + index0 += 2 + } + cv = load6432(src, s) + continue + } + const repOff2 = 1 + + // We deviate from the reference encoder and also check offset 2. + // Still slower and not much better, so disabled. + // repIndex = s - offset2 + repOff2 + if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) { + // Consider history as well. + var seq seq + length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src) + + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + repOff2 + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + tMin := max(s-e.maxMatchOff, 0) + for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 2 + seq.offset = 2 + if debugSequences { + println("repeat sequence 2", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + s += length + repOff2 + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + + // Index skipped... + for index0 < s-1 { + cv0 := load6432(src, index0) + cv1 := cv0 >> 8 + h0 := hashLen(cv0, betterLongTableBits, betterLongLen) + off := index0 + e.cur + e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} + e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)} + index0 += 2 + } + cv = load6432(src, s) + // Swap offsets + offset1, offset2 = offset2, offset1 + continue + } + } + // Find the offsets of our two matches. + coffsetL := candidateL.offset - e.cur + coffsetLP := candidateL.prev - e.cur + + // Check if we have a long match. + if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) { + // Found a long match, at least 8 bytes. + matched = e.matchlen(s+8, coffsetL+8, src) + 8 + t = coffsetL + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugMatches { + println("long match") + } + + if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) { + // Found a long match, at least 8 bytes. + prevMatch := e.matchlen(s+8, coffsetLP+8, src) + 8 + if prevMatch > matched { + matched = prevMatch + t = coffsetLP + } + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugMatches { + println("long match") + } + } + break + } + + // Check if we have a long match on prev. + if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) { + // Found a long match, at least 8 bytes. + matched = e.matchlen(s+8, coffsetLP+8, src) + 8 + t = coffsetLP + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugMatches { + println("long match") + } + break + } + + coffsetS := candidateS.offset - e.cur + + // Check if we have a short match. + if s-coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val { + // found a regular match + matched = e.matchlen(s+4, coffsetS+4, src) + 4 + + // See if we can find a long match at s+1 + const checkAt = 1 + cv := load6432(src, s+checkAt) + nextHashL = hashLen(cv, betterLongTableBits, betterLongLen) + candidateL = e.longTable[nextHashL] + coffsetL = candidateL.offset - e.cur + + // We can store it, since we have at least a 4 byte match. + e.longTable[nextHashL] = prevEntry{offset: s + checkAt + e.cur, prev: candidateL.offset} + if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) { + // Found a long match, at least 8 bytes. + matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8 + if matchedNext > matched { + t = coffsetL + s += checkAt + matched = matchedNext + if debugMatches { + println("long match (after short)") + } + break + } + } + + // Check prev long... + coffsetL = candidateL.prev - e.cur + if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) { + // Found a long match, at least 8 bytes. + matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8 + if matchedNext > matched { + t = coffsetL + s += checkAt + matched = matchedNext + if debugMatches { + println("prev long match (after short)") + } + break + } + } + t = coffsetS + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugAsserts && t < 0 { + panic("t<0") + } + if debugMatches { + println("short match") + } + break + } + + // No match found, move forward in input. + s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1)) + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + } + + // Try to find a better match by searching for a long match at the end of the current best match + if s+matched < sLimit { + // Allow some bytes at the beginning to mismatch. + // Sweet spot is around 3 bytes, but depends on input. + // The skipped bytes are tested in Extend backwards, + // and still picked up as part of the match if they do. + const skipBeginning = 3 + + nextHashL := hashLen(load6432(src, s+matched), betterLongTableBits, betterLongLen) + s2 := s + skipBeginning + cv := load3232(src, s2) + candidateL := e.longTable[nextHashL] + coffsetL := candidateL.offset - e.cur - matched + skipBeginning + if coffsetL >= 0 && coffsetL < s2 && s2-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) { + // Found a long match, at least 4 bytes. + matchedNext := e.matchlen(s2+4, coffsetL+4, src) + 4 + if matchedNext > matched { + t = coffsetL + s = s2 + matched = matchedNext + if debugMatches { + println("long match at end-of-match") + } + } + } + + // Check prev long... + if true { + coffsetL = candidateL.prev - e.cur - matched + skipBeginning + if coffsetL >= 0 && coffsetL < s2 && s2-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) { + // Found a long match, at least 4 bytes. + matchedNext := e.matchlen(s2+4, coffsetL+4, src) + 4 + if matchedNext > matched { + t = coffsetL + s = s2 + matched = matchedNext + if debugMatches { + println("prev long match at end-of-match") + } + } + } + } + } + // A match has been found. Update recent offsets. + offset2 = offset1 + offset1 = s - t + + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + + if debugAsserts && canRepeat && int(offset1) > len(src) { + panic("invalid offset") + } + + // Extend the n-byte match as long as possible. + l := matched + + // Extend backwards + tMin := max(s-e.maxMatchOff, 0) + for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength { + s-- + t-- + l++ + } + + // Write our sequence + var seq seq + seq.litLen = uint32(s - nextEmit) + seq.matchLen = uint32(l - zstdMinMatch) + if seq.litLen > 0 { + blk.literals = append(blk.literals, src[nextEmit:s]...) + } + seq.offset = uint32(s-t) + 3 + s += l + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + nextEmit = s + if s >= sLimit { + break encodeLoop + } + + // Index match start+1 (long) -> s - 1 + off := index0 + e.cur + for index0 < s-1 { + cv0 := load6432(src, index0) + cv1 := cv0 >> 8 + h0 := hashLen(cv0, betterLongTableBits, betterLongLen) + e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} + e.table[hashLen(cv1, betterShortTableBits, betterShortLen)] = tableEntry{offset: off + 1, val: uint32(cv1)} + index0 += 2 + off += 2 + } + + cv = load6432(src, s) + if !canRepeat { + continue + } + + // Check offset 2 + for { + o2 := s - offset2 + if load3232(src, o2) != uint32(cv) { + // Do regular search + break + } + + // Store this, since we have it. + nextHashL := hashLen(cv, betterLongTableBits, betterLongLen) + nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) + + // We have at least 4 byte match. + // No need to check backwards. We come straight from a match + l := 4 + e.matchlen(s+4, o2+4, src) + + e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: e.longTable[nextHashL].offset} + e.table[nextHashS] = tableEntry{offset: s + e.cur, val: uint32(cv)} + seq.matchLen = uint32(l) - zstdMinMatch + seq.litLen = 0 + + // Since litlen is always 0, this is offset 1. + seq.offset = 1 + s += l + nextEmit = s + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Swap offset 1 and 2. + offset1, offset2 = offset2, offset1 + if s >= sLimit { + // Finished + break encodeLoop + } + cv = load6432(src, s) + } + } + + if int(nextEmit) < len(src) { + blk.literals = append(blk.literals, src[nextEmit:]...) + blk.extraLits = len(src) - int(nextEmit) + } + blk.recentOffsets[0] = uint32(offset1) + blk.recentOffsets[1] = uint32(offset2) + if debugEncoder { + println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits) + } +} + +// EncodeNoHist will encode a block with no history and no following blocks. +// Most notable difference is that src will not be copied for history and +// we do not need to check for max match length. +func (e *betterFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) { + e.ensureHist(len(src)) + e.Encode(blk, src) +} + +// Encode improves compression... +func (e *betterFastEncoderDict) Encode(blk *blockEnc, src []byte) { + const ( + // Input margin is the number of bytes we read (8) + // and the maximum we will read ahead (2) + inputMargin = 8 + 2 + minNonLiteralBlockSize = 16 + ) + + // Protect against e.cur wraparound. + for e.cur >= e.bufferReset-int32(len(e.hist)) { + if len(e.hist) == 0 { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + for i := range e.longTable[:] { + e.longTable[i] = prevEntry{} + } + e.cur = e.maxMatchOff + e.allDirty = true + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff + for i := range e.table[:] { + v := e.table[i].offset + if v < minOff { + v = 0 + } else { + v = v - e.cur + e.maxMatchOff + } + e.table[i].offset = v + } + for i := range e.longTable[:] { + v := e.longTable[i].offset + v2 := e.longTable[i].prev + if v < minOff { + v = 0 + v2 = 0 + } else { + v = v - e.cur + e.maxMatchOff + if v2 < minOff { + v2 = 0 + } else { + v2 = v2 - e.cur + e.maxMatchOff + } + } + e.longTable[i] = prevEntry{ + offset: v, + prev: v2, + } + } + e.allDirty = true + e.cur = e.maxMatchOff + break + } + + s := e.addBlock(src) + blk.size = len(src) + if len(src) < minNonLiteralBlockSize { + blk.extraLits = len(src) + blk.literals = blk.literals[:len(src)] + copy(blk.literals, src) + return + } + + // Override src + src = e.hist + sLimit := int32(len(src)) - inputMargin + // stepSize is the number of bytes to skip on every main loop iteration. + // It should be >= 1. + const stepSize = 1 + + const kSearchStrength = 9 + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := s + cv := load6432(src, s) + + // Relative offsets + offset1 := int32(blk.recentOffsets[0]) + offset2 := int32(blk.recentOffsets[1]) + + addLiterals := func(s *seq, until int32) { + if until == nextEmit { + return + } + blk.literals = append(blk.literals, src[nextEmit:until]...) + s.litLen = uint32(until - nextEmit) + } + if debugEncoder { + println("recent offsets:", blk.recentOffsets) + } + +encodeLoop: + for { + var t int32 + // We allow the encoder to optionally turn off repeat offsets across blocks + canRepeat := len(blk.sequences) > 2 + var matched, index0 int32 + + for { + if debugAsserts && canRepeat && offset1 == 0 { + panic("offset0 was 0") + } + + nextHashL := hashLen(cv, betterLongTableBits, betterLongLen) + nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) + candidateL := e.longTable[nextHashL] + candidateS := e.table[nextHashS] + + const repOff = 1 + repIndex := s - offset1 + repOff + off := s + e.cur + e.longTable[nextHashL] = prevEntry{offset: off, prev: candidateL.offset} + e.markLongShardDirty(nextHashL) + e.table[nextHashS] = tableEntry{offset: off, val: uint32(cv)} + e.markShortShardDirty(nextHashS) + index0 = s + 1 + + if canRepeat { + if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { + // Consider history as well. + var seq seq + length := 4 + e.matchlen(s+4+repOff, repIndex+4, src) + + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + repOff + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + tMin := max(s-e.maxMatchOff, 0) + for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 0 + seq.offset = 1 + if debugSequences { + println("repeat sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Index match start+1 (long) -> s - 1 + s += length + repOff + + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + // Index skipped... + for index0 < s-1 { + cv0 := load6432(src, index0) + cv1 := cv0 >> 8 + h0 := hashLen(cv0, betterLongTableBits, betterLongLen) + off := index0 + e.cur + e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} + e.markLongShardDirty(h0) + h1 := hashLen(cv1, betterShortTableBits, betterShortLen) + e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)} + e.markShortShardDirty(h1) + index0 += 2 + } + cv = load6432(src, s) + continue + } + const repOff2 = 1 + + // We deviate from the reference encoder and also check offset 2. + // Still slower and not much better, so disabled. + // repIndex = s - offset2 + repOff2 + if false && repIndex >= 0 && load6432(src, repIndex) == load6432(src, s+repOff) { + // Consider history as well. + var seq seq + length := 8 + e.matchlen(s+8+repOff2, repIndex+8, src) + + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + repOff2 + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + tMin := max(s-e.maxMatchOff, 0) + for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 2 + seq.offset = 2 + if debugSequences { + println("repeat sequence 2", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + s += length + repOff2 + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + + // Index skipped... + for index0 < s-1 { + cv0 := load6432(src, index0) + cv1 := cv0 >> 8 + h0 := hashLen(cv0, betterLongTableBits, betterLongLen) + off := index0 + e.cur + e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} + e.markLongShardDirty(h0) + h1 := hashLen(cv1, betterShortTableBits, betterShortLen) + e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)} + e.markShortShardDirty(h1) + index0 += 2 + } + cv = load6432(src, s) + // Swap offsets + offset1, offset2 = offset2, offset1 + continue + } + } + // Find the offsets of our two matches. + coffsetL := candidateL.offset - e.cur + coffsetLP := candidateL.prev - e.cur + + // Check if we have a long match. + if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) { + // Found a long match, at least 8 bytes. + matched = e.matchlen(s+8, coffsetL+8, src) + 8 + t = coffsetL + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugMatches { + println("long match") + } + + if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) { + // Found a long match, at least 8 bytes. + prevMatch := e.matchlen(s+8, coffsetLP+8, src) + 8 + if prevMatch > matched { + matched = prevMatch + t = coffsetLP + } + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugMatches { + println("long match") + } + } + break + } + + // Check if we have a long match on prev. + if s-coffsetLP < e.maxMatchOff && cv == load6432(src, coffsetLP) { + // Found a long match, at least 8 bytes. + matched = e.matchlen(s+8, coffsetLP+8, src) + 8 + t = coffsetLP + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugMatches { + println("long match") + } + break + } + + coffsetS := candidateS.offset - e.cur + + // Check if we have a short match. + if s-coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val { + // found a regular match + matched = e.matchlen(s+4, coffsetS+4, src) + 4 + + // See if we can find a long match at s+1 + const checkAt = 1 + cv := load6432(src, s+checkAt) + nextHashL = hashLen(cv, betterLongTableBits, betterLongLen) + candidateL = e.longTable[nextHashL] + coffsetL = candidateL.offset - e.cur + + // We can store it, since we have at least a 4 byte match. + e.longTable[nextHashL] = prevEntry{offset: s + checkAt + e.cur, prev: candidateL.offset} + e.markLongShardDirty(nextHashL) + if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) { + // Found a long match, at least 8 bytes. + matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8 + if matchedNext > matched { + t = coffsetL + s += checkAt + matched = matchedNext + if debugMatches { + println("long match (after short)") + } + break + } + } + + // Check prev long... + coffsetL = candidateL.prev - e.cur + if s-coffsetL < e.maxMatchOff && cv == load6432(src, coffsetL) { + // Found a long match, at least 8 bytes. + matchedNext := e.matchlen(s+8+checkAt, coffsetL+8, src) + 8 + if matchedNext > matched { + t = coffsetL + s += checkAt + matched = matchedNext + if debugMatches { + println("prev long match (after short)") + } + break + } + } + t = coffsetS + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugAsserts && t < 0 { + panic("t<0") + } + if debugMatches { + println("short match") + } + break + } + + // No match found, move forward in input. + s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1)) + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + } + // Try to find a better match by searching for a long match at the end of the current best match + if s+matched < sLimit { + nextHashL := hashLen(load6432(src, s+matched), betterLongTableBits, betterLongLen) + cv := load3232(src, s) + candidateL := e.longTable[nextHashL] + coffsetL := candidateL.offset - e.cur - matched + if coffsetL >= 0 && coffsetL < s && s-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) { + // Found a long match, at least 4 bytes. + matchedNext := e.matchlen(s+4, coffsetL+4, src) + 4 + if matchedNext > matched { + t = coffsetL + matched = matchedNext + if debugMatches { + println("long match at end-of-match") + } + } + } + + // Check prev long... + if true { + coffsetL = candidateL.prev - e.cur - matched + if coffsetL >= 0 && coffsetL < s && s-coffsetL < e.maxMatchOff && cv == load3232(src, coffsetL) { + // Found a long match, at least 4 bytes. + matchedNext := e.matchlen(s+4, coffsetL+4, src) + 4 + if matchedNext > matched { + t = coffsetL + matched = matchedNext + if debugMatches { + println("prev long match at end-of-match") + } + } + } + } + } + // A match has been found. Update recent offsets. + offset2 = offset1 + offset1 = s - t + + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + + if debugAsserts && canRepeat && int(offset1) > len(src) { + panic("invalid offset") + } + + // Extend the n-byte match as long as possible. + l := matched + + // Extend backwards + tMin := max(s-e.maxMatchOff, 0) + for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength { + s-- + t-- + l++ + } + + // Write our sequence + var seq seq + seq.litLen = uint32(s - nextEmit) + seq.matchLen = uint32(l - zstdMinMatch) + if seq.litLen > 0 { + blk.literals = append(blk.literals, src[nextEmit:s]...) + } + seq.offset = uint32(s-t) + 3 + s += l + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + nextEmit = s + if s >= sLimit { + break encodeLoop + } + + // Index match start+1 (long) -> s - 1 + off := index0 + e.cur + for index0 < s-1 { + cv0 := load6432(src, index0) + cv1 := cv0 >> 8 + h0 := hashLen(cv0, betterLongTableBits, betterLongLen) + e.longTable[h0] = prevEntry{offset: off, prev: e.longTable[h0].offset} + e.markLongShardDirty(h0) + h1 := hashLen(cv1, betterShortTableBits, betterShortLen) + e.table[h1] = tableEntry{offset: off + 1, val: uint32(cv1)} + e.markShortShardDirty(h1) + index0 += 2 + off += 2 + } + + cv = load6432(src, s) + if !canRepeat { + continue + } + + // Check offset 2 + for { + o2 := s - offset2 + if load3232(src, o2) != uint32(cv) { + // Do regular search + break + } + + // Store this, since we have it. + nextHashL := hashLen(cv, betterLongTableBits, betterLongLen) + nextHashS := hashLen(cv, betterShortTableBits, betterShortLen) + + // We have at least 4 byte match. + // No need to check backwards. We come straight from a match + l := 4 + e.matchlen(s+4, o2+4, src) + + e.longTable[nextHashL] = prevEntry{offset: s + e.cur, prev: e.longTable[nextHashL].offset} + e.markLongShardDirty(nextHashL) + e.table[nextHashS] = tableEntry{offset: s + e.cur, val: uint32(cv)} + e.markShortShardDirty(nextHashS) + seq.matchLen = uint32(l) - zstdMinMatch + seq.litLen = 0 + + // Since litlen is always 0, this is offset 1. + seq.offset = 1 + s += l + nextEmit = s + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Swap offset 1 and 2. + offset1, offset2 = offset2, offset1 + if s >= sLimit { + // Finished + break encodeLoop + } + cv = load6432(src, s) + } + } + + if int(nextEmit) < len(src) { + blk.literals = append(blk.literals, src[nextEmit:]...) + blk.extraLits = len(src) - int(nextEmit) + } + blk.recentOffsets[0] = uint32(offset1) + blk.recentOffsets[1] = uint32(offset2) + if debugEncoder { + println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits) + } +} + +// ResetDict will reset and set a dictionary if not nil +func (e *betterFastEncoder) Reset(d *dict, singleBlock bool) { + e.resetBase(d, singleBlock) + if d != nil { + panic("betterFastEncoder: Reset with dict") + } +} + +func (e *betterFastEncoder) ResetPrefix(prefix []byte) { + e.resetBasePrefix(prefix) + if len(prefix) < 8 { + return + } + end := e.cur + int32(len(prefix)) - 8 + for i := e.cur; i < end; i += 2 { + cv := load6432(prefix, i-e.cur) + h := hashLen(cv, betterLongTableBits, betterLongLen) + e.longTable[h] = prevEntry{offset: i, prev: e.longTable[h].offset} + e.table[hashLen(cv>>8, betterShortTableBits, betterShortLen)] = tableEntry{val: uint32(cv >> 8), offset: i + 1} + } +} + +// ResetDict will reset and set a dictionary if not nil +func (e *betterFastEncoderDict) Reset(d *dict, singleBlock bool) { + e.resetBase(d, singleBlock) + if d == nil { + return + } + dictChanged := d != e.lastDict + // Init or copy dict table + if len(e.dictTable) != len(e.table) || dictChanged { + if len(e.dictTable) != len(e.table) { + e.dictTable = make([]tableEntry, len(e.table)) + } else { + clear(e.dictTable) + } + end := int32(len(d.content)) - 8 + e.maxMatchOff + for i := e.maxMatchOff; i < end; i += 4 { + const hashLog = betterShortTableBits + + cv := load6432(d.content, i-e.maxMatchOff) + nextHash := hashLen(cv, hashLog, betterShortLen) // 0 -> 4 + nextHash1 := hashLen(cv>>8, hashLog, betterShortLen) // 1 -> 5 + nextHash2 := hashLen(cv>>16, hashLog, betterShortLen) // 2 -> 6 + nextHash3 := hashLen(cv>>24, hashLog, betterShortLen) // 3 -> 7 + e.dictTable[nextHash] = tableEntry{ + val: uint32(cv), + offset: i, + } + e.dictTable[nextHash1] = tableEntry{ + val: uint32(cv >> 8), + offset: i + 1, + } + e.dictTable[nextHash2] = tableEntry{ + val: uint32(cv >> 16), + offset: i + 2, + } + e.dictTable[nextHash3] = tableEntry{ + val: uint32(cv >> 24), + offset: i + 3, + } + } + e.allDirty = true + } + + // Init or copy dict long table + if len(e.dictLongTable) != len(e.longTable) || dictChanged { + if len(e.dictLongTable) != len(e.longTable) { + e.dictLongTable = make([]prevEntry, len(e.longTable)) + } else { + clear(e.dictLongTable) + } + if len(d.content) >= 8 { + cv := load6432(d.content, 0) + h := hashLen(cv, betterLongTableBits, betterLongLen) + e.dictLongTable[h] = prevEntry{ + offset: e.maxMatchOff, + prev: e.dictLongTable[h].offset, + } + + end := int32(len(d.content)) - 8 + e.maxMatchOff + off := 8 // First to read + for i := e.maxMatchOff + 1; i < end; i++ { + cv = cv>>8 | (uint64(d.content[off]) << 56) + h := hashLen(cv, betterLongTableBits, betterLongLen) + e.dictLongTable[h] = prevEntry{ + offset: i, + prev: e.dictLongTable[h].offset, + } + off++ + } + } + e.allDirty = true + } + e.lastDict = d + + // Reset table to initial state + { + dirtyShardCnt := 0 + if !e.allDirty { + for i := range e.shortTableShardDirty { + if e.shortTableShardDirty[i] { + dirtyShardCnt++ + } + } + } + const shardCnt = betterShortTableShardCnt + const shardSize = betterShortTableShardSize + if e.allDirty || dirtyShardCnt > shardCnt*4/6 { + copy(e.table[:], e.dictTable) + for i := range e.shortTableShardDirty { + e.shortTableShardDirty[i] = false + } + } else { + for i := range e.shortTableShardDirty { + if !e.shortTableShardDirty[i] { + continue + } + + copy(e.table[i*shardSize:(i+1)*shardSize], e.dictTable[i*shardSize:(i+1)*shardSize]) + e.shortTableShardDirty[i] = false + } + } + } + { + dirtyShardCnt := 0 + if !e.allDirty { + for i := range e.shortTableShardDirty { + if e.shortTableShardDirty[i] { + dirtyShardCnt++ + } + } + } + const shardCnt = betterLongTableShardCnt + const shardSize = betterLongTableShardSize + if e.allDirty || dirtyShardCnt > shardCnt*4/6 { + copy(e.longTable[:], e.dictLongTable) + for i := range e.longTableShardDirty { + e.longTableShardDirty[i] = false + } + } else { + for i := range e.longTableShardDirty { + if !e.longTableShardDirty[i] { + continue + } + + copy(e.longTable[i*shardSize:(i+1)*shardSize], e.dictLongTable[i*shardSize:(i+1)*shardSize]) + e.longTableShardDirty[i] = false + } + } + } + e.cur = e.maxMatchOff + e.allDirty = false +} + +func (e *betterFastEncoderDict) ResetPrefix([]byte) { + panic("ResetPrefix not supported for dict encoders") +} + +func (e *betterFastEncoderDict) markLongShardDirty(entryNum uint32) { + e.longTableShardDirty[entryNum/betterLongTableShardSize] = true +} + +func (e *betterFastEncoderDict) markShortShardDirty(entryNum uint32) { + e.shortTableShardDirty[entryNum/betterShortTableShardSize] = true +} diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go new file mode 100644 index 0000000..712ba7a --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go @@ -0,0 +1,1123 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import "fmt" + +const ( + dFastLongTableBits = 17 // Bits used in the long match table + dFastLongTableSize = 1 << dFastLongTableBits // Size of the table + dFastLongTableMask = dFastLongTableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks. + dFastLongLen = 8 // Bytes used for table hash + + dLongTableShardCnt = 1 << (dFastLongTableBits - dictShardBits) // Number of shards in the table + dLongTableShardSize = dFastLongTableSize / dLongTableShardCnt // Size of an individual shard + + dFastShortTableBits = tableBits // Bits used in the short match table + dFastShortTableSize = 1 << dFastShortTableBits // Size of the table + dFastShortTableMask = dFastShortTableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks. + dFastShortLen = 5 // Bytes used for table hash + +) + +type doubleFastEncoder struct { + fastEncoder + longTable [dFastLongTableSize]tableEntry +} + +type doubleFastEncoderDict struct { + fastEncoderDict + longTable [dFastLongTableSize]tableEntry + dictLongTable []tableEntry + longTableShardDirty [dLongTableShardCnt]bool +} + +// Encode mimmics functionality in zstd_dfast.c +func (e *doubleFastEncoder) Encode(blk *blockEnc, src []byte) { + const ( + // Input margin is the number of bytes we read (8) + // and the maximum we will read ahead (2) + inputMargin = 8 + 2 + minNonLiteralBlockSize = 16 + ) + + // Protect against e.cur wraparound. + for e.cur >= e.bufferReset-int32(len(e.hist)) { + if len(e.hist) == 0 { + e.table = [dFastShortTableSize]tableEntry{} + e.longTable = [dFastLongTableSize]tableEntry{} + e.cur = e.maxMatchOff + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff + for i := range e.table[:] { + v := e.table[i].offset + if v < minOff { + v = 0 + } else { + v = v - e.cur + e.maxMatchOff + } + e.table[i].offset = v + } + for i := range e.longTable[:] { + v := e.longTable[i].offset + if v < minOff { + v = 0 + } else { + v = v - e.cur + e.maxMatchOff + } + e.longTable[i].offset = v + } + e.cur = e.maxMatchOff + break + } + + s := e.addBlock(src) + blk.size = len(src) + if len(src) < minNonLiteralBlockSize { + blk.extraLits = len(src) + blk.literals = blk.literals[:len(src)] + copy(blk.literals, src) + return + } + + // Override src + src = e.hist + sLimit := int32(len(src)) - inputMargin + // stepSize is the number of bytes to skip on every main loop iteration. + // It should be >= 1. + const stepSize = 1 + + const kSearchStrength = 8 + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := s + cv := load6432(src, s) + + // Relative offsets + offset1 := int32(blk.recentOffsets[0]) + offset2 := int32(blk.recentOffsets[1]) + + addLiterals := func(s *seq, until int32) { + if until == nextEmit { + return + } + blk.literals = append(blk.literals, src[nextEmit:until]...) + s.litLen = uint32(until - nextEmit) + } + if debugEncoder { + println("recent offsets:", blk.recentOffsets) + } + +encodeLoop: + for { + var t int32 + // We allow the encoder to optionally turn off repeat offsets across blocks + canRepeat := len(blk.sequences) > 2 + + for { + if debugAsserts && canRepeat && offset1 == 0 { + panic("offset0 was 0") + } + + nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) + candidateL := e.longTable[nextHashL] + candidateS := e.table[nextHashS] + + const repOff = 1 + repIndex := s - offset1 + repOff + entry := tableEntry{offset: s + e.cur, val: uint32(cv)} + e.longTable[nextHashL] = entry + e.table[nextHashS] = entry + + if canRepeat { + if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { + // Consider history as well. + var seq seq + length := 4 + e.matchlen(s+4+repOff, repIndex+4, src) + + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + repOff + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + tMin := max(s-e.maxMatchOff, 0) + for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 0 + seq.offset = 1 + if debugSequences { + println("repeat sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + s += length + repOff + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + cv = load6432(src, s) + continue + } + } + // Find the offsets of our two matches. + coffsetL := s - (candidateL.offset - e.cur) + coffsetS := s - (candidateS.offset - e.cur) + + // Check if we have a long match. + if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val { + // Found a long match, likely at least 8 bytes. + // Reference encoder checks all 8 bytes, we only check 4, + // but the likelihood of both the first 4 bytes and the hash matching should be enough. + t = candidateL.offset - e.cur + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugMatches { + println("long match") + } + break + } + + // Check if we have a short match. + if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val { + // found a regular match + // See if we can find a long match at s+1 + const checkAt = 1 + cv := load6432(src, s+checkAt) + nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen) + candidateL = e.longTable[nextHashL] + coffsetL = s - (candidateL.offset - e.cur) + checkAt + + // We can store it, since we have at least a 4 byte match. + e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)} + if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val { + // Found a long match, likely at least 8 bytes. + // Reference encoder checks all 8 bytes, we only check 4, + // but the likelihood of both the first 4 bytes and the hash matching should be enough. + t = candidateL.offset - e.cur + s += checkAt + if debugMatches { + println("long match (after short)") + } + break + } + + t = candidateS.offset - e.cur + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugAsserts && t < 0 { + panic("t<0") + } + if debugMatches { + println("short match") + } + break + } + + // No match found, move forward in input. + s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1)) + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + } + + // A 4-byte match has been found. Update recent offsets. + // We'll later see if more than 4 bytes. + offset2 = offset1 + offset1 = s - t + + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + + if debugAsserts && canRepeat && int(offset1) > len(src) { + panic("invalid offset") + } + + // Extend the 4-byte match as long as possible. + l := e.matchlen(s+4, t+4, src) + 4 + + // Extend backwards + tMin := max(s-e.maxMatchOff, 0) + for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength { + s-- + t-- + l++ + } + + // Write our sequence + var seq seq + seq.litLen = uint32(s - nextEmit) + seq.matchLen = uint32(l - zstdMinMatch) + if seq.litLen > 0 { + blk.literals = append(blk.literals, src[nextEmit:s]...) + } + seq.offset = uint32(s-t) + 3 + s += l + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + nextEmit = s + if s >= sLimit { + break encodeLoop + } + + // Index match start+1 (long) and start+2 (short) + index0 := s - l + 1 + // Index match end-2 (long) and end-1 (short) + index1 := s - 2 + + cv0 := load6432(src, index0) + cv1 := load6432(src, index1) + te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)} + te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)} + e.longTable[hashLen(cv0, dFastLongTableBits, dFastLongLen)] = te0 + e.longTable[hashLen(cv1, dFastLongTableBits, dFastLongLen)] = te1 + cv0 >>= 8 + cv1 >>= 8 + te0.offset++ + te1.offset++ + te0.val = uint32(cv0) + te1.val = uint32(cv1) + e.table[hashLen(cv0, dFastShortTableBits, dFastShortLen)] = te0 + e.table[hashLen(cv1, dFastShortTableBits, dFastShortLen)] = te1 + + cv = load6432(src, s) + + if !canRepeat { + continue + } + + // Check offset 2 + for { + o2 := s - offset2 + if load3232(src, o2) != uint32(cv) { + // Do regular search + break + } + + // Store this, since we have it. + nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) + nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + + // We have at least 4 byte match. + // No need to check backwards. We come straight from a match + l := 4 + e.matchlen(s+4, o2+4, src) + + entry := tableEntry{offset: s + e.cur, val: uint32(cv)} + e.longTable[nextHashL] = entry + e.table[nextHashS] = entry + seq.matchLen = uint32(l) - zstdMinMatch + seq.litLen = 0 + + // Since litlen is always 0, this is offset 1. + seq.offset = 1 + s += l + nextEmit = s + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Swap offset 1 and 2. + offset1, offset2 = offset2, offset1 + if s >= sLimit { + // Finished + break encodeLoop + } + cv = load6432(src, s) + } + } + + if int(nextEmit) < len(src) { + blk.literals = append(blk.literals, src[nextEmit:]...) + blk.extraLits = len(src) - int(nextEmit) + } + blk.recentOffsets[0] = uint32(offset1) + blk.recentOffsets[1] = uint32(offset2) + if debugEncoder { + println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits) + } +} + +// EncodeNoHist will encode a block with no history and no following blocks. +// Most notable difference is that src will not be copied for history and +// we do not need to check for max match length. +func (e *doubleFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) { + const ( + // Input margin is the number of bytes we read (8) + // and the maximum we will read ahead (2) + inputMargin = 8 + 2 + minNonLiteralBlockSize = 16 + ) + + // Protect against e.cur wraparound. + if e.cur >= e.bufferReset { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + for i := range e.longTable[:] { + e.longTable[i] = tableEntry{} + } + e.cur = e.maxMatchOff + } + + s := int32(0) + blk.size = len(src) + if len(src) < minNonLiteralBlockSize { + blk.extraLits = len(src) + blk.literals = blk.literals[:len(src)] + copy(blk.literals, src) + return + } + + // Override src + sLimit := int32(len(src)) - inputMargin + // stepSize is the number of bytes to skip on every main loop iteration. + // It should be >= 1. + const stepSize = 1 + + const kSearchStrength = 8 + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := s + cv := load6432(src, s) + + // Relative offsets + offset1 := int32(blk.recentOffsets[0]) + offset2 := int32(blk.recentOffsets[1]) + + addLiterals := func(s *seq, until int32) { + if until == nextEmit { + return + } + blk.literals = append(blk.literals, src[nextEmit:until]...) + s.litLen = uint32(until - nextEmit) + } + if debugEncoder { + println("recent offsets:", blk.recentOffsets) + } + +encodeLoop: + for { + var t int32 + for { + + nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) + candidateL := e.longTable[nextHashL] + candidateS := e.table[nextHashS] + + const repOff = 1 + repIndex := s - offset1 + repOff + entry := tableEntry{offset: s + e.cur, val: uint32(cv)} + e.longTable[nextHashL] = entry + e.table[nextHashS] = entry + + if len(blk.sequences) > 2 { + if load3232(src, repIndex) == uint32(cv>>(repOff*8)) { + // Consider history as well. + var seq seq + //length := 4 + e.matchlen(s+4+repOff, repIndex+4, src) + length := 4 + int32(matchLen(src[s+4+repOff:], src[repIndex+4:])) + + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + repOff + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + tMin := max(s-e.maxMatchOff, 0) + for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 0 + seq.offset = 1 + if debugSequences { + println("repeat sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + s += length + repOff + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + cv = load6432(src, s) + continue + } + } + // Find the offsets of our two matches. + coffsetL := s - (candidateL.offset - e.cur) + coffsetS := s - (candidateS.offset - e.cur) + + // Check if we have a long match. + if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val { + // Found a long match, likely at least 8 bytes. + // Reference encoder checks all 8 bytes, we only check 4, + // but the likelihood of both the first 4 bytes and the hash matching should be enough. + t = candidateL.offset - e.cur + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d). cur: %d", s, t, e.cur)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugMatches { + println("long match") + } + break + } + + // Check if we have a short match. + if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val { + // found a regular match + // See if we can find a long match at s+1 + const checkAt = 1 + cv := load6432(src, s+checkAt) + nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen) + candidateL = e.longTable[nextHashL] + coffsetL = s - (candidateL.offset - e.cur) + checkAt + + // We can store it, since we have at least a 4 byte match. + e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)} + if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val { + // Found a long match, likely at least 8 bytes. + // Reference encoder checks all 8 bytes, we only check 4, + // but the likelihood of both the first 4 bytes and the hash matching should be enough. + t = candidateL.offset - e.cur + s += checkAt + if debugMatches { + println("long match (after short)") + } + break + } + + t = candidateS.offset - e.cur + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugAsserts && t < 0 { + panic("t<0") + } + if debugMatches { + println("short match") + } + break + } + + // No match found, move forward in input. + s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1)) + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + } + + // A 4-byte match has been found. Update recent offsets. + // We'll later see if more than 4 bytes. + offset2 = offset1 + offset1 = s - t + + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + + // Extend the 4-byte match as long as possible. + //l := e.matchlen(s+4, t+4, src) + 4 + l := int32(matchLen(src[s+4:], src[t+4:])) + 4 + + // Extend backwards + tMin := max(s-e.maxMatchOff, 0) + for t > tMin && s > nextEmit && src[t-1] == src[s-1] { + s-- + t-- + l++ + } + + // Write our sequence + var seq seq + seq.litLen = uint32(s - nextEmit) + seq.matchLen = uint32(l - zstdMinMatch) + if seq.litLen > 0 { + blk.literals = append(blk.literals, src[nextEmit:s]...) + } + seq.offset = uint32(s-t) + 3 + s += l + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + nextEmit = s + if s >= sLimit { + break encodeLoop + } + + // Index match start+1 (long) and start+2 (short) + index0 := s - l + 1 + // Index match end-2 (long) and end-1 (short) + index1 := s - 2 + + cv0 := load6432(src, index0) + cv1 := load6432(src, index1) + te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)} + te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)} + e.longTable[hashLen(cv0, dFastLongTableBits, dFastLongLen)] = te0 + e.longTable[hashLen(cv1, dFastLongTableBits, dFastLongLen)] = te1 + cv0 >>= 8 + cv1 >>= 8 + te0.offset++ + te1.offset++ + te0.val = uint32(cv0) + te1.val = uint32(cv1) + e.table[hashLen(cv0, dFastShortTableBits, dFastShortLen)] = te0 + e.table[hashLen(cv1, dFastShortTableBits, dFastShortLen)] = te1 + + cv = load6432(src, s) + + if len(blk.sequences) <= 2 { + continue + } + + // Check offset 2 + for { + o2 := s - offset2 + if load3232(src, o2) != uint32(cv) { + // Do regular search + break + } + + // Store this, since we have it. + nextHashS := hashLen(cv1>>8, dFastShortTableBits, dFastShortLen) + nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + + // We have at least 4 byte match. + // No need to check backwards. We come straight from a match + //l := 4 + e.matchlen(s+4, o2+4, src) + l := 4 + int32(matchLen(src[s+4:], src[o2+4:])) + + entry := tableEntry{offset: s + e.cur, val: uint32(cv)} + e.longTable[nextHashL] = entry + e.table[nextHashS] = entry + seq.matchLen = uint32(l) - zstdMinMatch + seq.litLen = 0 + + // Since litlen is always 0, this is offset 1. + seq.offset = 1 + s += l + nextEmit = s + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Swap offset 1 and 2. + offset1, offset2 = offset2, offset1 + if s >= sLimit { + // Finished + break encodeLoop + } + cv = load6432(src, s) + } + } + + if int(nextEmit) < len(src) { + blk.literals = append(blk.literals, src[nextEmit:]...) + blk.extraLits = len(src) - int(nextEmit) + } + if debugEncoder { + println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits) + } + + // We do not store history, so we must offset e.cur to avoid false matches for next user. + if e.cur < e.bufferReset { + e.cur += int32(len(src)) + } +} + +// Encode will encode the content, with a dictionary if initialized for it. +func (e *doubleFastEncoderDict) Encode(blk *blockEnc, src []byte) { + const ( + // Input margin is the number of bytes we read (8) + // and the maximum we will read ahead (2) + inputMargin = 8 + 2 + minNonLiteralBlockSize = 16 + ) + + // Protect against e.cur wraparound. + for e.cur >= e.bufferReset-int32(len(e.hist)) { + if len(e.hist) == 0 { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + for i := range e.longTable[:] { + e.longTable[i] = tableEntry{} + } + e.markAllShardsDirty() + e.cur = e.maxMatchOff + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff + for i := range e.table[:] { + v := e.table[i].offset + if v < minOff { + v = 0 + } else { + v = v - e.cur + e.maxMatchOff + } + e.table[i].offset = v + } + for i := range e.longTable[:] { + v := e.longTable[i].offset + if v < minOff { + v = 0 + } else { + v = v - e.cur + e.maxMatchOff + } + e.longTable[i].offset = v + } + e.markAllShardsDirty() + e.cur = e.maxMatchOff + break + } + + s := e.addBlock(src) + blk.size = len(src) + if len(src) < minNonLiteralBlockSize { + blk.extraLits = len(src) + blk.literals = blk.literals[:len(src)] + copy(blk.literals, src) + return + } + + // Override src + src = e.hist + sLimit := int32(len(src)) - inputMargin + // stepSize is the number of bytes to skip on every main loop iteration. + // It should be >= 1. + const stepSize = 1 + + const kSearchStrength = 8 + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := s + cv := load6432(src, s) + + // Relative offsets + offset1 := int32(blk.recentOffsets[0]) + offset2 := int32(blk.recentOffsets[1]) + + addLiterals := func(s *seq, until int32) { + if until == nextEmit { + return + } + blk.literals = append(blk.literals, src[nextEmit:until]...) + s.litLen = uint32(until - nextEmit) + } + if debugEncoder { + println("recent offsets:", blk.recentOffsets) + } + +encodeLoop: + for { + var t int32 + // We allow the encoder to optionally turn off repeat offsets across blocks + canRepeat := len(blk.sequences) > 2 + + for { + if debugAsserts && canRepeat && offset1 == 0 { + panic("offset0 was 0") + } + + nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) + candidateL := e.longTable[nextHashL] + candidateS := e.table[nextHashS] + + const repOff = 1 + repIndex := s - offset1 + repOff + entry := tableEntry{offset: s + e.cur, val: uint32(cv)} + e.longTable[nextHashL] = entry + e.markLongShardDirty(nextHashL) + e.table[nextHashS] = entry + e.markShardDirty(nextHashS) + + if canRepeat { + if repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>(repOff*8)) { + // Consider history as well. + var seq seq + length := 4 + e.matchlen(s+4+repOff, repIndex+4, src) + + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + repOff + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + tMin := max(s-e.maxMatchOff, 0) + for repIndex > tMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch-1 { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 0 + seq.offset = 1 + if debugSequences { + println("repeat sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + s += length + repOff + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + cv = load6432(src, s) + continue + } + } + // Find the offsets of our two matches. + coffsetL := s - (candidateL.offset - e.cur) + coffsetS := s - (candidateS.offset - e.cur) + + // Check if we have a long match. + if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val { + // Found a long match, likely at least 8 bytes. + // Reference encoder checks all 8 bytes, we only check 4, + // but the likelihood of both the first 4 bytes and the hash matching should be enough. + t = candidateL.offset - e.cur + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugMatches { + println("long match") + } + break + } + + // Check if we have a short match. + if coffsetS < e.maxMatchOff && uint32(cv) == candidateS.val { + // found a regular match + // See if we can find a long match at s+1 + const checkAt = 1 + cv := load6432(src, s+checkAt) + nextHashL = hashLen(cv, dFastLongTableBits, dFastLongLen) + candidateL = e.longTable[nextHashL] + coffsetL = s - (candidateL.offset - e.cur) + checkAt + + // We can store it, since we have at least a 4 byte match. + e.longTable[nextHashL] = tableEntry{offset: s + checkAt + e.cur, val: uint32(cv)} + e.markLongShardDirty(nextHashL) + if coffsetL < e.maxMatchOff && uint32(cv) == candidateL.val { + // Found a long match, likely at least 8 bytes. + // Reference encoder checks all 8 bytes, we only check 4, + // but the likelihood of both the first 4 bytes and the hash matching should be enough. + t = candidateL.offset - e.cur + s += checkAt + if debugMatches { + println("long match (after short)") + } + break + } + + t = candidateS.offset - e.cur + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugAsserts && t < 0 { + panic("t<0") + } + if debugMatches { + println("short match") + } + break + } + + // No match found, move forward in input. + s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1)) + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + } + + // A 4-byte match has been found. Update recent offsets. + // We'll later see if more than 4 bytes. + offset2 = offset1 + offset1 = s - t + + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + + if debugAsserts && canRepeat && int(offset1) > len(src) { + panic("invalid offset") + } + + // Extend the 4-byte match as long as possible. + l := e.matchlen(s+4, t+4, src) + 4 + + // Extend backwards + tMin := max(s-e.maxMatchOff, 0) + for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength { + s-- + t-- + l++ + } + + // Write our sequence + var seq seq + seq.litLen = uint32(s - nextEmit) + seq.matchLen = uint32(l - zstdMinMatch) + if seq.litLen > 0 { + blk.literals = append(blk.literals, src[nextEmit:s]...) + } + seq.offset = uint32(s-t) + 3 + s += l + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + nextEmit = s + if s >= sLimit { + break encodeLoop + } + + // Index match start+1 (long) and start+2 (short) + index0 := s - l + 1 + // Index match end-2 (long) and end-1 (short) + index1 := s - 2 + + cv0 := load6432(src, index0) + cv1 := load6432(src, index1) + te0 := tableEntry{offset: index0 + e.cur, val: uint32(cv0)} + te1 := tableEntry{offset: index1 + e.cur, val: uint32(cv1)} + longHash1 := hashLen(cv0, dFastLongTableBits, dFastLongLen) + longHash2 := hashLen(cv1, dFastLongTableBits, dFastLongLen) + e.longTable[longHash1] = te0 + e.longTable[longHash2] = te1 + e.markLongShardDirty(longHash1) + e.markLongShardDirty(longHash2) + cv0 >>= 8 + cv1 >>= 8 + te0.offset++ + te1.offset++ + te0.val = uint32(cv0) + te1.val = uint32(cv1) + hashVal1 := hashLen(cv0, dFastShortTableBits, dFastShortLen) + hashVal2 := hashLen(cv1, dFastShortTableBits, dFastShortLen) + e.table[hashVal1] = te0 + e.markShardDirty(hashVal1) + e.table[hashVal2] = te1 + e.markShardDirty(hashVal2) + + cv = load6432(src, s) + + if !canRepeat { + continue + } + + // Check offset 2 + for { + o2 := s - offset2 + if load3232(src, o2) != uint32(cv) { + // Do regular search + break + } + + // Store this, since we have it. + nextHashL := hashLen(cv, dFastLongTableBits, dFastLongLen) + nextHashS := hashLen(cv, dFastShortTableBits, dFastShortLen) + + // We have at least 4 byte match. + // No need to check backwards. We come straight from a match + l := 4 + e.matchlen(s+4, o2+4, src) + + entry := tableEntry{offset: s + e.cur, val: uint32(cv)} + e.longTable[nextHashL] = entry + e.markLongShardDirty(nextHashL) + e.table[nextHashS] = entry + e.markShardDirty(nextHashS) + seq.matchLen = uint32(l) - zstdMinMatch + seq.litLen = 0 + + // Since litlen is always 0, this is offset 1. + seq.offset = 1 + s += l + nextEmit = s + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Swap offset 1 and 2. + offset1, offset2 = offset2, offset1 + if s >= sLimit { + // Finished + break encodeLoop + } + cv = load6432(src, s) + } + } + + if int(nextEmit) < len(src) { + blk.literals = append(blk.literals, src[nextEmit:]...) + blk.extraLits = len(src) - int(nextEmit) + } + blk.recentOffsets[0] = uint32(offset1) + blk.recentOffsets[1] = uint32(offset2) + if debugEncoder { + println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits) + } + // If we encoded more than 64K mark all dirty. + if len(src) > 64<<10 { + e.markAllShardsDirty() + } +} + +// ResetDict will reset and set a dictionary if not nil +func (e *doubleFastEncoder) Reset(d *dict, singleBlock bool) { + e.fastEncoder.Reset(d, singleBlock) + if d != nil { + panic("doubleFastEncoder: Reset with dict not supported") + } +} + +func (e *doubleFastEncoder) ResetPrefix(prefix []byte) { + e.fastEncoder.ResetPrefix(prefix) + if len(prefix) < 8 { + return + } + end := e.cur + int32(len(prefix)) - 8 + for i := e.cur + 1; i < end; i += 2 { + cv := load6432(prefix, i-e.cur) + e.longTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{val: uint32(cv), offset: i} + } +} + +// ResetDict will reset and set a dictionary if not nil +func (e *doubleFastEncoderDict) Reset(d *dict, singleBlock bool) { + allDirty := e.allDirty + dictChanged := d != e.lastDict + e.fastEncoderDict.Reset(d, singleBlock) + if d == nil { + return + } + + // Init or copy dict table + if len(e.dictLongTable) != len(e.longTable) || dictChanged { + if len(e.dictLongTable) != len(e.longTable) { + e.dictLongTable = make([]tableEntry, len(e.longTable)) + } else { + clear(e.dictLongTable) + } + if len(d.content) >= 8 { + cv := load6432(d.content, 0) + e.dictLongTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{ + val: uint32(cv), + offset: e.maxMatchOff, + } + end := int32(len(d.content)) - 8 + e.maxMatchOff + for i := e.maxMatchOff + 1; i < end; i++ { + cv = cv>>8 | (uint64(d.content[i-e.maxMatchOff+7]) << 56) + e.dictLongTable[hashLen(cv, dFastLongTableBits, dFastLongLen)] = tableEntry{ + val: uint32(cv), + offset: i, + } + } + } + allDirty = true + } + // Reset table to initial state + e.cur = e.maxMatchOff + + dirtyShardCnt := 0 + if !allDirty { + for i := range e.longTableShardDirty { + if e.longTableShardDirty[i] { + dirtyShardCnt++ + } + } + } + + if allDirty || dirtyShardCnt > dLongTableShardCnt/2 { + //copy(e.longTable[:], e.dictLongTable) + e.longTable = *(*[dFastLongTableSize]tableEntry)(e.dictLongTable) + for i := range e.longTableShardDirty { + e.longTableShardDirty[i] = false + } + return + } + for i := range e.longTableShardDirty { + if !e.longTableShardDirty[i] { + continue + } + + // copy(e.longTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize], e.dictLongTable[i*dLongTableShardSize:(i+1)*dLongTableShardSize]) + *(*[dLongTableShardSize]tableEntry)(e.longTable[i*dLongTableShardSize:]) = *(*[dLongTableShardSize]tableEntry)(e.dictLongTable[i*dLongTableShardSize:]) + + e.longTableShardDirty[i] = false + } +} + +func (e *doubleFastEncoderDict) ResetPrefix([]byte) { + panic("ResetPrefix not supported for dict encoders") +} + +func (e *doubleFastEncoderDict) markLongShardDirty(entryNum uint32) { + e.longTableShardDirty[entryNum/dLongTableShardSize] = true +} diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go new file mode 100644 index 0000000..06045e2 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go @@ -0,0 +1,892 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "fmt" +) + +const ( + tableBits = 15 // Bits used in the table + tableSize = 1 << tableBits // Size of the table + tableShardCnt = 1 << (tableBits - dictShardBits) // Number of shards in the table + tableShardSize = tableSize / tableShardCnt // Size of an individual shard + tableFastHashLen = 6 + tableMask = tableSize - 1 // Mask for table indices. Redundant, but can eliminate bounds checks. + maxMatchLength = 131074 +) + +type tableEntry struct { + val uint32 + offset int32 +} + +type fastEncoder struct { + fastBase + table [tableSize]tableEntry +} + +type fastEncoderDict struct { + fastEncoder + dictTable []tableEntry + tableShardDirty [tableShardCnt]bool + allDirty bool +} + +// Encode mimmics functionality in zstd_fast.c +func (e *fastEncoder) Encode(blk *blockEnc, src []byte) { + const ( + inputMargin = 8 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + + // Protect against e.cur wraparound. + for e.cur >= e.bufferReset-int32(len(e.hist)) { + if len(e.hist) == 0 { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + e.cur = e.maxMatchOff + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff + for i := range e.table[:] { + v := e.table[i].offset + if v < minOff { + v = 0 + } else { + v = v - e.cur + e.maxMatchOff + } + e.table[i].offset = v + } + e.cur = e.maxMatchOff + break + } + + s := e.addBlock(src) + blk.size = len(src) + if len(src) < minNonLiteralBlockSize { + blk.extraLits = len(src) + blk.literals = blk.literals[:len(src)] + copy(blk.literals, src) + return + } + + // Override src + src = e.hist + sLimit := int32(len(src)) - inputMargin + // stepSize is the number of bytes to skip on every main loop iteration. + // It should be >= 2. + const stepSize = 2 + + // TEMPLATE + const hashLog = tableBits + // seems global, but would be nice to tweak. + const kSearchStrength = 6 + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := s + cv := load6432(src, s) + + // Relative offsets + offset1 := int32(blk.recentOffsets[0]) + offset2 := int32(blk.recentOffsets[1]) + + addLiterals := func(s *seq, until int32) { + if until == nextEmit { + return + } + blk.literals = append(blk.literals, src[nextEmit:until]...) + s.litLen = uint32(until - nextEmit) + } + if debugEncoder { + println("recent offsets:", blk.recentOffsets) + } + +encodeLoop: + for { + // t will contain the match offset when we find one. + // When existing the search loop, we have already checked 4 bytes. + var t int32 + + // We will not use repeat offsets across blocks. + // By not using them for the first 3 matches + canRepeat := len(blk.sequences) > 2 + + for { + if debugAsserts && canRepeat && offset1 == 0 { + panic("offset0 was 0") + } + + nextHash := hashLen(cv, hashLog, tableFastHashLen) + nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen) + candidate := e.table[nextHash] + candidate2 := e.table[nextHash2] + repIndex := s - offset1 + 2 + + e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)} + e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)} + + if canRepeat && repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>16) { + // Consider history as well. + var seq seq + length := 4 + e.matchlen(s+6, repIndex+4, src) + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + 2 + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + sMin := max(s-e.maxMatchOff, 0) + for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 0 + seq.offset = 1 + if debugSequences { + println("repeat sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + s += length + 2 + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + cv = load6432(src, s) + continue + } + coffset0 := s - (candidate.offset - e.cur) + coffset1 := s - (candidate2.offset - e.cur) + 1 + if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val { + // found a regular match + t = candidate.offset - e.cur + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + break + } + + if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val { + // found a regular match + t = candidate2.offset - e.cur + s++ + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugAsserts && t < 0 { + panic("t<0") + } + break + } + s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1)) + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + } + // A 4-byte match has been found. We'll later see if more than 4 bytes. + offset2 = offset1 + offset1 = s - t + + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + + if debugAsserts && canRepeat && int(offset1) > len(src) { + panic("invalid offset") + } + + // Extend the 4-byte match as long as possible. + l := e.matchlen(s+4, t+4, src) + 4 + + // Extend backwards + tMin := max(s-e.maxMatchOff, 0) + for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength { + s-- + t-- + l++ + } + + // Write our sequence. + var seq seq + seq.litLen = uint32(s - nextEmit) + seq.matchLen = uint32(l - zstdMinMatch) + if seq.litLen > 0 { + blk.literals = append(blk.literals, src[nextEmit:s]...) + } + // Don't use repeat offsets + seq.offset = uint32(s-t) + 3 + s += l + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + nextEmit = s + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + + // Check offset 2 + if o2 := s - offset2; canRepeat && load3232(src, o2) == uint32(cv) { + // We have at least 4 byte match. + // No need to check backwards. We come straight from a match + l := 4 + e.matchlen(s+4, o2+4, src) + + // Store this, since we have it. + nextHash := hashLen(cv, hashLog, tableFastHashLen) + e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)} + seq.matchLen = uint32(l) - zstdMinMatch + seq.litLen = 0 + // Since litlen is always 0, this is offset 1. + seq.offset = 1 + s += l + nextEmit = s + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Swap offset 1 and 2. + offset1, offset2 = offset2, offset1 + if s >= sLimit { + break encodeLoop + } + // Prepare next loop. + cv = load6432(src, s) + } + } + + if int(nextEmit) < len(src) { + blk.literals = append(blk.literals, src[nextEmit:]...) + blk.extraLits = len(src) - int(nextEmit) + } + blk.recentOffsets[0] = uint32(offset1) + blk.recentOffsets[1] = uint32(offset2) + if debugEncoder { + println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits) + } +} + +// EncodeNoHist will encode a block with no history and no following blocks. +// Most notable difference is that src will not be copied for history and +// we do not need to check for max match length. +func (e *fastEncoder) EncodeNoHist(blk *blockEnc, src []byte) { + const ( + inputMargin = 8 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + if debugEncoder { + if len(src) > maxCompressedBlockSize { + panic("src too big") + } + } + + // Protect against e.cur wraparound. + if e.cur >= e.bufferReset { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + e.cur = e.maxMatchOff + } + + s := int32(0) + blk.size = len(src) + if len(src) < minNonLiteralBlockSize { + blk.extraLits = len(src) + blk.literals = blk.literals[:len(src)] + copy(blk.literals, src) + return + } + + sLimit := int32(len(src)) - inputMargin + // stepSize is the number of bytes to skip on every main loop iteration. + // It should be >= 2. + const stepSize = 2 + + // TEMPLATE + const hashLog = tableBits + // seems global, but would be nice to tweak. + const kSearchStrength = 6 + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := s + cv := load6432(src, s) + + // Relative offsets + offset1 := int32(blk.recentOffsets[0]) + offset2 := int32(blk.recentOffsets[1]) + + addLiterals := func(s *seq, until int32) { + if until == nextEmit { + return + } + blk.literals = append(blk.literals, src[nextEmit:until]...) + s.litLen = uint32(until - nextEmit) + } + if debugEncoder { + println("recent offsets:", blk.recentOffsets) + } + +encodeLoop: + for { + // t will contain the match offset when we find one. + // When existing the search loop, we have already checked 4 bytes. + var t int32 + + // We will not use repeat offsets across blocks. + // By not using them for the first 3 matches + + for { + nextHash := hashLen(cv, hashLog, tableFastHashLen) + nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen) + candidate := e.table[nextHash] + candidate2 := e.table[nextHash2] + repIndex := s - offset1 + 2 + + e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)} + e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)} + + if len(blk.sequences) > 2 && load3232(src, repIndex) == uint32(cv>>16) { + // Consider history as well. + var seq seq + length := 4 + e.matchlen(s+6, repIndex+4, src) + + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + 2 + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + sMin := max(s-e.maxMatchOff, 0) + for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 0 + seq.offset = 1 + if debugSequences { + println("repeat sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + s += length + 2 + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + cv = load6432(src, s) + continue + } + coffset0 := s - (candidate.offset - e.cur) + coffset1 := s - (candidate2.offset - e.cur) + 1 + if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val { + // found a regular match + t = candidate.offset - e.cur + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugAsserts && t < 0 { + panic(fmt.Sprintf("t (%d) < 0, candidate.offset: %d, e.cur: %d, coffset0: %d, e.maxMatchOff: %d", t, candidate.offset, e.cur, coffset0, e.maxMatchOff)) + } + break + } + + if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val { + // found a regular match + t = candidate2.offset - e.cur + s++ + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugAsserts && t < 0 { + panic("t<0") + } + break + } + s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1)) + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + } + // A 4-byte match has been found. We'll later see if more than 4 bytes. + offset2 = offset1 + offset1 = s - t + + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + + if debugAsserts && t < 0 { + panic(fmt.Sprintf("t (%d) < 0 ", t)) + } + // Extend the 4-byte match as long as possible. + l := e.matchlen(s+4, t+4, src) + 4 + + // Extend backwards + tMin := max(s-e.maxMatchOff, 0) + for t > tMin && s > nextEmit && src[t-1] == src[s-1] { + s-- + t-- + l++ + } + + // Write our sequence. + var seq seq + seq.litLen = uint32(s - nextEmit) + seq.matchLen = uint32(l - zstdMinMatch) + if seq.litLen > 0 { + blk.literals = append(blk.literals, src[nextEmit:s]...) + } + // Don't use repeat offsets + seq.offset = uint32(s-t) + 3 + s += l + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + nextEmit = s + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + + // Check offset 2 + if o2 := s - offset2; len(blk.sequences) > 2 && load3232(src, o2) == uint32(cv) { + // We have at least 4 byte match. + // No need to check backwards. We come straight from a match + l := 4 + e.matchlen(s+4, o2+4, src) + + // Store this, since we have it. + nextHash := hashLen(cv, hashLog, tableFastHashLen) + e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)} + seq.matchLen = uint32(l) - zstdMinMatch + seq.litLen = 0 + // Since litlen is always 0, this is offset 1. + seq.offset = 1 + s += l + nextEmit = s + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Swap offset 1 and 2. + offset1, offset2 = offset2, offset1 + if s >= sLimit { + break encodeLoop + } + // Prepare next loop. + cv = load6432(src, s) + } + } + + if int(nextEmit) < len(src) { + blk.literals = append(blk.literals, src[nextEmit:]...) + blk.extraLits = len(src) - int(nextEmit) + } + if debugEncoder { + println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits) + } + // We do not store history, so we must offset e.cur to avoid false matches for next user. + if e.cur < e.bufferReset { + e.cur += int32(len(src)) + } +} + +// Encode will encode the content, with a dictionary if initialized for it. +func (e *fastEncoderDict) Encode(blk *blockEnc, src []byte) { + const ( + inputMargin = 8 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + if e.allDirty || len(src) > 32<<10 { + e.fastEncoder.Encode(blk, src) + e.allDirty = true + return + } + // Protect against e.cur wraparound. + for e.cur >= e.bufferReset-int32(len(e.hist)) { + if len(e.hist) == 0 { + e.table = [tableSize]tableEntry{} + e.cur = e.maxMatchOff + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - e.maxMatchOff + for i := range e.table[:] { + v := e.table[i].offset + if v < minOff { + v = 0 + } else { + v = v - e.cur + e.maxMatchOff + } + e.table[i].offset = v + } + e.cur = e.maxMatchOff + break + } + + s := e.addBlock(src) + blk.size = len(src) + if len(src) < minNonLiteralBlockSize { + blk.extraLits = len(src) + blk.literals = blk.literals[:len(src)] + copy(blk.literals, src) + return + } + + // Override src + src = e.hist + sLimit := int32(len(src)) - inputMargin + // stepSize is the number of bytes to skip on every main loop iteration. + // It should be >= 2. + const stepSize = 2 + + // TEMPLATE + const hashLog = tableBits + // seems global, but would be nice to tweak. + const kSearchStrength = 7 + + // nextEmit is where in src the next emitLiteral should start from. + nextEmit := s + cv := load6432(src, s) + + // Relative offsets + offset1 := int32(blk.recentOffsets[0]) + offset2 := int32(blk.recentOffsets[1]) + + addLiterals := func(s *seq, until int32) { + if until == nextEmit { + return + } + blk.literals = append(blk.literals, src[nextEmit:until]...) + s.litLen = uint32(until - nextEmit) + } + if debugEncoder { + println("recent offsets:", blk.recentOffsets) + } + +encodeLoop: + for { + // t will contain the match offset when we find one. + // When existing the search loop, we have already checked 4 bytes. + var t int32 + + // We will not use repeat offsets across blocks. + // By not using them for the first 3 matches + canRepeat := len(blk.sequences) > 2 + + for { + if debugAsserts && canRepeat && offset1 == 0 { + panic("offset0 was 0") + } + + nextHash := hashLen(cv, hashLog, tableFastHashLen) + nextHash2 := hashLen(cv>>8, hashLog, tableFastHashLen) + candidate := e.table[nextHash] + candidate2 := e.table[nextHash2] + repIndex := s - offset1 + 2 + + e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)} + e.markShardDirty(nextHash) + e.table[nextHash2] = tableEntry{offset: s + e.cur + 1, val: uint32(cv >> 8)} + e.markShardDirty(nextHash2) + + if canRepeat && repIndex >= 0 && load3232(src, repIndex) == uint32(cv>>16) { + // Consider history as well. + var seq seq + length := 4 + e.matchlen(s+6, repIndex+4, src) + + seq.matchLen = uint32(length - zstdMinMatch) + + // We might be able to match backwards. + // Extend as long as we can. + start := s + 2 + // We end the search early, so we don't risk 0 literals + // and have to do special offset treatment. + startLimit := nextEmit + 1 + + sMin := max(s-e.maxMatchOff, 0) + for repIndex > sMin && start > startLimit && src[repIndex-1] == src[start-1] && seq.matchLen < maxMatchLength-zstdMinMatch { + repIndex-- + start-- + seq.matchLen++ + } + addLiterals(&seq, start) + + // rep 0 + seq.offset = 1 + if debugSequences { + println("repeat sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + s += length + 2 + nextEmit = s + if s >= sLimit { + if debugEncoder { + println("repeat ended", s, length) + + } + break encodeLoop + } + cv = load6432(src, s) + continue + } + coffset0 := s - (candidate.offset - e.cur) + coffset1 := s - (candidate2.offset - e.cur) + 1 + if coffset0 < e.maxMatchOff && uint32(cv) == candidate.val { + // found a regular match + t = candidate.offset - e.cur + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + break + } + + if coffset1 < e.maxMatchOff && uint32(cv>>8) == candidate2.val { + // found a regular match + t = candidate2.offset - e.cur + s++ + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + if debugAsserts && s-t > e.maxMatchOff { + panic("s - t >e.maxMatchOff") + } + if debugAsserts && t < 0 { + panic("t<0") + } + break + } + s += stepSize + ((s - nextEmit) >> (kSearchStrength - 1)) + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + } + // A 4-byte match has been found. We'll later see if more than 4 bytes. + offset2 = offset1 + offset1 = s - t + + if debugAsserts && s <= t { + panic(fmt.Sprintf("s (%d) <= t (%d)", s, t)) + } + + if debugAsserts && canRepeat && int(offset1) > len(src) { + panic("invalid offset") + } + + // Extend the 4-byte match as long as possible. + l := e.matchlen(s+4, t+4, src) + 4 + + // Extend backwards + tMin := max(s-e.maxMatchOff, 0) + for t > tMin && s > nextEmit && src[t-1] == src[s-1] && l < maxMatchLength { + s-- + t-- + l++ + } + + // Write our sequence. + var seq seq + seq.litLen = uint32(s - nextEmit) + seq.matchLen = uint32(l - zstdMinMatch) + if seq.litLen > 0 { + blk.literals = append(blk.literals, src[nextEmit:s]...) + } + // Don't use repeat offsets + seq.offset = uint32(s-t) + 3 + s += l + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + nextEmit = s + if s >= sLimit { + break encodeLoop + } + cv = load6432(src, s) + + // Check offset 2 + if o2 := s - offset2; canRepeat && load3232(src, o2) == uint32(cv) { + // We have at least 4 byte match. + // No need to check backwards. We come straight from a match + l := 4 + e.matchlen(s+4, o2+4, src) + + // Store this, since we have it. + nextHash := hashLen(cv, hashLog, tableFastHashLen) + e.table[nextHash] = tableEntry{offset: s + e.cur, val: uint32(cv)} + e.markShardDirty(nextHash) + seq.matchLen = uint32(l) - zstdMinMatch + seq.litLen = 0 + // Since litlen is always 0, this is offset 1. + seq.offset = 1 + s += l + nextEmit = s + if debugSequences { + println("sequence", seq, "next s:", s) + } + blk.sequences = append(blk.sequences, seq) + + // Swap offset 1 and 2. + offset1, offset2 = offset2, offset1 + if s >= sLimit { + break encodeLoop + } + // Prepare next loop. + cv = load6432(src, s) + } + } + + if int(nextEmit) < len(src) { + blk.literals = append(blk.literals, src[nextEmit:]...) + blk.extraLits = len(src) - int(nextEmit) + } + blk.recentOffsets[0] = uint32(offset1) + blk.recentOffsets[1] = uint32(offset2) + if debugEncoder { + println("returning, recent offsets:", blk.recentOffsets, "extra literals:", blk.extraLits) + } +} + +// ResetDict will reset and set a dictionary if not nil +func (e *fastEncoder) Reset(d *dict, singleBlock bool) { + e.resetBase(d, singleBlock) + if d != nil { + panic("fastEncoder: Reset with dict") + } +} + +func (e *fastEncoder) ResetPrefix(prefix []byte) { + e.resetBasePrefix(prefix) + if len(prefix) < 8 { + return + } + end := e.cur + int32(len(prefix)) - 8 + // Index every 4th + for i := e.cur + 1; i < end; i += 4 { + cv := load6432(prefix, i-e.cur) + e.table[hashLen(cv, tableBits, tableFastHashLen)] = tableEntry{val: uint32(cv), offset: i} + } +} + +// ResetDict will reset and set a dictionary if not nil +func (e *fastEncoderDict) Reset(d *dict, singleBlock bool) { + e.resetBase(d, singleBlock) + if d == nil { + return + } + + // Init or copy dict table + if len(e.dictTable) != len(e.table) || d != e.lastDict { + if len(e.dictTable) != len(e.table) { + e.dictTable = make([]tableEntry, len(e.table)) + } else { + clear(e.dictTable) + } + if true { + end := e.maxMatchOff + int32(len(d.content)) - 8 + for i := e.maxMatchOff; i < end; i += 2 { + const hashLog = tableBits + + cv := load6432(d.content, i-e.maxMatchOff) + nextHash := hashLen(cv, hashLog, tableFastHashLen) // 0 -> 6 + nextHash1 := hashLen(cv>>8, hashLog, tableFastHashLen) // 1 -> 7 + e.dictTable[nextHash] = tableEntry{ + val: uint32(cv), + offset: i, + } + e.dictTable[nextHash1] = tableEntry{ + val: uint32(cv >> 8), + offset: i + 1, + } + } + } + e.lastDict = d + e.allDirty = true + } + + e.cur = e.maxMatchOff + dirtyShardCnt := 0 + if !e.allDirty { + for i := range e.tableShardDirty { + if e.tableShardDirty[i] { + dirtyShardCnt++ + } + } + } + + const shardCnt = tableShardCnt + const shardSize = tableShardSize + if e.allDirty || dirtyShardCnt > shardCnt*4/6 { + //copy(e.table[:], e.dictTable) + e.table = *(*[tableSize]tableEntry)(e.dictTable) + for i := range e.tableShardDirty { + e.tableShardDirty[i] = false + } + e.allDirty = false + return + } + for i := range e.tableShardDirty { + if !e.tableShardDirty[i] { + continue + } + + //copy(e.table[i*shardSize:(i+1)*shardSize], e.dictTable[i*shardSize:(i+1)*shardSize]) + *(*[shardSize]tableEntry)(e.table[i*shardSize:]) = *(*[shardSize]tableEntry)(e.dictTable[i*shardSize:]) + e.tableShardDirty[i] = false + } + e.allDirty = false +} + +func (e *fastEncoderDict) ResetPrefix([]byte) { + panic("ResetPrefix not supported for dict encoders") +} + +func (e *fastEncoderDict) markAllShardsDirty() { + e.allDirty = true +} + +func (e *fastEncoderDict) markShardDirty(entryNum uint32) { + e.tableShardDirty[entryNum/tableShardSize] = true +} diff --git a/vendor/github.com/klauspost/compress/zstd/enc_jobs.go b/vendor/github.com/klauspost/compress/zstd/enc_jobs.go new file mode 100644 index 0000000..95ce67a --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/enc_jobs.go @@ -0,0 +1,352 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "fmt" + rdebug "runtime/debug" + "sync" +) + +type encJob struct { + prefix []byte // overlap from previous job (nil for first) + input []byte // job's own input data (swapped from filling) + last bool // last block of last job gets last=true + output []byte // compressed blocks (filled by worker) + err error // encoding error + done chan struct{} // closed when complete +} + +type jobState struct { + jobSize int + overlapSize int + filling []byte // accumulates input up to jobSize + nextPrefix []byte // overlap prefix prepared for the next dispatched job + + jobSeq int // next job sequence number + + jobCh chan *encJob // dispatch to workers + resultCh chan *encJob // ordered results to flusher + + workerWg sync.WaitGroup + flusherWg sync.WaitGroup + + mu sync.Mutex + flushedSeq int // last flushed sequence number + cond *sync.Cond + + flusherErr error + started bool + + inputPool sync.Pool // *[]byte buffers of jobSize cap + outputPool sync.Pool // *[]byte buffers for compressed output + overlapPool sync.Pool // *[]byte buffers for overlap prefixes +} + +func (e *Encoder) startJobWorkers() { + js := &e.state.jobs + n := e.o.concurrent + js.jobCh = make(chan *encJob, n) + js.resultCh = make(chan *encJob, n) + js.flushedSeq = 0 + js.cond = sync.NewCond(&js.mu) + + // Workers borrow encoders from the shared e.encoders pool per-job. + // Ensure the pool is initialized before any worker tries to borrow. + e.init.Do(e.initialize) + + for range n { + js.workerWg.Add(1) + go e.jobWorker() + } + js.flusherWg.Add(1) + go e.jobFlusher() + js.started = true +} + +func (e *Encoder) jobWorker() { + js := &e.state.jobs + defer js.workerWg.Done() + for job := range js.jobCh { + enc := <-e.encoders + e.compressJob(enc, job) + e.encoders <- enc + close(job.done) + } +} + +func (e *Encoder) compressJob(enc encoder, job *encJob) { + defer func() { + if r := recover(); r != nil { + job.err = fmt.Errorf("panic in parallel job: %v", r) + rdebug.PrintStack() + } + }() + + if len(job.prefix) > 0 { + enc.ResetPrefix(job.prefix) + } else { + enc.Reset(nil, false) + } + + data := job.input + if len(data) == 0 && job.last { + blk := enc.Block() + blk.reset(nil) + blk.last = true + blk.encodeRaw(nil) + job.output = append(job.output, blk.output...) + return + } + + blk := enc.Block() + for len(data) > 0 { + todo := data + if len(todo) > e.o.blockSize { + todo = todo[:e.o.blockSize] + } + data = data[len(todo):] + + blk.pushOffsets() + enc.Encode(blk, todo) + blk.last = len(data) == 0 && job.last + + err := blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy) + if err != nil { + job.err = err + return + } + job.output = append(job.output, blk.output...) + blk.reset(nil) + } +} + +func (js *jobState) getInputBuf(size int) []byte { + if v := js.inputPool.Get(); v != nil { + bp := v.(*[]byte) + b := *bp + if cap(b) >= size { + return b[:0] + } + } + return make([]byte, 0, size) +} + +func (js *jobState) putInputBuf(b []byte) { + if cap(b) > 0 { + b = b[:0] + js.inputPool.Put(&b) + } +} + +func (js *jobState) getOutputBuf(size int) []byte { + if v := js.outputPool.Get(); v != nil { + bp := v.(*[]byte) + b := *bp + if cap(b) >= size { + return b[:0] + } + } + return make([]byte, 0, size) +} + +func (js *jobState) putOutputBuf(b []byte) { + if cap(b) > 0 { + b = b[:0] + js.outputPool.Put(&b) + } +} + +func (js *jobState) getOverlapBuf(size int) []byte { + if v := js.overlapPool.Get(); v != nil { + bp := v.(*[]byte) + b := *bp + if cap(b) >= size { + return b[:size] + } + } + return make([]byte, size) +} + +func (js *jobState) putOverlapBuf(b []byte) { + if cap(b) > 0 { + b = b[:0] + js.overlapPool.Put(&b) + } +} + +func (e *Encoder) jobFlusher() { + js := &e.state.jobs + defer js.flusherWg.Done() + for job := range js.resultCh { + <-job.done + // Worker has fully exited compressJob, so the prefix is no longer + // in use. Return it to the pool regardless of outcome. + if job.prefix != nil { + js.putOverlapBuf(job.prefix) + job.prefix = nil + } + if job.err != nil { + js.mu.Lock() + js.flusherErr = job.err + js.cond.Broadcast() + js.mu.Unlock() + for range js.resultCh { + } + return + } + if len(job.output) > 0 { + _, err := e.state.w.Write(job.output) + if err != nil { + js.mu.Lock() + js.flusherErr = err + js.cond.Broadcast() + js.mu.Unlock() + for range js.resultCh { + } + return + } + e.state.nWritten += int64(len(job.output)) + } + // Return buffers to pools. + js.putInputBuf(job.input) + js.putOutputBuf(job.output) + job.input = nil + job.output = nil + + js.mu.Lock() + js.flushedSeq++ + js.cond.Broadcast() + js.mu.Unlock() + } +} + +func (e *Encoder) shutdownJobWorkers() { + js := &e.state.jobs + if !js.started { + return + } + close(js.jobCh) + js.workerWg.Wait() + close(js.resultCh) + js.flusherWg.Wait() + js.started = false +} + +// waitAllJobs blocks until all dispatched jobs have been flushed. +func (e *Encoder) waitAllJobs() { + js := &e.state.jobs + if !js.started { + return + } + js.mu.Lock() + for js.flushedSeq < js.jobSeq && js.flusherErr == nil { + js.cond.Wait() + } + js.mu.Unlock() +} + +func (e *Encoder) dispatchJob(final bool) error { + s := &e.state + js := &s.jobs + + js.mu.Lock() + fErr := js.flusherErr + js.mu.Unlock() + if fErr != nil { + return fErr + } + + if !s.headerWritten { + // Single-block optimization: fall through to encodeAll path. + if final && len(js.filling) > 0 && len(js.filling) <= e.o.blockSize { + s.current = e.encodeAll(s.encoder, js.filling, s.current[:0]) + var n2 int + n2, s.err = s.w.Write(s.current) + if s.err != nil { + return s.err + } + s.nWritten += int64(n2) + s.nInput += int64(len(js.filling)) + s.current = s.current[:0] + js.filling = js.filling[:0] + s.headerWritten = true + s.fullFrameWritten = true + s.eofWritten = true + return nil + } + if final && len(js.filling) == 0 && !e.o.fullZero { + s.headerWritten = true + s.fullFrameWritten = true + s.eofWritten = true + return nil + } + + var tmp [maxHeaderSize]byte + fh := frameHeader{ + ContentSize: uint64(s.frameContentSize), + WindowSize: uint32(s.encoder.WindowSize(s.frameContentSize)), + SingleSegment: false, + Checksum: e.o.crc, + DictID: 0, + } + dst := fh.appendTo(tmp[:0]) + var n2 int + n2, s.err = s.w.Write(dst) + if s.err != nil { + return s.err + } + s.nWritten += int64(n2) + s.headerWritten = true + } + + if len(js.filling) == 0 && !final { + return nil + } + + if !js.started { + e.startJobWorkers() + } + + // Estimate output size for pooled buffer. + outputEst := max(len(js.filling)/2, 512) + + job := &encJob{ + last: final, + done: make(chan struct{}), + output: js.getOutputBuf(outputEst), + } + + // Each job owns its prefix slice; the flusher returns it to the pool + // after <-job.done, so workers and dispatch never share a buffer. + if js.nextPrefix != nil { + job.prefix = js.nextPrefix + js.nextPrefix = nil + } + + // Build the next job's prefix from the tail of this job's input. + if !final && len(js.filling) > 0 { + overlapLen := min(js.overlapSize, len(js.filling)) + np := js.getOverlapBuf(overlapLen) + copy(np, js.filling[len(js.filling)-overlapLen:]) + js.nextPrefix = np + } + + // Swap filling buffer into job — zero-copy for the input data. + job.input = js.filling + js.filling = js.getInputBuf(js.jobSize) + + s.nInput += int64(len(job.input)) + js.jobSeq++ + + if final { + s.eofWritten = true + } + + js.resultCh <- job + js.jobCh <- job + + return nil +} diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go new file mode 100644 index 0000000..6ee96d8 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/encoder.go @@ -0,0 +1,873 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "crypto/rand" + "errors" + "fmt" + "io" + "math" + rdebug "runtime/debug" + "sync" + + "github.com/klauspost/compress/zstd/internal/xxhash" +) + +// Encoder provides encoding to Zstandard. +// An Encoder can be used for either compressing a stream via the +// io.WriteCloser interface supported by the Encoder or as multiple independent +// tasks via the EncodeAll function. +// Smaller encodes are encouraged to use the EncodeAll function. +// Use NewWriter to create a new instance. +type Encoder struct { + o encoderOptions + encoders chan encoder + state encoderState + init sync.Once +} + +type encoder interface { + Encode(blk *blockEnc, src []byte) + EncodeNoHist(blk *blockEnc, src []byte) + Block() *blockEnc + CRC() *xxhash.Digest + AppendCRC([]byte) []byte + WindowSize(size int64) int32 + UseBlock(*blockEnc) + Reset(d *dict, singleBlock bool) + ResetPrefix(prefix []byte) +} + +type encoderState struct { + w io.Writer + filling []byte + current []byte + previous []byte + encoder encoder + writing *blockEnc + err error + writeErr error + nWritten int64 + nInput int64 + frameContentSize int64 + headerWritten bool + eofWritten bool + fullFrameWritten bool + + // This waitgroup indicates an encode is running. + wg sync.WaitGroup + // This waitgroup indicates we have a block encoding/writing. + wWg sync.WaitGroup + + // Parallel job state (used when concurrentBlocks is enabled). + jobs jobState +} + +// NewWriter will create a new Zstandard encoder. +// If the encoder will be used for encoding blocks a nil writer can be used. +func NewWriter(w io.Writer, opts ...EOption) (*Encoder, error) { + initPredefined() + var e Encoder + e.o.setDefault() + for _, o := range opts { + err := o(&e.o) + if err != nil { + return nil, err + } + } + if e.o.concurrentBlocks && (e.o.dict != nil || e.o.concurrent <= 1) { + e.o.concurrentBlocks = false + } + if w != nil { + e.Reset(w) + } + return &e, nil +} + +func (e *Encoder) initialize() { + if e.o.concurrent == 0 { + e.o.setDefault() + } + e.encoders = make(chan encoder, e.o.concurrent) + for i := 0; i < e.o.concurrent; i++ { + enc := e.o.encoder() + e.encoders <- enc + } +} + +// Reset will re-initialize the writer and new writes will encode to the supplied writer +// as a new, independent stream. +func (e *Encoder) Reset(w io.Writer) { + s := &e.state + + if e.o.concurrentBlocks { + e.shutdownJobWorkers() + js := &s.jobs + js.jobSize = e.o.jobSize() + js.overlapSize = e.o.overlapSize() + // js.filling is allocated lazily on first Write/ReadFrom so callers + // that only use EncodeAll don't pay the (up to ~32 MB) jobSize cost. + js.filling = js.filling[:0] + if js.nextPrefix != nil { + js.putOverlapBuf(js.nextPrefix) + js.nextPrefix = nil + } + js.jobSeq = 0 + js.flushedSeq = 0 + js.flusherErr = nil + js.started = false + } + + s.wg.Wait() + s.wWg.Wait() + if cap(s.filling) == 0 { + s.filling = make([]byte, 0, e.o.blockSize) + } + if e.o.concurrent > 1 && !e.o.concurrentBlocks { + if cap(s.current) == 0 { + s.current = make([]byte, 0, e.o.blockSize) + } + if cap(s.previous) == 0 { + s.previous = make([]byte, 0, e.o.blockSize) + } + s.current = s.current[:0] + s.previous = s.previous[:0] + if s.writing == nil { + s.writing = &blockEnc{lowMem: e.o.lowMem} + s.writing.init() + } + s.writing.initNewEncode() + } + if s.encoder == nil { + s.encoder = e.o.encoder() + } + s.filling = s.filling[:0] + s.encoder.Reset(e.o.dict, false) + s.headerWritten = false + s.eofWritten = false + s.fullFrameWritten = false + s.w = w + s.err = nil + s.nWritten = 0 + s.nInput = 0 + s.writeErr = nil + s.frameContentSize = 0 +} + +// ResetWithOptions will re-initialize the writer and apply the given options +// as a new, independent stream. +// Options are applied on top of the existing options. +// Some options cannot be changed on reset and will return an error. +func (e *Encoder) ResetWithOptions(w io.Writer, opts ...EOption) error { + e.o.resetOpt = true + defer func() { e.o.resetOpt = false }() + hadDict := e.o.dict != nil + for _, o := range opts { + if err := o(&e.o); err != nil { + return err + } + } + hasDict := e.o.dict != nil + if e.o.concurrentBlocks && hasDict { + e.o.concurrentBlocks = false + } + if hadDict != hasDict { + // Dict presence changed — encoder type must be recreated. + e.state.encoder = nil + e.init = sync.Once{} + } + e.Reset(w) + return nil +} + +// ResetContentSize will reset and set a content size for the next stream. +// If the bytes written does not match the size given an error will be returned +// when calling Close(). +// This is removed when Reset is called. +// Sizes <= 0 results in no content size set. +func (e *Encoder) ResetContentSize(w io.Writer, size int64) { + e.Reset(w) + if size >= 0 { + e.state.frameContentSize = size + } +} + +// Write data to the encoder. +// Input data will be buffered and as the buffer fills up +// content will be compressed and written to the output. +// When done writing, use Close to flush the remaining output +// and write CRC if requested. +func (e *Encoder) Write(p []byte) (n int, err error) { + s := &e.state + if s.eofWritten { + return 0, ErrEncoderClosed + } + if e.o.concurrentBlocks { + return e.writeJobs(p) + } + return e.writeBlocks(p) +} + +func (e *Encoder) writeJobs(p []byte) (n int, err error) { + s := &e.state + js := &s.jobs + jobSize := js.jobSize + if cap(js.filling) == 0 && len(p) > 0 { + js.filling = make([]byte, 0, jobSize) + } + for len(p) > 0 { + if len(p)+len(js.filling) < jobSize { + if e.o.crc { + _, _ = s.encoder.CRC().Write(p) + } + js.filling = append(js.filling, p...) + return n + len(p), nil + } + add := p + if len(p)+len(js.filling) > jobSize { + add = add[:jobSize-len(js.filling)] + } + if e.o.crc { + _, _ = s.encoder.CRC().Write(add) + } + js.filling = append(js.filling, add...) + p = p[len(add):] + n += len(add) + if len(js.filling) < jobSize { + return n, nil + } + if err := e.dispatchJob(false); err != nil { + return n, err + } + } + return n, nil +} + +func (e *Encoder) writeBlocks(p []byte) (n int, err error) { + s := &e.state + for len(p) > 0 { + if len(p)+len(s.filling) < e.o.blockSize { + if e.o.crc { + _, _ = s.encoder.CRC().Write(p) + } + s.filling = append(s.filling, p...) + return n + len(p), nil + } + add := p + if len(p)+len(s.filling) > e.o.blockSize { + add = add[:e.o.blockSize-len(s.filling)] + } + if e.o.crc { + _, _ = s.encoder.CRC().Write(add) + } + s.filling = append(s.filling, add...) + p = p[len(add):] + n += len(add) + if len(s.filling) < e.o.blockSize { + return n, nil + } + err := e.nextBlock(false) + if err != nil { + return n, err + } + if debugAsserts && len(s.filling) > 0 { + panic(len(s.filling)) + } + } + return n, nil +} + +// nextBlock will synchronize and start compressing input in e.state.filling. +// If an error has occurred during encoding it will be returned. +func (e *Encoder) nextBlock(final bool) error { + s := &e.state + // Wait for current block. + s.wg.Wait() + if s.err != nil { + return s.err + } + if len(s.filling) > e.o.blockSize { + return fmt.Errorf("block > maxStoreBlockSize") + } + if !s.headerWritten { + // If we have a single block encode, do a sync compression. + if final && len(s.filling) == 0 && !e.o.fullZero { + s.headerWritten = true + s.fullFrameWritten = true + s.eofWritten = true + return nil + } + if final && len(s.filling) > 0 { + s.current = e.encodeAll(s.encoder, s.filling, s.current[:0]) + var n2 int + n2, s.err = s.w.Write(s.current) + if s.err != nil { + return s.err + } + s.nWritten += int64(n2) + s.nInput += int64(len(s.filling)) + s.current = s.current[:0] + s.filling = s.filling[:0] + s.headerWritten = true + s.fullFrameWritten = true + s.eofWritten = true + return nil + } + + var tmp [maxHeaderSize]byte + fh := frameHeader{ + ContentSize: uint64(s.frameContentSize), + WindowSize: uint32(s.encoder.WindowSize(s.frameContentSize)), + SingleSegment: false, + Checksum: e.o.crc, + DictID: e.o.dict.ID(), + } + + dst := fh.appendTo(tmp[:0]) + s.headerWritten = true + s.wWg.Wait() + var n2 int + n2, s.err = s.w.Write(dst) + if s.err != nil { + return s.err + } + s.nWritten += int64(n2) + } + if s.eofWritten { + // Ensure we only write it once. + final = false + } + + if len(s.filling) == 0 { + // Final block, but no data. + if final { + enc := s.encoder + blk := enc.Block() + blk.reset(nil) + blk.last = true + blk.encodeRaw(nil) + s.wWg.Wait() + _, s.err = s.w.Write(blk.output) + s.nWritten += int64(len(blk.output)) + s.eofWritten = true + } + return s.err + } + + // SYNC: + if e.o.concurrent == 1 { + src := s.filling + s.nInput += int64(len(s.filling)) + if debugEncoder { + println("Adding sync block,", len(src), "bytes, final:", final) + } + enc := s.encoder + blk := enc.Block() + blk.reset(nil) + enc.Encode(blk, src) + blk.last = final + if final { + s.eofWritten = true + } + + s.err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy) + if s.err != nil { + return s.err + } + _, s.err = s.w.Write(blk.output) + s.nWritten += int64(len(blk.output)) + s.filling = s.filling[:0] + return s.err + } + + // Move blocks forward. + s.filling, s.current, s.previous = s.previous[:0], s.filling, s.current + s.nInput += int64(len(s.current)) + s.wg.Add(1) + if final { + s.eofWritten = true + } + go func(src []byte) { + if debugEncoder { + println("Adding block,", len(src), "bytes, final:", final) + } + defer func() { + if r := recover(); r != nil { + s.err = fmt.Errorf("panic while encoding: %v", r) + rdebug.PrintStack() + } + s.wg.Done() + }() + enc := s.encoder + blk := enc.Block() + enc.Encode(blk, src) + blk.last = final + // Wait for pending writes. + s.wWg.Wait() + if s.writeErr != nil { + s.err = s.writeErr + return + } + // Transfer encoders from previous write block. + blk.swapEncoders(s.writing) + // Transfer recent offsets to next. + enc.UseBlock(s.writing) + s.writing = blk + s.wWg.Add(1) + go func() { + defer func() { + if r := recover(); r != nil { + s.writeErr = fmt.Errorf("panic while encoding/writing: %v", r) + rdebug.PrintStack() + } + s.wWg.Done() + }() + s.writeErr = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy) + if s.writeErr != nil { + return + } + _, s.writeErr = s.w.Write(blk.output) + s.nWritten += int64(len(blk.output)) + }() + }(s.current) + return nil +} + +// ReadFrom reads data from r until EOF or error. +// The return value n is the number of bytes read. +// Any error except io.EOF encountered during the read is also returned. +// +// The Copy function uses ReaderFrom if available. +func (e *Encoder) ReadFrom(r io.Reader) (n int64, err error) { + if debugEncoder { + println("Using ReadFrom") + } + + if e.o.concurrentBlocks { + return e.readFromJobs(r) + } + + // Flush any current writes. + if len(e.state.filling) > 0 { + if err := e.nextBlock(false); err != nil { + return 0, err + } + } + e.state.filling = e.state.filling[:e.o.blockSize] + src := e.state.filling + for { + n2, err := r.Read(src) + if e.o.crc { + _, _ = e.state.encoder.CRC().Write(src[:n2]) + } + src = src[n2:] + n += int64(n2) + switch err { + case io.EOF: + e.state.filling = e.state.filling[:len(e.state.filling)-len(src)] + if debugEncoder { + println("ReadFrom: got EOF final block:", len(e.state.filling)) + } + return n, nil + case nil: + default: + if debugEncoder { + println("ReadFrom: got error:", err) + } + e.state.err = err + return n, err + } + if len(src) > 0 { + if debugEncoder { + println("ReadFrom: got space left in source:", len(src)) + } + continue + } + err = e.nextBlock(false) + if err != nil { + return n, err + } + e.state.filling = e.state.filling[:e.o.blockSize] + src = e.state.filling + } +} + +func (e *Encoder) readFromJobs(r io.Reader) (n int64, err error) { + js := &e.state.jobs + jobSize := js.jobSize + + // Flush any current filling. + if len(js.filling) > 0 { + if err := e.dispatchJob(false); err != nil { + return 0, err + } + } + + if cap(js.filling) < jobSize { + js.filling = make([]byte, 0, jobSize) + } + js.filling = js.filling[:jobSize] + src := js.filling + for { + n2, err := r.Read(src) + if e.o.crc { + _, _ = e.state.encoder.CRC().Write(src[:n2]) + } + src = src[n2:] + n += int64(n2) + switch err { + case io.EOF: + js.filling = js.filling[:len(js.filling)-len(src)] + return n, nil + case nil: + default: + e.state.err = err + return n, err + } + if len(src) > 0 { + continue + } + if err = e.dispatchJob(false); err != nil { + return n, err + } + if cap(js.filling) < jobSize { + js.filling = make([]byte, 0, jobSize) + } + js.filling = js.filling[:jobSize] + src = js.filling + } +} + +// Flush will send the currently written data to output +// and block until everything has been written. +// This should only be used on rare occasions where pushing the currently queued data is critical. +func (e *Encoder) Flush() error { + s := &e.state + if e.o.concurrentBlocks { + return e.flushJobs() + } + if len(s.filling) > 0 { + err := e.nextBlock(false) + if err != nil { + if errors.Is(s.err, ErrEncoderClosed) { + return nil + } + return err + } + } + s.wg.Wait() + s.wWg.Wait() + if s.err != nil { + if errors.Is(s.err, ErrEncoderClosed) { + return nil + } + return s.err + } + return s.writeErr +} + +func (e *Encoder) flushJobs() error { + js := &e.state.jobs + if len(js.filling) > 0 { + if err := e.dispatchJob(false); err != nil { + return err + } + } + e.waitAllJobs() + js.mu.Lock() + fErr := js.flusherErr + js.mu.Unlock() + return fErr +} + +// Close will flush the final output and close the stream. +// The function will block until everything has been written. +// The Encoder can still be re-used after calling this. +func (e *Encoder) Close() error { + s := &e.state + if s.encoder == nil { + return nil + } + if e.o.concurrentBlocks { + return e.closeJobs() + } + if s.w == nil { + if len(s.filling) == 0 && !s.headerWritten && !s.eofWritten && s.nInput == 0 { + return nil + } + return errors.New("zstd: encoder has no writer") + } + + err := e.nextBlock(true) + if err != nil { + if errors.Is(s.err, ErrEncoderClosed) { + return nil + } + return err + } + if s.frameContentSize > 0 { + if s.nInput != s.frameContentSize { + return fmt.Errorf("frame content size %d given, but %d bytes was written", s.frameContentSize, s.nInput) + } + } + if e.state.fullFrameWritten { + return s.err + } + s.wg.Wait() + s.wWg.Wait() + + if s.err != nil { + return s.err + } + if s.writeErr != nil { + return s.writeErr + } + + // Write CRC + if e.o.crc && s.err == nil { + // heap alloc. + var tmp [4]byte + _, s.err = s.w.Write(s.encoder.AppendCRC(tmp[:0])) + s.nWritten += 4 + } + + // Add padding with content from crypto/rand.Reader + if s.err == nil && e.o.pad > 0 { + add := calcSkippableFrame(s.nWritten, int64(e.o.pad)) + frame, err := skippableFrame(s.filling[:0], add, rand.Reader) + if err != nil { + return err + } + _, s.err = s.w.Write(frame) + } + if s.err == nil { + s.err = ErrEncoderClosed + return nil + } + + return s.err +} + +func (e *Encoder) closeJobs() error { + s := &e.state + js := &s.jobs + + if errors.Is(s.err, ErrEncoderClosed) { + return nil + } + + if s.w == nil { + if len(js.filling) == 0 && !s.headerWritten && !s.eofWritten && s.nInput == 0 { + return nil + } + return errors.New("zstd: encoder has no writer") + } + + if err := e.dispatchJob(true); err != nil { + e.shutdownJobWorkers() + if errors.Is(s.err, ErrEncoderClosed) { + return nil + } + return err + } + + if s.frameContentSize > 0 && s.nInput != s.frameContentSize { + e.shutdownJobWorkers() + return fmt.Errorf("frame content size %d given, but %d bytes was written", s.frameContentSize, s.nInput) + } + + if s.fullFrameWritten { + e.shutdownJobWorkers() + s.err = ErrEncoderClosed + return nil + } + + e.shutdownJobWorkers() + if js.flusherErr != nil { + return js.flusherErr + } + + // Write CRC + if e.o.crc { + var tmp [4]byte + _, s.err = s.w.Write(s.encoder.AppendCRC(tmp[:0])) + s.nWritten += 4 + } + + // Add padding + if s.err == nil && e.o.pad > 0 { + add := calcSkippableFrame(s.nWritten, int64(e.o.pad)) + frame, err := skippableFrame(js.filling[:0], add, rand.Reader) + if err != nil { + return err + } + _, s.err = s.w.Write(frame) + } + if s.err == nil { + s.err = ErrEncoderClosed + return nil + } + return s.err +} + +// EncodeAll will encode all input in src and append it to dst. +// This function can be called concurrently, but each call will only run on a single goroutine. +// If empty input is given, nothing is returned, unless WithZeroFrames is specified. +// Encoded blocks can be concatenated and the result will be the combined input stream. +// Data compressed with EncodeAll can be decoded with the Decoder, +// using either a stream or DecodeAll. +func (e *Encoder) EncodeAll(src, dst []byte) []byte { + e.init.Do(e.initialize) + enc := <-e.encoders + defer func() { + e.encoders <- enc + }() + return e.encodeAll(enc, src, dst) +} + +func (e *Encoder) encodeAll(enc encoder, src, dst []byte) []byte { + if len(src) == 0 { + if e.o.fullZero { + // Add frame header. + fh := frameHeader{ + ContentSize: 0, + WindowSize: MinWindowSize, + SingleSegment: true, + // Adding a checksum would be a waste of space. + Checksum: false, + DictID: 0, + } + dst = fh.appendTo(dst) + + // Write raw block as last one only. + var blk blockHeader + blk.setSize(0) + blk.setType(blockTypeRaw) + blk.setLast(true) + dst = blk.appendTo(dst) + } + return dst + } + + // Use single segments when above minimum window and below window size. + single := len(src) <= e.o.windowSize && len(src) > MinWindowSize + if e.o.single != nil { + single = *e.o.single + } + fh := frameHeader{ + ContentSize: uint64(len(src)), + WindowSize: uint32(enc.WindowSize(int64(len(src)))), + SingleSegment: single, + Checksum: e.o.crc, + DictID: e.o.dict.ID(), + } + + // If less than 1MB, allocate a buffer up front. + if len(dst) == 0 && cap(dst) == 0 && len(src) < 1<<20 && !e.o.lowMem { + dst = make([]byte, 0, len(src)) + } + dst = fh.appendTo(dst) + + // If we can do everything in one block, prefer that. + if len(src) <= e.o.blockSize { + enc.Reset(e.o.dict, true) + // Slightly faster with no history and everything in one block. + if e.o.crc { + _, _ = enc.CRC().Write(src) + } + blk := enc.Block() + blk.last = true + if e.o.dict == nil { + enc.EncodeNoHist(blk, src) + } else { + enc.Encode(blk, src) + } + + // If we got the exact same number of literals as input, + // assume the literals cannot be compressed. + oldout := blk.output + // Output directly to dst + blk.output = dst + + err := blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy) + if err != nil { + panic(err) + } + dst = blk.output + blk.output = oldout + } else { + enc.Reset(e.o.dict, false) + blk := enc.Block() + for len(src) > 0 { + todo := src + if len(todo) > e.o.blockSize { + todo = todo[:e.o.blockSize] + } + src = src[len(todo):] + if e.o.crc { + _, _ = enc.CRC().Write(todo) + } + blk.pushOffsets() + enc.Encode(blk, todo) + if len(src) == 0 { + blk.last = true + } + err := blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy) + if err != nil { + panic(err) + } + dst = append(dst, blk.output...) + blk.reset(nil) + } + } + if e.o.crc { + dst = enc.AppendCRC(dst) + } + // Add padding with content from crypto/rand.Reader + if e.o.pad > 0 { + add := calcSkippableFrame(int64(len(dst)), int64(e.o.pad)) + var err error + dst, err = skippableFrame(dst, add, rand.Reader) + if err != nil { + panic(err) + } + } + return dst +} + +// MaxEncodedSize returns the expected maximum +// size of an encoded block or stream. +func (e *Encoder) MaxEncodedSize(size int) int { + frameHeader := 4 + 2 // magic + frame header & window descriptor + if e.o.dict != nil { + frameHeader += 4 + } + // Frame content size: + if size < 256 { + frameHeader++ + } else if size < 65536+256 { + frameHeader += 2 + } else if size < math.MaxInt32 { + frameHeader += 4 + } else { + frameHeader += 8 + } + // Final crc + if e.o.crc { + frameHeader += 4 + } + + // Max overhead is 3 bytes/block. + // There cannot be 0 blocks. + blocks := (size + e.o.blockSize) / e.o.blockSize + + // Combine, add padding. + maxSz := frameHeader + 3*blocks + size + if e.o.pad > 1 { + maxSz += calcSkippableFrame(int64(maxSz), int64(e.o.pad)) + } + return maxSz +} diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go new file mode 100644 index 0000000..a808149 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go @@ -0,0 +1,415 @@ +package zstd + +import ( + "errors" + "fmt" + "math" + "math/bits" + "runtime" + "strings" +) + +// EOption is an option for creating a encoder. +type EOption func(*encoderOptions) error + +// options retains accumulated state of multiple options. +type encoderOptions struct { + resetOpt bool + concurrent int + level EncoderLevel + single *bool + pad int + blockSize int + windowSize int + crc bool + fullZero bool + noEntropy bool + allLitEntropy bool + customWindow bool + customALEntropy bool + customBlockSize bool + lowMem bool + dict *dict + concurrentBlocks bool +} + +func (o *encoderOptions) setDefault() { + *o = encoderOptions{ + concurrent: runtime.GOMAXPROCS(0), + crc: true, + single: nil, + blockSize: maxCompressedBlockSize, + windowSize: 8 << 20, + level: SpeedDefault, + allLitEntropy: false, + lowMem: false, + fullZero: true, + } +} + +// encoder returns an encoder with the selected options. +func (o encoderOptions) encoder() encoder { + switch o.level { + case SpeedFastest: + if o.dict != nil { + return &fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}} + } + return &fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}} + + case SpeedDefault: + if o.dict != nil { + return &doubleFastEncoderDict{fastEncoderDict: fastEncoderDict{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}}} + } + return &doubleFastEncoder{fastEncoder: fastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}} + case SpeedBetterCompression: + if o.dict != nil { + return &betterFastEncoderDict{betterFastEncoder: betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}}} + } + return &betterFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}} + case SpeedBestCompression: + return &bestFastEncoder{fastBase: fastBase{maxMatchOff: int32(o.windowSize), bufferReset: math.MaxInt32 - int32(o.windowSize*2), lowMem: o.lowMem}} + } + panic("unknown compression level") +} + +// WithEncoderCRC will add CRC value to output. +// Output will be 4 bytes larger. +// Can be changed with ResetWithOptions. +func WithEncoderCRC(b bool) EOption { + return func(o *encoderOptions) error { o.crc = b; return nil } +} + +// WithEncoderConcurrency will set the concurrency, +// meaning the maximum number of encoders to run concurrently. +// The value supplied must be at least 0. +// When a value of 0 is provided GOMAXPROCS will be used. +// For streams, setting a value of 1 will disable async compression. +// By default this will be set to GOMAXPROCS. +// Cannot be changed with ResetWithOptions. +func WithEncoderConcurrency(n int) EOption { + return func(o *encoderOptions) error { + if n < 0 { + return errors.New("concurrency must at least 0") + } + if n == 0 { + n = runtime.GOMAXPROCS(0) + } + if o.resetOpt && n != o.concurrent { + return errors.New("WithEncoderConcurrency cannot be changed on Reset") + } + o.concurrent = n + return nil + } +} + +// WithWindowSize will set the maximum allowed back-reference distance. +// The value must be a power of two between MinWindowSize and MaxWindowSize. +// A larger value will enable better compression but allocate more memory and, +// for above-default values, take considerably longer. +// The default value is determined by the compression level and max 8MB. +// Cannot be changed with ResetWithOptions. +func WithWindowSize(n int) EOption { + return func(o *encoderOptions) error { + switch { + case n < MinWindowSize: + return fmt.Errorf("window size must be at least %d", MinWindowSize) + case n > MaxWindowSize: + return fmt.Errorf("window size must be at most %d", MaxWindowSize) + case (n & (n - 1)) != 0: + return errors.New("window size must be a power of 2") + } + if o.resetOpt && n != o.windowSize { + return errors.New("WithWindowSize cannot be changed on Reset") + } + + o.windowSize = n + o.customWindow = true + if o.blockSize > o.windowSize { + o.blockSize = o.windowSize + o.customBlockSize = true + } + return nil + } +} + +// WithEncoderPadding will add padding to all output so the size will be a multiple of n. +// This can be used to obfuscate the exact output size or make blocks of a certain size. +// The contents will be a skippable frame, so it will be invisible by the decoder. +// n must be > 0 and <= 1GB, 1<<30 bytes. +// The padded area will be filled with data from crypto/rand.Reader. +// If `EncodeAll` is used with data already in the destination, the total size will be multiple of this. +// Can be changed with ResetWithOptions. +func WithEncoderPadding(n int) EOption { + return func(o *encoderOptions) error { + if n <= 0 { + return fmt.Errorf("padding must be at least 1") + } + // No need to waste our time. + if n == 1 { + n = 0 + } + if n > 1<<30 { + return fmt.Errorf("padding must less than 1GB (1<<30 bytes) ") + } + o.pad = n + return nil + } +} + +// EncoderLevel predefines encoder compression levels. +// Only use the constants made available, since the actual mapping +// of these values are very likely to change and your compression could change +// unpredictably when upgrading the library. +type EncoderLevel int + +const ( + speedNotSet EncoderLevel = iota + + // SpeedFastest will choose the fastest reasonable compression. + // This is roughly equivalent to the fastest Zstandard mode. + SpeedFastest + + // SpeedDefault is the default "pretty fast" compression option. + // This is roughly equivalent to the default Zstandard mode (level 3). + SpeedDefault + + // SpeedBetterCompression will yield better compression than the default. + // Currently it is about zstd level 7-8 with ~ 2x-3x the default CPU usage. + // By using this, notice that CPU usage may go up in the future. + SpeedBetterCompression + + // SpeedBestCompression will choose the best available compression option. + // This will offer the best compression no matter the CPU cost. + SpeedBestCompression + + // speedLast should be kept as the last actual compression option. + // The is not for external usage, but is used to keep track of the valid options. + speedLast +) + +// EncoderLevelFromString will convert a string representation of an encoding level back +// to a compression level. The compare is not case sensitive. +// If the string wasn't recognized, (false, SpeedDefault) will be returned. +func EncoderLevelFromString(s string) (bool, EncoderLevel) { + for l := speedNotSet + 1; l < speedLast; l++ { + if strings.EqualFold(s, l.String()) { + return true, l + } + } + return false, SpeedDefault +} + +// EncoderLevelFromZstd will return an encoder level that closest matches the compression +// ratio of a specific zstd compression level. +// Many input values will provide the same compression level. +func EncoderLevelFromZstd(level int) EncoderLevel { + switch { + case level < 3: + return SpeedFastest + case level >= 3 && level < 6: + return SpeedDefault + case level >= 6 && level < 10: + return SpeedBetterCompression + default: + return SpeedBestCompression + } +} + +// String provides a string representation of the compression level. +func (e EncoderLevel) String() string { + switch e { + case SpeedFastest: + return "fastest" + case SpeedDefault: + return "default" + case SpeedBetterCompression: + return "better" + case SpeedBestCompression: + return "best" + default: + return "invalid" + } +} + +// WithEncoderLevel specifies a predefined compression level. +// Cannot be changed with ResetWithOptions. +func WithEncoderLevel(l EncoderLevel) EOption { + return func(o *encoderOptions) error { + switch { + case l <= speedNotSet || l >= speedLast: + return fmt.Errorf("unknown encoder level") + } + if o.resetOpt && l != o.level { + return errors.New("WithEncoderLevel cannot be changed on Reset") + } + o.level = l + if !o.customWindow { + switch o.level { + case SpeedFastest: + o.windowSize = 4 << 20 + if !o.customBlockSize { + o.blockSize = 1 << 16 + } + case SpeedDefault: + o.windowSize = 8 << 20 + case SpeedBetterCompression: + o.windowSize = 8 << 20 + case SpeedBestCompression: + o.windowSize = 8 << 20 + } + } + if !o.customALEntropy { + o.allLitEntropy = l > SpeedDefault + } + + return nil + } +} + +// WithZeroFrames will encode 0 length input as full frames. +// This can be needed for compatibility with zstandard usage, +// but is not needed for this package. +// Can be changed with ResetWithOptions. +func WithZeroFrames(b bool) EOption { + return func(o *encoderOptions) error { + o.fullZero = b + return nil + } +} + +// WithAllLitEntropyCompression will apply entropy compression if no matches are found. +// Disabling this will skip incompressible data faster, but in cases with no matches but +// skewed character distribution compression is lost. +// Default value depends on the compression level selected. +// Can be changed with ResetWithOptions. +func WithAllLitEntropyCompression(b bool) EOption { + return func(o *encoderOptions) error { + o.customALEntropy = true + o.allLitEntropy = b + return nil + } +} + +// WithNoEntropyCompression will always skip entropy compression of literals. +// This can be useful if content has matches, but unlikely to benefit from entropy +// compression. Usually the slight speed improvement is not worth enabling this. +// Can be changed with ResetWithOptions. +func WithNoEntropyCompression(b bool) EOption { + return func(o *encoderOptions) error { + o.noEntropy = b + return nil + } +} + +// WithSingleSegment will set the "single segment" flag when EncodeAll is used. +// If this flag is set, data must be regenerated within a single continuous memory segment. +// In this case, Window_Descriptor byte is skipped, but Frame_Content_Size is necessarily present. +// As a consequence, the decoder must allocate a memory segment of size equal or larger than size of your content. +// In order to preserve the decoder from unreasonable memory requirements, +// a decoder is allowed to reject a compressed frame which requests a memory size beyond decoder's authorized range. +// For broader compatibility, decoders are recommended to support memory sizes of at least 8 MB. +// This is only a recommendation, each decoder is free to support higher or lower limits, depending on local limitations. +// If this is not specified, block encodes will automatically choose this based on the input size and the window size. +// This setting has no effect on streamed encodes. +// Can be changed with ResetWithOptions. +func WithSingleSegment(b bool) EOption { + return func(o *encoderOptions) error { + o.single = &b + return nil + } +} + +// WithLowerEncoderMem will trade in some memory cases trade less memory usage for +// slower encoding speed. +// This will not change the window size which is the primary function for reducing +// memory usage. See WithWindowSize. +// Cannot be changed with ResetWithOptions. +func WithLowerEncoderMem(b bool) EOption { + return func(o *encoderOptions) error { + if o.resetOpt && b != o.lowMem { + return errors.New("WithLowerEncoderMem cannot be changed on Reset") + } + o.lowMem = b + return nil + } +} + +// WithConcurrentBlocks enables job-based parallel compression for streams. +// When enabled and concurrent > 1, input is split into large sections (jobs) +// that are compressed simultaneously by multiple goroutines. +// Each non-first job receives an overlap prefix from the previous job for match context. +// Output is flushed in order, producing a valid single-frame zstd stream. +// +// Currently disabled when used with dictionary encoding. +// Cannot be changed with ResetWithOptions. +func WithConcurrentBlocks(b bool) EOption { + return func(o *encoderOptions) error { + if o.resetOpt && b != o.concurrentBlocks { + return errors.New("WithConcurrentBlocks cannot be changed on Reset") + } + o.concurrentBlocks = b + return nil + } +} + +// jobSize returns the input section size per parallel job. +func (o *encoderOptions) jobSize() int { + s := max(o.windowSize*4, 512<<10) + return s +} + +// overlapSize returns the overlap prefix size for parallel jobs. +func (o *encoderOptions) overlapSize() int { + switch o.level { + case SpeedBestCompression: + return o.windowSize / 2 + case SpeedBetterCompression: + return o.windowSize / 4 + default: + return o.windowSize / 8 + } +} + +// WithEncoderDict allows to register a dictionary that will be used for the encode. +// +// The slice dict must be in the [dictionary format] produced by +// "zstd --train" from the Zstandard reference implementation. +// +// The encoder *may* choose to use no dictionary instead for certain payloads. +// Can be changed with ResetWithOptions. +// +// [dictionary format]: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format +func WithEncoderDict(dict []byte) EOption { + return func(o *encoderOptions) error { + d, err := loadDict(dict) + if err != nil { + return err + } + o.dict = d + return nil + } +} + +// WithEncoderDictRaw registers a dictionary that may be used by the encoder. +// +// The slice content may contain arbitrary data. It will be used as an initial +// history. +// Can be changed with ResetWithOptions. +func WithEncoderDictRaw(id uint32, content []byte) EOption { + return func(o *encoderOptions) error { + if bits.UintSize > 32 && uint(len(content)) > dictMaxLength { + return fmt.Errorf("dictionary of size %d > 2GiB too large", len(content)) + } + o.dict = &dict{id: id, content: content, offsets: [3]int{1, 4, 8}} + return nil + } +} + +// WithEncoderDictDelete clears the dictionary, so no dictionary will be used. +// Should be used with ResetWithOptions. +func WithEncoderDictDelete() EOption { + return func(o *encoderOptions) error { + o.dict = nil + return nil + } +} diff --git a/vendor/github.com/klauspost/compress/zstd/framedec.go b/vendor/github.com/klauspost/compress/zstd/framedec.go new file mode 100644 index 0000000..d88f067 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/framedec.go @@ -0,0 +1,412 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "encoding/binary" + "encoding/hex" + "errors" + "io" + + "github.com/klauspost/compress/zstd/internal/xxhash" +) + +type frameDec struct { + o decoderOptions + crc *xxhash.Digest + + WindowSize uint64 + + // Frame history passed between blocks + history history + + rawInput byteBuffer + + // Byte buffer that can be reused for small input blocks. + bBuf byteBuf + + FrameContentSize uint64 + + DictionaryID uint32 + HasCheckSum bool + SingleSegment bool +} + +const ( + // MinWindowSize is the minimum Window Size, which is 1 KB. + MinWindowSize = 1 << 10 + + // MaxWindowSize is the maximum encoder window size + // and the default decoder maximum window size. + MaxWindowSize = 1 << 29 +) + +const ( + frameMagic = "\x28\xb5\x2f\xfd" + skippableFrameMagic = "\x2a\x4d\x18" +) + +func newFrameDec(o decoderOptions) *frameDec { + if o.maxWindowSize > o.maxDecodedSize { + o.maxWindowSize = o.maxDecodedSize + } + d := frameDec{ + o: o, + } + return &d +} + +// reset will read the frame header and prepare for block decoding. +// If nothing can be read from the input, io.EOF will be returned. +// Any other error indicated that the stream contained data, but +// there was a problem. +func (d *frameDec) reset(br byteBuffer) error { + d.HasCheckSum = false + d.WindowSize = 0 + var signature [4]byte + for { + var err error + // Check if we can read more... + b, err := br.readSmall(1) + switch err { + case io.EOF, io.ErrUnexpectedEOF: + return io.EOF + case nil: + signature[0] = b[0] + default: + return err + } + // Read the rest, don't allow io.ErrUnexpectedEOF + b, err = br.readSmall(3) + switch err { + case io.EOF: + return io.EOF + case nil: + copy(signature[1:], b) + default: + return err + } + + if string(signature[1:4]) != skippableFrameMagic || signature[0]&0xf0 != 0x50 { + if debugDecoder { + println("Not skippable", hex.EncodeToString(signature[:]), hex.EncodeToString([]byte(skippableFrameMagic))) + } + // Break if not skippable frame. + break + } + // Read size to skip + b, err = br.readSmall(4) + if err != nil { + if debugDecoder { + println("Reading Frame Size", err) + } + return err + } + n := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24) + println("Skipping frame with", n, "bytes.") + err = br.skipN(int64(n)) + if err != nil { + if debugDecoder { + println("Reading discarded frame", err) + } + return err + } + } + if string(signature[:]) != frameMagic { + if debugDecoder { + println("Got magic numbers: ", signature, "want:", []byte(frameMagic)) + } + return ErrMagicMismatch + } + + // Read Frame_Header_Descriptor + fhd, err := br.readByte() + if err != nil { + if debugDecoder { + println("Reading Frame_Header_Descriptor", err) + } + return err + } + d.SingleSegment = fhd&(1<<5) != 0 + + if fhd&(1<<3) != 0 { + return errors.New("reserved bit set on frame header") + } + + // Read Window_Descriptor + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#window_descriptor + d.WindowSize = 0 + if !d.SingleSegment { + wd, err := br.readByte() + if err != nil { + if debugDecoder { + println("Reading Window_Descriptor", err) + } + return err + } + if debugDecoder { + printf("raw: %x, mantissa: %d, exponent: %d\n", wd, wd&7, wd>>3) + } + windowLog := 10 + (wd >> 3) + windowBase := uint64(1) << windowLog + windowAdd := (windowBase / 8) * uint64(wd&0x7) + d.WindowSize = windowBase + windowAdd + } + + // Read Dictionary_ID + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary_id + d.DictionaryID = 0 + if size := fhd & 3; size != 0 { + if size == 3 { + size = 4 + } + + b, err := br.readSmall(int(size)) + if err != nil { + println("Reading Dictionary_ID", err) + return err + } + var id uint32 + switch len(b) { + case 1: + id = uint32(b[0]) + case 2: + id = uint32(b[0]) | (uint32(b[1]) << 8) + case 4: + id = uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24) + } + if debugDecoder { + println("Dict size", size, "ID:", id) + } + d.DictionaryID = id + } + + // Read Frame_Content_Size + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#frame_content_size + var fcsSize int + v := fhd >> 6 + switch v { + case 0: + if d.SingleSegment { + fcsSize = 1 + } + default: + fcsSize = 1 << v + } + d.FrameContentSize = fcsUnknown + if fcsSize > 0 { + b, err := br.readSmall(fcsSize) + if err != nil { + println("Reading Frame content", err) + return err + } + switch len(b) { + case 1: + d.FrameContentSize = uint64(b[0]) + case 2: + // When FCS_Field_Size is 2, the offset of 256 is added. + d.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) + 256 + case 4: + d.FrameContentSize = uint64(b[0]) | (uint64(b[1]) << 8) | (uint64(b[2]) << 16) | (uint64(b[3]) << 24) + case 8: + d1 := uint32(b[0]) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24) + d2 := uint32(b[4]) | (uint32(b[5]) << 8) | (uint32(b[6]) << 16) | (uint32(b[7]) << 24) + d.FrameContentSize = uint64(d1) | (uint64(d2) << 32) + } + if debugDecoder { + println("Read FCS:", d.FrameContentSize) + } + } + + // Move this to shared. + d.HasCheckSum = fhd&(1<<2) != 0 + if d.HasCheckSum { + if d.crc == nil { + d.crc = xxhash.New() + } + d.crc.Reset() + } + + if d.WindowSize > d.o.maxWindowSize { + if debugDecoder { + printf("window size %d > max %d\n", d.WindowSize, d.o.maxWindowSize) + } + return ErrWindowSizeExceeded + } + + if d.WindowSize == 0 && d.SingleSegment { + // We may not need window in this case. + d.WindowSize = max(d.FrameContentSize, MinWindowSize) + if d.WindowSize > d.o.maxDecodedSize { + if debugDecoder { + printf("window size %d > max %d\n", d.WindowSize, d.o.maxWindowSize) + } + return ErrDecoderSizeExceeded + } + } + + // The minimum Window_Size is 1 KB. + if d.WindowSize < MinWindowSize { + if debugDecoder { + println("got window size: ", d.WindowSize) + } + return ErrWindowSizeTooSmall + } + d.history.windowSize = int(d.WindowSize) + if !d.o.lowMem || d.history.windowSize < maxBlockSize { + // Alloc 2x window size if not low-mem, or window size below 2MB. + d.history.allocFrameBuffer = d.history.windowSize * 2 + } else { + if d.o.lowMem { + // Alloc with 1MB extra. + d.history.allocFrameBuffer = d.history.windowSize + maxBlockSize/2 + } else { + // Alloc with 2MB extra. + d.history.allocFrameBuffer = d.history.windowSize + maxBlockSize + } + } + + if debugDecoder { + println("Frame: Dict:", d.DictionaryID, "FrameContentSize:", d.FrameContentSize, "singleseg:", d.SingleSegment, "window:", d.WindowSize, "crc:", d.HasCheckSum) + } + + // history contains input - maybe we do something + d.rawInput = br + return nil +} + +// next will start decoding the next block from stream. +func (d *frameDec) next(block *blockDec) error { + if debugDecoder { + println("decoding new block") + } + err := block.reset(d.rawInput, d.WindowSize) + if err != nil { + println("block error:", err) + // Signal the frame decoder we have a problem. + block.sendErr(err) + return err + } + return nil +} + +// checkCRC will check the checksum, assuming the frame has one. +// Will return ErrCRCMismatch if crc check failed, otherwise nil. +func (d *frameDec) checkCRC() error { + // We can overwrite upper tmp now + buf, err := d.rawInput.readSmall(4) + if err != nil { + println("CRC missing?", err) + return err + } + + want := binary.LittleEndian.Uint32(buf[:4]) + got := uint32(d.crc.Sum64()) + + if got != want { + if debugDecoder { + printf("CRC check failed: got %08x, want %08x\n", got, want) + } + return ErrCRCMismatch + } + if debugDecoder { + printf("CRC ok %08x\n", got) + } + return nil +} + +// consumeCRC skips over the checksum, assuming the frame has one. +func (d *frameDec) consumeCRC() error { + _, err := d.rawInput.readSmall(4) + if err != nil { + println("CRC missing?", err) + } + return err +} + +// runDecoder will run the decoder for the remainder of the frame. +func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) { + saved := d.history.b + + // We use the history for output to avoid copying it. + d.history.b = dst + d.history.ignoreBuffer = len(dst) + // Store input length, so we only check new data. + crcStart := len(dst) + d.history.decoders.maxSyncLen = 0 + if d.o.limitToCap { + d.history.decoders.maxSyncLen = uint64(cap(dst) - len(dst)) + } + if d.FrameContentSize != fcsUnknown { + if !d.o.limitToCap || d.FrameContentSize+uint64(len(dst)) < d.history.decoders.maxSyncLen { + d.history.decoders.maxSyncLen = d.FrameContentSize + uint64(len(dst)) + } + if d.history.decoders.maxSyncLen > d.o.maxDecodedSize { + if debugDecoder { + println("maxSyncLen:", d.history.decoders.maxSyncLen, "> maxDecodedSize:", d.o.maxDecodedSize) + } + return dst, ErrDecoderSizeExceeded + } + if debugDecoder { + println("maxSyncLen:", d.history.decoders.maxSyncLen) + } + if !d.o.limitToCap && uint64(cap(dst)) < d.history.decoders.maxSyncLen { + // Alloc for output + dst2 := make([]byte, len(dst), d.history.decoders.maxSyncLen+compressedBlockOverAlloc) + copy(dst2, dst) + dst = dst2 + } + } + var err error + for { + err = dec.reset(d.rawInput, d.WindowSize) + if err != nil { + break + } + if debugDecoder { + println("next block:", dec) + } + err = dec.decodeBuf(&d.history) + if err != nil { + break + } + if uint64(len(d.history.b)-crcStart) > d.o.maxDecodedSize { + println("runDecoder: maxDecodedSize exceeded", uint64(len(d.history.b)-crcStart), ">", d.o.maxDecodedSize) + err = ErrDecoderSizeExceeded + break + } + if d.o.limitToCap && len(d.history.b) > cap(dst) { + println("runDecoder: cap exceeded", uint64(len(d.history.b)), ">", cap(dst)) + err = ErrDecoderSizeExceeded + break + } + if uint64(len(d.history.b)-crcStart) > d.FrameContentSize { + println("runDecoder: FrameContentSize exceeded", uint64(len(d.history.b)-crcStart), ">", d.FrameContentSize) + err = ErrFrameSizeExceeded + break + } + if dec.Last { + break + } + if debugDecoder { + println("runDecoder: FrameContentSize", uint64(len(d.history.b)-crcStart), "<=", d.FrameContentSize) + } + } + dst = d.history.b + if err == nil { + if d.FrameContentSize != fcsUnknown && uint64(len(d.history.b)-crcStart) != d.FrameContentSize { + err = ErrFrameSizeMismatch + } else if d.HasCheckSum { + if d.o.ignoreChecksum { + err = d.consumeCRC() + } else { + d.crc.Write(dst[crcStart:]) + err = d.checkCRC() + } + } + } + d.history.b = saved + return dst, err +} diff --git a/vendor/github.com/klauspost/compress/zstd/frameenc.go b/vendor/github.com/klauspost/compress/zstd/frameenc.go new file mode 100644 index 0000000..667ca06 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/frameenc.go @@ -0,0 +1,137 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "encoding/binary" + "fmt" + "io" + "math" + "math/bits" +) + +type frameHeader struct { + ContentSize uint64 + WindowSize uint32 + SingleSegment bool + Checksum bool + DictID uint32 +} + +const maxHeaderSize = 14 + +func (f frameHeader) appendTo(dst []byte) []byte { + dst = append(dst, frameMagic...) + var fhd uint8 + if f.Checksum { + fhd |= 1 << 2 + } + if f.SingleSegment { + fhd |= 1 << 5 + } + + var dictIDContent []byte + if f.DictID > 0 { + var tmp [4]byte + if f.DictID < 256 { + fhd |= 1 + tmp[0] = uint8(f.DictID) + dictIDContent = tmp[:1] + } else if f.DictID < 1<<16 { + fhd |= 2 + binary.LittleEndian.PutUint16(tmp[:2], uint16(f.DictID)) + dictIDContent = tmp[:2] + } else { + fhd |= 3 + binary.LittleEndian.PutUint32(tmp[:4], f.DictID) + dictIDContent = tmp[:4] + } + } + var fcs uint8 + if f.ContentSize >= 256 { + fcs++ + } + if f.ContentSize >= 65536+256 { + fcs++ + } + if f.ContentSize >= 0xffffffff { + fcs++ + } + + fhd |= fcs << 6 + + dst = append(dst, fhd) + if !f.SingleSegment { + const winLogMin = 10 + windowLog := (bits.Len32(f.WindowSize-1) - winLogMin) << 3 + dst = append(dst, uint8(windowLog)) + } + if f.DictID > 0 { + dst = append(dst, dictIDContent...) + } + switch fcs { + case 0: + if f.SingleSegment { + dst = append(dst, uint8(f.ContentSize)) + } + // Unless SingleSegment is set, framessizes < 256 are not stored. + case 1: + f.ContentSize -= 256 + dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8)) + case 2: + dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24)) + case 3: + dst = append(dst, uint8(f.ContentSize), uint8(f.ContentSize>>8), uint8(f.ContentSize>>16), uint8(f.ContentSize>>24), + uint8(f.ContentSize>>32), uint8(f.ContentSize>>40), uint8(f.ContentSize>>48), uint8(f.ContentSize>>56)) + default: + panic("invalid fcs") + } + return dst +} + +const skippableFrameHeader = 4 + 4 + +// calcSkippableFrame will return a total size to be added for written +// to be divisible by multiple. +// The value will always be > skippableFrameHeader. +// The function will panic if written < 0 or wantMultiple <= 0. +func calcSkippableFrame(written, wantMultiple int64) int { + if wantMultiple <= 0 { + panic("wantMultiple <= 0") + } + if written < 0 { + panic("written < 0") + } + leftOver := written % wantMultiple + if leftOver == 0 { + return 0 + } + toAdd := wantMultiple - leftOver + for toAdd < skippableFrameHeader { + toAdd += wantMultiple + } + return int(toAdd) +} + +// skippableFrame will add a skippable frame with a total size of bytes. +// total should be >= skippableFrameHeader and < math.MaxUint32. +func skippableFrame(dst []byte, total int, r io.Reader) ([]byte, error) { + if total == 0 { + return dst, nil + } + if total < skippableFrameHeader { + return dst, fmt.Errorf("requested skippable frame (%d) < 8", total) + } + if int64(total) > math.MaxUint32 { + return dst, fmt.Errorf("requested skippable frame (%d) > max uint32", total) + } + dst = append(dst, 0x50, 0x2a, 0x4d, 0x18) + f := uint32(total - skippableFrameHeader) + dst = append(dst, uint8(f), uint8(f>>8), uint8(f>>16), uint8(f>>24)) + start := len(dst) + dst = append(dst, make([]byte, f)...) + _, err := io.ReadFull(r, dst[start:]) + return dst, err +} diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go new file mode 100644 index 0000000..2f8860a --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder.go @@ -0,0 +1,307 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "encoding/binary" + "errors" + "fmt" + "io" +) + +const ( + tablelogAbsoluteMax = 9 +) + +const ( + /*!MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + * Increasing memory usage improves compression ratio + * Reduced memory usage can improve speed, due to cache effect + * Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ + maxMemoryUsage = tablelogAbsoluteMax + 2 + + maxTableLog = maxMemoryUsage - 2 + maxTablesize = 1 << maxTableLog + maxTableMask = (1 << maxTableLog) - 1 + minTablelog = 5 + maxSymbolValue = 255 +) + +// fseDecoder provides temporary storage for compression and decompression. +type fseDecoder struct { + dt [maxTablesize]decSymbol // Decompression table. + symbolLen uint16 // Length of active part of the symbol table. + actualTableLog uint8 // Selected tablelog. + maxBits uint8 // Maximum number of additional bits + + // used for table creation to avoid allocations. + stateTable [256]uint16 + norm [maxSymbolValue + 1]int16 + preDefined bool +} + +// tableStep returns the next table index. +func tableStep(tableSize uint32) uint32 { + return (tableSize >> 1) + (tableSize >> 3) + 3 +} + +// readNCount will read the symbol distribution so decoding tables can be constructed. +func (s *fseDecoder) readNCount(b *byteReader, maxSymbol uint16) error { + var ( + charnum uint16 + previous0 bool + ) + if b.remain() < 4 { + return errors.New("input too small") + } + bitStream := b.Uint32NC() + nbBits := uint((bitStream & 0xF) + minTablelog) // extract tableLog + if nbBits > tablelogAbsoluteMax { + println("Invalid tablelog:", nbBits) + return errors.New("tableLog too large") + } + bitStream >>= 4 + bitCount := uint(4) + + s.actualTableLog = uint8(nbBits) + remaining := int32((1 << nbBits) + 1) + threshold := int32(1 << nbBits) + gotTotal := int32(0) + nbBits++ + + for remaining > 1 && charnum <= maxSymbol { + if previous0 { + //println("prev0") + n0 := charnum + for (bitStream & 0xFFFF) == 0xFFFF { + //println("24 x 0") + n0 += 24 + if r := b.remain(); r > 5 { + b.advance(2) + // The check above should make sure we can read 32 bits + bitStream = b.Uint32NC() >> bitCount + } else { + // end of bit stream + bitStream >>= 16 + bitCount += 16 + } + } + //printf("bitstream: %d, 0b%b", bitStream&3, bitStream) + for (bitStream & 3) == 3 { + n0 += 3 + bitStream >>= 2 + bitCount += 2 + } + n0 += uint16(bitStream & 3) + bitCount += 2 + + if n0 > maxSymbolValue { + return errors.New("maxSymbolValue too small") + } + //println("inserting ", n0-charnum, "zeroes from idx", charnum, "ending before", n0) + for charnum < n0 { + s.norm[uint8(charnum)] = 0 + charnum++ + } + + if r := b.remain(); r >= 7 || r-int(bitCount>>3) >= 4 { + b.advance(bitCount >> 3) + bitCount &= 7 + // The check above should make sure we can read 32 bits + bitStream = b.Uint32NC() >> bitCount + } else { + bitStream >>= 2 + } + } + + max := (2*threshold - 1) - remaining + var count int32 + + if int32(bitStream)&(threshold-1) < max { + count = int32(bitStream) & (threshold - 1) + if debugAsserts && nbBits < 1 { + panic("nbBits underflow") + } + bitCount += nbBits - 1 + } else { + count = int32(bitStream) & (2*threshold - 1) + if count >= threshold { + count -= max + } + bitCount += nbBits + } + + // extra accuracy + count-- + if count < 0 { + // -1 means +1 + remaining += count + gotTotal -= count + } else { + remaining -= count + gotTotal += count + } + s.norm[charnum&0xff] = int16(count) + charnum++ + previous0 = count == 0 + for remaining < threshold { + nbBits-- + threshold >>= 1 + } + + if r := b.remain(); r >= 7 || r-int(bitCount>>3) >= 4 { + b.advance(bitCount >> 3) + bitCount &= 7 + // The check above should make sure we can read 32 bits + bitStream = b.Uint32NC() >> (bitCount & 31) + } else { + bitCount -= (uint)(8 * (len(b.b) - 4 - b.off)) + b.off = len(b.b) - 4 + bitStream = b.Uint32() >> (bitCount & 31) + } + } + s.symbolLen = charnum + if s.symbolLen <= 1 { + return fmt.Errorf("symbolLen (%d) too small", s.symbolLen) + } + if s.symbolLen > maxSymbolValue+1 { + return fmt.Errorf("symbolLen (%d) too big", s.symbolLen) + } + if remaining != 1 { + return fmt.Errorf("corruption detected (remaining %d != 1)", remaining) + } + if bitCount > 32 { + return fmt.Errorf("corruption detected (bitCount %d > 32)", bitCount) + } + if gotTotal != 1<> 3) + return s.buildDtable() +} + +func (s *fseDecoder) mustReadFrom(r io.Reader) { + fatalErr := func(err error) { + if err != nil { + panic(err) + } + } + // dt [maxTablesize]decSymbol // Decompression table. + // symbolLen uint16 // Length of active part of the symbol table. + // actualTableLog uint8 // Selected tablelog. + // maxBits uint8 // Maximum number of additional bits + // // used for table creation to avoid allocations. + // stateTable [256]uint16 + // norm [maxSymbolValue + 1]int16 + // preDefined bool + fatalErr(binary.Read(r, binary.LittleEndian, &s.dt)) + fatalErr(binary.Read(r, binary.LittleEndian, &s.symbolLen)) + fatalErr(binary.Read(r, binary.LittleEndian, &s.actualTableLog)) + fatalErr(binary.Read(r, binary.LittleEndian, &s.maxBits)) + fatalErr(binary.Read(r, binary.LittleEndian, &s.stateTable)) + fatalErr(binary.Read(r, binary.LittleEndian, &s.norm)) + fatalErr(binary.Read(r, binary.LittleEndian, &s.preDefined)) +} + +// decSymbol contains information about a state entry, +// Including the state offset base, the output symbol and +// the number of bits to read for the low part of the destination state. +// Using a composite uint64 is faster than a struct with separate members. +type decSymbol uint64 + +func newDecSymbol(nbits, addBits uint8, newState uint16, baseline uint32) decSymbol { + return decSymbol(nbits) | (decSymbol(addBits) << 8) | (decSymbol(newState) << 16) | (decSymbol(baseline) << 32) +} + +func (d decSymbol) nbBits() uint8 { + return uint8(d) +} + +func (d decSymbol) addBits() uint8 { + return uint8(d >> 8) +} + +func (d decSymbol) newState() uint16 { + return uint16(d >> 16) +} + +func (d decSymbol) baselineInt() int { + return int(d >> 32) +} + +func (d *decSymbol) setNBits(nBits uint8) { + const mask = 0xffffffffffffff00 + *d = (*d & mask) | decSymbol(nBits) +} + +func (d *decSymbol) setAddBits(addBits uint8) { + const mask = 0xffffffffffff00ff + *d = (*d & mask) | (decSymbol(addBits) << 8) +} + +func (d *decSymbol) setNewState(state uint16) { + const mask = 0xffffffff0000ffff + *d = (*d & mask) | decSymbol(state)<<16 +} + +func (d *decSymbol) setExt(addBits uint8, baseline uint32) { + const mask = 0xffff00ff + *d = (*d & mask) | (decSymbol(addBits) << 8) | (decSymbol(baseline) << 32) +} + +// decSymbolValue returns the transformed decSymbol for the given symbol. +func decSymbolValue(symb uint8, t []baseOffset) (decSymbol, error) { + if int(symb) >= len(t) { + return 0, fmt.Errorf("rle symbol %d >= max %d", symb, len(t)) + } + lu := t[symb] + return newDecSymbol(0, lu.addBits, 0, lu.baseLine), nil +} + +// setRLE will set the decoder til RLE mode. +func (s *fseDecoder) setRLE(symbol decSymbol) { + s.actualTableLog = 0 + s.maxBits = symbol.addBits() + s.dt[0] = symbol +} + +// transform will transform the decoder table into a table usable for +// decoding without having to apply the transformation while decoding. +// The state will contain the base value and the number of bits to read. +func (s *fseDecoder) transform(t []baseOffset) error { + tableSize := uint16(1 << s.actualTableLog) + s.maxBits = 0 + for i, v := range s.dt[:tableSize] { + add := v.addBits() + if int(add) >= len(t) { + return fmt.Errorf("invalid decoding table entry %d, symbol %d >= max (%d)", i, v.addBits(), len(t)) + } + lu := t[add] + if lu.addBits > s.maxBits { + s.maxBits = lu.addBits + } + v.setExt(lu.addBits, lu.baseLine) + s.dt[i] = v + } + return nil +} + +type fseState struct { + dt []decSymbol + state decSymbol +} + +// Initialize and decodeAsync first state and symbol. +func (s *fseState) init(br *bitReader, tableLog uint8, dt []decSymbol) { + s.dt = dt + br.fill() + s.state = dt[br.getBits(tableLog)] +} + +// final returns the current state symbol without decoding the next. +func (s decSymbol) final() (int, uint8) { + return s.baselineInt(), s.addBits() +} diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s new file mode 100644 index 0000000..deeadc4 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_amd64.s @@ -0,0 +1,126 @@ +// Code generated by command: go run gen_fse.go -out ../fse_decoder.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT. + +//go:build !appengine && !noasm && gc && !noasm + +// func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int +TEXT ·buildDtable_asm(SB), $0-24 + MOVQ ctx+8(FP), CX + MOVQ s+0(FP), DI + + // Load values + MOVBQZX 4098(DI), DX + XORQ AX, AX + BTSQ DX, AX + MOVQ (CX), BX + MOVQ 16(CX), SI + LEAQ -1(AX), R8 + MOVQ 8(CX), CX + MOVWQZX 4096(DI), DI + + // End load values + // Init, lay down lowprob symbols + XORQ R9, R9 + JMP init_main_loop_condition + +init_main_loop: + MOVWQSX (CX)(R9*2), R10 + CMPW R10, $-1 + JNE do_not_update_high_threshold + MOVB R9, 1(SI)(R8*8) + DECQ R8 + MOVQ $0x0000000000000001, R10 + +do_not_update_high_threshold: + MOVW R10, (BX)(R9*2) + INCQ R9 + +init_main_loop_condition: + CMPQ R9, DI + JL init_main_loop + + // Spread symbols + // Calculate table step + MOVQ AX, R9 + SHRQ $0x01, R9 + MOVQ AX, R10 + SHRQ $0x03, R10 + LEAQ 3(R9)(R10*1), R9 + + // Fill add bits values + LEAQ -1(AX), R10 + XORQ R11, R11 + XORQ R12, R12 + JMP spread_main_loop_condition + +spread_main_loop: + XORQ R13, R13 + MOVWQSX (CX)(R12*2), R14 + JMP spread_inner_loop_condition + +spread_inner_loop: + MOVB R12, 1(SI)(R11*8) + +adjust_position: + ADDQ R9, R11 + ANDQ R10, R11 + CMPQ R11, R8 + JG adjust_position + INCQ R13 + +spread_inner_loop_condition: + CMPQ R13, R14 + JL spread_inner_loop + INCQ R12 + +spread_main_loop_condition: + CMPQ R12, DI + JL spread_main_loop + TESTQ R11, R11 + JZ spread_check_ok + MOVQ ctx+8(FP), AX + MOVQ R11, 24(AX) + MOVQ $+1, ret+16(FP) + RET + +spread_check_ok: + // Build Decoding table + XORQ DI, DI + +build_table_main_table: + MOVBQZX 1(SI)(DI*8), CX + MOVWQZX (BX)(CX*2), R8 + LEAQ 1(R8), R9 + MOVW R9, (BX)(CX*2) + MOVQ R8, R9 + BSRQ R9, R9 + MOVQ DX, CX + SUBQ R9, CX + SHLQ CL, R8 + SUBQ AX, R8 + MOVB CL, (SI)(DI*8) + MOVW R8, 2(SI)(DI*8) + CMPQ R8, AX + JLE build_table_check1_ok + MOVQ ctx+8(FP), CX + MOVQ R8, 24(CX) + MOVQ AX, 32(CX) + MOVQ $+2, ret+16(FP) + RET + +build_table_check1_ok: + TESTB CL, CL + JNZ build_table_check2_ok + CMPW R8, DI + JNE build_table_check2_ok + MOVQ ctx+8(FP), AX + MOVQ R8, 24(AX) + MOVQ DI, 32(AX) + MOVQ $+3, ret+16(FP) + RET + +build_table_check2_ok: + INCQ DI + CMPQ DI, AX + JL build_table_main_table + MOVQ $+0, ret+16(FP) + RET diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s b/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s new file mode 100644 index 0000000..77ee391 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_arm64.s @@ -0,0 +1,153 @@ +// Code generated by command: go run gen_fse.go -out ../fse_decoder.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT. +// EXPERIMENTAL arm64 output lowered from an amd64 avo program. + +//go:build arm64 && !appengine && !noasm && gc && !noasm + +// func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int +TEXT ·buildDtable_asm(SB), $0-24 + MOVD ctx+8(FP), R1 + MOVD s+0(FP), R6 + + // Load values + MOVBU 4098(R6), R2 + MOVD $0, R0 + MOVD $1, R16 + LSL R2, R16, R16 + ORR R16, R0, R0 + MOVD (R1), R3 + MOVD 16(R1), R5 + SUB $1, R0, R7 + MOVD 8(R1), R1 + MOVHU 4096(R6), R6 + + // End load values + // Init, lay down lowprob symbols + MOVD $0, R8 + JMP init_main_loop_condition + +init_main_loop: + ADD R8<<1, R1, R15 + MOVH (R15), R9 + AND $0xffff, R9, R15 + MOVD $-1, R16 + AND $0xffff, R16, R16 + CMP R16, R15 + BNE do_not_update_high_threshold + ADD R7<<3, R5, R15 + MOVB R8, 1(R15) + SUB $1, R7, R7 + MOVD $0x0000000000000001, R9 + +do_not_update_high_threshold: + ADD R8<<1, R3, R15 + MOVH R9, (R15) + ADD $1, R8, R8 + +init_main_loop_condition: + CMP R6, R8 + BLT init_main_loop + + // Spread symbols + // Calculate table step + MOVD R0, R8 + LSR $0x01, R8, R8 + MOVD R0, R9 + LSR $0x03, R9, R9 + ADD R9, R8, R8 + ADD $3, R8, R8 + + // Fill add bits values + SUB $1, R0, R9 + MOVD $0, R10 + MOVD $0, R11 + JMP spread_main_loop_condition + +spread_main_loop: + MOVD $0, R12 + ADD R11<<1, R1, R15 + MOVH (R15), R13 + JMP spread_inner_loop_condition + +spread_inner_loop: + ADD R10<<3, R5, R15 + MOVB R11, 1(R15) + +adjust_position: + ADD R8, R10, R10 + AND R9, R10, R10 + CMP R7, R10 + BGT adjust_position + ADD $1, R12, R12 + +spread_inner_loop_condition: + CMP R13, R12 + BLT spread_inner_loop + ADD $1, R11, R11 + +spread_main_loop_condition: + CMP R6, R11 + BLT spread_main_loop + TST R10, R10 + BEQ spread_check_ok + MOVD ctx+8(FP), R0 + MOVD R10, 24(R0) + MOVD $+1, R16 + MOVD R16, ret+16(FP) + RET + +spread_check_ok: + // Build Decoding table + MOVD $0, R6 + +build_table_main_table: + ADD R6<<3, R5, R15 + MOVBU 1(R15), R1 + ADD R1<<1, R3, R15 + MOVHU (R15), R7 + ADD $1, R7, R8 + ADD R1<<1, R3, R15 + MOVH R8, (R15) + MOVD R7, R8 + CLZ R8, R16 + MOVD $63, R8 + SUB R16, R8, R8 + MOVD R2, R1 + SUB R8, R1, R1 + LSL R1, R7, R7 + SUB R0, R7, R7 + ADD R6<<3, R5, R15 + MOVB R1, (R15) + ADD R6<<3, R5, R15 + MOVH R7, 2(R15) + CMP R0, R7 + BLE build_table_check1_ok + MOVD ctx+8(FP), R1 + MOVD R7, 24(R1) + MOVD R0, 32(R1) + MOVD $+2, R16 + MOVD R16, ret+16(FP) + RET + +build_table_check1_ok: + AND $0xff, R1, R15 + AND $0xff, R1, R16 + TST R16, R15 + BNE build_table_check2_ok + AND $0xffff, R7, R15 + AND $0xffff, R6, R16 + CMP R16, R15 + BNE build_table_check2_ok + MOVD ctx+8(FP), R0 + MOVD R7, 24(R0) + MOVD R6, 32(R0) + MOVD $+3, R16 + MOVD R16, ret+16(FP) + RET + +build_table_check2_ok: + ADD $1, R6, R6 + CMP R0, R6 + BLT build_table_main_table + MOVD $+0, R16 + MOVD R16, ret+16(FP) + RET diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_asm.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_asm.go new file mode 100644 index 0000000..4ffc7e3 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_asm.go @@ -0,0 +1,68 @@ +//go:build (amd64 || arm64) && !appengine && !noasm && gc + +package zstd + +import ( + "fmt" +) + +// buildDtable_asm is generated by _generate/gen_fse.go and lowered to each +// architecture (amd64 by goasm, arm64 by the avo arm64 lowering printer). The +// Go side is identical across architectures, so it lives here. + +type buildDtableAsmContext struct { + // inputs + stateTable *uint16 + norm *int16 + dt *uint64 + + // outputs --- set by the procedure in the case of error; + // for interpretation please see the error handling part below + errParam1 uint64 + errParam2 uint64 +} + +// buildDtable_asm is an assembly implementation of fseDecoder.buildDtable. +// Function returns non-zero exit code on error. +// +//go:noescape +func buildDtable_asm(s *fseDecoder, ctx *buildDtableAsmContext) int + +// please keep in sync with _generate/gen_fse.go +const ( + errorCorruptedNormalizedCounter = 1 + errorNewStateTooBig = 2 + errorNewStateNoBits = 3 +) + +// buildDtable will build the decoding table. +func (s *fseDecoder) buildDtable() error { + ctx := buildDtableAsmContext{ + stateTable: &s.stateTable[0], + norm: &s.norm[0], + dt: (*uint64)(&s.dt[0]), + } + code := buildDtable_asm(s, &ctx) + + if code != 0 { + switch code { + case errorCorruptedNormalizedCounter: + position := ctx.errParam1 + return fmt.Errorf("corrupted input (position=%d, expected 0)", position) + + case errorNewStateTooBig: + newState := decSymbol(ctx.errParam1) + size := ctx.errParam2 + return fmt.Errorf("newState (%d) outside table size (%d)", newState, size) + + case errorNewStateNoBits: + newState := decSymbol(ctx.errParam1) + oldState := decSymbol(ctx.errParam2) + return fmt.Errorf("newState (%d) == oldState (%d) and no bits", newState, oldState) + + default: + return fmt.Errorf("buildDtable_asm returned unhandled nonzero code = %d", code) + } + } + return nil +} diff --git a/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go new file mode 100644 index 0000000..38fd2cc --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/fse_decoder_generic.go @@ -0,0 +1,72 @@ +//go:build (!amd64 && !arm64) || appengine || !gc || noasm + +package zstd + +import ( + "errors" + "fmt" +) + +// buildDtable will build the decoding table. +func (s *fseDecoder) buildDtable() error { + tableSize := uint32(1 << s.actualTableLog) + highThreshold := tableSize - 1 + symbolNext := s.stateTable[:256] + + // Init, lay down lowprob symbols + { + for i, v := range s.norm[:s.symbolLen] { + if v == -1 { + s.dt[highThreshold].setAddBits(uint8(i)) + highThreshold-- + v = 1 + } + symbolNext[i] = uint16(v) + } + } + + // Spread symbols + { + tableMask := tableSize - 1 + step := tableStep(tableSize) + position := uint32(0) + for ss, v := range s.norm[:s.symbolLen] { + for i := 0; i < int(v); i++ { + s.dt[position].setAddBits(uint8(ss)) + for { + // lowprob area + position = (position + step) & tableMask + if position <= highThreshold { + break + } + } + } + } + if position != 0 { + // position must reach all cells once, otherwise normalizedCounter is incorrect + return errors.New("corrupted input (position != 0)") + } + } + + // Build Decoding table + { + tableSize := uint16(1 << s.actualTableLog) + for u, v := range s.dt[:tableSize] { + symbol := v.addBits() + nextState := symbolNext[symbol] + symbolNext[symbol] = nextState + 1 + nBits := s.actualTableLog - byte(highBits(uint32(nextState))) + s.dt[u&maxTableMask].setNBits(nBits) + newState := (nextState << nBits) - tableSize + if newState > tableSize { + return fmt.Errorf("newState (%d) outside table size (%d)", newState, tableSize) + } + if newState == uint16(u) && nBits == 0 { + // Seems weird that this is possible with nbits > 0. + return fmt.Errorf("newState (%d) == oldState (%d) and no bits", newState, u) + } + s.dt[u&maxTableMask].setNewState(newState) + } + } + return nil +} diff --git a/vendor/github.com/klauspost/compress/zstd/fse_encoder.go b/vendor/github.com/klauspost/compress/zstd/fse_encoder.go new file mode 100644 index 0000000..3a0f4e7 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/fse_encoder.go @@ -0,0 +1,701 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "errors" + "fmt" + "math" +) + +const ( + // For encoding we only support up to + maxEncTableLog = 8 + maxEncTablesize = 1 << maxTableLog + maxEncTableMask = (1 << maxTableLog) - 1 + minEncTablelog = 5 + maxEncSymbolValue = maxMatchLengthSymbol +) + +// Scratch provides temporary storage for compression and decompression. +type fseEncoder struct { + symbolLen uint16 // Length of active part of the symbol table. + actualTableLog uint8 // Selected tablelog. + ct cTable // Compression tables. + maxCount int // count of the most probable symbol + zeroBits bool // no bits has prob > 50%. + clearCount bool // clear count + useRLE bool // This encoder is for RLE + preDefined bool // This encoder is predefined. + reUsed bool // Set to know when the encoder has been reused. + rleVal uint8 // RLE Symbol + maxBits uint8 // Maximum output bits after transform. + + // TODO: Technically zstd should be fine with 64 bytes. + count [256]uint32 + norm [256]int16 +} + +// cTable contains tables used for compression. +type cTable struct { + tableSymbol []byte + stateTable []uint16 + symbolTT []symbolTransform +} + +// symbolTransform contains the state transform for a symbol. +type symbolTransform struct { + deltaNbBits uint32 + deltaFindState int16 + outBits uint8 +} + +// String prints values as a human readable string. +func (s symbolTransform) String() string { + return fmt.Sprintf("{deltabits: %08x, findstate:%d outbits:%d}", s.deltaNbBits, s.deltaFindState, s.outBits) +} + +// Histogram allows to populate the histogram and skip that step in the compression, +// It otherwise allows to inspect the histogram when compression is done. +// To indicate that you have populated the histogram call HistogramFinished +// with the value of the highest populated symbol, as well as the number of entries +// in the most populated entry. These are accepted at face value. +func (s *fseEncoder) Histogram() *[256]uint32 { + return &s.count +} + +// HistogramFinished can be called to indicate that the histogram has been populated. +// maxSymbol is the index of the highest set symbol of the next data segment. +// maxCount is the number of entries in the most populated entry. +// These are accepted at face value. +func (s *fseEncoder) HistogramFinished(maxSymbol uint8, maxCount int) { + s.maxCount = maxCount + s.symbolLen = uint16(maxSymbol) + 1 + s.clearCount = maxCount != 0 +} + +// allocCtable will allocate tables needed for compression. +// If existing tables a re big enough, they are simply re-used. +func (s *fseEncoder) allocCtable() { + tableSize := 1 << s.actualTableLog + // get tableSymbol that is big enough. + if cap(s.ct.tableSymbol) < tableSize { + s.ct.tableSymbol = make([]byte, tableSize) + } + s.ct.tableSymbol = s.ct.tableSymbol[:tableSize] + + ctSize := tableSize + if cap(s.ct.stateTable) < ctSize { + s.ct.stateTable = make([]uint16, ctSize) + } + s.ct.stateTable = s.ct.stateTable[:ctSize] + + if cap(s.ct.symbolTT) < 256 { + s.ct.symbolTT = make([]symbolTransform, 256) + } + s.ct.symbolTT = s.ct.symbolTT[:256] +} + +// buildCTable will populate the compression table so it is ready to be used. +func (s *fseEncoder) buildCTable() error { + tableSize := uint32(1 << s.actualTableLog) + highThreshold := tableSize - 1 + var cumul [256]int16 + + s.allocCtable() + tableSymbol := s.ct.tableSymbol[:tableSize] + // symbol start positions + { + cumul[0] = 0 + for ui, v := range s.norm[:s.symbolLen-1] { + u := byte(ui) // one less than reference + if v == -1 { + // Low proba symbol + cumul[u+1] = cumul[u] + 1 + tableSymbol[highThreshold] = u + highThreshold-- + } else { + cumul[u+1] = cumul[u] + v + } + } + // Encode last symbol separately to avoid overflowing u + u := int(s.symbolLen - 1) + v := s.norm[s.symbolLen-1] + if v == -1 { + // Low proba symbol + cumul[u+1] = cumul[u] + 1 + tableSymbol[highThreshold] = byte(u) + highThreshold-- + } else { + cumul[u+1] = cumul[u] + v + } + if uint32(cumul[s.symbolLen]) != tableSize { + return fmt.Errorf("internal error: expected cumul[s.symbolLen] (%d) == tableSize (%d)", cumul[s.symbolLen], tableSize) + } + cumul[s.symbolLen] = int16(tableSize) + 1 + } + // Spread symbols + s.zeroBits = false + { + step := tableStep(tableSize) + tableMask := tableSize - 1 + var position uint32 + // if any symbol > largeLimit, we may have 0 bits output. + largeLimit := int16(1 << (s.actualTableLog - 1)) + for ui, v := range s.norm[:s.symbolLen] { + symbol := byte(ui) + if v > largeLimit { + s.zeroBits = true + } + for range v { + tableSymbol[position] = symbol + position = (position + step) & tableMask + for position > highThreshold { + position = (position + step) & tableMask + } /* Low proba area */ + } + } + + // Check if we have gone through all positions + if position != 0 { + return errors.New("position!=0") + } + } + + // Build table + table := s.ct.stateTable + { + tsi := int(tableSize) + for u, v := range tableSymbol { + // TableU16 : sorted by symbol order; gives next state value + table[cumul[v]] = uint16(tsi + u) + cumul[v]++ + } + } + + // Build Symbol Transformation Table + { + total := int16(0) + symbolTT := s.ct.symbolTT[:s.symbolLen] + tableLog := s.actualTableLog + tl := (uint32(tableLog) << 16) - (1 << tableLog) + for i, v := range s.norm[:s.symbolLen] { + switch v { + case 0: + case -1, 1: + symbolTT[i].deltaNbBits = tl + symbolTT[i].deltaFindState = total - 1 + total++ + default: + maxBitsOut := uint32(tableLog) - highBit(uint32(v-1)) + minStatePlus := uint32(v) << maxBitsOut + symbolTT[i].deltaNbBits = (maxBitsOut << 16) - minStatePlus + symbolTT[i].deltaFindState = total - v + total += v + } + } + if total != int16(tableSize) { + return fmt.Errorf("total mismatch %d (got) != %d (want)", total, tableSize) + } + } + return nil +} + +var rtbTable = [...]uint32{0, 473195, 504333, 520860, 550000, 700000, 750000, 830000} + +func (s *fseEncoder) setRLE(val byte) { + s.allocCtable() + s.actualTableLog = 0 + s.ct.stateTable = s.ct.stateTable[:1] + s.ct.symbolTT[val] = symbolTransform{ + deltaFindState: 0, + deltaNbBits: 0, + } + if debugEncoder { + println("setRLE: val", val, "symbolTT", s.ct.symbolTT[val]) + } + s.rleVal = val + s.useRLE = true +} + +// setBits will set output bits for the transform. +// if nil is provided, the number of bits is equal to the index. +func (s *fseEncoder) setBits(transform []byte) { + if s.reUsed || s.preDefined { + return + } + if s.useRLE { + if transform == nil { + s.ct.symbolTT[s.rleVal].outBits = s.rleVal + s.maxBits = s.rleVal + return + } + s.maxBits = transform[s.rleVal] + s.ct.symbolTT[s.rleVal].outBits = s.maxBits + return + } + if transform == nil { + for i := range s.ct.symbolTT[:s.symbolLen] { + s.ct.symbolTT[i].outBits = uint8(i) + } + s.maxBits = uint8(s.symbolLen - 1) + return + } + s.maxBits = 0 + for i, v := range transform[:s.symbolLen] { + s.ct.symbolTT[i].outBits = v + if v > s.maxBits { + // We could assume bits always going up, but we play safe. + s.maxBits = v + } + } +} + +// normalizeCount will normalize the count of the symbols so +// the total is equal to the table size. +// If successful, compression tables will also be made ready. +func (s *fseEncoder) normalizeCount(length int) error { + if s.reUsed { + return nil + } + s.optimalTableLog(length) + var ( + tableLog = s.actualTableLog + scale = 62 - uint64(tableLog) + step = (1 << 62) / uint64(length) + vStep = uint64(1) << (scale - 20) + stillToDistribute = int16(1 << tableLog) + largest int + largestP int16 + lowThreshold = (uint32)(length >> tableLog) + ) + if s.maxCount == length { + s.useRLE = true + return nil + } + s.useRLE = false + for i, cnt := range s.count[:s.symbolLen] { + // already handled + // if (count[s] == s.length) return 0; /* rle special case */ + + if cnt == 0 { + s.norm[i] = 0 + continue + } + if cnt <= lowThreshold { + s.norm[i] = -1 + stillToDistribute-- + } else { + proba := (int16)((uint64(cnt) * step) >> scale) + if proba < 8 { + restToBeat := vStep * uint64(rtbTable[proba]) + v := uint64(cnt)*step - (uint64(proba) << scale) + if v > restToBeat { + proba++ + } + } + if proba > largestP { + largestP = proba + largest = i + } + s.norm[i] = proba + stillToDistribute -= proba + } + } + + if -stillToDistribute >= (s.norm[largest] >> 1) { + // corner case, need another normalization method + err := s.normalizeCount2(length) + if err != nil { + return err + } + if debugAsserts { + err = s.validateNorm() + if err != nil { + return err + } + } + return s.buildCTable() + } + s.norm[largest] += stillToDistribute + if debugAsserts { + err := s.validateNorm() + if err != nil { + return err + } + } + return s.buildCTable() +} + +// Secondary normalization method. +// To be used when primary method fails. +func (s *fseEncoder) normalizeCount2(length int) error { + const notYetAssigned = -2 + var ( + distributed uint32 + total = uint32(length) + tableLog = s.actualTableLog + lowThreshold = total >> tableLog + lowOne = (total * 3) >> (tableLog + 1) + ) + for i, cnt := range s.count[:s.symbolLen] { + if cnt == 0 { + s.norm[i] = 0 + continue + } + if cnt <= lowThreshold { + s.norm[i] = -1 + distributed++ + total -= cnt + continue + } + if cnt <= lowOne { + s.norm[i] = 1 + distributed++ + total -= cnt + continue + } + s.norm[i] = notYetAssigned + } + toDistribute := (1 << tableLog) - distributed + + if (total / toDistribute) > lowOne { + // risk of rounding to zero + lowOne = (total * 3) / (toDistribute * 2) + for i, cnt := range s.count[:s.symbolLen] { + if (s.norm[i] == notYetAssigned) && (cnt <= lowOne) { + s.norm[i] = 1 + distributed++ + total -= cnt + continue + } + } + toDistribute = (1 << tableLog) - distributed + } + if distributed == uint32(s.symbolLen)+1 { + // all values are pretty poor; + // probably incompressible data (should have already been detected); + // find max, then give all remaining points to max + var maxV int + var maxC uint32 + for i, cnt := range s.count[:s.symbolLen] { + if cnt > maxC { + maxV = i + maxC = cnt + } + } + s.norm[maxV] += int16(toDistribute) + return nil + } + + if total == 0 { + // all of the symbols were low enough for the lowOne or lowThreshold + for i := uint32(0); toDistribute > 0; i = (i + 1) % (uint32(s.symbolLen)) { + if s.norm[i] > 0 { + toDistribute-- + s.norm[i]++ + } + } + return nil + } + + var ( + vStepLog = 62 - uint64(tableLog) + mid = uint64((1 << (vStepLog - 1)) - 1) + rStep = (((1 << vStepLog) * uint64(toDistribute)) + mid) / uint64(total) // scale on remaining + tmpTotal = mid + ) + for i, cnt := range s.count[:s.symbolLen] { + if s.norm[i] == notYetAssigned { + var ( + end = tmpTotal + uint64(cnt)*rStep + sStart = uint32(tmpTotal >> vStepLog) + sEnd = uint32(end >> vStepLog) + weight = sEnd - sStart + ) + if weight < 1 { + return errors.New("weight < 1") + } + s.norm[i] = int16(weight) + tmpTotal = end + } + } + return nil +} + +// optimalTableLog calculates and sets the optimal tableLog in s.actualTableLog +func (s *fseEncoder) optimalTableLog(length int) { + tableLog := uint8(maxEncTableLog) + minBitsSrc := highBit(uint32(length)) + 1 + minBitsSymbols := highBit(uint32(s.symbolLen-1)) + 2 + minBits := uint8(minBitsSymbols) + if minBitsSrc < minBitsSymbols { + minBits = uint8(minBitsSrc) + } + + maxBitsSrc := uint8(highBit(uint32(length-1))) - 2 + if maxBitsSrc < tableLog { + // Accuracy can be reduced + tableLog = maxBitsSrc + } + if minBits > tableLog { + tableLog = minBits + } + // Need a minimum to safely represent all symbol values + if tableLog < minEncTablelog { + tableLog = minEncTablelog + } + if tableLog > maxEncTableLog { + tableLog = maxEncTableLog + } + s.actualTableLog = tableLog +} + +// validateNorm validates the normalized histogram table. +func (s *fseEncoder) validateNorm() (err error) { + var total int + for _, v := range s.norm[:s.symbolLen] { + if v >= 0 { + total += int(v) + } else { + total -= int(v) + } + } + defer func() { + if err == nil { + return + } + fmt.Printf("selected TableLog: %d, Symbol length: %d\n", s.actualTableLog, s.symbolLen) + for i, v := range s.norm[:s.symbolLen] { + fmt.Printf("%3d: %5d -> %4d \n", i, s.count[i], v) + } + }() + if total != (1 << s.actualTableLog) { + return fmt.Errorf("warning: Total == %d != %d", total, 1<> 3) + 3 + 2 + + // Write Table Size + bitStream = uint32(tableLog - minEncTablelog) + bitCount = uint(4) + remaining = int16(tableSize + 1) /* +1 for extra accuracy */ + threshold = int16(tableSize) + nbBits = uint(tableLog + 1) + outP = len(out) + ) + if cap(out) < outP+maxHeaderSize { + out = append(out, make([]byte, maxHeaderSize*3)...) + out = out[:len(out)-maxHeaderSize*3] + } + out = out[:outP+maxHeaderSize] + + // stops at 1 + for remaining > 1 { + if previous0 { + start := charnum + for s.norm[charnum] == 0 { + charnum++ + } + for charnum >= start+24 { + start += 24 + bitStream += uint32(0xFFFF) << bitCount + out[outP] = byte(bitStream) + out[outP+1] = byte(bitStream >> 8) + outP += 2 + bitStream >>= 16 + } + for charnum >= start+3 { + start += 3 + bitStream += 3 << bitCount + bitCount += 2 + } + bitStream += uint32(charnum-start) << bitCount + bitCount += 2 + if bitCount > 16 { + out[outP] = byte(bitStream) + out[outP+1] = byte(bitStream >> 8) + outP += 2 + bitStream >>= 16 + bitCount -= 16 + } + } + + count := s.norm[charnum] + charnum++ + max := (2*threshold - 1) - remaining + if count < 0 { + remaining += count + } else { + remaining -= count + } + count++ // +1 for extra accuracy + if count >= threshold { + count += max // [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ + } + bitStream += uint32(count) << bitCount + bitCount += nbBits + if count < max { + bitCount-- + } + + previous0 = count == 1 + if remaining < 1 { + return nil, errors.New("internal error: remaining < 1") + } + for remaining < threshold { + nbBits-- + threshold >>= 1 + } + + if bitCount > 16 { + out[outP] = byte(bitStream) + out[outP+1] = byte(bitStream >> 8) + outP += 2 + bitStream >>= 16 + bitCount -= 16 + } + } + + if outP+2 > len(out) { + return nil, fmt.Errorf("internal error: %d > %d, maxheader: %d, sl: %d, tl: %d, normcount: %v", outP+2, len(out), maxHeaderSize, s.symbolLen, int(tableLog), s.norm[:s.symbolLen]) + } + out[outP] = byte(bitStream) + out[outP+1] = byte(bitStream >> 8) + outP += int((bitCount + 7) / 8) + + if charnum > s.symbolLen { + return nil, errors.New("internal error: charnum > s.symbolLen") + } + return out[:outP], nil +} + +// Approximate symbol cost, as fractional value, using fixed-point format (accuracyLog fractional bits) +// note 1 : assume symbolValue is valid (<= maxSymbolValue) +// note 2 : if freq[symbolValue]==0, @return a fake cost of tableLog+1 bits * +func (s *fseEncoder) bitCost(symbolValue uint8, accuracyLog uint32) uint32 { + minNbBits := s.ct.symbolTT[symbolValue].deltaNbBits >> 16 + threshold := (minNbBits + 1) << 16 + if debugAsserts { + if !(s.actualTableLog < 16) { + panic("!s.actualTableLog < 16") + } + // ensure enough room for renormalization double shift + if !(uint8(accuracyLog) < 31-s.actualTableLog) { + panic("!uint8(accuracyLog) < 31-s.actualTableLog") + } + } + tableSize := uint32(1) << s.actualTableLog + deltaFromThreshold := threshold - (s.ct.symbolTT[symbolValue].deltaNbBits + tableSize) + // linear interpolation (very approximate) + normalizedDeltaFromThreshold := (deltaFromThreshold << accuracyLog) >> s.actualTableLog + bitMultiplier := uint32(1) << accuracyLog + if debugAsserts { + if s.ct.symbolTT[symbolValue].deltaNbBits+tableSize > threshold { + panic("s.ct.symbolTT[symbolValue].deltaNbBits+tableSize > threshold") + } + if normalizedDeltaFromThreshold > bitMultiplier { + panic("normalizedDeltaFromThreshold > bitMultiplier") + } + } + return (minNbBits+1)*bitMultiplier - normalizedDeltaFromThreshold +} + +// Returns the cost in bits of encoding the distribution in count using ctable. +// Histogram should only be up to the last non-zero symbol. +// Returns an -1 if ctable cannot represent all the symbols in count. +func (s *fseEncoder) approxSize(hist []uint32) uint32 { + if int(s.symbolLen) < len(hist) { + // More symbols than we have. + return math.MaxUint32 + } + if s.useRLE { + // We will never reuse RLE encoders. + return math.MaxUint32 + } + const kAccuracyLog = 8 + badCost := (uint32(s.actualTableLog) + 1) << kAccuracyLog + var cost uint32 + for i, v := range hist { + if v == 0 { + continue + } + if s.norm[i] == 0 { + return math.MaxUint32 + } + bitCost := s.bitCost(uint8(i), kAccuracyLog) + if bitCost > badCost { + return math.MaxUint32 + } + cost += v * bitCost + } + return cost >> kAccuracyLog +} + +// maxHeaderSize returns the maximum header size in bits. +// This is not exact size, but we want a penalty for new tables anyway. +func (s *fseEncoder) maxHeaderSize() uint32 { + if s.preDefined { + return 0 + } + if s.useRLE { + return 8 + } + return (((uint32(s.symbolLen) * uint32(s.actualTableLog)) >> 3) + 3) * 8 +} + +// cState contains the compression state of a stream. +type cState struct { + bw *bitWriter + stateTable []uint16 + state uint16 +} + +// init will initialize the compression state to the first symbol of the stream. +func (c *cState) init(bw *bitWriter, ct *cTable, first symbolTransform) { + c.bw = bw + c.stateTable = ct.stateTable + if len(c.stateTable) == 1 { + // RLE + c.stateTable[0] = uint16(0) + c.state = 0 + return + } + nbBitsOut := (first.deltaNbBits + (1 << 15)) >> 16 + im := int32((nbBitsOut << 16) - first.deltaNbBits) + lu := (im >> nbBitsOut) + int32(first.deltaFindState) + c.state = c.stateTable[lu] +} + +// flush will write the tablelog to the output and flush the remaining full bytes. +func (c *cState) flush(tableLog uint8) { + c.bw.flush32() + c.bw.addBits16NC(c.state, tableLog) +} diff --git a/vendor/github.com/klauspost/compress/zstd/fse_predefined.go b/vendor/github.com/klauspost/compress/zstd/fse_predefined.go new file mode 100644 index 0000000..474cb77 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/fse_predefined.go @@ -0,0 +1,158 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "fmt" + "math" + "sync" +) + +var ( + // fsePredef are the predefined fse tables as defined here: + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#default-distributions + // These values are already transformed. + fsePredef [3]fseDecoder + + // fsePredefEnc are the predefined encoder based on fse tables as defined here: + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#default-distributions + // These values are already transformed. + fsePredefEnc [3]fseEncoder + + // symbolTableX contain the transformations needed for each type as defined in + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#the-codes-for-literals-lengths-match-lengths-and-offsets + symbolTableX [3][]baseOffset + + // maxTableSymbol is the biggest supported symbol for each table type + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#the-codes-for-literals-lengths-match-lengths-and-offsets + maxTableSymbol = [3]uint8{tableLiteralLengths: maxLiteralLengthSymbol, tableOffsets: maxOffsetLengthSymbol, tableMatchLengths: maxMatchLengthSymbol} + + // bitTables is the bits table for each table. + bitTables = [3][]byte{tableLiteralLengths: llBitsTable[:], tableOffsets: nil, tableMatchLengths: mlBitsTable[:]} +) + +type tableIndex uint8 + +const ( + // indexes for fsePredef and symbolTableX + tableLiteralLengths tableIndex = 0 + tableOffsets tableIndex = 1 + tableMatchLengths tableIndex = 2 + + maxLiteralLengthSymbol = 35 + maxOffsetLengthSymbol = 30 + maxMatchLengthSymbol = 52 +) + +// baseOffset is used for calculating transformations. +type baseOffset struct { + baseLine uint32 + addBits uint8 +} + +// fillBase will precalculate base offsets with the given bit distributions. +func fillBase(dst []baseOffset, base uint32, bits ...uint8) { + if len(bits) != len(dst) { + panic(fmt.Sprintf("len(dst) (%d) != len(bits) (%d)", len(dst), len(bits))) + } + for i, bit := range bits { + if base > math.MaxInt32 { + panic("invalid decoding table, base overflows int32") + } + + dst[i] = baseOffset{ + baseLine: base, + addBits: bit, + } + base += 1 << bit + } +} + +var predef sync.Once + +func initPredefined() { + predef.Do(func() { + // Literals length codes + tmp := make([]baseOffset, 36) + for i := range tmp[:16] { + tmp[i] = baseOffset{ + baseLine: uint32(i), + addBits: 0, + } + } + fillBase(tmp[16:], 16, 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + symbolTableX[tableLiteralLengths] = tmp + + // Match length codes + tmp = make([]baseOffset, 53) + for i := range tmp[:32] { + tmp[i] = baseOffset{ + // The transformation adds the 3 length. + baseLine: uint32(i) + 3, + addBits: 0, + } + } + fillBase(tmp[32:], 35, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + symbolTableX[tableMatchLengths] = tmp + + // Offset codes + tmp = make([]baseOffset, maxOffsetBits+1) + tmp[1] = baseOffset{ + baseLine: 1, + addBits: 1, + } + fillBase(tmp[2:], 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30) + symbolTableX[tableOffsets] = tmp + + // Fill predefined tables and transform them. + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#default-distributions + for i := range fsePredef[:] { + f := &fsePredef[i] + switch tableIndex(i) { + case tableLiteralLengths: + // https://github.com/facebook/zstd/blob/ededcfca57366461021c922720878c81a5854a0a/lib/decompress/zstd_decompress_block.c#L243 + f.actualTableLog = 6 + copy(f.norm[:], []int16{4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, + -1, -1, -1, -1}) + f.symbolLen = 36 + case tableOffsets: + // https://github.com/facebook/zstd/blob/ededcfca57366461021c922720878c81a5854a0a/lib/decompress/zstd_decompress_block.c#L281 + f.actualTableLog = 5 + copy(f.norm[:], []int16{ + 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1}) + f.symbolLen = 29 + case tableMatchLengths: + //https://github.com/facebook/zstd/blob/ededcfca57366461021c922720878c81a5854a0a/lib/decompress/zstd_decompress_block.c#L304 + f.actualTableLog = 6 + copy(f.norm[:], []int16{ + 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, + -1, -1, -1, -1, -1}) + f.symbolLen = 53 + } + if err := f.buildDtable(); err != nil { + panic(fmt.Errorf("building table %v: %v", tableIndex(i), err)) + } + if err := f.transform(symbolTableX[i]); err != nil { + panic(fmt.Errorf("building table %v: %v", tableIndex(i), err)) + } + f.preDefined = true + + // Create encoder as well + enc := &fsePredefEnc[i] + copy(enc.norm[:], f.norm[:]) + enc.symbolLen = f.symbolLen + enc.actualTableLog = f.actualTableLog + if err := enc.buildCTable(); err != nil { + panic(fmt.Errorf("building encoding table %v: %v", tableIndex(i), err)) + } + enc.setBits(bitTables[i]) + enc.preDefined = true + } + }) +} diff --git a/vendor/github.com/klauspost/compress/zstd/hash.go b/vendor/github.com/klauspost/compress/zstd/hash.go new file mode 100644 index 0000000..5d73c21 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/hash.go @@ -0,0 +1,35 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +const ( + prime3bytes = 506832829 + prime4bytes = 2654435761 + prime5bytes = 889523592379 + prime6bytes = 227718039650203 + prime7bytes = 58295818150454627 + prime8bytes = 0xcf1bbcdcb7a56463 +) + +// hashLen returns a hash of the lowest mls bytes of with length output bits. +// mls must be >=3 and <=8. Any other value will return hash for 4 bytes. +// length should always be < 32. +// Preferably length and mls should be a constant for inlining. +func hashLen(u uint64, length, mls uint8) uint32 { + switch mls { + case 3: + return (uint32(u<<8) * prime3bytes) >> (32 - length) + case 5: + return uint32(((u << (64 - 40)) * prime5bytes) >> (64 - length)) + case 6: + return uint32(((u << (64 - 48)) * prime6bytes) >> (64 - length)) + case 7: + return uint32(((u << (64 - 56)) * prime7bytes) >> (64 - length)) + case 8: + return uint32((u * prime8bytes) >> (64 - length)) + default: + return (uint32(u) * prime4bytes) >> (32 - length) + } +} diff --git a/vendor/github.com/klauspost/compress/zstd/history.go b/vendor/github.com/klauspost/compress/zstd/history.go new file mode 100644 index 0000000..0916485 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/history.go @@ -0,0 +1,116 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "github.com/klauspost/compress/huff0" +) + +// history contains the information transferred between blocks. +type history struct { + // Literal decompression + huffTree *huff0.Scratch + + // Sequence decompression + decoders sequenceDecs + recentOffsets [3]int + + // History buffer... + b []byte + + // ignoreBuffer is meant to ignore a number of bytes + // when checking for matches in history + ignoreBuffer int + + windowSize int + allocFrameBuffer int // needed? + error bool + dict *dict +} + +// reset will reset the history to initial state of a frame. +// The history must already have been initialized to the desired size. +func (h *history) reset() { + h.b = h.b[:0] + h.ignoreBuffer = 0 + h.error = false + h.recentOffsets = [3]int{1, 4, 8} + h.decoders.freeDecoders() + h.decoders = sequenceDecs{br: h.decoders.br} + h.freeHuffDecoder() + h.huffTree = nil + h.dict = nil + //printf("history created: %+v (l: %d, c: %d)", *h, len(h.b), cap(h.b)) +} + +func (h *history) freeHuffDecoder() { + if h.huffTree != nil { + if h.dict == nil || h.dict.litEnc != h.huffTree { + huffDecoderPool.Put(h.huffTree) + h.huffTree = nil + } + } +} + +func (h *history) setDict(dict *dict) { + if dict == nil { + return + } + h.dict = dict + h.decoders.litLengths = dict.llDec + h.decoders.offsets = dict.ofDec + h.decoders.matchLengths = dict.mlDec + h.decoders.dict = dict.content + h.recentOffsets = dict.offsets + h.huffTree = dict.litEnc +} + +// append bytes to history. +// This function will make sure there is space for it, +// if the buffer has been allocated with enough extra space. +func (h *history) append(b []byte) { + if len(b) >= h.windowSize { + // Discard all history by simply overwriting + h.b = h.b[:h.windowSize] + copy(h.b, b[len(b)-h.windowSize:]) + return + } + + // If there is space, append it. + if len(b) < cap(h.b)-len(h.b) { + h.b = append(h.b, b...) + return + } + + // Move data down so we only have window size left. + // We know we have less than window size in b at this point. + discard := len(b) + len(h.b) - h.windowSize + copy(h.b, h.b[discard:]) + h.b = h.b[:h.windowSize] + copy(h.b[h.windowSize-len(b):], b) +} + +// ensureBlock will ensure there is space for at least one block... +func (h *history) ensureBlock() { + if cap(h.b) < h.allocFrameBuffer { + h.b = make([]byte, 0, h.allocFrameBuffer) + return + } + + avail := cap(h.b) - len(h.b) + if avail >= h.windowSize || avail > maxCompressedBlockSize { + return + } + // Move data down so we only have window size left. + // We know we have less than window size in b at this point. + discard := len(h.b) - h.windowSize + copy(h.b, h.b[discard:]) + h.b = h.b[:h.windowSize] +} + +// append bytes to history without ever discarding anything. +func (h *history) appendKeep(b []byte) { + h.b = append(h.b, b...) +} diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt new file mode 100644 index 0000000..24b5306 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2016 Caleb Spare + +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. diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/README.md b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/README.md new file mode 100644 index 0000000..777290d --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/README.md @@ -0,0 +1,71 @@ +# xxhash + +VENDORED: Go to [github.com/cespare/xxhash](https://github.com/cespare/xxhash) for original package. + +xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a +high-quality hashing algorithm that is much faster than anything in the Go +standard library. + +This package provides a straightforward API: + +``` +func Sum64(b []byte) uint64 +func Sum64String(s string) uint64 +type Digest struct{ ... } + func New() *Digest +``` + +The `Digest` type implements hash.Hash64. Its key methods are: + +``` +func (*Digest) Write([]byte) (int, error) +func (*Digest) WriteString(string) (int, error) +func (*Digest) Sum64() uint64 +``` + +The package is written with optimized pure Go and also contains even faster +assembly implementations for amd64 and arm64. If desired, the `purego` build tag +opts into using the Go code even on those architectures. + +[xxHash]: http://cyan4973.github.io/xxHash/ + +## Compatibility + +This package is in a module and the latest code is in version 2 of the module. +You need a version of Go with at least "minimal module compatibility" to use +github.com/cespare/xxhash/v2: + +* 1.9.7+ for Go 1.9 +* 1.10.3+ for Go 1.10 +* Go 1.11 or later + +I recommend using the latest release of Go. + +## Benchmarks + +Here are some quick benchmarks comparing the pure-Go and assembly +implementations of Sum64. + +| input size | purego | asm | +| ---------- | --------- | --------- | +| 4 B | 1.3 GB/s | 1.2 GB/s | +| 16 B | 2.9 GB/s | 3.5 GB/s | +| 100 B | 6.9 GB/s | 8.1 GB/s | +| 4 KB | 11.7 GB/s | 16.7 GB/s | +| 10 MB | 12.0 GB/s | 17.3 GB/s | + +These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C +CPU using the following commands under Go 1.19.2: + +``` +benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$') +benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$') +``` + +## Projects using this package + +- [InfluxDB](https://github.com/influxdata/influxdb) +- [Prometheus](https://github.com/prometheus/prometheus) +- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) +- [FreeCache](https://github.com/coocood/freecache) +- [FastCache](https://github.com/VictoriaMetrics/fastcache) diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go new file mode 100644 index 0000000..fc40c82 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go @@ -0,0 +1,230 @@ +// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described +// at http://cyan4973.github.io/xxHash/. +// THIS IS VENDORED: Go to github.com/cespare/xxhash for original package. + +package xxhash + +import ( + "encoding/binary" + "errors" + "math/bits" +) + +const ( + prime1 uint64 = 11400714785074694791 + prime2 uint64 = 14029467366897019727 + prime3 uint64 = 1609587929392839161 + prime4 uint64 = 9650029242287828579 + prime5 uint64 = 2870177450012600261 +) + +// Store the primes in an array as well. +// +// The consts are used when possible in Go code to avoid MOVs but we need a +// contiguous array of the assembly code. +var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5} + +// Digest implements hash.Hash64. +type Digest struct { + v1 uint64 + v2 uint64 + v3 uint64 + v4 uint64 + total uint64 + mem [32]byte + n int // how much of mem is used +} + +// New creates a new Digest that computes the 64-bit xxHash algorithm. +func New() *Digest { + var d Digest + d.Reset() + return &d +} + +// Reset clears the Digest's state so that it can be reused. +func (d *Digest) Reset() { + d.v1 = primes[0] + prime2 + d.v2 = prime2 + d.v3 = 0 + d.v4 = -primes[0] + d.total = 0 + d.n = 0 +} + +// Size always returns 8 bytes. +func (d *Digest) Size() int { return 8 } + +// BlockSize always returns 32 bytes. +func (d *Digest) BlockSize() int { return 32 } + +// Write adds more data to d. It always returns len(b), nil. +func (d *Digest) Write(b []byte) (n int, err error) { + n = len(b) + d.total += uint64(n) + + memleft := d.mem[d.n&(len(d.mem)-1):] + + if d.n+n < 32 { + // This new data doesn't even fill the current block. + copy(memleft, b) + d.n += n + return + } + + if d.n > 0 { + // Finish off the partial block. + c := copy(memleft, b) + d.v1 = round(d.v1, u64(d.mem[0:8])) + d.v2 = round(d.v2, u64(d.mem[8:16])) + d.v3 = round(d.v3, u64(d.mem[16:24])) + d.v4 = round(d.v4, u64(d.mem[24:32])) + b = b[c:] + d.n = 0 + } + + if len(b) >= 32 { + // One or more full blocks left. + nw := writeBlocks(d, b) + b = b[nw:] + } + + // Store any remaining partial block. + copy(d.mem[:], b) + d.n = len(b) + + return +} + +// Sum appends the current hash to b and returns the resulting slice. +func (d *Digest) Sum(b []byte) []byte { + s := d.Sum64() + return append( + b, + byte(s>>56), + byte(s>>48), + byte(s>>40), + byte(s>>32), + byte(s>>24), + byte(s>>16), + byte(s>>8), + byte(s), + ) +} + +// Sum64 returns the current hash. +func (d *Digest) Sum64() uint64 { + var h uint64 + + if d.total >= 32 { + v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 + h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) + h = mergeRound(h, v1) + h = mergeRound(h, v2) + h = mergeRound(h, v3) + h = mergeRound(h, v4) + } else { + h = d.v3 + prime5 + } + + h += d.total + + b := d.mem[:d.n&(len(d.mem)-1)] + for ; len(b) >= 8; b = b[8:] { + k1 := round(0, u64(b[:8])) + h ^= k1 + h = rol27(h)*prime1 + prime4 + } + if len(b) >= 4 { + h ^= uint64(u32(b[:4])) * prime1 + h = rol23(h)*prime2 + prime3 + b = b[4:] + } + for ; len(b) > 0; b = b[1:] { + h ^= uint64(b[0]) * prime5 + h = rol11(h) * prime1 + } + + h ^= h >> 33 + h *= prime2 + h ^= h >> 29 + h *= prime3 + h ^= h >> 32 + + return h +} + +const ( + magic = "xxh\x06" + marshaledSize = len(magic) + 8*5 + 32 +) + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (d *Digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint64(b, d.v1) + b = appendUint64(b, d.v2) + b = appendUint64(b, d.v3) + b = appendUint64(b, d.v4) + b = appendUint64(b, d.total) + b = append(b, d.mem[:d.n]...) + b = b[:len(b)+len(d.mem)-d.n] + return b, nil +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +func (d *Digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("xxhash: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("xxhash: invalid hash state size") + } + b = b[len(magic):] + b, d.v1 = consumeUint64(b) + b, d.v2 = consumeUint64(b) + b, d.v3 = consumeUint64(b) + b, d.v4 = consumeUint64(b) + b, d.total = consumeUint64(b) + copy(d.mem[:], b) + d.n = int(d.total % uint64(len(d.mem))) + return nil +} + +func appendUint64(b []byte, x uint64) []byte { + var a [8]byte + binary.LittleEndian.PutUint64(a[:], x) + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + x := u64(b) + return b[8:], x +} + +func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) } +func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } + +func round(acc, input uint64) uint64 { + acc += input * prime2 + acc = rol31(acc) + acc *= prime1 + return acc +} + +func mergeRound(acc, val uint64) uint64 { + val = round(0, val) + acc ^= val + acc = acc*prime1 + prime4 + return acc +} + +func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) } +func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) } +func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) } +func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) } +func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) } +func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) } +func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) } +func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) } diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s new file mode 100644 index 0000000..ddb63aa --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s @@ -0,0 +1,210 @@ +//go:build !appengine && gc && !purego && !noasm +// +build !appengine +// +build gc +// +build !purego +// +build !noasm + +#include "textflag.h" + +// Registers: +#define h AX +#define d AX +#define p SI // pointer to advance through b +#define n DX +#define end BX // loop end +#define v1 R8 +#define v2 R9 +#define v3 R10 +#define v4 R11 +#define x R12 +#define prime1 R13 +#define prime2 R14 +#define prime4 DI + +#define round(acc, x) \ + IMULQ prime2, x \ + ADDQ x, acc \ + ROLQ $31, acc \ + IMULQ prime1, acc + +// round0 performs the operation x = round(0, x). +#define round0(x) \ + IMULQ prime2, x \ + ROLQ $31, x \ + IMULQ prime1, x + +// mergeRound applies a merge round on the two registers acc and x. +// It assumes that prime1, prime2, and prime4 have been loaded. +#define mergeRound(acc, x) \ + round0(x) \ + XORQ x, acc \ + IMULQ prime1, acc \ + ADDQ prime4, acc + +// blockLoop processes as many 32-byte blocks as possible, +// updating v1, v2, v3, and v4. It assumes that there is at least one block +// to process. +#define blockLoop() \ +loop: \ + MOVQ +0(p), x \ + round(v1, x) \ + MOVQ +8(p), x \ + round(v2, x) \ + MOVQ +16(p), x \ + round(v3, x) \ + MOVQ +24(p), x \ + round(v4, x) \ + ADDQ $32, p \ + CMPQ p, end \ + JLE loop + +// func Sum64(b []byte) uint64 +TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32 + // Load fixed primes. + MOVQ ·primes+0(SB), prime1 + MOVQ ·primes+8(SB), prime2 + MOVQ ·primes+24(SB), prime4 + + // Load slice. + MOVQ b_base+0(FP), p + MOVQ b_len+8(FP), n + LEAQ (p)(n*1), end + + // The first loop limit will be len(b)-32. + SUBQ $32, end + + // Check whether we have at least one block. + CMPQ n, $32 + JLT noBlocks + + // Set up initial state (v1, v2, v3, v4). + MOVQ prime1, v1 + ADDQ prime2, v1 + MOVQ prime2, v2 + XORQ v3, v3 + XORQ v4, v4 + SUBQ prime1, v4 + + blockLoop() + + MOVQ v1, h + ROLQ $1, h + MOVQ v2, x + ROLQ $7, x + ADDQ x, h + MOVQ v3, x + ROLQ $12, x + ADDQ x, h + MOVQ v4, x + ROLQ $18, x + ADDQ x, h + + mergeRound(h, v1) + mergeRound(h, v2) + mergeRound(h, v3) + mergeRound(h, v4) + + JMP afterBlocks + +noBlocks: + MOVQ ·primes+32(SB), h + +afterBlocks: + ADDQ n, h + + ADDQ $24, end + CMPQ p, end + JG try4 + +loop8: + MOVQ (p), x + ADDQ $8, p + round0(x) + XORQ x, h + ROLQ $27, h + IMULQ prime1, h + ADDQ prime4, h + + CMPQ p, end + JLE loop8 + +try4: + ADDQ $4, end + CMPQ p, end + JG try1 + + MOVL (p), x + ADDQ $4, p + IMULQ prime1, x + XORQ x, h + + ROLQ $23, h + IMULQ prime2, h + ADDQ ·primes+16(SB), h + +try1: + ADDQ $4, end + CMPQ p, end + JGE finalize + +loop1: + MOVBQZX (p), x + ADDQ $1, p + IMULQ ·primes+32(SB), x + XORQ x, h + ROLQ $11, h + IMULQ prime1, h + + CMPQ p, end + JL loop1 + +finalize: + MOVQ h, x + SHRQ $33, x + XORQ x, h + IMULQ prime2, h + MOVQ h, x + SHRQ $29, x + XORQ x, h + IMULQ ·primes+16(SB), h + MOVQ h, x + SHRQ $32, x + XORQ x, h + + MOVQ h, ret+24(FP) + RET + +// func writeBlocks(d *Digest, b []byte) int +TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 + // Load fixed primes needed for round. + MOVQ ·primes+0(SB), prime1 + MOVQ ·primes+8(SB), prime2 + + // Load slice. + MOVQ b_base+8(FP), p + MOVQ b_len+16(FP), n + LEAQ (p)(n*1), end + SUBQ $32, end + + // Load vN from d. + MOVQ s+0(FP), d + MOVQ 0(d), v1 + MOVQ 8(d), v2 + MOVQ 16(d), v3 + MOVQ 24(d), v4 + + // We don't need to check the loop condition here; this function is + // always called with at least one block of data to process. + blockLoop() + + // Copy vN back to d. + MOVQ v1, 0(d) + MOVQ v2, 8(d) + MOVQ v3, 16(d) + MOVQ v4, 24(d) + + // The number of bytes written is p minus the old base pointer. + SUBQ b_base+8(FP), p + MOVQ p, ret+32(FP) + + RET diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s new file mode 100644 index 0000000..ae7d4d3 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s @@ -0,0 +1,184 @@ +//go:build !appengine && gc && !purego && !noasm +// +build !appengine +// +build gc +// +build !purego +// +build !noasm + +#include "textflag.h" + +// Registers: +#define digest R1 +#define h R2 // return value +#define p R3 // input pointer +#define n R4 // input length +#define nblocks R5 // n / 32 +#define prime1 R7 +#define prime2 R8 +#define prime3 R9 +#define prime4 R10 +#define prime5 R11 +#define v1 R12 +#define v2 R13 +#define v3 R14 +#define v4 R15 +#define x1 R20 +#define x2 R21 +#define x3 R22 +#define x4 R23 + +#define round(acc, x) \ + MADD prime2, acc, x, acc \ + ROR $64-31, acc \ + MUL prime1, acc + +// round0 performs the operation x = round(0, x). +#define round0(x) \ + MUL prime2, x \ + ROR $64-31, x \ + MUL prime1, x + +#define mergeRound(acc, x) \ + round0(x) \ + EOR x, acc \ + MADD acc, prime4, prime1, acc + +// blockLoop processes as many 32-byte blocks as possible, +// updating v1, v2, v3, and v4. It assumes that n >= 32. +#define blockLoop() \ + LSR $5, n, nblocks \ + PCALIGN $16 \ + loop: \ + LDP.P 16(p), (x1, x2) \ + LDP.P 16(p), (x3, x4) \ + round(v1, x1) \ + round(v2, x2) \ + round(v3, x3) \ + round(v4, x4) \ + SUB $1, nblocks \ + CBNZ nblocks, loop + +// func Sum64(b []byte) uint64 +TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32 + LDP b_base+0(FP), (p, n) + + LDP ·primes+0(SB), (prime1, prime2) + LDP ·primes+16(SB), (prime3, prime4) + MOVD ·primes+32(SB), prime5 + + CMP $32, n + CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 } + BLT afterLoop + + ADD prime1, prime2, v1 + MOVD prime2, v2 + MOVD $0, v3 + NEG prime1, v4 + + blockLoop() + + ROR $64-1, v1, x1 + ROR $64-7, v2, x2 + ADD x1, x2 + ROR $64-12, v3, x3 + ROR $64-18, v4, x4 + ADD x3, x4 + ADD x2, x4, h + + mergeRound(h, v1) + mergeRound(h, v2) + mergeRound(h, v3) + mergeRound(h, v4) + +afterLoop: + ADD n, h + + TBZ $4, n, try8 + LDP.P 16(p), (x1, x2) + + round0(x1) + + // NOTE: here and below, sequencing the EOR after the ROR (using a + // rotated register) is worth a small but measurable speedup for small + // inputs. + ROR $64-27, h + EOR x1 @> 64-27, h, h + MADD h, prime4, prime1, h + + round0(x2) + ROR $64-27, h + EOR x2 @> 64-27, h, h + MADD h, prime4, prime1, h + +try8: + TBZ $3, n, try4 + MOVD.P 8(p), x1 + + round0(x1) + ROR $64-27, h + EOR x1 @> 64-27, h, h + MADD h, prime4, prime1, h + +try4: + TBZ $2, n, try2 + MOVWU.P 4(p), x2 + + MUL prime1, x2 + ROR $64-23, h + EOR x2 @> 64-23, h, h + MADD h, prime3, prime2, h + +try2: + TBZ $1, n, try1 + MOVHU.P 2(p), x3 + AND $255, x3, x1 + LSR $8, x3, x2 + + MUL prime5, x1 + ROR $64-11, h + EOR x1 @> 64-11, h, h + MUL prime1, h + + MUL prime5, x2 + ROR $64-11, h + EOR x2 @> 64-11, h, h + MUL prime1, h + +try1: + TBZ $0, n, finalize + MOVBU (p), x4 + + MUL prime5, x4 + ROR $64-11, h + EOR x4 @> 64-11, h, h + MUL prime1, h + +finalize: + EOR h >> 33, h + MUL prime2, h + EOR h >> 29, h + MUL prime3, h + EOR h >> 32, h + + MOVD h, ret+24(FP) + RET + +// func writeBlocks(s *Digest, b []byte) int +TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 + LDP ·primes+0(SB), (prime1, prime2) + + // Load state. Assume v[1-4] are stored contiguously. + MOVD s+0(FP), digest + LDP 0(digest), (v1, v2) + LDP 16(digest), (v3, v4) + + LDP b_base+8(FP), (p, n) + + blockLoop() + + // Store updated state. + STP (v1, v2), 0(digest) + STP (v3, v4), 16(digest) + + BIC $31, n + MOVD n, ret+32(FP) + RET diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_asm.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_asm.go new file mode 100644 index 0000000..d4221ed --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_asm.go @@ -0,0 +1,16 @@ +//go:build (amd64 || arm64) && !appengine && gc && !purego && !noasm +// +build amd64 arm64 +// +build !appengine +// +build gc +// +build !purego +// +build !noasm + +package xxhash + +// Sum64 computes the 64-bit xxHash digest of b. +// +//go:noescape +func Sum64(b []byte) uint64 + +//go:noescape +func writeBlocks(s *Digest, b []byte) int diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go new file mode 100644 index 0000000..9576426 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go @@ -0,0 +1,75 @@ +//go:build (!amd64 && !arm64) || appengine || !gc || purego || noasm + +package xxhash + +// Sum64 computes the 64-bit xxHash digest of b. +func Sum64(b []byte) uint64 { + // A simpler version would be + // d := New() + // d.Write(b) + // return d.Sum64() + // but this is faster, particularly for small inputs. + + n := len(b) + var h uint64 + + if n >= 32 { + v1 := primes[0] + prime2 + v2 := prime2 + v3 := uint64(0) + v4 := -primes[0] + for len(b) >= 32 { + v1 = round(v1, u64(b[0:8:len(b)])) + v2 = round(v2, u64(b[8:16:len(b)])) + v3 = round(v3, u64(b[16:24:len(b)])) + v4 = round(v4, u64(b[24:32:len(b)])) + b = b[32:len(b):len(b)] + } + h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) + h = mergeRound(h, v1) + h = mergeRound(h, v2) + h = mergeRound(h, v3) + h = mergeRound(h, v4) + } else { + h = prime5 + } + + h += uint64(n) + + for ; len(b) >= 8; b = b[8:] { + k1 := round(0, u64(b[:8])) + h ^= k1 + h = rol27(h)*prime1 + prime4 + } + if len(b) >= 4 { + h ^= uint64(u32(b[:4])) * prime1 + h = rol23(h)*prime2 + prime3 + b = b[4:] + } + for ; len(b) > 0; b = b[1:] { + h ^= uint64(b[0]) * prime5 + h = rol11(h) * prime1 + } + + h ^= h >> 33 + h *= prime2 + h ^= h >> 29 + h *= prime3 + h ^= h >> 32 + + return h +} + +func writeBlocks(d *Digest, b []byte) int { + v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 + n := len(b) + for len(b) >= 32 { + v1 = round(v1, u64(b[0:8:len(b)])) + v2 = round(v2, u64(b[8:16:len(b)])) + v3 = round(v3, u64(b[16:24:len(b)])) + v4 = round(v4, u64(b[24:32:len(b)])) + b = b[32:len(b):len(b)] + } + d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4 + return n - len(b) +} diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_safe.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_safe.go new file mode 100644 index 0000000..6f3b0cb --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_safe.go @@ -0,0 +1,11 @@ +package xxhash + +// Sum64String computes the 64-bit xxHash digest of s. +func Sum64String(s string) uint64 { + return Sum64([]byte(s)) +} + +// WriteString adds more data to d. It always returns len(s), nil. +func (d *Digest) WriteString(s string) (n int, err error) { + return d.Write([]byte(s)) +} diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go new file mode 100644 index 0000000..1ed1892 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.go @@ -0,0 +1,15 @@ +//go:build amd64 && !appengine && !noasm && gc + +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. + +package zstd + +// matchLen returns how many bytes match in a and b +// +// It assumes that: +// +// len(a) <= len(b) and len(a) > 0 +// +//go:noescape +func matchLen(a []byte, b []byte) int diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s new file mode 100644 index 0000000..0782b86 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s @@ -0,0 +1,66 @@ +// Copied from S2 implementation. + +//go:build !appengine && !noasm && gc && !noasm + +#include "textflag.h" + +// func matchLen(a []byte, b []byte) int +TEXT ·matchLen(SB), NOSPLIT, $0-56 + MOVQ a_base+0(FP), AX + MOVQ b_base+24(FP), CX + MOVQ a_len+8(FP), DX + + // matchLen + XORL SI, SI + CMPL DX, $0x08 + JB matchlen_match4_standalone + +matchlen_loopback_standalone: + MOVQ (AX)(SI*1), BX + XORQ (CX)(SI*1), BX + JZ matchlen_loop_standalone + +#ifdef GOAMD64_v3 + TZCNTQ BX, BX +#else + BSFQ BX, BX +#endif + SHRL $0x03, BX + LEAL (SI)(BX*1), SI + JMP gen_match_len_end + +matchlen_loop_standalone: + LEAL -8(DX), DX + LEAL 8(SI), SI + CMPL DX, $0x08 + JAE matchlen_loopback_standalone + +matchlen_match4_standalone: + CMPL DX, $0x04 + JB matchlen_match2_standalone + MOVL (AX)(SI*1), BX + CMPL (CX)(SI*1), BX + JNE matchlen_match2_standalone + LEAL -4(DX), DX + LEAL 4(SI), SI + +matchlen_match2_standalone: + CMPL DX, $0x02 + JB matchlen_match1_standalone + MOVW (AX)(SI*1), BX + CMPW (CX)(SI*1), BX + JNE matchlen_match1_standalone + LEAL -2(DX), DX + LEAL 2(SI), SI + +matchlen_match1_standalone: + CMPL DX, $0x01 + JB gen_match_len_end + MOVB (AX)(SI*1), BL + CMPB (CX)(SI*1), BL + JNE gen_match_len_end + INCL SI + +gen_match_len_end: + MOVQ SI, ret+48(FP) + RET diff --git a/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go b/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go new file mode 100644 index 0000000..379746c --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/matchlen_generic.go @@ -0,0 +1,37 @@ +//go:build !amd64 || appengine || !gc || noasm + +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. + +package zstd + +import ( + "math/bits" + + "github.com/klauspost/compress/internal/le" +) + +// matchLen returns the maximum common prefix length of a and b. +// a must be the shortest of the two. +func matchLen(a, b []byte) (n int) { + left := len(a) + for left >= 8 { + diff := le.Load64(a, n) ^ le.Load64(b, n) + if diff != 0 { + return n + bits.TrailingZeros64(diff)>>3 + } + n += 8 + left -= 8 + } + a = a[n:] + b = b[n:] + + for i := range a { + if a[i] != b[i] { + break + } + n++ + } + return n + +} diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec.go b/vendor/github.com/klauspost/compress/zstd/seqdec.go new file mode 100644 index 0000000..0bfb0e4 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/seqdec.go @@ -0,0 +1,500 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "errors" + "fmt" + "io" +) + +type seq struct { + litLen uint32 + matchLen uint32 + offset uint32 + + // Codes are stored here for the encoder + // so they only have to be looked up once. + llCode, mlCode, ofCode uint8 +} + +type seqVals struct { + ll, ml, mo int +} + +func (s seq) String() string { + if s.offset <= 3 { + if s.offset == 0 { + return fmt.Sprint("litLen:", s.litLen, ", matchLen:", s.matchLen+zstdMinMatch, ", offset: INVALID (0)") + } + return fmt.Sprint("litLen:", s.litLen, ", matchLen:", s.matchLen+zstdMinMatch, ", offset:", s.offset, " (repeat)") + } + return fmt.Sprint("litLen:", s.litLen, ", matchLen:", s.matchLen+zstdMinMatch, ", offset:", s.offset-3, " (new)") +} + +type seqCompMode uint8 + +const ( + compModePredefined seqCompMode = iota + compModeRLE + compModeFSE + compModeRepeat +) + +type sequenceDec struct { + // decoder keeps track of the current state and updates it from the bitstream. + fse *fseDecoder + state fseState + repeat bool +} + +// init the state of the decoder with input from stream. +func (s *sequenceDec) init(br *bitReader) error { + if s.fse == nil { + return errors.New("sequence decoder not defined") + } + s.state.init(br, s.fse.actualTableLog, s.fse.dt[:1< cap(s.out) { + addBytes := s.seqSize + len(s.out) + s.out = append(s.out, make([]byte, addBytes)...) + s.out = s.out[:len(s.out)-addBytes] + } + + if debugDecoder { + printf("Execute %d seqs with hist %d, dict %d, literals: %d into %d bytes\n", len(seqs), len(hist), len(s.dict), len(s.literals), s.seqSize) + } + + var t = len(s.out) + out := s.out[:t+s.seqSize] + + for _, seq := range seqs { + // Add literals + copy(out[t:], s.literals[:seq.ll]) + t += seq.ll + s.literals = s.literals[seq.ll:] + + // Copy from dictionary... + if seq.mo > t+len(hist) || seq.mo > s.windowSize { + if len(s.dict) == 0 { + return fmt.Errorf("match offset (%d) bigger than current history (%d)", seq.mo, t+len(hist)) + } + + // we may be in dictionary. + dictO := len(s.dict) - (seq.mo - (t + len(hist))) + if dictO < 0 || dictO >= len(s.dict) { + return fmt.Errorf("match offset (%d) bigger than current history+dict (%d)", seq.mo, t+len(hist)+len(s.dict)) + } + end := dictO + seq.ml + if end > len(s.dict) { + n := len(s.dict) - dictO + copy(out[t:], s.dict[dictO:]) + t += n + seq.ml -= n + } else { + copy(out[t:], s.dict[dictO:end]) + t += end - dictO + continue + } + } + + // Copy from history. + if v := seq.mo - t; v > 0 { + // v is the start position in history from end. + start := len(hist) - v + if seq.ml > v { + // Some goes into current block. + // Copy remainder of history + copy(out[t:], hist[start:]) + t += v + seq.ml -= v + } else { + copy(out[t:], hist[start:start+seq.ml]) + t += seq.ml + continue + } + } + // We must be in current buffer now + if seq.ml > 0 { + start := t - seq.mo + if seq.ml <= t-start { + // No overlap + copy(out[t:], out[start:start+seq.ml]) + t += seq.ml + continue + } else { + // Overlapping copy + // Extend destination slice and copy one byte at the time. + src := out[start : start+seq.ml] + dst := out[t:] + dst = dst[:len(src)] + t += len(src) + // Destination is the space we just added. + for i := range src { + dst[i] = src[i] + } + } + } + } + + // Add final literals + copy(out[t:], s.literals) + if debugDecoder { + t += len(s.literals) + if t != len(out) { + panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize)) + } + } + s.out = out + + return nil +} + +// decode sequences from the stream with the provided history. +func (s *sequenceDecs) decodeSync(hist []byte) error { + supported, err := s.decodeSyncSimple(hist) + if supported { + return err + } + + br := s.br + seqs := s.nSeqs + startSize := len(s.out) + // Grab full sizes tables, to avoid bounds checks. + llTable, mlTable, ofTable := s.litLengths.fse.dt[:maxTablesize], s.matchLengths.fse.dt[:maxTablesize], s.offsets.fse.dt[:maxTablesize] + llState, mlState, ofState := s.litLengths.state.state, s.matchLengths.state.state, s.offsets.state.state + out := s.out + maxBlockSize := min(s.windowSize, maxCompressedBlockSize) + + if debugDecoder { + println("decodeSync: decoding", seqs, "sequences", br.remain(), "bits remain on stream") + } + for i := seqs - 1; i >= 0; i-- { + if br.overread() { + printf("reading sequence %d, exceeded available data. Overread by %d\n", seqs-i, -br.remain()) + return io.ErrUnexpectedEOF + } + var ll, mo, ml int + if br.cursor > 4+((maxOffsetBits+16+16)>>3) { + // inlined function: + // ll, mo, ml = s.nextFast(br, llState, mlState, ofState) + + // Final will not read from stream. + var llB, mlB, moB uint8 + ll, llB = llState.final() + ml, mlB = mlState.final() + mo, moB = ofState.final() + + // extra bits are stored in reverse order. + br.fillFast() + mo += br.getBits(moB) + if s.maxBits > 32 { + br.fillFast() + } + ml += br.getBits(mlB) + ll += br.getBits(llB) + + if moB > 1 { + s.prevOffset[2] = s.prevOffset[1] + s.prevOffset[1] = s.prevOffset[0] + s.prevOffset[0] = mo + } else { + // mo = s.adjustOffset(mo, ll, moB) + // Inlined for rather big speedup + if ll == 0 { + // There is an exception though, when current sequence's literals_length = 0. + // In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2, + // an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte. + mo++ + } + + if mo == 0 { + mo = s.prevOffset[0] + } else { + var temp int + if mo == 3 { + temp = s.prevOffset[0] - 1 + } else { + temp = s.prevOffset[mo] + } + + if temp == 0 { + // 0 is not valid; input is corrupted; force offset to 1 + println("WARNING: temp was 0") + temp = 1 + } + + if mo != 1 { + s.prevOffset[2] = s.prevOffset[1] + } + s.prevOffset[1] = s.prevOffset[0] + s.prevOffset[0] = temp + mo = temp + } + } + br.fillFast() + } else { + ll, mo, ml = s.next(br, llState, mlState, ofState) + br.fill() + } + + if debugSequences { + println("Seq", seqs-i-1, "Litlen:", ll, "mo:", mo, "(abs) ml:", ml) + } + + if ll > len(s.literals) { + return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, len(s.literals)) + } + size := ll + ml + len(out) + if size-startSize > maxBlockSize { + return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) + } + if size > cap(out) { + // Not enough size, which can happen under high volume block streaming conditions + // but could be if destination slice is too small for sync operations. + // over-allocating here can create a large amount of GC pressure so we try to keep + // it as contained as possible + used := len(out) - startSize + addBytes := 256 + ll + ml + used>>2 + // Clamp to max block size. + if used+addBytes > maxBlockSize { + addBytes = maxBlockSize - used + } + out = append(out, make([]byte, addBytes)...) + out = out[:len(out)-addBytes] + } + if ml > maxMatchLen { + return fmt.Errorf("match len (%d) bigger than max allowed length", ml) + } + + // Add literals + out = append(out, s.literals[:ll]...) + s.literals = s.literals[ll:] + + if mo == 0 && ml > 0 { + return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml) + } + + if mo > len(out)+len(hist) || mo > s.windowSize { + if len(s.dict) == 0 { + return fmt.Errorf("match offset (%d) bigger than current history (%d)", mo, len(out)+len(hist)-startSize) + } + + // we may be in dictionary. + dictO := len(s.dict) - (mo - (len(out) + len(hist))) + if dictO < 0 || dictO >= len(s.dict) { + return fmt.Errorf("match offset (%d) bigger than current history (%d)", mo, len(out)+len(hist)-startSize) + } + end := dictO + ml + if end > len(s.dict) { + out = append(out, s.dict[dictO:]...) + ml -= len(s.dict) - dictO + } else { + out = append(out, s.dict[dictO:end]...) + mo = 0 + ml = 0 + } + } + + // Copy from history. + // TODO: Blocks without history could be made to ignore this completely. + if v := mo - len(out); v > 0 { + // v is the start position in history from end. + start := len(hist) - v + if ml > v { + // Some goes into current block. + // Copy remainder of history + out = append(out, hist[start:]...) + ml -= v + } else { + out = append(out, hist[start:start+ml]...) + ml = 0 + } + } + // We must be in current buffer now + if ml > 0 { + start := len(out) - mo + if ml <= len(out)-start { + // No overlap + out = append(out, out[start:start+ml]...) + } else { + // Overlapping copy + // Extend destination slice and copy one byte at the time. + out = out[:len(out)+ml] + src := out[start : start+ml] + // Destination is the space we just added. + dst := out[len(out)-ml:] + dst = dst[:len(src)] + for i := range src { + dst[i] = src[i] + } + } + } + if i == 0 { + // This is the last sequence, so we shouldn't update state. + break + } + + // Manually inlined, ~ 5-20% faster + // Update all 3 states at once. Approx 20% faster. + nBits := llState.nbBits() + mlState.nbBits() + ofState.nbBits() + if nBits == 0 { + llState = llTable[llState.newState()&maxTableMask] + mlState = mlTable[mlState.newState()&maxTableMask] + ofState = ofTable[ofState.newState()&maxTableMask] + } else { + bits := br.get32BitsFast(nBits) + + lowBits := uint16(bits >> ((ofState.nbBits() + mlState.nbBits()) & 31)) + llState = llTable[(llState.newState()+lowBits)&maxTableMask] + + lowBits = uint16(bits >> (ofState.nbBits() & 31)) + lowBits &= bitMask[mlState.nbBits()&15] + mlState = mlTable[(mlState.newState()+lowBits)&maxTableMask] + + lowBits = uint16(bits) & bitMask[ofState.nbBits()&15] + ofState = ofTable[(ofState.newState()+lowBits)&maxTableMask] + } + } + + if size := len(s.literals) + len(out) - startSize; size > maxBlockSize { + return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) + } + + // Add final literals + s.out = append(out, s.literals...) + return br.close() +} + +var bitMask [16]uint16 + +func init() { + for i := range bitMask[:] { + bitMask[i] = uint16((1 << uint(i)) - 1) + } +} + +func (s *sequenceDecs) next(br *bitReader, llState, mlState, ofState decSymbol) (ll, mo, ml int) { + // Final will not read from stream. + ll, llB := llState.final() + ml, mlB := mlState.final() + mo, moB := ofState.final() + + // extra bits are stored in reverse order. + br.fill() + mo += br.getBits(moB) + if s.maxBits > 32 { + br.fill() + } + // matchlength+literal length, max 32 bits + ml += br.getBits(mlB) + ll += br.getBits(llB) + mo = s.adjustOffset(mo, ll, moB) + return +} + +func (s *sequenceDecs) adjustOffset(offset, litLen int, offsetB uint8) int { + if offsetB > 1 { + s.prevOffset[2] = s.prevOffset[1] + s.prevOffset[1] = s.prevOffset[0] + s.prevOffset[0] = offset + return offset + } + + if litLen == 0 { + // There is an exception though, when current sequence's literals_length = 0. + // In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2, + // an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte. + offset++ + } + + if offset == 0 { + return s.prevOffset[0] + } + var temp int + if offset == 3 { + temp = s.prevOffset[0] - 1 + } else { + temp = s.prevOffset[offset] + } + + if temp == 0 { + // 0 is not valid; input is corrupted; force offset to 1 + println("temp was 0") + temp = 1 + } + + if offset != 1 { + s.prevOffset[2] = s.prevOffset[1] + } + s.prevOffset[1] = s.prevOffset[0] + s.prevOffset[0] = temp + return temp +} diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go new file mode 100644 index 0000000..1281da8 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.go @@ -0,0 +1,105 @@ +//go:build amd64 && !appengine && !noasm && gc + +package zstd + +import ( + "github.com/klauspost/compress/internal/cpuinfo" +) + +// The shared decode/decodeSync/executeSimple wrappers and context structs live +// in seqdec_asm.go; this file only declares the amd64 asm routines and the +// dispatch helpers that pick the BMI2 / non-BMI2 (and 56-bit / safe) variant. + +// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm. +// +// Please refer to seqdec_generic.go for the reference implementation. +// +//go:noescape +func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int + +// sequenceDecs_decode_56_amd64 implements the main loop of sequenceDecs in x86 asm. +// +//go:noescape +func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int + +// sequenceDecs_decode_bmi2 implements the main loop of sequenceDecs in x86 asm with BMI2 extensions. +// +//go:noescape +func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int + +// sequenceDecs_decode_56_bmi2 implements the main loop of sequenceDecs in x86 asm with BMI2 extensions. +// +//go:noescape +func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int + +// decodeAsm runs the sequenceDecs decode loop, choosing the BMI2 / 56-bit variant. +func decodeAsm(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext, lte56bits bool) int { + if cpuinfo.HasBMI2() { + if lte56bits { + return sequenceDecs_decode_56_bmi2(s, br, ctx) + } + return sequenceDecs_decode_bmi2(s, br, ctx) + } + if lte56bits { + return sequenceDecs_decode_56_amd64(s, br, ctx) + } + return sequenceDecs_decode_amd64(s, br, ctx) +} + +// sequenceDecs_decodeSync_amd64 implements the main loop of sequenceDecs.decodeSync in x86 asm. +// +// Please refer to seqdec_generic.go for the reference implementation. +// +//go:noescape +func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int + +// sequenceDecs_decodeSync_bmi2 implements the main loop of sequenceDecs.decodeSync in x86 asm with BMI2 extensions. +// +//go:noescape +func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int + +// sequenceDecs_decodeSync_safe_amd64 does the same as above, but does not write more than output buffer. +// +//go:noescape +func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int + +// sequenceDecs_decodeSync_safe_bmi2 does the same as above, but does not write more than output buffer. +// +//go:noescape +func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int + +// decodeSyncAsm runs the decodeSync loop, choosing the BMI2 / safe variant. +func decodeSyncAsm(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext, safe bool) int { + if cpuinfo.HasBMI2() { + if safe { + return sequenceDecs_decodeSync_safe_bmi2(s, br, ctx) + } + return sequenceDecs_decodeSync_bmi2(s, br, ctx) + } + if safe { + return sequenceDecs_decodeSync_safe_amd64(s, br, ctx) + } + return sequenceDecs_decodeSync_amd64(s, br, ctx) +} + +// sequenceDecs_executeSimple_amd64 implements the main loop of sequenceDecs.executeSimple in x86 asm. +// +// Returns false if a match offset is too big. +// +// Please refer to seqdec_generic.go for the reference implementation. +// +//go:noescape +func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool + +// Same as above, but with safe memcopies +// +//go:noescape +func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool + +// executeSimpleAsm runs the executeSimple loop, choosing the safe variant. +func executeSimpleAsm(ctx *executeAsmContext, safe bool) bool { + if safe { + return sequenceDecs_executeSimple_safe_amd64(ctx) + } + return sequenceDecs_executeSimple_amd64(ctx) +} diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s new file mode 100644 index 0000000..4d3188f --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_amd64.s @@ -0,0 +1,4151 @@ +// Code generated by command: go run gen.go -out ../seqdec.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT. + +//go:build !appengine && !noasm && gc && !noasm + +// func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int +// Requires: CMOV +TEXT ·sequenceDecs_decode_amd64(SB), $8-32 + MOVQ br+8(FP), CX + MOVQ 24(CX), DX + MOVBQZX 40(CX), BX + MOVQ (CX), AX + MOVQ 32(CX), SI + ADDQ SI, AX + MOVQ AX, (SP) + MOVQ ctx+16(FP), AX + MOVQ 72(AX), DI + MOVQ 80(AX), R8 + MOVQ 88(AX), R9 + MOVQ 104(AX), R10 + MOVQ s+0(FP), AX + MOVQ 144(AX), R11 + MOVQ 152(AX), R12 + MOVQ 160(AX), R13 + +sequenceDecs_decode_amd64_main_loop: + MOVQ (SP), R14 + + // Fill bitreader to have enough for the offset and match length. + CMPQ SI, $0x08 + JL sequenceDecs_decode_amd64_fill_byte_by_byte + MOVQ BX, AX + SHRQ $0x03, AX + SUBQ AX, R14 + MOVQ (R14), DX + SUBQ AX, SI + ANDQ $0x07, BX + JMP sequenceDecs_decode_amd64_fill_end + +sequenceDecs_decode_amd64_fill_byte_by_byte: + CMPQ SI, $0x00 + JLE sequenceDecs_decode_amd64_fill_check_overread + CMPQ BX, $0x07 + JLE sequenceDecs_decode_amd64_fill_end + SHLQ $0x08, DX + SUBQ $0x01, R14 + SUBQ $0x01, SI + SUBQ $0x08, BX + MOVBQZX (R14), AX + ORQ AX, DX + JMP sequenceDecs_decode_amd64_fill_byte_by_byte + +sequenceDecs_decode_amd64_fill_check_overread: + CMPQ BX, $0x40 + JA error_overread + +sequenceDecs_decode_amd64_fill_end: + // Update offset + MOVQ R9, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decode_amd64_of_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decode_amd64_of_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decode_amd64_of_update_zero + NEGQ CX + SHRQ CL, R15 + ADDQ R15, AX + +sequenceDecs_decode_amd64_of_update_zero: + MOVQ AX, 16(R10) + + // Update match length + MOVQ R8, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decode_amd64_ml_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decode_amd64_ml_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decode_amd64_ml_update_zero + NEGQ CX + SHRQ CL, R15 + ADDQ R15, AX + +sequenceDecs_decode_amd64_ml_update_zero: + MOVQ AX, 8(R10) + + // Fill bitreader to have enough for the remaining + CMPQ SI, $0x08 + JL sequenceDecs_decode_amd64_fill_2_byte_by_byte + MOVQ BX, AX + SHRQ $0x03, AX + SUBQ AX, R14 + MOVQ (R14), DX + SUBQ AX, SI + ANDQ $0x07, BX + JMP sequenceDecs_decode_amd64_fill_2_end + +sequenceDecs_decode_amd64_fill_2_byte_by_byte: + CMPQ SI, $0x00 + JLE sequenceDecs_decode_amd64_fill_2_check_overread + CMPQ BX, $0x07 + JLE sequenceDecs_decode_amd64_fill_2_end + SHLQ $0x08, DX + SUBQ $0x01, R14 + SUBQ $0x01, SI + SUBQ $0x08, BX + MOVBQZX (R14), AX + ORQ AX, DX + JMP sequenceDecs_decode_amd64_fill_2_byte_by_byte + +sequenceDecs_decode_amd64_fill_2_check_overread: + CMPQ BX, $0x40 + JA error_overread + +sequenceDecs_decode_amd64_fill_2_end: + // Update literal length + MOVQ DI, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decode_amd64_ll_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decode_amd64_ll_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decode_amd64_ll_update_zero + NEGQ CX + SHRQ CL, R15 + ADDQ R15, AX + +sequenceDecs_decode_amd64_ll_update_zero: + MOVQ AX, (R10) + + // Fill bitreader for state updates + MOVQ R14, (SP) + MOVQ R9, AX + SHRQ $0x08, AX + MOVBQZX AL, AX + MOVQ ctx+16(FP), CX + CMPQ 96(CX), $0x00 + JZ sequenceDecs_decode_amd64_skip_update + + // Update Literal Length State + MOVBQZX DI, R14 + SHRL $0x10, DI + LEAQ (BX)(R14*1), CX + MOVQ DX, R15 + MOVQ CX, BX + ROLQ CL, R15 + MOVL $0x00000001, BP + MOVB R14, CL + SHLL CL, BP + DECL BP + ANDQ BP, R15 + ADDQ R15, DI + + // Load ctx.llTable + MOVQ ctx+16(FP), CX + MOVQ (CX), CX + MOVQ (CX)(DI*8), DI + + // Update Match Length State + MOVBQZX R8, R14 + SHRL $0x10, R8 + LEAQ (BX)(R14*1), CX + MOVQ DX, R15 + MOVQ CX, BX + ROLQ CL, R15 + MOVL $0x00000001, BP + MOVB R14, CL + SHLL CL, BP + DECL BP + ANDQ BP, R15 + ADDQ R15, R8 + + // Load ctx.mlTable + MOVQ ctx+16(FP), CX + MOVQ 24(CX), CX + MOVQ (CX)(R8*8), R8 + + // Update Offset State + MOVBQZX R9, R14 + SHRL $0x10, R9 + LEAQ (BX)(R14*1), CX + MOVQ DX, R15 + MOVQ CX, BX + ROLQ CL, R15 + MOVL $0x00000001, BP + MOVB R14, CL + SHLL CL, BP + DECL BP + ANDQ BP, R15 + ADDQ R15, R9 + + // Load ctx.ofTable + MOVQ ctx+16(FP), CX + MOVQ 48(CX), CX + MOVQ (CX)(R9*8), R9 + +sequenceDecs_decode_amd64_skip_update: + // Adjust offset + MOVQ 16(R10), CX + CMPQ AX, $0x01 + JBE sequenceDecs_decode_amd64_adjust_offsetB_1_or_0 + MOVQ R12, R13 + MOVQ R11, R12 + MOVQ CX, R11 + JMP sequenceDecs_decode_amd64_after_adjust + +sequenceDecs_decode_amd64_adjust_offsetB_1_or_0: + CMPQ (R10), $0x00000000 + JNE sequenceDecs_decode_amd64_adjust_offset_maybezero + INCQ CX + JMP sequenceDecs_decode_amd64_adjust_offset_nonzero + +sequenceDecs_decode_amd64_adjust_offset_maybezero: + TESTQ CX, CX + JNZ sequenceDecs_decode_amd64_adjust_offset_nonzero + MOVQ R11, CX + JMP sequenceDecs_decode_amd64_after_adjust + +sequenceDecs_decode_amd64_adjust_offset_nonzero: + CMPQ CX, $0x01 + JB sequenceDecs_decode_amd64_adjust_zero + JEQ sequenceDecs_decode_amd64_adjust_one + CMPQ CX, $0x02 + JA sequenceDecs_decode_amd64_adjust_three + JMP sequenceDecs_decode_amd64_adjust_two + +sequenceDecs_decode_amd64_adjust_zero: + MOVQ R11, AX + JMP sequenceDecs_decode_amd64_adjust_test_temp_valid + +sequenceDecs_decode_amd64_adjust_one: + MOVQ R12, AX + JMP sequenceDecs_decode_amd64_adjust_test_temp_valid + +sequenceDecs_decode_amd64_adjust_two: + MOVQ R13, AX + JMP sequenceDecs_decode_amd64_adjust_test_temp_valid + +sequenceDecs_decode_amd64_adjust_three: + LEAQ -1(R11), AX + +sequenceDecs_decode_amd64_adjust_test_temp_valid: + TESTQ AX, AX + JNZ sequenceDecs_decode_amd64_adjust_temp_valid + MOVQ $0x00000001, AX + +sequenceDecs_decode_amd64_adjust_temp_valid: + CMPQ CX, $0x01 + CMOVQNE R12, R13 + MOVQ R11, R12 + MOVQ AX, R11 + MOVQ AX, CX + +sequenceDecs_decode_amd64_after_adjust: + MOVQ CX, 16(R10) + + // Check values + MOVQ 8(R10), AX + MOVQ (R10), R14 + LEAQ (AX)(R14*1), R15 + MOVQ s+0(FP), BP + ADDQ R15, 256(BP) + MOVQ ctx+16(FP), R15 + SUBQ R14, 128(R15) + JS error_not_enough_literals + CMPQ AX, $0x00020002 + JA sequenceDecs_decode_amd64_error_match_len_too_big + TESTQ CX, CX + JNZ sequenceDecs_decode_amd64_match_len_ofs_ok + TESTQ AX, AX + JNZ sequenceDecs_decode_amd64_error_match_len_ofs_mismatch + +sequenceDecs_decode_amd64_match_len_ofs_ok: + ADDQ $0x18, R10 + MOVQ ctx+16(FP), AX + DECQ 96(AX) + JNS sequenceDecs_decode_amd64_main_loop + MOVQ s+0(FP), AX + MOVQ R11, 144(AX) + MOVQ R12, 152(AX) + MOVQ R13, 160(AX) + MOVQ br+8(FP), AX + MOVQ DX, 24(AX) + MOVB BL, 40(AX) + MOVQ SI, 32(AX) + + // Return success + MOVQ $0x00000000, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decode_amd64_error_match_len_ofs_mismatch: + MOVQ $0x00000001, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decode_amd64_error_match_len_too_big: + MOVQ $0x00000002, ret+24(FP) + RET + + // Return with match offset too long error + MOVQ $0x00000003, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVQ $0x00000004, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + +// func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int +// Requires: CMOV +TEXT ·sequenceDecs_decode_56_amd64(SB), $8-32 + MOVQ br+8(FP), CX + MOVQ 24(CX), DX + MOVBQZX 40(CX), BX + MOVQ (CX), AX + MOVQ 32(CX), SI + ADDQ SI, AX + MOVQ AX, (SP) + MOVQ ctx+16(FP), AX + MOVQ 72(AX), DI + MOVQ 80(AX), R8 + MOVQ 88(AX), R9 + MOVQ 104(AX), R10 + MOVQ s+0(FP), AX + MOVQ 144(AX), R11 + MOVQ 152(AX), R12 + MOVQ 160(AX), R13 + +sequenceDecs_decode_56_amd64_main_loop: + MOVQ (SP), R14 + + // Fill bitreader to have enough for the offset and match length. + CMPQ SI, $0x08 + JL sequenceDecs_decode_56_amd64_fill_byte_by_byte + MOVQ BX, AX + SHRQ $0x03, AX + SUBQ AX, R14 + MOVQ (R14), DX + SUBQ AX, SI + ANDQ $0x07, BX + JMP sequenceDecs_decode_56_amd64_fill_end + +sequenceDecs_decode_56_amd64_fill_byte_by_byte: + CMPQ SI, $0x00 + JLE sequenceDecs_decode_56_amd64_fill_check_overread + CMPQ BX, $0x07 + JLE sequenceDecs_decode_56_amd64_fill_end + SHLQ $0x08, DX + SUBQ $0x01, R14 + SUBQ $0x01, SI + SUBQ $0x08, BX + MOVBQZX (R14), AX + ORQ AX, DX + JMP sequenceDecs_decode_56_amd64_fill_byte_by_byte + +sequenceDecs_decode_56_amd64_fill_check_overread: + CMPQ BX, $0x40 + JA error_overread + +sequenceDecs_decode_56_amd64_fill_end: + // Update offset + MOVQ R9, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decode_56_amd64_of_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decode_56_amd64_of_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decode_56_amd64_of_update_zero + NEGQ CX + SHRQ CL, R15 + ADDQ R15, AX + +sequenceDecs_decode_56_amd64_of_update_zero: + MOVQ AX, 16(R10) + + // Update match length + MOVQ R8, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decode_56_amd64_ml_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decode_56_amd64_ml_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decode_56_amd64_ml_update_zero + NEGQ CX + SHRQ CL, R15 + ADDQ R15, AX + +sequenceDecs_decode_56_amd64_ml_update_zero: + MOVQ AX, 8(R10) + + // Update literal length + MOVQ DI, AX + MOVQ BX, CX + MOVQ DX, R15 + SHLQ CL, R15 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decode_56_amd64_ll_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decode_56_amd64_ll_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decode_56_amd64_ll_update_zero + NEGQ CX + SHRQ CL, R15 + ADDQ R15, AX + +sequenceDecs_decode_56_amd64_ll_update_zero: + MOVQ AX, (R10) + + // Fill bitreader for state updates + MOVQ R14, (SP) + MOVQ R9, AX + SHRQ $0x08, AX + MOVBQZX AL, AX + MOVQ ctx+16(FP), CX + CMPQ 96(CX), $0x00 + JZ sequenceDecs_decode_56_amd64_skip_update + + // Update Literal Length State + MOVBQZX DI, R14 + SHRL $0x10, DI + LEAQ (BX)(R14*1), CX + MOVQ DX, R15 + MOVQ CX, BX + ROLQ CL, R15 + MOVL $0x00000001, BP + MOVB R14, CL + SHLL CL, BP + DECL BP + ANDQ BP, R15 + ADDQ R15, DI + + // Load ctx.llTable + MOVQ ctx+16(FP), CX + MOVQ (CX), CX + MOVQ (CX)(DI*8), DI + + // Update Match Length State + MOVBQZX R8, R14 + SHRL $0x10, R8 + LEAQ (BX)(R14*1), CX + MOVQ DX, R15 + MOVQ CX, BX + ROLQ CL, R15 + MOVL $0x00000001, BP + MOVB R14, CL + SHLL CL, BP + DECL BP + ANDQ BP, R15 + ADDQ R15, R8 + + // Load ctx.mlTable + MOVQ ctx+16(FP), CX + MOVQ 24(CX), CX + MOVQ (CX)(R8*8), R8 + + // Update Offset State + MOVBQZX R9, R14 + SHRL $0x10, R9 + LEAQ (BX)(R14*1), CX + MOVQ DX, R15 + MOVQ CX, BX + ROLQ CL, R15 + MOVL $0x00000001, BP + MOVB R14, CL + SHLL CL, BP + DECL BP + ANDQ BP, R15 + ADDQ R15, R9 + + // Load ctx.ofTable + MOVQ ctx+16(FP), CX + MOVQ 48(CX), CX + MOVQ (CX)(R9*8), R9 + +sequenceDecs_decode_56_amd64_skip_update: + // Adjust offset + MOVQ 16(R10), CX + CMPQ AX, $0x01 + JBE sequenceDecs_decode_56_amd64_adjust_offsetB_1_or_0 + MOVQ R12, R13 + MOVQ R11, R12 + MOVQ CX, R11 + JMP sequenceDecs_decode_56_amd64_after_adjust + +sequenceDecs_decode_56_amd64_adjust_offsetB_1_or_0: + CMPQ (R10), $0x00000000 + JNE sequenceDecs_decode_56_amd64_adjust_offset_maybezero + INCQ CX + JMP sequenceDecs_decode_56_amd64_adjust_offset_nonzero + +sequenceDecs_decode_56_amd64_adjust_offset_maybezero: + TESTQ CX, CX + JNZ sequenceDecs_decode_56_amd64_adjust_offset_nonzero + MOVQ R11, CX + JMP sequenceDecs_decode_56_amd64_after_adjust + +sequenceDecs_decode_56_amd64_adjust_offset_nonzero: + CMPQ CX, $0x01 + JB sequenceDecs_decode_56_amd64_adjust_zero + JEQ sequenceDecs_decode_56_amd64_adjust_one + CMPQ CX, $0x02 + JA sequenceDecs_decode_56_amd64_adjust_three + JMP sequenceDecs_decode_56_amd64_adjust_two + +sequenceDecs_decode_56_amd64_adjust_zero: + MOVQ R11, AX + JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid + +sequenceDecs_decode_56_amd64_adjust_one: + MOVQ R12, AX + JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid + +sequenceDecs_decode_56_amd64_adjust_two: + MOVQ R13, AX + JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid + +sequenceDecs_decode_56_amd64_adjust_three: + LEAQ -1(R11), AX + +sequenceDecs_decode_56_amd64_adjust_test_temp_valid: + TESTQ AX, AX + JNZ sequenceDecs_decode_56_amd64_adjust_temp_valid + MOVQ $0x00000001, AX + +sequenceDecs_decode_56_amd64_adjust_temp_valid: + CMPQ CX, $0x01 + CMOVQNE R12, R13 + MOVQ R11, R12 + MOVQ AX, R11 + MOVQ AX, CX + +sequenceDecs_decode_56_amd64_after_adjust: + MOVQ CX, 16(R10) + + // Check values + MOVQ 8(R10), AX + MOVQ (R10), R14 + LEAQ (AX)(R14*1), R15 + MOVQ s+0(FP), BP + ADDQ R15, 256(BP) + MOVQ ctx+16(FP), R15 + SUBQ R14, 128(R15) + JS error_not_enough_literals + CMPQ AX, $0x00020002 + JA sequenceDecs_decode_56_amd64_error_match_len_too_big + TESTQ CX, CX + JNZ sequenceDecs_decode_56_amd64_match_len_ofs_ok + TESTQ AX, AX + JNZ sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch + +sequenceDecs_decode_56_amd64_match_len_ofs_ok: + ADDQ $0x18, R10 + MOVQ ctx+16(FP), AX + DECQ 96(AX) + JNS sequenceDecs_decode_56_amd64_main_loop + MOVQ s+0(FP), AX + MOVQ R11, 144(AX) + MOVQ R12, 152(AX) + MOVQ R13, 160(AX) + MOVQ br+8(FP), AX + MOVQ DX, 24(AX) + MOVB BL, 40(AX) + MOVQ SI, 32(AX) + + // Return success + MOVQ $0x00000000, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch: + MOVQ $0x00000001, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decode_56_amd64_error_match_len_too_big: + MOVQ $0x00000002, ret+24(FP) + RET + + // Return with match offset too long error + MOVQ $0x00000003, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVQ $0x00000004, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + +// func sequenceDecs_decode_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int +// Requires: BMI, BMI2, CMOV +TEXT ·sequenceDecs_decode_bmi2(SB), $8-32 + MOVQ br+8(FP), BX + MOVQ 24(BX), AX + MOVBQZX 40(BX), DX + MOVQ (BX), CX + MOVQ 32(BX), BX + ADDQ BX, CX + MOVQ CX, (SP) + MOVQ ctx+16(FP), CX + MOVQ 72(CX), SI + MOVQ 80(CX), DI + MOVQ 88(CX), R8 + MOVQ 104(CX), R9 + MOVQ s+0(FP), CX + MOVQ 144(CX), R10 + MOVQ 152(CX), R11 + MOVQ 160(CX), R12 + +sequenceDecs_decode_bmi2_main_loop: + MOVQ (SP), R13 + + // Fill bitreader to have enough for the offset and match length. + CMPQ BX, $0x08 + JL sequenceDecs_decode_bmi2_fill_byte_by_byte + MOVQ DX, CX + SHRQ $0x03, CX + SUBQ CX, R13 + MOVQ (R13), AX + SUBQ CX, BX + ANDQ $0x07, DX + JMP sequenceDecs_decode_bmi2_fill_end + +sequenceDecs_decode_bmi2_fill_byte_by_byte: + CMPQ BX, $0x00 + JLE sequenceDecs_decode_bmi2_fill_check_overread + CMPQ DX, $0x07 + JLE sequenceDecs_decode_bmi2_fill_end + SHLQ $0x08, AX + SUBQ $0x01, R13 + SUBQ $0x01, BX + SUBQ $0x08, DX + MOVBQZX (R13), CX + ORQ CX, AX + JMP sequenceDecs_decode_bmi2_fill_byte_by_byte + +sequenceDecs_decode_bmi2_fill_check_overread: + CMPQ DX, $0x40 + JA error_overread + +sequenceDecs_decode_bmi2_fill_end: + // Update offset + MOVQ $0x00000808, CX + BEXTRQ CX, R8, R14 + MOVQ AX, R15 + LEAQ (DX)(R14*1), CX + ROLQ CL, R15 + BZHIQ R14, R15, R15 + MOVQ CX, DX + MOVQ R8, CX + SHRQ $0x20, CX + ADDQ R15, CX + MOVQ CX, 16(R9) + + // Update match length + MOVQ $0x00000808, CX + BEXTRQ CX, DI, R14 + MOVQ AX, R15 + LEAQ (DX)(R14*1), CX + ROLQ CL, R15 + BZHIQ R14, R15, R15 + MOVQ CX, DX + MOVQ DI, CX + SHRQ $0x20, CX + ADDQ R15, CX + MOVQ CX, 8(R9) + + // Fill bitreader to have enough for the remaining + CMPQ BX, $0x08 + JL sequenceDecs_decode_bmi2_fill_2_byte_by_byte + MOVQ DX, CX + SHRQ $0x03, CX + SUBQ CX, R13 + MOVQ (R13), AX + SUBQ CX, BX + ANDQ $0x07, DX + JMP sequenceDecs_decode_bmi2_fill_2_end + +sequenceDecs_decode_bmi2_fill_2_byte_by_byte: + CMPQ BX, $0x00 + JLE sequenceDecs_decode_bmi2_fill_2_check_overread + CMPQ DX, $0x07 + JLE sequenceDecs_decode_bmi2_fill_2_end + SHLQ $0x08, AX + SUBQ $0x01, R13 + SUBQ $0x01, BX + SUBQ $0x08, DX + MOVBQZX (R13), CX + ORQ CX, AX + JMP sequenceDecs_decode_bmi2_fill_2_byte_by_byte + +sequenceDecs_decode_bmi2_fill_2_check_overread: + CMPQ DX, $0x40 + JA error_overread + +sequenceDecs_decode_bmi2_fill_2_end: + // Update literal length + MOVQ $0x00000808, CX + BEXTRQ CX, SI, R14 + MOVQ AX, R15 + LEAQ (DX)(R14*1), CX + ROLQ CL, R15 + BZHIQ R14, R15, R15 + MOVQ CX, DX + MOVQ SI, CX + SHRQ $0x20, CX + ADDQ R15, CX + MOVQ CX, (R9) + + // Fill bitreader for state updates + MOVQ R13, (SP) + MOVQ $0x00000808, CX + BEXTRQ CX, R8, R13 + MOVQ ctx+16(FP), CX + CMPQ 96(CX), $0x00 + JZ sequenceDecs_decode_bmi2_skip_update + LEAQ (SI)(DI*1), R14 + ADDQ R8, R14 + MOVBQZX R14, R14 + LEAQ (DX)(R14*1), CX + MOVQ AX, R15 + MOVQ CX, DX + ROLQ CL, R15 + BZHIQ R14, R15, R15 + + // Update Offset State + BZHIQ R8, R15, CX + SHRXQ R8, R15, R15 + SHRL $0x10, R8 + ADDQ CX, R8 + + // Load ctx.ofTable + MOVQ ctx+16(FP), CX + MOVQ 48(CX), CX + MOVQ (CX)(R8*8), R8 + + // Update Match Length State + BZHIQ DI, R15, CX + SHRXQ DI, R15, R15 + SHRL $0x10, DI + ADDQ CX, DI + + // Load ctx.mlTable + MOVQ ctx+16(FP), CX + MOVQ 24(CX), CX + MOVQ (CX)(DI*8), DI + + // Update Literal Length State + BZHIQ SI, R15, CX + SHRL $0x10, SI + ADDQ CX, SI + + // Load ctx.llTable + MOVQ ctx+16(FP), CX + MOVQ (CX), CX + MOVQ (CX)(SI*8), SI + +sequenceDecs_decode_bmi2_skip_update: + // Adjust offset + MOVQ 16(R9), CX + CMPQ R13, $0x01 + JBE sequenceDecs_decode_bmi2_adjust_offsetB_1_or_0 + MOVQ R11, R12 + MOVQ R10, R11 + MOVQ CX, R10 + JMP sequenceDecs_decode_bmi2_after_adjust + +sequenceDecs_decode_bmi2_adjust_offsetB_1_or_0: + CMPQ (R9), $0x00000000 + JNE sequenceDecs_decode_bmi2_adjust_offset_maybezero + INCQ CX + JMP sequenceDecs_decode_bmi2_adjust_offset_nonzero + +sequenceDecs_decode_bmi2_adjust_offset_maybezero: + TESTQ CX, CX + JNZ sequenceDecs_decode_bmi2_adjust_offset_nonzero + MOVQ R10, CX + JMP sequenceDecs_decode_bmi2_after_adjust + +sequenceDecs_decode_bmi2_adjust_offset_nonzero: + CMPQ CX, $0x01 + JB sequenceDecs_decode_bmi2_adjust_zero + JEQ sequenceDecs_decode_bmi2_adjust_one + CMPQ CX, $0x02 + JA sequenceDecs_decode_bmi2_adjust_three + JMP sequenceDecs_decode_bmi2_adjust_two + +sequenceDecs_decode_bmi2_adjust_zero: + MOVQ R10, R13 + JMP sequenceDecs_decode_bmi2_adjust_test_temp_valid + +sequenceDecs_decode_bmi2_adjust_one: + MOVQ R11, R13 + JMP sequenceDecs_decode_bmi2_adjust_test_temp_valid + +sequenceDecs_decode_bmi2_adjust_two: + MOVQ R12, R13 + JMP sequenceDecs_decode_bmi2_adjust_test_temp_valid + +sequenceDecs_decode_bmi2_adjust_three: + LEAQ -1(R10), R13 + +sequenceDecs_decode_bmi2_adjust_test_temp_valid: + TESTQ R13, R13 + JNZ sequenceDecs_decode_bmi2_adjust_temp_valid + MOVQ $0x00000001, R13 + +sequenceDecs_decode_bmi2_adjust_temp_valid: + CMPQ CX, $0x01 + CMOVQNE R11, R12 + MOVQ R10, R11 + MOVQ R13, R10 + MOVQ R13, CX + +sequenceDecs_decode_bmi2_after_adjust: + MOVQ CX, 16(R9) + + // Check values + MOVQ 8(R9), R13 + MOVQ (R9), R14 + LEAQ (R13)(R14*1), R15 + MOVQ s+0(FP), BP + ADDQ R15, 256(BP) + MOVQ ctx+16(FP), R15 + SUBQ R14, 128(R15) + JS error_not_enough_literals + CMPQ R13, $0x00020002 + JA sequenceDecs_decode_bmi2_error_match_len_too_big + TESTQ CX, CX + JNZ sequenceDecs_decode_bmi2_match_len_ofs_ok + TESTQ R13, R13 + JNZ sequenceDecs_decode_bmi2_error_match_len_ofs_mismatch + +sequenceDecs_decode_bmi2_match_len_ofs_ok: + ADDQ $0x18, R9 + MOVQ ctx+16(FP), CX + DECQ 96(CX) + JNS sequenceDecs_decode_bmi2_main_loop + MOVQ s+0(FP), CX + MOVQ R10, 144(CX) + MOVQ R11, 152(CX) + MOVQ R12, 160(CX) + MOVQ br+8(FP), CX + MOVQ AX, 24(CX) + MOVB DL, 40(CX) + MOVQ BX, 32(CX) + + // Return success + MOVQ $0x00000000, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decode_bmi2_error_match_len_ofs_mismatch: + MOVQ $0x00000001, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decode_bmi2_error_match_len_too_big: + MOVQ $0x00000002, ret+24(FP) + RET + + // Return with match offset too long error + MOVQ $0x00000003, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVQ $0x00000004, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + +// func sequenceDecs_decode_56_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int +// Requires: BMI, BMI2, CMOV +TEXT ·sequenceDecs_decode_56_bmi2(SB), $8-32 + MOVQ br+8(FP), BX + MOVQ 24(BX), AX + MOVBQZX 40(BX), DX + MOVQ (BX), CX + MOVQ 32(BX), BX + ADDQ BX, CX + MOVQ CX, (SP) + MOVQ ctx+16(FP), CX + MOVQ 72(CX), SI + MOVQ 80(CX), DI + MOVQ 88(CX), R8 + MOVQ 104(CX), R9 + MOVQ s+0(FP), CX + MOVQ 144(CX), R10 + MOVQ 152(CX), R11 + MOVQ 160(CX), R12 + +sequenceDecs_decode_56_bmi2_main_loop: + MOVQ (SP), R13 + + // Fill bitreader to have enough for the offset and match length. + CMPQ BX, $0x08 + JL sequenceDecs_decode_56_bmi2_fill_byte_by_byte + MOVQ DX, CX + SHRQ $0x03, CX + SUBQ CX, R13 + MOVQ (R13), AX + SUBQ CX, BX + ANDQ $0x07, DX + JMP sequenceDecs_decode_56_bmi2_fill_end + +sequenceDecs_decode_56_bmi2_fill_byte_by_byte: + CMPQ BX, $0x00 + JLE sequenceDecs_decode_56_bmi2_fill_check_overread + CMPQ DX, $0x07 + JLE sequenceDecs_decode_56_bmi2_fill_end + SHLQ $0x08, AX + SUBQ $0x01, R13 + SUBQ $0x01, BX + SUBQ $0x08, DX + MOVBQZX (R13), CX + ORQ CX, AX + JMP sequenceDecs_decode_56_bmi2_fill_byte_by_byte + +sequenceDecs_decode_56_bmi2_fill_check_overread: + CMPQ DX, $0x40 + JA error_overread + +sequenceDecs_decode_56_bmi2_fill_end: + // Update offset + MOVQ $0x00000808, CX + BEXTRQ CX, R8, R14 + MOVQ AX, R15 + LEAQ (DX)(R14*1), CX + ROLQ CL, R15 + BZHIQ R14, R15, R15 + MOVQ CX, DX + MOVQ R8, CX + SHRQ $0x20, CX + ADDQ R15, CX + MOVQ CX, 16(R9) + + // Update match length + MOVQ $0x00000808, CX + BEXTRQ CX, DI, R14 + MOVQ AX, R15 + LEAQ (DX)(R14*1), CX + ROLQ CL, R15 + BZHIQ R14, R15, R15 + MOVQ CX, DX + MOVQ DI, CX + SHRQ $0x20, CX + ADDQ R15, CX + MOVQ CX, 8(R9) + + // Update literal length + MOVQ $0x00000808, CX + BEXTRQ CX, SI, R14 + MOVQ AX, R15 + LEAQ (DX)(R14*1), CX + ROLQ CL, R15 + BZHIQ R14, R15, R15 + MOVQ CX, DX + MOVQ SI, CX + SHRQ $0x20, CX + ADDQ R15, CX + MOVQ CX, (R9) + + // Fill bitreader for state updates + MOVQ R13, (SP) + MOVQ $0x00000808, CX + BEXTRQ CX, R8, R13 + MOVQ ctx+16(FP), CX + CMPQ 96(CX), $0x00 + JZ sequenceDecs_decode_56_bmi2_skip_update + LEAQ (SI)(DI*1), R14 + ADDQ R8, R14 + MOVBQZX R14, R14 + LEAQ (DX)(R14*1), CX + MOVQ AX, R15 + MOVQ CX, DX + ROLQ CL, R15 + BZHIQ R14, R15, R15 + + // Update Offset State + BZHIQ R8, R15, CX + SHRXQ R8, R15, R15 + SHRL $0x10, R8 + ADDQ CX, R8 + + // Load ctx.ofTable + MOVQ ctx+16(FP), CX + MOVQ 48(CX), CX + MOVQ (CX)(R8*8), R8 + + // Update Match Length State + BZHIQ DI, R15, CX + SHRXQ DI, R15, R15 + SHRL $0x10, DI + ADDQ CX, DI + + // Load ctx.mlTable + MOVQ ctx+16(FP), CX + MOVQ 24(CX), CX + MOVQ (CX)(DI*8), DI + + // Update Literal Length State + BZHIQ SI, R15, CX + SHRL $0x10, SI + ADDQ CX, SI + + // Load ctx.llTable + MOVQ ctx+16(FP), CX + MOVQ (CX), CX + MOVQ (CX)(SI*8), SI + +sequenceDecs_decode_56_bmi2_skip_update: + // Adjust offset + MOVQ 16(R9), CX + CMPQ R13, $0x01 + JBE sequenceDecs_decode_56_bmi2_adjust_offsetB_1_or_0 + MOVQ R11, R12 + MOVQ R10, R11 + MOVQ CX, R10 + JMP sequenceDecs_decode_56_bmi2_after_adjust + +sequenceDecs_decode_56_bmi2_adjust_offsetB_1_or_0: + CMPQ (R9), $0x00000000 + JNE sequenceDecs_decode_56_bmi2_adjust_offset_maybezero + INCQ CX + JMP sequenceDecs_decode_56_bmi2_adjust_offset_nonzero + +sequenceDecs_decode_56_bmi2_adjust_offset_maybezero: + TESTQ CX, CX + JNZ sequenceDecs_decode_56_bmi2_adjust_offset_nonzero + MOVQ R10, CX + JMP sequenceDecs_decode_56_bmi2_after_adjust + +sequenceDecs_decode_56_bmi2_adjust_offset_nonzero: + CMPQ CX, $0x01 + JB sequenceDecs_decode_56_bmi2_adjust_zero + JEQ sequenceDecs_decode_56_bmi2_adjust_one + CMPQ CX, $0x02 + JA sequenceDecs_decode_56_bmi2_adjust_three + JMP sequenceDecs_decode_56_bmi2_adjust_two + +sequenceDecs_decode_56_bmi2_adjust_zero: + MOVQ R10, R13 + JMP sequenceDecs_decode_56_bmi2_adjust_test_temp_valid + +sequenceDecs_decode_56_bmi2_adjust_one: + MOVQ R11, R13 + JMP sequenceDecs_decode_56_bmi2_adjust_test_temp_valid + +sequenceDecs_decode_56_bmi2_adjust_two: + MOVQ R12, R13 + JMP sequenceDecs_decode_56_bmi2_adjust_test_temp_valid + +sequenceDecs_decode_56_bmi2_adjust_three: + LEAQ -1(R10), R13 + +sequenceDecs_decode_56_bmi2_adjust_test_temp_valid: + TESTQ R13, R13 + JNZ sequenceDecs_decode_56_bmi2_adjust_temp_valid + MOVQ $0x00000001, R13 + +sequenceDecs_decode_56_bmi2_adjust_temp_valid: + CMPQ CX, $0x01 + CMOVQNE R11, R12 + MOVQ R10, R11 + MOVQ R13, R10 + MOVQ R13, CX + +sequenceDecs_decode_56_bmi2_after_adjust: + MOVQ CX, 16(R9) + + // Check values + MOVQ 8(R9), R13 + MOVQ (R9), R14 + LEAQ (R13)(R14*1), R15 + MOVQ s+0(FP), BP + ADDQ R15, 256(BP) + MOVQ ctx+16(FP), R15 + SUBQ R14, 128(R15) + JS error_not_enough_literals + CMPQ R13, $0x00020002 + JA sequenceDecs_decode_56_bmi2_error_match_len_too_big + TESTQ CX, CX + JNZ sequenceDecs_decode_56_bmi2_match_len_ofs_ok + TESTQ R13, R13 + JNZ sequenceDecs_decode_56_bmi2_error_match_len_ofs_mismatch + +sequenceDecs_decode_56_bmi2_match_len_ofs_ok: + ADDQ $0x18, R9 + MOVQ ctx+16(FP), CX + DECQ 96(CX) + JNS sequenceDecs_decode_56_bmi2_main_loop + MOVQ s+0(FP), CX + MOVQ R10, 144(CX) + MOVQ R11, 152(CX) + MOVQ R12, 160(CX) + MOVQ br+8(FP), CX + MOVQ AX, 24(CX) + MOVB DL, 40(CX) + MOVQ BX, 32(CX) + + // Return success + MOVQ $0x00000000, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decode_56_bmi2_error_match_len_ofs_mismatch: + MOVQ $0x00000001, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decode_56_bmi2_error_match_len_too_big: + MOVQ $0x00000002, ret+24(FP) + RET + + // Return with match offset too long error + MOVQ $0x00000003, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVQ $0x00000004, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + +// func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool +// Requires: SSE +TEXT ·sequenceDecs_executeSimple_amd64(SB), $8-9 + MOVQ ctx+0(FP), R10 + MOVQ 8(R10), CX + TESTQ CX, CX + JZ empty_seqs + MOVQ (R10), AX + MOVQ 24(R10), DX + MOVQ 32(R10), BX + MOVQ 80(R10), SI + MOVQ 104(R10), DI + MOVQ 120(R10), R8 + MOVQ 56(R10), R9 + MOVQ 64(R10), R10 + ADDQ R10, R9 + + // seqsBase += 24 * seqIndex + LEAQ (DX)(DX*2), R11 + SHLQ $0x03, R11 + ADDQ R11, AX + + // outBase += outPosition + ADDQ DI, BX + +main_loop: + MOVQ (AX), R11 + MOVQ 16(AX), R12 + MOVQ 8(AX), R13 + + // Copy literals + TESTQ R11, R11 + JZ check_offset + XORQ R14, R14 + +copy_1: + MOVUPS (SI)(R14*1), X0 + MOVUPS X0, (BX)(R14*1) + ADDQ $0x10, R14 + CMPQ R14, R11 + JB copy_1 + ADDQ R11, SI + ADDQ R11, BX + ADDQ R11, DI + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + LEAQ (DI)(R10*1), R11 + CMPQ R12, R11 + JG error_match_off_too_big + CMPQ R12, R8 + JG error_match_off_too_big + + // Copy match from history + MOVQ R12, R11 + SUBQ DI, R11 + JLS copy_match + MOVQ R9, R14 + SUBQ R11, R14 + CMPQ R13, R11 + JG copy_all_from_history + MOVQ R13, R11 + SUBQ $0x10, R11 + JB copy_4_small + +copy_4_loop: + MOVUPS (R14), X0 + MOVUPS X0, (BX) + ADDQ $0x10, R14 + ADDQ $0x10, BX + SUBQ $0x10, R11 + JAE copy_4_loop + LEAQ 16(R14)(R11*1), R14 + LEAQ 16(BX)(R11*1), BX + MOVUPS -16(R14), X0 + MOVUPS X0, -16(BX) + JMP copy_4_end + +copy_4_small: + CMPQ R13, $0x03 + JE copy_4_move_3 + CMPQ R13, $0x08 + JB copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVW (R14), R11 + MOVB 2(R14), R12 + MOVW R11, (BX) + MOVB R12, 2(BX) + ADDQ R13, R14 + ADDQ R13, BX + JMP copy_4_end + +copy_4_move_4through7: + MOVL (R14), R11 + MOVL -4(R14)(R13*1), R12 + MOVL R11, (BX) + MOVL R12, -4(BX)(R13*1) + ADDQ R13, R14 + ADDQ R13, BX + JMP copy_4_end + +copy_4_move_8through16: + MOVQ (R14), R11 + MOVQ -8(R14)(R13*1), R12 + MOVQ R11, (BX) + MOVQ R12, -8(BX)(R13*1) + ADDQ R13, R14 + ADDQ R13, BX + +copy_4_end: + ADDQ R13, DI + ADDQ $0x18, AX + INCQ DX + CMPQ DX, CX + JB main_loop + JMP loop_finished + +copy_all_from_history: + MOVQ R11, R15 + SUBQ $0x10, R15 + JB copy_5_small + +copy_5_loop: + MOVUPS (R14), X0 + MOVUPS X0, (BX) + ADDQ $0x10, R14 + ADDQ $0x10, BX + SUBQ $0x10, R15 + JAE copy_5_loop + LEAQ 16(R14)(R15*1), R14 + LEAQ 16(BX)(R15*1), BX + MOVUPS -16(R14), X0 + MOVUPS X0, -16(BX) + JMP copy_5_end + +copy_5_small: + CMPQ R11, $0x03 + JE copy_5_move_3 + JB copy_5_move_1or2 + CMPQ R11, $0x08 + JB copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVB (R14), R15 + MOVB -1(R14)(R11*1), BP + MOVB R15, (BX) + MOVB BP, -1(BX)(R11*1) + ADDQ R11, R14 + ADDQ R11, BX + JMP copy_5_end + +copy_5_move_3: + MOVW (R14), R15 + MOVB 2(R14), BP + MOVW R15, (BX) + MOVB BP, 2(BX) + ADDQ R11, R14 + ADDQ R11, BX + JMP copy_5_end + +copy_5_move_4through7: + MOVL (R14), R15 + MOVL -4(R14)(R11*1), BP + MOVL R15, (BX) + MOVL BP, -4(BX)(R11*1) + ADDQ R11, R14 + ADDQ R11, BX + JMP copy_5_end + +copy_5_move_8through16: + MOVQ (R14), R15 + MOVQ -8(R14)(R11*1), BP + MOVQ R15, (BX) + MOVQ BP, -8(BX)(R11*1) + ADDQ R11, R14 + ADDQ R11, BX + +copy_5_end: + ADDQ R11, DI + SUBQ R11, R13 + + // Copy match from the current buffer +copy_match: + MOVQ BX, R11 + SUBQ R12, R11 + + // ml <= mo + CMPQ R13, R12 + JA copy_overlapping_match + + // Copy non-overlapping match + ADDQ R13, DI + MOVQ BX, R12 + ADDQ R13, BX + +copy_2: + MOVUPS (R11), X0 + MOVUPS X0, (R12) + ADDQ $0x10, R11 + ADDQ $0x10, R12 + SUBQ $0x10, R13 + JHI copy_2 + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADDQ R13, DI + +copy_slow_3: + MOVB (R11), R12 + MOVB R12, (BX) + INCQ R11 + INCQ BX + DECQ R13 + JNZ copy_slow_3 + +handle_loop: + ADDQ $0x18, AX + INCQ DX + CMPQ DX, CX + JB main_loop + +loop_finished: + // Return value + MOVB $0x01, ret+8(FP) + + // Update the context + MOVQ ctx+0(FP), AX + MOVQ DX, 24(AX) + MOVQ DI, 104(AX) + SUBQ 80(AX), SI + MOVQ SI, 112(AX) + RET + +error_match_off_too_big: + // Return value + MOVB $0x00, ret+8(FP) + + // Update the context + MOVQ ctx+0(FP), AX + MOVQ DX, 24(AX) + MOVQ DI, 104(AX) + SUBQ 80(AX), SI + MOVQ SI, 112(AX) + RET + +empty_seqs: + // Return value + MOVB $0x01, ret+8(FP) + RET + +// func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool +// Requires: SSE +TEXT ·sequenceDecs_executeSimple_safe_amd64(SB), $8-9 + MOVQ ctx+0(FP), R10 + MOVQ 8(R10), CX + TESTQ CX, CX + JZ empty_seqs + MOVQ (R10), AX + MOVQ 24(R10), DX + MOVQ 32(R10), BX + MOVQ 80(R10), SI + MOVQ 104(R10), DI + MOVQ 120(R10), R8 + MOVQ 56(R10), R9 + MOVQ 64(R10), R10 + ADDQ R10, R9 + + // seqsBase += 24 * seqIndex + LEAQ (DX)(DX*2), R11 + SHLQ $0x03, R11 + ADDQ R11, AX + + // outBase += outPosition + ADDQ DI, BX + +main_loop: + MOVQ (AX), R11 + MOVQ 16(AX), R12 + MOVQ 8(AX), R13 + + // Copy literals + TESTQ R11, R11 + JZ check_offset + MOVQ R11, R14 + SUBQ $0x10, R14 + JB copy_1_small + +copy_1_loop: + MOVUPS (SI), X0 + MOVUPS X0, (BX) + ADDQ $0x10, SI + ADDQ $0x10, BX + SUBQ $0x10, R14 + JAE copy_1_loop + LEAQ 16(SI)(R14*1), SI + LEAQ 16(BX)(R14*1), BX + MOVUPS -16(SI), X0 + MOVUPS X0, -16(BX) + JMP copy_1_end + +copy_1_small: + CMPQ R11, $0x03 + JE copy_1_move_3 + JB copy_1_move_1or2 + CMPQ R11, $0x08 + JB copy_1_move_4through7 + JMP copy_1_move_8through16 + +copy_1_move_1or2: + MOVB (SI), R14 + MOVB -1(SI)(R11*1), R15 + MOVB R14, (BX) + MOVB R15, -1(BX)(R11*1) + ADDQ R11, SI + ADDQ R11, BX + JMP copy_1_end + +copy_1_move_3: + MOVW (SI), R14 + MOVB 2(SI), R15 + MOVW R14, (BX) + MOVB R15, 2(BX) + ADDQ R11, SI + ADDQ R11, BX + JMP copy_1_end + +copy_1_move_4through7: + MOVL (SI), R14 + MOVL -4(SI)(R11*1), R15 + MOVL R14, (BX) + MOVL R15, -4(BX)(R11*1) + ADDQ R11, SI + ADDQ R11, BX + JMP copy_1_end + +copy_1_move_8through16: + MOVQ (SI), R14 + MOVQ -8(SI)(R11*1), R15 + MOVQ R14, (BX) + MOVQ R15, -8(BX)(R11*1) + ADDQ R11, SI + ADDQ R11, BX + +copy_1_end: + ADDQ R11, DI + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + LEAQ (DI)(R10*1), R11 + CMPQ R12, R11 + JG error_match_off_too_big + CMPQ R12, R8 + JG error_match_off_too_big + + // Copy match from history + MOVQ R12, R11 + SUBQ DI, R11 + JLS copy_match + MOVQ R9, R14 + SUBQ R11, R14 + CMPQ R13, R11 + JG copy_all_from_history + MOVQ R13, R11 + SUBQ $0x10, R11 + JB copy_4_small + +copy_4_loop: + MOVUPS (R14), X0 + MOVUPS X0, (BX) + ADDQ $0x10, R14 + ADDQ $0x10, BX + SUBQ $0x10, R11 + JAE copy_4_loop + LEAQ 16(R14)(R11*1), R14 + LEAQ 16(BX)(R11*1), BX + MOVUPS -16(R14), X0 + MOVUPS X0, -16(BX) + JMP copy_4_end + +copy_4_small: + CMPQ R13, $0x03 + JE copy_4_move_3 + CMPQ R13, $0x08 + JB copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVW (R14), R11 + MOVB 2(R14), R12 + MOVW R11, (BX) + MOVB R12, 2(BX) + ADDQ R13, R14 + ADDQ R13, BX + JMP copy_4_end + +copy_4_move_4through7: + MOVL (R14), R11 + MOVL -4(R14)(R13*1), R12 + MOVL R11, (BX) + MOVL R12, -4(BX)(R13*1) + ADDQ R13, R14 + ADDQ R13, BX + JMP copy_4_end + +copy_4_move_8through16: + MOVQ (R14), R11 + MOVQ -8(R14)(R13*1), R12 + MOVQ R11, (BX) + MOVQ R12, -8(BX)(R13*1) + ADDQ R13, R14 + ADDQ R13, BX + +copy_4_end: + ADDQ R13, DI + ADDQ $0x18, AX + INCQ DX + CMPQ DX, CX + JB main_loop + JMP loop_finished + +copy_all_from_history: + MOVQ R11, R15 + SUBQ $0x10, R15 + JB copy_5_small + +copy_5_loop: + MOVUPS (R14), X0 + MOVUPS X0, (BX) + ADDQ $0x10, R14 + ADDQ $0x10, BX + SUBQ $0x10, R15 + JAE copy_5_loop + LEAQ 16(R14)(R15*1), R14 + LEAQ 16(BX)(R15*1), BX + MOVUPS -16(R14), X0 + MOVUPS X0, -16(BX) + JMP copy_5_end + +copy_5_small: + CMPQ R11, $0x03 + JE copy_5_move_3 + JB copy_5_move_1or2 + CMPQ R11, $0x08 + JB copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVB (R14), R15 + MOVB -1(R14)(R11*1), BP + MOVB R15, (BX) + MOVB BP, -1(BX)(R11*1) + ADDQ R11, R14 + ADDQ R11, BX + JMP copy_5_end + +copy_5_move_3: + MOVW (R14), R15 + MOVB 2(R14), BP + MOVW R15, (BX) + MOVB BP, 2(BX) + ADDQ R11, R14 + ADDQ R11, BX + JMP copy_5_end + +copy_5_move_4through7: + MOVL (R14), R15 + MOVL -4(R14)(R11*1), BP + MOVL R15, (BX) + MOVL BP, -4(BX)(R11*1) + ADDQ R11, R14 + ADDQ R11, BX + JMP copy_5_end + +copy_5_move_8through16: + MOVQ (R14), R15 + MOVQ -8(R14)(R11*1), BP + MOVQ R15, (BX) + MOVQ BP, -8(BX)(R11*1) + ADDQ R11, R14 + ADDQ R11, BX + +copy_5_end: + ADDQ R11, DI + SUBQ R11, R13 + + // Copy match from the current buffer +copy_match: + MOVQ BX, R11 + SUBQ R12, R11 + + // ml <= mo + CMPQ R13, R12 + JA copy_overlapping_match + + // Copy non-overlapping match + ADDQ R13, DI + MOVQ R13, R12 + SUBQ $0x10, R12 + JB copy_2_small + +copy_2_loop: + MOVUPS (R11), X0 + MOVUPS X0, (BX) + ADDQ $0x10, R11 + ADDQ $0x10, BX + SUBQ $0x10, R12 + JAE copy_2_loop + LEAQ 16(R11)(R12*1), R11 + LEAQ 16(BX)(R12*1), BX + MOVUPS -16(R11), X0 + MOVUPS X0, -16(BX) + JMP copy_2_end + +copy_2_small: + CMPQ R13, $0x03 + JE copy_2_move_3 + JB copy_2_move_1or2 + CMPQ R13, $0x08 + JB copy_2_move_4through7 + JMP copy_2_move_8through16 + +copy_2_move_1or2: + MOVB (R11), R12 + MOVB -1(R11)(R13*1), R14 + MOVB R12, (BX) + MOVB R14, -1(BX)(R13*1) + ADDQ R13, R11 + ADDQ R13, BX + JMP copy_2_end + +copy_2_move_3: + MOVW (R11), R12 + MOVB 2(R11), R14 + MOVW R12, (BX) + MOVB R14, 2(BX) + ADDQ R13, R11 + ADDQ R13, BX + JMP copy_2_end + +copy_2_move_4through7: + MOVL (R11), R12 + MOVL -4(R11)(R13*1), R14 + MOVL R12, (BX) + MOVL R14, -4(BX)(R13*1) + ADDQ R13, R11 + ADDQ R13, BX + JMP copy_2_end + +copy_2_move_8through16: + MOVQ (R11), R12 + MOVQ -8(R11)(R13*1), R14 + MOVQ R12, (BX) + MOVQ R14, -8(BX)(R13*1) + ADDQ R13, R11 + ADDQ R13, BX + +copy_2_end: + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADDQ R13, DI + +copy_slow_3: + MOVB (R11), R12 + MOVB R12, (BX) + INCQ R11 + INCQ BX + DECQ R13 + JNZ copy_slow_3 + +handle_loop: + ADDQ $0x18, AX + INCQ DX + CMPQ DX, CX + JB main_loop + +loop_finished: + // Return value + MOVB $0x01, ret+8(FP) + + // Update the context + MOVQ ctx+0(FP), AX + MOVQ DX, 24(AX) + MOVQ DI, 104(AX) + SUBQ 80(AX), SI + MOVQ SI, 112(AX) + RET + +error_match_off_too_big: + // Return value + MOVB $0x00, ret+8(FP) + + // Update the context + MOVQ ctx+0(FP), AX + MOVQ DX, 24(AX) + MOVQ DI, 104(AX) + SUBQ 80(AX), SI + MOVQ SI, 112(AX) + RET + +empty_seqs: + // Return value + MOVB $0x01, ret+8(FP) + RET + +// func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int +// Requires: CMOV, SSE +TEXT ·sequenceDecs_decodeSync_amd64(SB), $64-32 + MOVQ br+8(FP), CX + MOVQ 24(CX), DX + MOVBQZX 40(CX), BX + MOVQ (CX), AX + MOVQ 32(CX), SI + ADDQ SI, AX + MOVQ AX, (SP) + MOVQ ctx+16(FP), AX + MOVQ 72(AX), DI + MOVQ 80(AX), R8 + MOVQ 88(AX), R9 + XORQ CX, CX + MOVQ CX, 8(SP) + MOVQ CX, 16(SP) + MOVQ CX, 24(SP) + MOVQ 112(AX), R10 + MOVQ 128(AX), CX + MOVQ CX, 32(SP) + MOVQ 144(AX), R11 + MOVQ 136(AX), R12 + MOVQ 200(AX), CX + MOVQ CX, 56(SP) + MOVQ 176(AX), CX + MOVQ CX, 48(SP) + MOVQ 184(AX), AX + MOVQ AX, 40(SP) + MOVQ 40(SP), AX + ADDQ AX, 48(SP) + + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) + ADDQ R10, 32(SP) + + // outBase += outPosition + ADDQ R12, R10 + +sequenceDecs_decodeSync_amd64_main_loop: + MOVQ (SP), R13 + + // Fill bitreader to have enough for the offset and match length. + CMPQ SI, $0x08 + JL sequenceDecs_decodeSync_amd64_fill_byte_by_byte + MOVQ BX, AX + SHRQ $0x03, AX + SUBQ AX, R13 + MOVQ (R13), DX + SUBQ AX, SI + ANDQ $0x07, BX + JMP sequenceDecs_decodeSync_amd64_fill_end + +sequenceDecs_decodeSync_amd64_fill_byte_by_byte: + CMPQ SI, $0x00 + JLE sequenceDecs_decodeSync_amd64_fill_check_overread + CMPQ BX, $0x07 + JLE sequenceDecs_decodeSync_amd64_fill_end + SHLQ $0x08, DX + SUBQ $0x01, R13 + SUBQ $0x01, SI + SUBQ $0x08, BX + MOVBQZX (R13), AX + ORQ AX, DX + JMP sequenceDecs_decodeSync_amd64_fill_byte_by_byte + +sequenceDecs_decodeSync_amd64_fill_check_overread: + CMPQ BX, $0x40 + JA error_overread + +sequenceDecs_decodeSync_amd64_fill_end: + // Update offset + MOVQ R9, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decodeSync_amd64_of_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decodeSync_amd64_of_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decodeSync_amd64_of_update_zero + NEGQ CX + SHRQ CL, R14 + ADDQ R14, AX + +sequenceDecs_decodeSync_amd64_of_update_zero: + MOVQ AX, 8(SP) + + // Update match length + MOVQ R8, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decodeSync_amd64_ml_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decodeSync_amd64_ml_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decodeSync_amd64_ml_update_zero + NEGQ CX + SHRQ CL, R14 + ADDQ R14, AX + +sequenceDecs_decodeSync_amd64_ml_update_zero: + MOVQ AX, 16(SP) + + // Fill bitreader to have enough for the remaining + CMPQ SI, $0x08 + JL sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte + MOVQ BX, AX + SHRQ $0x03, AX + SUBQ AX, R13 + MOVQ (R13), DX + SUBQ AX, SI + ANDQ $0x07, BX + JMP sequenceDecs_decodeSync_amd64_fill_2_end + +sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte: + CMPQ SI, $0x00 + JLE sequenceDecs_decodeSync_amd64_fill_2_check_overread + CMPQ BX, $0x07 + JLE sequenceDecs_decodeSync_amd64_fill_2_end + SHLQ $0x08, DX + SUBQ $0x01, R13 + SUBQ $0x01, SI + SUBQ $0x08, BX + MOVBQZX (R13), AX + ORQ AX, DX + JMP sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte + +sequenceDecs_decodeSync_amd64_fill_2_check_overread: + CMPQ BX, $0x40 + JA error_overread + +sequenceDecs_decodeSync_amd64_fill_2_end: + // Update literal length + MOVQ DI, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decodeSync_amd64_ll_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decodeSync_amd64_ll_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decodeSync_amd64_ll_update_zero + NEGQ CX + SHRQ CL, R14 + ADDQ R14, AX + +sequenceDecs_decodeSync_amd64_ll_update_zero: + MOVQ AX, 24(SP) + + // Fill bitreader for state updates + MOVQ R13, (SP) + MOVQ R9, AX + SHRQ $0x08, AX + MOVBQZX AL, AX + MOVQ ctx+16(FP), CX + CMPQ 96(CX), $0x00 + JZ sequenceDecs_decodeSync_amd64_skip_update + + // Update Literal Length State + MOVBQZX DI, R13 + SHRL $0x10, DI + LEAQ (BX)(R13*1), CX + MOVQ DX, R14 + MOVQ CX, BX + ROLQ CL, R14 + MOVL $0x00000001, R15 + MOVB R13, CL + SHLL CL, R15 + DECL R15 + ANDQ R15, R14 + ADDQ R14, DI + + // Load ctx.llTable + MOVQ ctx+16(FP), CX + MOVQ (CX), CX + MOVQ (CX)(DI*8), DI + + // Update Match Length State + MOVBQZX R8, R13 + SHRL $0x10, R8 + LEAQ (BX)(R13*1), CX + MOVQ DX, R14 + MOVQ CX, BX + ROLQ CL, R14 + MOVL $0x00000001, R15 + MOVB R13, CL + SHLL CL, R15 + DECL R15 + ANDQ R15, R14 + ADDQ R14, R8 + + // Load ctx.mlTable + MOVQ ctx+16(FP), CX + MOVQ 24(CX), CX + MOVQ (CX)(R8*8), R8 + + // Update Offset State + MOVBQZX R9, R13 + SHRL $0x10, R9 + LEAQ (BX)(R13*1), CX + MOVQ DX, R14 + MOVQ CX, BX + ROLQ CL, R14 + MOVL $0x00000001, R15 + MOVB R13, CL + SHLL CL, R15 + DECL R15 + ANDQ R15, R14 + ADDQ R14, R9 + + // Load ctx.ofTable + MOVQ ctx+16(FP), CX + MOVQ 48(CX), CX + MOVQ (CX)(R9*8), R9 + +sequenceDecs_decodeSync_amd64_skip_update: + // Adjust offset + MOVQ s+0(FP), CX + MOVQ 8(SP), R13 + CMPQ AX, $0x01 + JBE sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0 + MOVUPS 144(CX), X0 + MOVQ R13, 144(CX) + MOVUPS X0, 152(CX) + JMP sequenceDecs_decodeSync_amd64_after_adjust + +sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0: + CMPQ 24(SP), $0x00000000 + JNE sequenceDecs_decodeSync_amd64_adjust_offset_maybezero + INCQ R13 + JMP sequenceDecs_decodeSync_amd64_adjust_offset_nonzero + +sequenceDecs_decodeSync_amd64_adjust_offset_maybezero: + TESTQ R13, R13 + JNZ sequenceDecs_decodeSync_amd64_adjust_offset_nonzero + MOVQ 144(CX), R13 + JMP sequenceDecs_decodeSync_amd64_after_adjust + +sequenceDecs_decodeSync_amd64_adjust_offset_nonzero: + MOVQ R13, AX + XORQ R14, R14 + MOVQ $-1, R15 + CMPQ R13, $0x03 + CMOVQEQ R14, AX + CMOVQEQ R15, R14 + ADDQ 144(CX)(AX*8), R14 + JNZ sequenceDecs_decodeSync_amd64_adjust_temp_valid + MOVQ $0x00000001, R14 + +sequenceDecs_decodeSync_amd64_adjust_temp_valid: + CMPQ R13, $0x01 + JZ sequenceDecs_decodeSync_amd64_adjust_skip + MOVQ 152(CX), AX + MOVQ AX, 160(CX) + +sequenceDecs_decodeSync_amd64_adjust_skip: + MOVQ 144(CX), AX + MOVQ AX, 152(CX) + MOVQ R14, 144(CX) + MOVQ R14, R13 + +sequenceDecs_decodeSync_amd64_after_adjust: + MOVQ R13, 8(SP) + + // Check values + MOVQ 16(SP), AX + MOVQ 24(SP), CX + LEAQ (AX)(CX*1), R14 + MOVQ s+0(FP), R15 + ADDQ R14, 256(R15) + MOVQ ctx+16(FP), R14 + SUBQ CX, 104(R14) + JS error_not_enough_literals + CMPQ AX, $0x00020002 + JA sequenceDecs_decodeSync_amd64_error_match_len_too_big + TESTQ R13, R13 + JNZ sequenceDecs_decodeSync_amd64_match_len_ofs_ok + TESTQ AX, AX + JNZ sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch + +sequenceDecs_decodeSync_amd64_match_len_ofs_ok: + MOVQ 24(SP), AX + MOVQ 8(SP), CX + MOVQ 16(SP), R13 + + // Check if we have enough space in s.out + LEAQ 16(AX)(R13*1), R14 + ADDQ R10, R14 + CMPQ R14, 32(SP) + JA error_not_enough_space + + // Copy literals + TESTQ AX, AX + JZ check_offset + XORQ R14, R14 + +copy_1: + MOVUPS (R11)(R14*1), X0 + MOVUPS X0, (R10)(R14*1) + ADDQ $0x10, R14 + CMPQ R14, AX + JB copy_1 + ADDQ AX, R11 + ADDQ AX, R10 + ADDQ AX, R12 + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + MOVQ R12, AX + ADDQ 40(SP), AX + CMPQ CX, AX + JG error_match_off_too_big + CMPQ CX, 56(SP) + JG error_match_off_too_big + + // Copy match from history + MOVQ CX, AX + SUBQ R12, AX + JLS copy_match + MOVQ 48(SP), R14 + SUBQ AX, R14 + CMPQ R13, AX + JG copy_all_from_history + MOVQ R13, AX + SUBQ $0x10, AX + JB copy_4_small + +copy_4_loop: + MOVUPS (R14), X0 + MOVUPS X0, (R10) + ADDQ $0x10, R14 + ADDQ $0x10, R10 + SUBQ $0x10, AX + JAE copy_4_loop + LEAQ 16(R14)(AX*1), R14 + LEAQ 16(R10)(AX*1), R10 + MOVUPS -16(R14), X0 + MOVUPS X0, -16(R10) + JMP copy_4_end + +copy_4_small: + CMPQ R13, $0x03 + JE copy_4_move_3 + CMPQ R13, $0x08 + JB copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVW (R14), AX + MOVB 2(R14), CL + MOVW AX, (R10) + MOVB CL, 2(R10) + ADDQ R13, R14 + ADDQ R13, R10 + JMP copy_4_end + +copy_4_move_4through7: + MOVL (R14), AX + MOVL -4(R14)(R13*1), CX + MOVL AX, (R10) + MOVL CX, -4(R10)(R13*1) + ADDQ R13, R14 + ADDQ R13, R10 + JMP copy_4_end + +copy_4_move_8through16: + MOVQ (R14), AX + MOVQ -8(R14)(R13*1), CX + MOVQ AX, (R10) + MOVQ CX, -8(R10)(R13*1) + ADDQ R13, R14 + ADDQ R13, R10 + +copy_4_end: + ADDQ R13, R12 + JMP handle_loop + JMP loop_finished + +copy_all_from_history: + MOVQ AX, R15 + SUBQ $0x10, R15 + JB copy_5_small + +copy_5_loop: + MOVUPS (R14), X0 + MOVUPS X0, (R10) + ADDQ $0x10, R14 + ADDQ $0x10, R10 + SUBQ $0x10, R15 + JAE copy_5_loop + LEAQ 16(R14)(R15*1), R14 + LEAQ 16(R10)(R15*1), R10 + MOVUPS -16(R14), X0 + MOVUPS X0, -16(R10) + JMP copy_5_end + +copy_5_small: + CMPQ AX, $0x03 + JE copy_5_move_3 + JB copy_5_move_1or2 + CMPQ AX, $0x08 + JB copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVB (R14), R15 + MOVB -1(R14)(AX*1), BP + MOVB R15, (R10) + MOVB BP, -1(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 + JMP copy_5_end + +copy_5_move_3: + MOVW (R14), R15 + MOVB 2(R14), BP + MOVW R15, (R10) + MOVB BP, 2(R10) + ADDQ AX, R14 + ADDQ AX, R10 + JMP copy_5_end + +copy_5_move_4through7: + MOVL (R14), R15 + MOVL -4(R14)(AX*1), BP + MOVL R15, (R10) + MOVL BP, -4(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 + JMP copy_5_end + +copy_5_move_8through16: + MOVQ (R14), R15 + MOVQ -8(R14)(AX*1), BP + MOVQ R15, (R10) + MOVQ BP, -8(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 + +copy_5_end: + ADDQ AX, R12 + SUBQ AX, R13 + + // Copy match from the current buffer +copy_match: + MOVQ R10, AX + SUBQ CX, AX + + // ml <= mo + CMPQ R13, CX + JA copy_overlapping_match + + // Copy non-overlapping match + ADDQ R13, R12 + MOVQ R10, CX + ADDQ R13, R10 + +copy_2: + MOVUPS (AX), X0 + MOVUPS X0, (CX) + ADDQ $0x10, AX + ADDQ $0x10, CX + SUBQ $0x10, R13 + JHI copy_2 + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADDQ R13, R12 + +copy_slow_3: + MOVB (AX), CL + MOVB CL, (R10) + INCQ AX + INCQ R10 + DECQ R13 + JNZ copy_slow_3 + +handle_loop: + MOVQ ctx+16(FP), AX + DECQ 96(AX) + JNS sequenceDecs_decodeSync_amd64_main_loop + +loop_finished: + MOVQ br+8(FP), AX + MOVQ DX, 24(AX) + MOVB BL, 40(AX) + MOVQ SI, 32(AX) + + // Update the context + MOVQ ctx+16(FP), AX + MOVQ R12, 136(AX) + MOVQ 144(AX), CX + SUBQ CX, R11 + MOVQ R11, 168(AX) + + // Return success + MOVQ $0x00000000, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch: + MOVQ 16(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 216(CX) + MOVQ $0x00000001, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decodeSync_amd64_error_match_len_too_big: + MOVQ ctx+16(FP), AX + MOVQ 16(SP), CX + MOVQ CX, 216(AX) + MOVQ $0x00000002, ret+24(FP) + RET + + // Return with match offset too long error +error_match_off_too_big: + MOVQ ctx+16(FP), AX + MOVQ 8(SP), CX + MOVQ CX, 224(AX) + MOVQ R12, 136(AX) + MOVQ $0x00000003, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVQ ctx+16(FP), AX + MOVQ 24(SP), CX + MOVQ CX, 208(AX) + MOVQ $0x00000004, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + + // Return with not enough output space error +error_not_enough_space: + MOVQ ctx+16(FP), AX + MOVQ 24(SP), CX + MOVQ CX, 208(AX) + MOVQ 16(SP), CX + MOVQ CX, 216(AX) + MOVQ R12, 136(AX) + MOVQ $0x00000005, ret+24(FP) + RET + +// func sequenceDecs_decodeSync_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int +// Requires: BMI, BMI2, CMOV, SSE +TEXT ·sequenceDecs_decodeSync_bmi2(SB), $64-32 + MOVQ br+8(FP), BX + MOVQ 24(BX), AX + MOVBQZX 40(BX), DX + MOVQ (BX), CX + MOVQ 32(BX), BX + ADDQ BX, CX + MOVQ CX, (SP) + MOVQ ctx+16(FP), CX + MOVQ 72(CX), SI + MOVQ 80(CX), DI + MOVQ 88(CX), R8 + XORQ R9, R9 + MOVQ R9, 8(SP) + MOVQ R9, 16(SP) + MOVQ R9, 24(SP) + MOVQ 112(CX), R9 + MOVQ 128(CX), R10 + MOVQ R10, 32(SP) + MOVQ 144(CX), R10 + MOVQ 136(CX), R11 + MOVQ 200(CX), R12 + MOVQ R12, 56(SP) + MOVQ 176(CX), R12 + MOVQ R12, 48(SP) + MOVQ 184(CX), CX + MOVQ CX, 40(SP) + MOVQ 40(SP), CX + ADDQ CX, 48(SP) + + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) + ADDQ R9, 32(SP) + + // outBase += outPosition + ADDQ R11, R9 + +sequenceDecs_decodeSync_bmi2_main_loop: + MOVQ (SP), R12 + + // Fill bitreader to have enough for the offset and match length. + CMPQ BX, $0x08 + JL sequenceDecs_decodeSync_bmi2_fill_byte_by_byte + MOVQ DX, CX + SHRQ $0x03, CX + SUBQ CX, R12 + MOVQ (R12), AX + SUBQ CX, BX + ANDQ $0x07, DX + JMP sequenceDecs_decodeSync_bmi2_fill_end + +sequenceDecs_decodeSync_bmi2_fill_byte_by_byte: + CMPQ BX, $0x00 + JLE sequenceDecs_decodeSync_bmi2_fill_check_overread + CMPQ DX, $0x07 + JLE sequenceDecs_decodeSync_bmi2_fill_end + SHLQ $0x08, AX + SUBQ $0x01, R12 + SUBQ $0x01, BX + SUBQ $0x08, DX + MOVBQZX (R12), CX + ORQ CX, AX + JMP sequenceDecs_decodeSync_bmi2_fill_byte_by_byte + +sequenceDecs_decodeSync_bmi2_fill_check_overread: + CMPQ DX, $0x40 + JA error_overread + +sequenceDecs_decodeSync_bmi2_fill_end: + // Update offset + MOVQ $0x00000808, CX + BEXTRQ CX, R8, R13 + MOVQ AX, R14 + LEAQ (DX)(R13*1), CX + ROLQ CL, R14 + BZHIQ R13, R14, R14 + MOVQ CX, DX + MOVQ R8, CX + SHRQ $0x20, CX + ADDQ R14, CX + MOVQ CX, 8(SP) + + // Update match length + MOVQ $0x00000808, CX + BEXTRQ CX, DI, R13 + MOVQ AX, R14 + LEAQ (DX)(R13*1), CX + ROLQ CL, R14 + BZHIQ R13, R14, R14 + MOVQ CX, DX + MOVQ DI, CX + SHRQ $0x20, CX + ADDQ R14, CX + MOVQ CX, 16(SP) + + // Fill bitreader to have enough for the remaining + CMPQ BX, $0x08 + JL sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte + MOVQ DX, CX + SHRQ $0x03, CX + SUBQ CX, R12 + MOVQ (R12), AX + SUBQ CX, BX + ANDQ $0x07, DX + JMP sequenceDecs_decodeSync_bmi2_fill_2_end + +sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte: + CMPQ BX, $0x00 + JLE sequenceDecs_decodeSync_bmi2_fill_2_check_overread + CMPQ DX, $0x07 + JLE sequenceDecs_decodeSync_bmi2_fill_2_end + SHLQ $0x08, AX + SUBQ $0x01, R12 + SUBQ $0x01, BX + SUBQ $0x08, DX + MOVBQZX (R12), CX + ORQ CX, AX + JMP sequenceDecs_decodeSync_bmi2_fill_2_byte_by_byte + +sequenceDecs_decodeSync_bmi2_fill_2_check_overread: + CMPQ DX, $0x40 + JA error_overread + +sequenceDecs_decodeSync_bmi2_fill_2_end: + // Update literal length + MOVQ $0x00000808, CX + BEXTRQ CX, SI, R13 + MOVQ AX, R14 + LEAQ (DX)(R13*1), CX + ROLQ CL, R14 + BZHIQ R13, R14, R14 + MOVQ CX, DX + MOVQ SI, CX + SHRQ $0x20, CX + ADDQ R14, CX + MOVQ CX, 24(SP) + + // Fill bitreader for state updates + MOVQ R12, (SP) + MOVQ $0x00000808, CX + BEXTRQ CX, R8, R12 + MOVQ ctx+16(FP), CX + CMPQ 96(CX), $0x00 + JZ sequenceDecs_decodeSync_bmi2_skip_update + LEAQ (SI)(DI*1), R13 + ADDQ R8, R13 + MOVBQZX R13, R13 + LEAQ (DX)(R13*1), CX + MOVQ AX, R14 + MOVQ CX, DX + ROLQ CL, R14 + BZHIQ R13, R14, R14 + + // Update Offset State + BZHIQ R8, R14, CX + SHRXQ R8, R14, R14 + SHRL $0x10, R8 + ADDQ CX, R8 + + // Load ctx.ofTable + MOVQ ctx+16(FP), CX + MOVQ 48(CX), CX + MOVQ (CX)(R8*8), R8 + + // Update Match Length State + BZHIQ DI, R14, CX + SHRXQ DI, R14, R14 + SHRL $0x10, DI + ADDQ CX, DI + + // Load ctx.mlTable + MOVQ ctx+16(FP), CX + MOVQ 24(CX), CX + MOVQ (CX)(DI*8), DI + + // Update Literal Length State + BZHIQ SI, R14, CX + SHRL $0x10, SI + ADDQ CX, SI + + // Load ctx.llTable + MOVQ ctx+16(FP), CX + MOVQ (CX), CX + MOVQ (CX)(SI*8), SI + +sequenceDecs_decodeSync_bmi2_skip_update: + // Adjust offset + MOVQ s+0(FP), CX + MOVQ 8(SP), R13 + CMPQ R12, $0x01 + JBE sequenceDecs_decodeSync_bmi2_adjust_offsetB_1_or_0 + MOVUPS 144(CX), X0 + MOVQ R13, 144(CX) + MOVUPS X0, 152(CX) + JMP sequenceDecs_decodeSync_bmi2_after_adjust + +sequenceDecs_decodeSync_bmi2_adjust_offsetB_1_or_0: + CMPQ 24(SP), $0x00000000 + JNE sequenceDecs_decodeSync_bmi2_adjust_offset_maybezero + INCQ R13 + JMP sequenceDecs_decodeSync_bmi2_adjust_offset_nonzero + +sequenceDecs_decodeSync_bmi2_adjust_offset_maybezero: + TESTQ R13, R13 + JNZ sequenceDecs_decodeSync_bmi2_adjust_offset_nonzero + MOVQ 144(CX), R13 + JMP sequenceDecs_decodeSync_bmi2_after_adjust + +sequenceDecs_decodeSync_bmi2_adjust_offset_nonzero: + MOVQ R13, R12 + XORQ R14, R14 + MOVQ $-1, R15 + CMPQ R13, $0x03 + CMOVQEQ R14, R12 + CMOVQEQ R15, R14 + ADDQ 144(CX)(R12*8), R14 + JNZ sequenceDecs_decodeSync_bmi2_adjust_temp_valid + MOVQ $0x00000001, R14 + +sequenceDecs_decodeSync_bmi2_adjust_temp_valid: + CMPQ R13, $0x01 + JZ sequenceDecs_decodeSync_bmi2_adjust_skip + MOVQ 152(CX), R12 + MOVQ R12, 160(CX) + +sequenceDecs_decodeSync_bmi2_adjust_skip: + MOVQ 144(CX), R12 + MOVQ R12, 152(CX) + MOVQ R14, 144(CX) + MOVQ R14, R13 + +sequenceDecs_decodeSync_bmi2_after_adjust: + MOVQ R13, 8(SP) + + // Check values + MOVQ 16(SP), CX + MOVQ 24(SP), R12 + LEAQ (CX)(R12*1), R14 + MOVQ s+0(FP), R15 + ADDQ R14, 256(R15) + MOVQ ctx+16(FP), R14 + SUBQ R12, 104(R14) + JS error_not_enough_literals + CMPQ CX, $0x00020002 + JA sequenceDecs_decodeSync_bmi2_error_match_len_too_big + TESTQ R13, R13 + JNZ sequenceDecs_decodeSync_bmi2_match_len_ofs_ok + TESTQ CX, CX + JNZ sequenceDecs_decodeSync_bmi2_error_match_len_ofs_mismatch + +sequenceDecs_decodeSync_bmi2_match_len_ofs_ok: + MOVQ 24(SP), CX + MOVQ 8(SP), R12 + MOVQ 16(SP), R13 + + // Check if we have enough space in s.out + LEAQ 16(CX)(R13*1), R14 + ADDQ R9, R14 + CMPQ R14, 32(SP) + JA error_not_enough_space + + // Copy literals + TESTQ CX, CX + JZ check_offset + XORQ R14, R14 + +copy_1: + MOVUPS (R10)(R14*1), X0 + MOVUPS X0, (R9)(R14*1) + ADDQ $0x10, R14 + CMPQ R14, CX + JB copy_1 + ADDQ CX, R10 + ADDQ CX, R9 + ADDQ CX, R11 + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + MOVQ R11, CX + ADDQ 40(SP), CX + CMPQ R12, CX + JG error_match_off_too_big + CMPQ R12, 56(SP) + JG error_match_off_too_big + + // Copy match from history + MOVQ R12, CX + SUBQ R11, CX + JLS copy_match + MOVQ 48(SP), R14 + SUBQ CX, R14 + CMPQ R13, CX + JG copy_all_from_history + MOVQ R13, CX + SUBQ $0x10, CX + JB copy_4_small + +copy_4_loop: + MOVUPS (R14), X0 + MOVUPS X0, (R9) + ADDQ $0x10, R14 + ADDQ $0x10, R9 + SUBQ $0x10, CX + JAE copy_4_loop + LEAQ 16(R14)(CX*1), R14 + LEAQ 16(R9)(CX*1), R9 + MOVUPS -16(R14), X0 + MOVUPS X0, -16(R9) + JMP copy_4_end + +copy_4_small: + CMPQ R13, $0x03 + JE copy_4_move_3 + CMPQ R13, $0x08 + JB copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVW (R14), CX + MOVB 2(R14), R12 + MOVW CX, (R9) + MOVB R12, 2(R9) + ADDQ R13, R14 + ADDQ R13, R9 + JMP copy_4_end + +copy_4_move_4through7: + MOVL (R14), CX + MOVL -4(R14)(R13*1), R12 + MOVL CX, (R9) + MOVL R12, -4(R9)(R13*1) + ADDQ R13, R14 + ADDQ R13, R9 + JMP copy_4_end + +copy_4_move_8through16: + MOVQ (R14), CX + MOVQ -8(R14)(R13*1), R12 + MOVQ CX, (R9) + MOVQ R12, -8(R9)(R13*1) + ADDQ R13, R14 + ADDQ R13, R9 + +copy_4_end: + ADDQ R13, R11 + JMP handle_loop + JMP loop_finished + +copy_all_from_history: + MOVQ CX, R15 + SUBQ $0x10, R15 + JB copy_5_small + +copy_5_loop: + MOVUPS (R14), X0 + MOVUPS X0, (R9) + ADDQ $0x10, R14 + ADDQ $0x10, R9 + SUBQ $0x10, R15 + JAE copy_5_loop + LEAQ 16(R14)(R15*1), R14 + LEAQ 16(R9)(R15*1), R9 + MOVUPS -16(R14), X0 + MOVUPS X0, -16(R9) + JMP copy_5_end + +copy_5_small: + CMPQ CX, $0x03 + JE copy_5_move_3 + JB copy_5_move_1or2 + CMPQ CX, $0x08 + JB copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVB (R14), R15 + MOVB -1(R14)(CX*1), BP + MOVB R15, (R9) + MOVB BP, -1(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 + JMP copy_5_end + +copy_5_move_3: + MOVW (R14), R15 + MOVB 2(R14), BP + MOVW R15, (R9) + MOVB BP, 2(R9) + ADDQ CX, R14 + ADDQ CX, R9 + JMP copy_5_end + +copy_5_move_4through7: + MOVL (R14), R15 + MOVL -4(R14)(CX*1), BP + MOVL R15, (R9) + MOVL BP, -4(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 + JMP copy_5_end + +copy_5_move_8through16: + MOVQ (R14), R15 + MOVQ -8(R14)(CX*1), BP + MOVQ R15, (R9) + MOVQ BP, -8(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 + +copy_5_end: + ADDQ CX, R11 + SUBQ CX, R13 + + // Copy match from the current buffer +copy_match: + MOVQ R9, CX + SUBQ R12, CX + + // ml <= mo + CMPQ R13, R12 + JA copy_overlapping_match + + // Copy non-overlapping match + ADDQ R13, R11 + MOVQ R9, R12 + ADDQ R13, R9 + +copy_2: + MOVUPS (CX), X0 + MOVUPS X0, (R12) + ADDQ $0x10, CX + ADDQ $0x10, R12 + SUBQ $0x10, R13 + JHI copy_2 + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADDQ R13, R11 + +copy_slow_3: + MOVB (CX), R12 + MOVB R12, (R9) + INCQ CX + INCQ R9 + DECQ R13 + JNZ copy_slow_3 + +handle_loop: + MOVQ ctx+16(FP), CX + DECQ 96(CX) + JNS sequenceDecs_decodeSync_bmi2_main_loop + +loop_finished: + MOVQ br+8(FP), CX + MOVQ AX, 24(CX) + MOVB DL, 40(CX) + MOVQ BX, 32(CX) + + // Update the context + MOVQ ctx+16(FP), AX + MOVQ R11, 136(AX) + MOVQ 144(AX), CX + SUBQ CX, R10 + MOVQ R10, 168(AX) + + // Return success + MOVQ $0x00000000, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decodeSync_bmi2_error_match_len_ofs_mismatch: + MOVQ 16(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 216(CX) + MOVQ $0x00000001, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decodeSync_bmi2_error_match_len_too_big: + MOVQ ctx+16(FP), AX + MOVQ 16(SP), CX + MOVQ CX, 216(AX) + MOVQ $0x00000002, ret+24(FP) + RET + + // Return with match offset too long error +error_match_off_too_big: + MOVQ ctx+16(FP), AX + MOVQ 8(SP), CX + MOVQ CX, 224(AX) + MOVQ R11, 136(AX) + MOVQ $0x00000003, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVQ ctx+16(FP), AX + MOVQ 24(SP), CX + MOVQ CX, 208(AX) + MOVQ $0x00000004, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + + // Return with not enough output space error +error_not_enough_space: + MOVQ ctx+16(FP), AX + MOVQ 24(SP), CX + MOVQ CX, 208(AX) + MOVQ 16(SP), CX + MOVQ CX, 216(AX) + MOVQ R11, 136(AX) + MOVQ $0x00000005, ret+24(FP) + RET + +// func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int +// Requires: CMOV, SSE +TEXT ·sequenceDecs_decodeSync_safe_amd64(SB), $64-32 + MOVQ br+8(FP), CX + MOVQ 24(CX), DX + MOVBQZX 40(CX), BX + MOVQ (CX), AX + MOVQ 32(CX), SI + ADDQ SI, AX + MOVQ AX, (SP) + MOVQ ctx+16(FP), AX + MOVQ 72(AX), DI + MOVQ 80(AX), R8 + MOVQ 88(AX), R9 + XORQ CX, CX + MOVQ CX, 8(SP) + MOVQ CX, 16(SP) + MOVQ CX, 24(SP) + MOVQ 112(AX), R10 + MOVQ 128(AX), CX + MOVQ CX, 32(SP) + MOVQ 144(AX), R11 + MOVQ 136(AX), R12 + MOVQ 200(AX), CX + MOVQ CX, 56(SP) + MOVQ 176(AX), CX + MOVQ CX, 48(SP) + MOVQ 184(AX), AX + MOVQ AX, 40(SP) + MOVQ 40(SP), AX + ADDQ AX, 48(SP) + + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) + ADDQ R10, 32(SP) + + // outBase += outPosition + ADDQ R12, R10 + +sequenceDecs_decodeSync_safe_amd64_main_loop: + MOVQ (SP), R13 + + // Fill bitreader to have enough for the offset and match length. + CMPQ SI, $0x08 + JL sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte + MOVQ BX, AX + SHRQ $0x03, AX + SUBQ AX, R13 + MOVQ (R13), DX + SUBQ AX, SI + ANDQ $0x07, BX + JMP sequenceDecs_decodeSync_safe_amd64_fill_end + +sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte: + CMPQ SI, $0x00 + JLE sequenceDecs_decodeSync_safe_amd64_fill_check_overread + CMPQ BX, $0x07 + JLE sequenceDecs_decodeSync_safe_amd64_fill_end + SHLQ $0x08, DX + SUBQ $0x01, R13 + SUBQ $0x01, SI + SUBQ $0x08, BX + MOVBQZX (R13), AX + ORQ AX, DX + JMP sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte + +sequenceDecs_decodeSync_safe_amd64_fill_check_overread: + CMPQ BX, $0x40 + JA error_overread + +sequenceDecs_decodeSync_safe_amd64_fill_end: + // Update offset + MOVQ R9, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decodeSync_safe_amd64_of_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decodeSync_safe_amd64_of_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decodeSync_safe_amd64_of_update_zero + NEGQ CX + SHRQ CL, R14 + ADDQ R14, AX + +sequenceDecs_decodeSync_safe_amd64_of_update_zero: + MOVQ AX, 8(SP) + + // Update match length + MOVQ R8, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decodeSync_safe_amd64_ml_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decodeSync_safe_amd64_ml_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decodeSync_safe_amd64_ml_update_zero + NEGQ CX + SHRQ CL, R14 + ADDQ R14, AX + +sequenceDecs_decodeSync_safe_amd64_ml_update_zero: + MOVQ AX, 16(SP) + + // Fill bitreader to have enough for the remaining + CMPQ SI, $0x08 + JL sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte + MOVQ BX, AX + SHRQ $0x03, AX + SUBQ AX, R13 + MOVQ (R13), DX + SUBQ AX, SI + ANDQ $0x07, BX + JMP sequenceDecs_decodeSync_safe_amd64_fill_2_end + +sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte: + CMPQ SI, $0x00 + JLE sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread + CMPQ BX, $0x07 + JLE sequenceDecs_decodeSync_safe_amd64_fill_2_end + SHLQ $0x08, DX + SUBQ $0x01, R13 + SUBQ $0x01, SI + SUBQ $0x08, BX + MOVBQZX (R13), AX + ORQ AX, DX + JMP sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte + +sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread: + CMPQ BX, $0x40 + JA error_overread + +sequenceDecs_decodeSync_safe_amd64_fill_2_end: + // Update literal length + MOVQ DI, AX + MOVQ BX, CX + MOVQ DX, R14 + SHLQ CL, R14 + MOVB AH, CL + SHRQ $0x20, AX + TESTQ CX, CX + JZ sequenceDecs_decodeSync_safe_amd64_ll_update_zero + ADDQ CX, BX + CMPQ BX, $0x40 + JA sequenceDecs_decodeSync_safe_amd64_ll_update_zero + CMPQ CX, $0x40 + JAE sequenceDecs_decodeSync_safe_amd64_ll_update_zero + NEGQ CX + SHRQ CL, R14 + ADDQ R14, AX + +sequenceDecs_decodeSync_safe_amd64_ll_update_zero: + MOVQ AX, 24(SP) + + // Fill bitreader for state updates + MOVQ R13, (SP) + MOVQ R9, AX + SHRQ $0x08, AX + MOVBQZX AL, AX + MOVQ ctx+16(FP), CX + CMPQ 96(CX), $0x00 + JZ sequenceDecs_decodeSync_safe_amd64_skip_update + + // Update Literal Length State + MOVBQZX DI, R13 + SHRL $0x10, DI + LEAQ (BX)(R13*1), CX + MOVQ DX, R14 + MOVQ CX, BX + ROLQ CL, R14 + MOVL $0x00000001, R15 + MOVB R13, CL + SHLL CL, R15 + DECL R15 + ANDQ R15, R14 + ADDQ R14, DI + + // Load ctx.llTable + MOVQ ctx+16(FP), CX + MOVQ (CX), CX + MOVQ (CX)(DI*8), DI + + // Update Match Length State + MOVBQZX R8, R13 + SHRL $0x10, R8 + LEAQ (BX)(R13*1), CX + MOVQ DX, R14 + MOVQ CX, BX + ROLQ CL, R14 + MOVL $0x00000001, R15 + MOVB R13, CL + SHLL CL, R15 + DECL R15 + ANDQ R15, R14 + ADDQ R14, R8 + + // Load ctx.mlTable + MOVQ ctx+16(FP), CX + MOVQ 24(CX), CX + MOVQ (CX)(R8*8), R8 + + // Update Offset State + MOVBQZX R9, R13 + SHRL $0x10, R9 + LEAQ (BX)(R13*1), CX + MOVQ DX, R14 + MOVQ CX, BX + ROLQ CL, R14 + MOVL $0x00000001, R15 + MOVB R13, CL + SHLL CL, R15 + DECL R15 + ANDQ R15, R14 + ADDQ R14, R9 + + // Load ctx.ofTable + MOVQ ctx+16(FP), CX + MOVQ 48(CX), CX + MOVQ (CX)(R9*8), R9 + +sequenceDecs_decodeSync_safe_amd64_skip_update: + // Adjust offset + MOVQ s+0(FP), CX + MOVQ 8(SP), R13 + CMPQ AX, $0x01 + JBE sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0 + MOVUPS 144(CX), X0 + MOVQ R13, 144(CX) + MOVUPS X0, 152(CX) + JMP sequenceDecs_decodeSync_safe_amd64_after_adjust + +sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0: + CMPQ 24(SP), $0x00000000 + JNE sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero + INCQ R13 + JMP sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero + +sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero: + TESTQ R13, R13 + JNZ sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero + MOVQ 144(CX), R13 + JMP sequenceDecs_decodeSync_safe_amd64_after_adjust + +sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero: + MOVQ R13, AX + XORQ R14, R14 + MOVQ $-1, R15 + CMPQ R13, $0x03 + CMOVQEQ R14, AX + CMOVQEQ R15, R14 + ADDQ 144(CX)(AX*8), R14 + JNZ sequenceDecs_decodeSync_safe_amd64_adjust_temp_valid + MOVQ $0x00000001, R14 + +sequenceDecs_decodeSync_safe_amd64_adjust_temp_valid: + CMPQ R13, $0x01 + JZ sequenceDecs_decodeSync_safe_amd64_adjust_skip + MOVQ 152(CX), AX + MOVQ AX, 160(CX) + +sequenceDecs_decodeSync_safe_amd64_adjust_skip: + MOVQ 144(CX), AX + MOVQ AX, 152(CX) + MOVQ R14, 144(CX) + MOVQ R14, R13 + +sequenceDecs_decodeSync_safe_amd64_after_adjust: + MOVQ R13, 8(SP) + + // Check values + MOVQ 16(SP), AX + MOVQ 24(SP), CX + LEAQ (AX)(CX*1), R14 + MOVQ s+0(FP), R15 + ADDQ R14, 256(R15) + MOVQ ctx+16(FP), R14 + SUBQ CX, 104(R14) + JS error_not_enough_literals + CMPQ AX, $0x00020002 + JA sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big + TESTQ R13, R13 + JNZ sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok + TESTQ AX, AX + JNZ sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch + +sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok: + MOVQ 24(SP), AX + MOVQ 8(SP), CX + MOVQ 16(SP), R13 + + // Check if we have enough space in s.out + LEAQ (AX)(R13*1), R14 + ADDQ R10, R14 + CMPQ R14, 32(SP) + JA error_not_enough_space + + // Copy literals + TESTQ AX, AX + JZ check_offset + MOVQ AX, R14 + SUBQ $0x10, R14 + JB copy_1_small + +copy_1_loop: + MOVUPS (R11), X0 + MOVUPS X0, (R10) + ADDQ $0x10, R11 + ADDQ $0x10, R10 + SUBQ $0x10, R14 + JAE copy_1_loop + LEAQ 16(R11)(R14*1), R11 + LEAQ 16(R10)(R14*1), R10 + MOVUPS -16(R11), X0 + MOVUPS X0, -16(R10) + JMP copy_1_end + +copy_1_small: + CMPQ AX, $0x03 + JE copy_1_move_3 + JB copy_1_move_1or2 + CMPQ AX, $0x08 + JB copy_1_move_4through7 + JMP copy_1_move_8through16 + +copy_1_move_1or2: + MOVB (R11), R14 + MOVB -1(R11)(AX*1), R15 + MOVB R14, (R10) + MOVB R15, -1(R10)(AX*1) + ADDQ AX, R11 + ADDQ AX, R10 + JMP copy_1_end + +copy_1_move_3: + MOVW (R11), R14 + MOVB 2(R11), R15 + MOVW R14, (R10) + MOVB R15, 2(R10) + ADDQ AX, R11 + ADDQ AX, R10 + JMP copy_1_end + +copy_1_move_4through7: + MOVL (R11), R14 + MOVL -4(R11)(AX*1), R15 + MOVL R14, (R10) + MOVL R15, -4(R10)(AX*1) + ADDQ AX, R11 + ADDQ AX, R10 + JMP copy_1_end + +copy_1_move_8through16: + MOVQ (R11), R14 + MOVQ -8(R11)(AX*1), R15 + MOVQ R14, (R10) + MOVQ R15, -8(R10)(AX*1) + ADDQ AX, R11 + ADDQ AX, R10 + +copy_1_end: + ADDQ AX, R12 + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + MOVQ R12, AX + ADDQ 40(SP), AX + CMPQ CX, AX + JG error_match_off_too_big + CMPQ CX, 56(SP) + JG error_match_off_too_big + + // Copy match from history + MOVQ CX, AX + SUBQ R12, AX + JLS copy_match + MOVQ 48(SP), R14 + SUBQ AX, R14 + CMPQ R13, AX + JG copy_all_from_history + MOVQ R13, AX + SUBQ $0x10, AX + JB copy_4_small + +copy_4_loop: + MOVUPS (R14), X0 + MOVUPS X0, (R10) + ADDQ $0x10, R14 + ADDQ $0x10, R10 + SUBQ $0x10, AX + JAE copy_4_loop + LEAQ 16(R14)(AX*1), R14 + LEAQ 16(R10)(AX*1), R10 + MOVUPS -16(R14), X0 + MOVUPS X0, -16(R10) + JMP copy_4_end + +copy_4_small: + CMPQ R13, $0x03 + JE copy_4_move_3 + CMPQ R13, $0x08 + JB copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVW (R14), AX + MOVB 2(R14), CL + MOVW AX, (R10) + MOVB CL, 2(R10) + ADDQ R13, R14 + ADDQ R13, R10 + JMP copy_4_end + +copy_4_move_4through7: + MOVL (R14), AX + MOVL -4(R14)(R13*1), CX + MOVL AX, (R10) + MOVL CX, -4(R10)(R13*1) + ADDQ R13, R14 + ADDQ R13, R10 + JMP copy_4_end + +copy_4_move_8through16: + MOVQ (R14), AX + MOVQ -8(R14)(R13*1), CX + MOVQ AX, (R10) + MOVQ CX, -8(R10)(R13*1) + ADDQ R13, R14 + ADDQ R13, R10 + +copy_4_end: + ADDQ R13, R12 + JMP handle_loop + JMP loop_finished + +copy_all_from_history: + MOVQ AX, R15 + SUBQ $0x10, R15 + JB copy_5_small + +copy_5_loop: + MOVUPS (R14), X0 + MOVUPS X0, (R10) + ADDQ $0x10, R14 + ADDQ $0x10, R10 + SUBQ $0x10, R15 + JAE copy_5_loop + LEAQ 16(R14)(R15*1), R14 + LEAQ 16(R10)(R15*1), R10 + MOVUPS -16(R14), X0 + MOVUPS X0, -16(R10) + JMP copy_5_end + +copy_5_small: + CMPQ AX, $0x03 + JE copy_5_move_3 + JB copy_5_move_1or2 + CMPQ AX, $0x08 + JB copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVB (R14), R15 + MOVB -1(R14)(AX*1), BP + MOVB R15, (R10) + MOVB BP, -1(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 + JMP copy_5_end + +copy_5_move_3: + MOVW (R14), R15 + MOVB 2(R14), BP + MOVW R15, (R10) + MOVB BP, 2(R10) + ADDQ AX, R14 + ADDQ AX, R10 + JMP copy_5_end + +copy_5_move_4through7: + MOVL (R14), R15 + MOVL -4(R14)(AX*1), BP + MOVL R15, (R10) + MOVL BP, -4(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 + JMP copy_5_end + +copy_5_move_8through16: + MOVQ (R14), R15 + MOVQ -8(R14)(AX*1), BP + MOVQ R15, (R10) + MOVQ BP, -8(R10)(AX*1) + ADDQ AX, R14 + ADDQ AX, R10 + +copy_5_end: + ADDQ AX, R12 + SUBQ AX, R13 + + // Copy match from the current buffer +copy_match: + MOVQ R10, AX + SUBQ CX, AX + + // ml <= mo + CMPQ R13, CX + JA copy_overlapping_match + + // Copy non-overlapping match + ADDQ R13, R12 + MOVQ R13, CX + SUBQ $0x10, CX + JB copy_2_small + +copy_2_loop: + MOVUPS (AX), X0 + MOVUPS X0, (R10) + ADDQ $0x10, AX + ADDQ $0x10, R10 + SUBQ $0x10, CX + JAE copy_2_loop + LEAQ 16(AX)(CX*1), AX + LEAQ 16(R10)(CX*1), R10 + MOVUPS -16(AX), X0 + MOVUPS X0, -16(R10) + JMP copy_2_end + +copy_2_small: + CMPQ R13, $0x03 + JE copy_2_move_3 + JB copy_2_move_1or2 + CMPQ R13, $0x08 + JB copy_2_move_4through7 + JMP copy_2_move_8through16 + +copy_2_move_1or2: + MOVB (AX), CL + MOVB -1(AX)(R13*1), R14 + MOVB CL, (R10) + MOVB R14, -1(R10)(R13*1) + ADDQ R13, AX + ADDQ R13, R10 + JMP copy_2_end + +copy_2_move_3: + MOVW (AX), CX + MOVB 2(AX), R14 + MOVW CX, (R10) + MOVB R14, 2(R10) + ADDQ R13, AX + ADDQ R13, R10 + JMP copy_2_end + +copy_2_move_4through7: + MOVL (AX), CX + MOVL -4(AX)(R13*1), R14 + MOVL CX, (R10) + MOVL R14, -4(R10)(R13*1) + ADDQ R13, AX + ADDQ R13, R10 + JMP copy_2_end + +copy_2_move_8through16: + MOVQ (AX), CX + MOVQ -8(AX)(R13*1), R14 + MOVQ CX, (R10) + MOVQ R14, -8(R10)(R13*1) + ADDQ R13, AX + ADDQ R13, R10 + +copy_2_end: + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADDQ R13, R12 + +copy_slow_3: + MOVB (AX), CL + MOVB CL, (R10) + INCQ AX + INCQ R10 + DECQ R13 + JNZ copy_slow_3 + +handle_loop: + MOVQ ctx+16(FP), AX + DECQ 96(AX) + JNS sequenceDecs_decodeSync_safe_amd64_main_loop + +loop_finished: + MOVQ br+8(FP), AX + MOVQ DX, 24(AX) + MOVB BL, 40(AX) + MOVQ SI, 32(AX) + + // Update the context + MOVQ ctx+16(FP), AX + MOVQ R12, 136(AX) + MOVQ 144(AX), CX + SUBQ CX, R11 + MOVQ R11, 168(AX) + + // Return success + MOVQ $0x00000000, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch: + MOVQ 16(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 216(CX) + MOVQ $0x00000001, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big: + MOVQ ctx+16(FP), AX + MOVQ 16(SP), CX + MOVQ CX, 216(AX) + MOVQ $0x00000002, ret+24(FP) + RET + + // Return with match offset too long error +error_match_off_too_big: + MOVQ ctx+16(FP), AX + MOVQ 8(SP), CX + MOVQ CX, 224(AX) + MOVQ R12, 136(AX) + MOVQ $0x00000003, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVQ ctx+16(FP), AX + MOVQ 24(SP), CX + MOVQ CX, 208(AX) + MOVQ $0x00000004, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + + // Return with not enough output space error +error_not_enough_space: + MOVQ ctx+16(FP), AX + MOVQ 24(SP), CX + MOVQ CX, 208(AX) + MOVQ 16(SP), CX + MOVQ CX, 216(AX) + MOVQ R12, 136(AX) + MOVQ $0x00000005, ret+24(FP) + RET + +// func sequenceDecs_decodeSync_safe_bmi2(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int +// Requires: BMI, BMI2, CMOV, SSE +TEXT ·sequenceDecs_decodeSync_safe_bmi2(SB), $64-32 + MOVQ br+8(FP), BX + MOVQ 24(BX), AX + MOVBQZX 40(BX), DX + MOVQ (BX), CX + MOVQ 32(BX), BX + ADDQ BX, CX + MOVQ CX, (SP) + MOVQ ctx+16(FP), CX + MOVQ 72(CX), SI + MOVQ 80(CX), DI + MOVQ 88(CX), R8 + XORQ R9, R9 + MOVQ R9, 8(SP) + MOVQ R9, 16(SP) + MOVQ R9, 24(SP) + MOVQ 112(CX), R9 + MOVQ 128(CX), R10 + MOVQ R10, 32(SP) + MOVQ 144(CX), R10 + MOVQ 136(CX), R11 + MOVQ 200(CX), R12 + MOVQ R12, 56(SP) + MOVQ 176(CX), R12 + MOVQ R12, 48(SP) + MOVQ 184(CX), CX + MOVQ CX, 40(SP) + MOVQ 40(SP), CX + ADDQ CX, 48(SP) + + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) + ADDQ R9, 32(SP) + + // outBase += outPosition + ADDQ R11, R9 + +sequenceDecs_decodeSync_safe_bmi2_main_loop: + MOVQ (SP), R12 + + // Fill bitreader to have enough for the offset and match length. + CMPQ BX, $0x08 + JL sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte + MOVQ DX, CX + SHRQ $0x03, CX + SUBQ CX, R12 + MOVQ (R12), AX + SUBQ CX, BX + ANDQ $0x07, DX + JMP sequenceDecs_decodeSync_safe_bmi2_fill_end + +sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte: + CMPQ BX, $0x00 + JLE sequenceDecs_decodeSync_safe_bmi2_fill_check_overread + CMPQ DX, $0x07 + JLE sequenceDecs_decodeSync_safe_bmi2_fill_end + SHLQ $0x08, AX + SUBQ $0x01, R12 + SUBQ $0x01, BX + SUBQ $0x08, DX + MOVBQZX (R12), CX + ORQ CX, AX + JMP sequenceDecs_decodeSync_safe_bmi2_fill_byte_by_byte + +sequenceDecs_decodeSync_safe_bmi2_fill_check_overread: + CMPQ DX, $0x40 + JA error_overread + +sequenceDecs_decodeSync_safe_bmi2_fill_end: + // Update offset + MOVQ $0x00000808, CX + BEXTRQ CX, R8, R13 + MOVQ AX, R14 + LEAQ (DX)(R13*1), CX + ROLQ CL, R14 + BZHIQ R13, R14, R14 + MOVQ CX, DX + MOVQ R8, CX + SHRQ $0x20, CX + ADDQ R14, CX + MOVQ CX, 8(SP) + + // Update match length + MOVQ $0x00000808, CX + BEXTRQ CX, DI, R13 + MOVQ AX, R14 + LEAQ (DX)(R13*1), CX + ROLQ CL, R14 + BZHIQ R13, R14, R14 + MOVQ CX, DX + MOVQ DI, CX + SHRQ $0x20, CX + ADDQ R14, CX + MOVQ CX, 16(SP) + + // Fill bitreader to have enough for the remaining + CMPQ BX, $0x08 + JL sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte + MOVQ DX, CX + SHRQ $0x03, CX + SUBQ CX, R12 + MOVQ (R12), AX + SUBQ CX, BX + ANDQ $0x07, DX + JMP sequenceDecs_decodeSync_safe_bmi2_fill_2_end + +sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte: + CMPQ BX, $0x00 + JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_check_overread + CMPQ DX, $0x07 + JLE sequenceDecs_decodeSync_safe_bmi2_fill_2_end + SHLQ $0x08, AX + SUBQ $0x01, R12 + SUBQ $0x01, BX + SUBQ $0x08, DX + MOVBQZX (R12), CX + ORQ CX, AX + JMP sequenceDecs_decodeSync_safe_bmi2_fill_2_byte_by_byte + +sequenceDecs_decodeSync_safe_bmi2_fill_2_check_overread: + CMPQ DX, $0x40 + JA error_overread + +sequenceDecs_decodeSync_safe_bmi2_fill_2_end: + // Update literal length + MOVQ $0x00000808, CX + BEXTRQ CX, SI, R13 + MOVQ AX, R14 + LEAQ (DX)(R13*1), CX + ROLQ CL, R14 + BZHIQ R13, R14, R14 + MOVQ CX, DX + MOVQ SI, CX + SHRQ $0x20, CX + ADDQ R14, CX + MOVQ CX, 24(SP) + + // Fill bitreader for state updates + MOVQ R12, (SP) + MOVQ $0x00000808, CX + BEXTRQ CX, R8, R12 + MOVQ ctx+16(FP), CX + CMPQ 96(CX), $0x00 + JZ sequenceDecs_decodeSync_safe_bmi2_skip_update + LEAQ (SI)(DI*1), R13 + ADDQ R8, R13 + MOVBQZX R13, R13 + LEAQ (DX)(R13*1), CX + MOVQ AX, R14 + MOVQ CX, DX + ROLQ CL, R14 + BZHIQ R13, R14, R14 + + // Update Offset State + BZHIQ R8, R14, CX + SHRXQ R8, R14, R14 + SHRL $0x10, R8 + ADDQ CX, R8 + + // Load ctx.ofTable + MOVQ ctx+16(FP), CX + MOVQ 48(CX), CX + MOVQ (CX)(R8*8), R8 + + // Update Match Length State + BZHIQ DI, R14, CX + SHRXQ DI, R14, R14 + SHRL $0x10, DI + ADDQ CX, DI + + // Load ctx.mlTable + MOVQ ctx+16(FP), CX + MOVQ 24(CX), CX + MOVQ (CX)(DI*8), DI + + // Update Literal Length State + BZHIQ SI, R14, CX + SHRL $0x10, SI + ADDQ CX, SI + + // Load ctx.llTable + MOVQ ctx+16(FP), CX + MOVQ (CX), CX + MOVQ (CX)(SI*8), SI + +sequenceDecs_decodeSync_safe_bmi2_skip_update: + // Adjust offset + MOVQ s+0(FP), CX + MOVQ 8(SP), R13 + CMPQ R12, $0x01 + JBE sequenceDecs_decodeSync_safe_bmi2_adjust_offsetB_1_or_0 + MOVUPS 144(CX), X0 + MOVQ R13, 144(CX) + MOVUPS X0, 152(CX) + JMP sequenceDecs_decodeSync_safe_bmi2_after_adjust + +sequenceDecs_decodeSync_safe_bmi2_adjust_offsetB_1_or_0: + CMPQ 24(SP), $0x00000000 + JNE sequenceDecs_decodeSync_safe_bmi2_adjust_offset_maybezero + INCQ R13 + JMP sequenceDecs_decodeSync_safe_bmi2_adjust_offset_nonzero + +sequenceDecs_decodeSync_safe_bmi2_adjust_offset_maybezero: + TESTQ R13, R13 + JNZ sequenceDecs_decodeSync_safe_bmi2_adjust_offset_nonzero + MOVQ 144(CX), R13 + JMP sequenceDecs_decodeSync_safe_bmi2_after_adjust + +sequenceDecs_decodeSync_safe_bmi2_adjust_offset_nonzero: + MOVQ R13, R12 + XORQ R14, R14 + MOVQ $-1, R15 + CMPQ R13, $0x03 + CMOVQEQ R14, R12 + CMOVQEQ R15, R14 + ADDQ 144(CX)(R12*8), R14 + JNZ sequenceDecs_decodeSync_safe_bmi2_adjust_temp_valid + MOVQ $0x00000001, R14 + +sequenceDecs_decodeSync_safe_bmi2_adjust_temp_valid: + CMPQ R13, $0x01 + JZ sequenceDecs_decodeSync_safe_bmi2_adjust_skip + MOVQ 152(CX), R12 + MOVQ R12, 160(CX) + +sequenceDecs_decodeSync_safe_bmi2_adjust_skip: + MOVQ 144(CX), R12 + MOVQ R12, 152(CX) + MOVQ R14, 144(CX) + MOVQ R14, R13 + +sequenceDecs_decodeSync_safe_bmi2_after_adjust: + MOVQ R13, 8(SP) + + // Check values + MOVQ 16(SP), CX + MOVQ 24(SP), R12 + LEAQ (CX)(R12*1), R14 + MOVQ s+0(FP), R15 + ADDQ R14, 256(R15) + MOVQ ctx+16(FP), R14 + SUBQ R12, 104(R14) + JS error_not_enough_literals + CMPQ CX, $0x00020002 + JA sequenceDecs_decodeSync_safe_bmi2_error_match_len_too_big + TESTQ R13, R13 + JNZ sequenceDecs_decodeSync_safe_bmi2_match_len_ofs_ok + TESTQ CX, CX + JNZ sequenceDecs_decodeSync_safe_bmi2_error_match_len_ofs_mismatch + +sequenceDecs_decodeSync_safe_bmi2_match_len_ofs_ok: + MOVQ 24(SP), CX + MOVQ 8(SP), R12 + MOVQ 16(SP), R13 + + // Check if we have enough space in s.out + LEAQ (CX)(R13*1), R14 + ADDQ R9, R14 + CMPQ R14, 32(SP) + JA error_not_enough_space + + // Copy literals + TESTQ CX, CX + JZ check_offset + MOVQ CX, R14 + SUBQ $0x10, R14 + JB copy_1_small + +copy_1_loop: + MOVUPS (R10), X0 + MOVUPS X0, (R9) + ADDQ $0x10, R10 + ADDQ $0x10, R9 + SUBQ $0x10, R14 + JAE copy_1_loop + LEAQ 16(R10)(R14*1), R10 + LEAQ 16(R9)(R14*1), R9 + MOVUPS -16(R10), X0 + MOVUPS X0, -16(R9) + JMP copy_1_end + +copy_1_small: + CMPQ CX, $0x03 + JE copy_1_move_3 + JB copy_1_move_1or2 + CMPQ CX, $0x08 + JB copy_1_move_4through7 + JMP copy_1_move_8through16 + +copy_1_move_1or2: + MOVB (R10), R14 + MOVB -1(R10)(CX*1), R15 + MOVB R14, (R9) + MOVB R15, -1(R9)(CX*1) + ADDQ CX, R10 + ADDQ CX, R9 + JMP copy_1_end + +copy_1_move_3: + MOVW (R10), R14 + MOVB 2(R10), R15 + MOVW R14, (R9) + MOVB R15, 2(R9) + ADDQ CX, R10 + ADDQ CX, R9 + JMP copy_1_end + +copy_1_move_4through7: + MOVL (R10), R14 + MOVL -4(R10)(CX*1), R15 + MOVL R14, (R9) + MOVL R15, -4(R9)(CX*1) + ADDQ CX, R10 + ADDQ CX, R9 + JMP copy_1_end + +copy_1_move_8through16: + MOVQ (R10), R14 + MOVQ -8(R10)(CX*1), R15 + MOVQ R14, (R9) + MOVQ R15, -8(R9)(CX*1) + ADDQ CX, R10 + ADDQ CX, R9 + +copy_1_end: + ADDQ CX, R11 + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + MOVQ R11, CX + ADDQ 40(SP), CX + CMPQ R12, CX + JG error_match_off_too_big + CMPQ R12, 56(SP) + JG error_match_off_too_big + + // Copy match from history + MOVQ R12, CX + SUBQ R11, CX + JLS copy_match + MOVQ 48(SP), R14 + SUBQ CX, R14 + CMPQ R13, CX + JG copy_all_from_history + MOVQ R13, CX + SUBQ $0x10, CX + JB copy_4_small + +copy_4_loop: + MOVUPS (R14), X0 + MOVUPS X0, (R9) + ADDQ $0x10, R14 + ADDQ $0x10, R9 + SUBQ $0x10, CX + JAE copy_4_loop + LEAQ 16(R14)(CX*1), R14 + LEAQ 16(R9)(CX*1), R9 + MOVUPS -16(R14), X0 + MOVUPS X0, -16(R9) + JMP copy_4_end + +copy_4_small: + CMPQ R13, $0x03 + JE copy_4_move_3 + CMPQ R13, $0x08 + JB copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVW (R14), CX + MOVB 2(R14), R12 + MOVW CX, (R9) + MOVB R12, 2(R9) + ADDQ R13, R14 + ADDQ R13, R9 + JMP copy_4_end + +copy_4_move_4through7: + MOVL (R14), CX + MOVL -4(R14)(R13*1), R12 + MOVL CX, (R9) + MOVL R12, -4(R9)(R13*1) + ADDQ R13, R14 + ADDQ R13, R9 + JMP copy_4_end + +copy_4_move_8through16: + MOVQ (R14), CX + MOVQ -8(R14)(R13*1), R12 + MOVQ CX, (R9) + MOVQ R12, -8(R9)(R13*1) + ADDQ R13, R14 + ADDQ R13, R9 + +copy_4_end: + ADDQ R13, R11 + JMP handle_loop + JMP loop_finished + +copy_all_from_history: + MOVQ CX, R15 + SUBQ $0x10, R15 + JB copy_5_small + +copy_5_loop: + MOVUPS (R14), X0 + MOVUPS X0, (R9) + ADDQ $0x10, R14 + ADDQ $0x10, R9 + SUBQ $0x10, R15 + JAE copy_5_loop + LEAQ 16(R14)(R15*1), R14 + LEAQ 16(R9)(R15*1), R9 + MOVUPS -16(R14), X0 + MOVUPS X0, -16(R9) + JMP copy_5_end + +copy_5_small: + CMPQ CX, $0x03 + JE copy_5_move_3 + JB copy_5_move_1or2 + CMPQ CX, $0x08 + JB copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVB (R14), R15 + MOVB -1(R14)(CX*1), BP + MOVB R15, (R9) + MOVB BP, -1(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 + JMP copy_5_end + +copy_5_move_3: + MOVW (R14), R15 + MOVB 2(R14), BP + MOVW R15, (R9) + MOVB BP, 2(R9) + ADDQ CX, R14 + ADDQ CX, R9 + JMP copy_5_end + +copy_5_move_4through7: + MOVL (R14), R15 + MOVL -4(R14)(CX*1), BP + MOVL R15, (R9) + MOVL BP, -4(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 + JMP copy_5_end + +copy_5_move_8through16: + MOVQ (R14), R15 + MOVQ -8(R14)(CX*1), BP + MOVQ R15, (R9) + MOVQ BP, -8(R9)(CX*1) + ADDQ CX, R14 + ADDQ CX, R9 + +copy_5_end: + ADDQ CX, R11 + SUBQ CX, R13 + + // Copy match from the current buffer +copy_match: + MOVQ R9, CX + SUBQ R12, CX + + // ml <= mo + CMPQ R13, R12 + JA copy_overlapping_match + + // Copy non-overlapping match + ADDQ R13, R11 + MOVQ R13, R12 + SUBQ $0x10, R12 + JB copy_2_small + +copy_2_loop: + MOVUPS (CX), X0 + MOVUPS X0, (R9) + ADDQ $0x10, CX + ADDQ $0x10, R9 + SUBQ $0x10, R12 + JAE copy_2_loop + LEAQ 16(CX)(R12*1), CX + LEAQ 16(R9)(R12*1), R9 + MOVUPS -16(CX), X0 + MOVUPS X0, -16(R9) + JMP copy_2_end + +copy_2_small: + CMPQ R13, $0x03 + JE copy_2_move_3 + JB copy_2_move_1or2 + CMPQ R13, $0x08 + JB copy_2_move_4through7 + JMP copy_2_move_8through16 + +copy_2_move_1or2: + MOVB (CX), R12 + MOVB -1(CX)(R13*1), R14 + MOVB R12, (R9) + MOVB R14, -1(R9)(R13*1) + ADDQ R13, CX + ADDQ R13, R9 + JMP copy_2_end + +copy_2_move_3: + MOVW (CX), R12 + MOVB 2(CX), R14 + MOVW R12, (R9) + MOVB R14, 2(R9) + ADDQ R13, CX + ADDQ R13, R9 + JMP copy_2_end + +copy_2_move_4through7: + MOVL (CX), R12 + MOVL -4(CX)(R13*1), R14 + MOVL R12, (R9) + MOVL R14, -4(R9)(R13*1) + ADDQ R13, CX + ADDQ R13, R9 + JMP copy_2_end + +copy_2_move_8through16: + MOVQ (CX), R12 + MOVQ -8(CX)(R13*1), R14 + MOVQ R12, (R9) + MOVQ R14, -8(R9)(R13*1) + ADDQ R13, CX + ADDQ R13, R9 + +copy_2_end: + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADDQ R13, R11 + +copy_slow_3: + MOVB (CX), R12 + MOVB R12, (R9) + INCQ CX + INCQ R9 + DECQ R13 + JNZ copy_slow_3 + +handle_loop: + MOVQ ctx+16(FP), CX + DECQ 96(CX) + JNS sequenceDecs_decodeSync_safe_bmi2_main_loop + +loop_finished: + MOVQ br+8(FP), CX + MOVQ AX, 24(CX) + MOVB DL, 40(CX) + MOVQ BX, 32(CX) + + // Update the context + MOVQ ctx+16(FP), AX + MOVQ R11, 136(AX) + MOVQ 144(AX), CX + SUBQ CX, R10 + MOVQ R10, 168(AX) + + // Return success + MOVQ $0x00000000, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decodeSync_safe_bmi2_error_match_len_ofs_mismatch: + MOVQ 16(SP), AX + MOVQ ctx+16(FP), CX + MOVQ AX, 216(CX) + MOVQ $0x00000001, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decodeSync_safe_bmi2_error_match_len_too_big: + MOVQ ctx+16(FP), AX + MOVQ 16(SP), CX + MOVQ CX, 216(AX) + MOVQ $0x00000002, ret+24(FP) + RET + + // Return with match offset too long error +error_match_off_too_big: + MOVQ ctx+16(FP), AX + MOVQ 8(SP), CX + MOVQ CX, 224(AX) + MOVQ R11, 136(AX) + MOVQ $0x00000003, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVQ ctx+16(FP), AX + MOVQ 24(SP), CX + MOVQ CX, 208(AX) + MOVQ $0x00000004, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVQ $0x00000006, ret+24(FP) + RET + + // Return with not enough output space error +error_not_enough_space: + MOVQ ctx+16(FP), AX + MOVQ 24(SP), CX + MOVQ CX, 208(AX) + MOVQ 16(SP), CX + MOVQ CX, 216(AX) + MOVQ R11, 136(AX) + MOVQ $0x00000005, ret+24(FP) + RET diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.go b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.go new file mode 100644 index 0000000..5ad262a --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.go @@ -0,0 +1,70 @@ +//go:build arm64 && !appengine && !noasm && gc + +package zstd + +// The shared decode/decodeSync/executeSimple wrappers and context structs live +// in seqdec_asm.go; this file only declares the arm64 asm routines (generated +// by the avo arm64 lowering printer) and the dispatch helpers. arm64 has no +// BMI2, so each helper selects only between the 56-bit / safe variants. + +// sequenceDecs_decode_arm64 implements the main loop of sequenceDecs in arm64 asm. +// +// Please refer to seqdec_generic.go for the reference implementation. +// +//go:noescape +func sequenceDecs_decode_arm64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int + +// sequenceDecs_decode_56_arm64 implements the main loop of sequenceDecs in arm64 asm. +// +//go:noescape +func sequenceDecs_decode_56_arm64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int + +// decodeAsm runs the sequenceDecs decode loop, choosing the 56-bit variant. +func decodeAsm(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext, lte56bits bool) int { + if lte56bits { + return sequenceDecs_decode_56_arm64(s, br, ctx) + } + return sequenceDecs_decode_arm64(s, br, ctx) +} + +// sequenceDecs_decodeSync_arm64 implements the main loop of sequenceDecs.decodeSync in arm64 asm. +// +// Please refer to seqdec_generic.go for the reference implementation. +// +//go:noescape +func sequenceDecs_decodeSync_arm64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int + +// sequenceDecs_decodeSync_safe_arm64 does the same as above, but does not write more than output buffer. +// +//go:noescape +func sequenceDecs_decodeSync_safe_arm64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int + +// decodeSyncAsm runs the decodeSync loop, choosing the safe variant. +func decodeSyncAsm(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext, safe bool) int { + if safe { + return sequenceDecs_decodeSync_safe_arm64(s, br, ctx) + } + return sequenceDecs_decodeSync_arm64(s, br, ctx) +} + +// sequenceDecs_executeSimple_arm64 implements the main loop of sequenceDecs.executeSimple in arm64 asm. +// +// Returns false if a match offset is too big. +// +// Please refer to seqdec_generic.go for the reference implementation. +// +//go:noescape +func sequenceDecs_executeSimple_arm64(ctx *executeAsmContext) bool + +// Same as above, but with safe memcopies +// +//go:noescape +func sequenceDecs_executeSimple_safe_arm64(ctx *executeAsmContext) bool + +// executeSimpleAsm runs the executeSimple loop, choosing the safe variant. +func executeSimpleAsm(ctx *executeAsmContext, safe bool) bool { + if safe { + return sequenceDecs_executeSimple_safe_arm64(ctx) + } + return sequenceDecs_executeSimple_arm64(ctx) +} diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s new file mode 100644 index 0000000..6f54ef2 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_arm64.s @@ -0,0 +1,2750 @@ +// Code generated by command: go run gen.go -out ../seqdec.s -arch amd64,arm64 -pkg=zstd. DO NOT EDIT. +// EXPERIMENTAL arm64 output lowered from an amd64 avo program. + +//go:build arm64 && !appengine && !noasm && gc && !noasm + +// func sequenceDecs_decode_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int +// Requires: CMOV +TEXT ·sequenceDecs_decode_arm64(SB), $8-32 + MOVD br+8(FP), R1 + MOVD 24(R1), R2 + MOVBU 40(R1), R3 + MOVD (R1), R0 + MOVD 32(R1), R5 + ADD R5, R0, R0 + MOVD R0, 8(RSP) + MOVD ctx+16(FP), R0 + MOVD 72(R0), R6 + MOVD 80(R0), R7 + MOVD 88(R0), R8 + MOVD 104(R0), R9 + MOVD s+0(FP), R0 + MOVD 144(R0), R10 + MOVD 152(R0), R11 + MOVD 160(R0), R12 + +sequenceDecs_decode_amd64_main_loop: + MOVD 8(RSP), R13 + + // Fill bitreader to have enough for the offset and match length. + CMP $0x08, R5 + BLT sequenceDecs_decode_amd64_fill_byte_by_byte + MOVD R3, R0 + LSR $0x03, R0, R0 + SUB R0, R13, R13 + MOVD (R13), R2 + SUB R0, R5, R5 + AND $0x07, R3, R3 + JMP sequenceDecs_decode_amd64_fill_end + +sequenceDecs_decode_amd64_fill_byte_by_byte: + CMP $0x00, R5 + BLE sequenceDecs_decode_amd64_fill_check_overread + CMP $0x07, R3 + BLE sequenceDecs_decode_amd64_fill_end + LSL $0x08, R2, R2 + SUB $0x01, R13, R13 + SUB $0x01, R5, R5 + SUB $0x08, R3, R3 + MOVBU (R13), R0 + ORR R0, R2, R2 + JMP sequenceDecs_decode_amd64_fill_byte_by_byte + +sequenceDecs_decode_amd64_fill_check_overread: + CMP $0x40, R3 + BHI error_overread + +sequenceDecs_decode_amd64_fill_end: + // Update offset + MOVD R8, R0 + MOVD R3, R1 + MOVD R2, R14 + LSL R1, R14, R14 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decode_amd64_of_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decode_amd64_of_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decode_amd64_of_update_zero + NEG R1, R1 + LSR R1, R14, R14 + ADD R14, R0, R0 + +sequenceDecs_decode_amd64_of_update_zero: + MOVD R0, 16(R9) + + // Update match length + MOVD R7, R0 + MOVD R3, R1 + MOVD R2, R14 + LSL R1, R14, R14 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decode_amd64_ml_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decode_amd64_ml_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decode_amd64_ml_update_zero + NEG R1, R1 + LSR R1, R14, R14 + ADD R14, R0, R0 + +sequenceDecs_decode_amd64_ml_update_zero: + MOVD R0, 8(R9) + + // Fill bitreader to have enough for the remaining + CMP $0x08, R5 + BLT sequenceDecs_decode_amd64_fill_2_byte_by_byte + MOVD R3, R0 + LSR $0x03, R0, R0 + SUB R0, R13, R13 + MOVD (R13), R2 + SUB R0, R5, R5 + AND $0x07, R3, R3 + JMP sequenceDecs_decode_amd64_fill_2_end + +sequenceDecs_decode_amd64_fill_2_byte_by_byte: + CMP $0x00, R5 + BLE sequenceDecs_decode_amd64_fill_2_check_overread + CMP $0x07, R3 + BLE sequenceDecs_decode_amd64_fill_2_end + LSL $0x08, R2, R2 + SUB $0x01, R13, R13 + SUB $0x01, R5, R5 + SUB $0x08, R3, R3 + MOVBU (R13), R0 + ORR R0, R2, R2 + JMP sequenceDecs_decode_amd64_fill_2_byte_by_byte + +sequenceDecs_decode_amd64_fill_2_check_overread: + CMP $0x40, R3 + BHI error_overread + +sequenceDecs_decode_amd64_fill_2_end: + // Update literal length + MOVD R6, R0 + MOVD R3, R1 + MOVD R2, R14 + LSL R1, R14, R14 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decode_amd64_ll_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decode_amd64_ll_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decode_amd64_ll_update_zero + NEG R1, R1 + LSR R1, R14, R14 + ADD R14, R0, R0 + +sequenceDecs_decode_amd64_ll_update_zero: + MOVD R0, (R9) + + // Fill bitreader for state updates + MOVD R13, 8(RSP) + MOVD R8, R0 + LSR $0x08, R0, R0 + MOVBU R0, R0 + MOVD ctx+16(FP), R1 + MOVD 96(R1), R16 + CMP $0x00, R16 + BEQ sequenceDecs_decode_amd64_skip_update + + // Update Literal Length State + MOVBU R6, R13 + LSRW $0x10, R6, R6 + ADD R13, R3, R1 + MOVD R2, R14 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R14, R14 + MOVD $0x00000001, R4 + BFI $0, R13, $8, R1 + LSLW R1, R4, R4 + SUBW $1, R4, R4 + AND R4, R14, R14 + ADD R14, R6, R6 + + // Load ctx.llTable + MOVD ctx+16(FP), R1 + MOVD (R1), R1 + ADD R6<<3, R1, R15 + MOVD (R15), R6 + + // Update Match Length State + MOVBU R7, R13 + LSRW $0x10, R7, R7 + ADD R13, R3, R1 + MOVD R2, R14 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R14, R14 + MOVD $0x00000001, R4 + BFI $0, R13, $8, R1 + LSLW R1, R4, R4 + SUBW $1, R4, R4 + AND R4, R14, R14 + ADD R14, R7, R7 + + // Load ctx.mlTable + MOVD ctx+16(FP), R1 + MOVD 24(R1), R1 + ADD R7<<3, R1, R15 + MOVD (R15), R7 + + // Update Offset State + MOVBU R8, R13 + LSRW $0x10, R8, R8 + ADD R13, R3, R1 + MOVD R2, R14 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R14, R14 + MOVD $0x00000001, R4 + BFI $0, R13, $8, R1 + LSLW R1, R4, R4 + SUBW $1, R4, R4 + AND R4, R14, R14 + ADD R14, R8, R8 + + // Load ctx.ofTable + MOVD ctx+16(FP), R1 + MOVD 48(R1), R1 + ADD R8<<3, R1, R15 + MOVD (R15), R8 + +sequenceDecs_decode_amd64_skip_update: + // Adjust offset + MOVD 16(R9), R1 + CMP $0x01, R0 + BLS sequenceDecs_decode_amd64_adjust_offsetB_1_or_0 + MOVD R11, R12 + MOVD R10, R11 + MOVD R1, R10 + JMP sequenceDecs_decode_amd64_after_adjust + +sequenceDecs_decode_amd64_adjust_offsetB_1_or_0: + MOVD (R9), R16 + CMP $0x00000000, R16 + BNE sequenceDecs_decode_amd64_adjust_offset_maybezero + ADD $1, R1, R1 + JMP sequenceDecs_decode_amd64_adjust_offset_nonzero + +sequenceDecs_decode_amd64_adjust_offset_maybezero: + TST R1, R1 + BNE sequenceDecs_decode_amd64_adjust_offset_nonzero + MOVD R10, R1 + JMP sequenceDecs_decode_amd64_after_adjust + +sequenceDecs_decode_amd64_adjust_offset_nonzero: + CMP $0x01, R1 + BLO sequenceDecs_decode_amd64_adjust_zero + BEQ sequenceDecs_decode_amd64_adjust_one + CMP $0x02, R1 + BHI sequenceDecs_decode_amd64_adjust_three + JMP sequenceDecs_decode_amd64_adjust_two + +sequenceDecs_decode_amd64_adjust_zero: + MOVD R10, R0 + JMP sequenceDecs_decode_amd64_adjust_test_temp_valid + +sequenceDecs_decode_amd64_adjust_one: + MOVD R11, R0 + JMP sequenceDecs_decode_amd64_adjust_test_temp_valid + +sequenceDecs_decode_amd64_adjust_two: + MOVD R12, R0 + JMP sequenceDecs_decode_amd64_adjust_test_temp_valid + +sequenceDecs_decode_amd64_adjust_three: + SUB $1, R10, R0 + +sequenceDecs_decode_amd64_adjust_test_temp_valid: + TST R0, R0 + BNE sequenceDecs_decode_amd64_adjust_temp_valid + MOVD $0x00000001, R0 + +sequenceDecs_decode_amd64_adjust_temp_valid: + CMP $0x01, R1 + CSEL NE, R11, R12, R12 + MOVD R10, R11 + MOVD R0, R10 + MOVD R0, R1 + +sequenceDecs_decode_amd64_after_adjust: + MOVD R1, 16(R9) + + // Check values + MOVD 8(R9), R0 + MOVD (R9), R13 + ADD R13, R0, R14 + MOVD s+0(FP), R4 + MOVD 256(R4), R16 + ADD R14, R16, R16 + MOVD R16, 256(R4) + MOVD ctx+16(FP), R14 + MOVD 128(R14), R16 + SUBS R13, R16, R16 + MOVD R16, 128(R14) + BMI error_not_enough_literals + CMP $0x00020002, R0 + BHI sequenceDecs_decode_amd64_error_match_len_too_big + TST R1, R1 + BNE sequenceDecs_decode_amd64_match_len_ofs_ok + TST R0, R0 + BNE sequenceDecs_decode_amd64_error_match_len_ofs_mismatch + +sequenceDecs_decode_amd64_match_len_ofs_ok: + ADD $0x18, R9, R9 + MOVD ctx+16(FP), R0 + MOVD 96(R0), R16 + SUBS $1, R16, R16 + MOVD R16, 96(R0) + BPL sequenceDecs_decode_amd64_main_loop + MOVD s+0(FP), R0 + MOVD R10, 144(R0) + MOVD R11, 152(R0) + MOVD R12, 160(R0) + MOVD br+8(FP), R0 + MOVD R2, 24(R0) + MOVB R3, 40(R0) + MOVD R5, 32(R0) + + // Return success + MOVD $0x00000000, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decode_amd64_error_match_len_ofs_mismatch: + MOVD $0x00000001, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decode_amd64_error_match_len_too_big: + MOVD $0x00000002, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match offset too long error + MOVD $0x00000003, R16 + MOVD R16, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVD $0x00000004, R16 + MOVD R16, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVD $0x00000006, R16 + MOVD R16, ret+24(FP) + RET + +// func sequenceDecs_decode_56_amd64(s *sequenceDecs, br *bitReader, ctx *decodeAsmContext) int +// Requires: CMOV +TEXT ·sequenceDecs_decode_56_arm64(SB), $8-32 + MOVD br+8(FP), R1 + MOVD 24(R1), R2 + MOVBU 40(R1), R3 + MOVD (R1), R0 + MOVD 32(R1), R5 + ADD R5, R0, R0 + MOVD R0, 8(RSP) + MOVD ctx+16(FP), R0 + MOVD 72(R0), R6 + MOVD 80(R0), R7 + MOVD 88(R0), R8 + MOVD 104(R0), R9 + MOVD s+0(FP), R0 + MOVD 144(R0), R10 + MOVD 152(R0), R11 + MOVD 160(R0), R12 + +sequenceDecs_decode_56_amd64_main_loop: + MOVD 8(RSP), R13 + + // Fill bitreader to have enough for the offset and match length. + CMP $0x08, R5 + BLT sequenceDecs_decode_56_amd64_fill_byte_by_byte + MOVD R3, R0 + LSR $0x03, R0, R0 + SUB R0, R13, R13 + MOVD (R13), R2 + SUB R0, R5, R5 + AND $0x07, R3, R3 + JMP sequenceDecs_decode_56_amd64_fill_end + +sequenceDecs_decode_56_amd64_fill_byte_by_byte: + CMP $0x00, R5 + BLE sequenceDecs_decode_56_amd64_fill_check_overread + CMP $0x07, R3 + BLE sequenceDecs_decode_56_amd64_fill_end + LSL $0x08, R2, R2 + SUB $0x01, R13, R13 + SUB $0x01, R5, R5 + SUB $0x08, R3, R3 + MOVBU (R13), R0 + ORR R0, R2, R2 + JMP sequenceDecs_decode_56_amd64_fill_byte_by_byte + +sequenceDecs_decode_56_amd64_fill_check_overread: + CMP $0x40, R3 + BHI error_overread + +sequenceDecs_decode_56_amd64_fill_end: + // Update offset + MOVD R8, R0 + MOVD R3, R1 + MOVD R2, R14 + LSL R1, R14, R14 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decode_56_amd64_of_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decode_56_amd64_of_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decode_56_amd64_of_update_zero + NEG R1, R1 + LSR R1, R14, R14 + ADD R14, R0, R0 + +sequenceDecs_decode_56_amd64_of_update_zero: + MOVD R0, 16(R9) + + // Update match length + MOVD R7, R0 + MOVD R3, R1 + MOVD R2, R14 + LSL R1, R14, R14 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decode_56_amd64_ml_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decode_56_amd64_ml_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decode_56_amd64_ml_update_zero + NEG R1, R1 + LSR R1, R14, R14 + ADD R14, R0, R0 + +sequenceDecs_decode_56_amd64_ml_update_zero: + MOVD R0, 8(R9) + + // Update literal length + MOVD R6, R0 + MOVD R3, R1 + MOVD R2, R14 + LSL R1, R14, R14 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decode_56_amd64_ll_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decode_56_amd64_ll_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decode_56_amd64_ll_update_zero + NEG R1, R1 + LSR R1, R14, R14 + ADD R14, R0, R0 + +sequenceDecs_decode_56_amd64_ll_update_zero: + MOVD R0, (R9) + + // Fill bitreader for state updates + MOVD R13, 8(RSP) + MOVD R8, R0 + LSR $0x08, R0, R0 + MOVBU R0, R0 + MOVD ctx+16(FP), R1 + MOVD 96(R1), R16 + CMP $0x00, R16 + BEQ sequenceDecs_decode_56_amd64_skip_update + + // Update Literal Length State + MOVBU R6, R13 + LSRW $0x10, R6, R6 + ADD R13, R3, R1 + MOVD R2, R14 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R14, R14 + MOVD $0x00000001, R4 + BFI $0, R13, $8, R1 + LSLW R1, R4, R4 + SUBW $1, R4, R4 + AND R4, R14, R14 + ADD R14, R6, R6 + + // Load ctx.llTable + MOVD ctx+16(FP), R1 + MOVD (R1), R1 + ADD R6<<3, R1, R15 + MOVD (R15), R6 + + // Update Match Length State + MOVBU R7, R13 + LSRW $0x10, R7, R7 + ADD R13, R3, R1 + MOVD R2, R14 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R14, R14 + MOVD $0x00000001, R4 + BFI $0, R13, $8, R1 + LSLW R1, R4, R4 + SUBW $1, R4, R4 + AND R4, R14, R14 + ADD R14, R7, R7 + + // Load ctx.mlTable + MOVD ctx+16(FP), R1 + MOVD 24(R1), R1 + ADD R7<<3, R1, R15 + MOVD (R15), R7 + + // Update Offset State + MOVBU R8, R13 + LSRW $0x10, R8, R8 + ADD R13, R3, R1 + MOVD R2, R14 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R14, R14 + MOVD $0x00000001, R4 + BFI $0, R13, $8, R1 + LSLW R1, R4, R4 + SUBW $1, R4, R4 + AND R4, R14, R14 + ADD R14, R8, R8 + + // Load ctx.ofTable + MOVD ctx+16(FP), R1 + MOVD 48(R1), R1 + ADD R8<<3, R1, R15 + MOVD (R15), R8 + +sequenceDecs_decode_56_amd64_skip_update: + // Adjust offset + MOVD 16(R9), R1 + CMP $0x01, R0 + BLS sequenceDecs_decode_56_amd64_adjust_offsetB_1_or_0 + MOVD R11, R12 + MOVD R10, R11 + MOVD R1, R10 + JMP sequenceDecs_decode_56_amd64_after_adjust + +sequenceDecs_decode_56_amd64_adjust_offsetB_1_or_0: + MOVD (R9), R16 + CMP $0x00000000, R16 + BNE sequenceDecs_decode_56_amd64_adjust_offset_maybezero + ADD $1, R1, R1 + JMP sequenceDecs_decode_56_amd64_adjust_offset_nonzero + +sequenceDecs_decode_56_amd64_adjust_offset_maybezero: + TST R1, R1 + BNE sequenceDecs_decode_56_amd64_adjust_offset_nonzero + MOVD R10, R1 + JMP sequenceDecs_decode_56_amd64_after_adjust + +sequenceDecs_decode_56_amd64_adjust_offset_nonzero: + CMP $0x01, R1 + BLO sequenceDecs_decode_56_amd64_adjust_zero + BEQ sequenceDecs_decode_56_amd64_adjust_one + CMP $0x02, R1 + BHI sequenceDecs_decode_56_amd64_adjust_three + JMP sequenceDecs_decode_56_amd64_adjust_two + +sequenceDecs_decode_56_amd64_adjust_zero: + MOVD R10, R0 + JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid + +sequenceDecs_decode_56_amd64_adjust_one: + MOVD R11, R0 + JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid + +sequenceDecs_decode_56_amd64_adjust_two: + MOVD R12, R0 + JMP sequenceDecs_decode_56_amd64_adjust_test_temp_valid + +sequenceDecs_decode_56_amd64_adjust_three: + SUB $1, R10, R0 + +sequenceDecs_decode_56_amd64_adjust_test_temp_valid: + TST R0, R0 + BNE sequenceDecs_decode_56_amd64_adjust_temp_valid + MOVD $0x00000001, R0 + +sequenceDecs_decode_56_amd64_adjust_temp_valid: + CMP $0x01, R1 + CSEL NE, R11, R12, R12 + MOVD R10, R11 + MOVD R0, R10 + MOVD R0, R1 + +sequenceDecs_decode_56_amd64_after_adjust: + MOVD R1, 16(R9) + + // Check values + MOVD 8(R9), R0 + MOVD (R9), R13 + ADD R13, R0, R14 + MOVD s+0(FP), R4 + MOVD 256(R4), R16 + ADD R14, R16, R16 + MOVD R16, 256(R4) + MOVD ctx+16(FP), R14 + MOVD 128(R14), R16 + SUBS R13, R16, R16 + MOVD R16, 128(R14) + BMI error_not_enough_literals + CMP $0x00020002, R0 + BHI sequenceDecs_decode_56_amd64_error_match_len_too_big + TST R1, R1 + BNE sequenceDecs_decode_56_amd64_match_len_ofs_ok + TST R0, R0 + BNE sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch + +sequenceDecs_decode_56_amd64_match_len_ofs_ok: + ADD $0x18, R9, R9 + MOVD ctx+16(FP), R0 + MOVD 96(R0), R16 + SUBS $1, R16, R16 + MOVD R16, 96(R0) + BPL sequenceDecs_decode_56_amd64_main_loop + MOVD s+0(FP), R0 + MOVD R10, 144(R0) + MOVD R11, 152(R0) + MOVD R12, 160(R0) + MOVD br+8(FP), R0 + MOVD R2, 24(R0) + MOVB R3, 40(R0) + MOVD R5, 32(R0) + + // Return success + MOVD $0x00000000, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decode_56_amd64_error_match_len_ofs_mismatch: + MOVD $0x00000001, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decode_56_amd64_error_match_len_too_big: + MOVD $0x00000002, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match offset too long error + MOVD $0x00000003, R16 + MOVD R16, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVD $0x00000004, R16 + MOVD R16, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVD $0x00000006, R16 + MOVD R16, ret+24(FP) + RET + +// skipped sequenceDecs_decode_bmi2 (generic twin preferred on arm64) + +// skipped sequenceDecs_decode_56_bmi2 (generic twin preferred on arm64) + +// func sequenceDecs_executeSimple_amd64(ctx *executeAsmContext) bool +// Requires: SSE +TEXT ·sequenceDecs_executeSimple_arm64(SB), $8-9 + MOVD ctx+0(FP), R9 + MOVD 8(R9), R1 + TST R1, R1 + BEQ empty_seqs + MOVD (R9), R0 + MOVD 24(R9), R2 + MOVD 32(R9), R3 + MOVD 80(R9), R5 + MOVD 104(R9), R6 + MOVD 120(R9), R7 + MOVD 56(R9), R8 + MOVD 64(R9), R9 + ADD R9, R8, R8 + + // seqsBase += 24 * seqIndex + ADD R2<<1, R2, R10 + LSL $0x03, R10, R10 + ADD R10, R0, R0 + + // outBase += outPosition + ADD R6, R3, R3 + +main_loop: + MOVD (R0), R10 + MOVD 16(R0), R11 + MOVD 8(R0), R12 + + // Copy literals + TST R10, R10 + BEQ check_offset + MOVD $0, R13 + +copy_1: + ADD R13, R5, R15 + VLD1 (R15), [V0.B16] + ADD R13, R3, R15 + VST1 [V0.B16], (R15) + ADD $0x10, R13, R13 + CMP R10, R13 + BLO copy_1 + ADD R10, R5, R5 + ADD R10, R3, R3 + ADD R10, R6, R6 + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + ADD R9, R6, R10 + CMP R10, R11 + BGT error_match_off_too_big + CMP R7, R11 + BGT error_match_off_too_big + + // Copy match from history + MOVD R11, R10 + SUBS R6, R10, R10 + BLS copy_match + MOVD R8, R13 + SUB R10, R13, R13 + CMP R10, R12 + BGT copy_all_from_history + MOVD R12, R10 + SUBS $0x10, R10, R10 + BLO copy_4_small + +copy_4_loop: + VLD1 (R13), [V0.B16] + VST1 [V0.B16], (R3) + ADD $0x10, R13, R13 + ADD $0x10, R3, R3 + SUBS $0x10, R10, R10 + BHS copy_4_loop + ADD R10, R13, R13 + ADD $16, R13, R13 + ADD R10, R3, R3 + ADD $16, R3, R3 + ADD $-16, R13, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R3, R15 + VST1 [V0.B16], (R15) + JMP copy_4_end + +copy_4_small: + CMP $0x03, R12 + BEQ copy_4_move_3 + CMP $0x08, R12 + BLO copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVHU (R13), R10 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R11 + MOVH R10, (R3) + MOVB R11, 2(R3) + ADD R12, R13, R13 + ADD R12, R3, R3 + JMP copy_4_end + +copy_4_move_4through7: + MOVWU (R13), R10 + ADD R12, R13, R15 + MOVWU -4(R15), R11 + MOVW R10, (R3) + ADD R12, R3, R15 + MOVW R11, -4(R15) + ADD R12, R13, R13 + ADD R12, R3, R3 + JMP copy_4_end + +copy_4_move_8through16: + MOVD (R13), R10 + ADD R12, R13, R15 + MOVD -8(R15), R11 + MOVD R10, (R3) + ADD R12, R3, R15 + MOVD R11, -8(R15) + ADD R12, R13, R13 + ADD R12, R3, R3 + +copy_4_end: + ADD R12, R6, R6 + ADD $0x18, R0, R0 + ADD $1, R2, R2 + CMP R1, R2 + BLO main_loop + JMP loop_finished + +copy_all_from_history: + MOVD R10, R14 + SUBS $0x10, R14, R14 + BLO copy_5_small + +copy_5_loop: + VLD1 (R13), [V0.B16] + VST1 [V0.B16], (R3) + ADD $0x10, R13, R13 + ADD $0x10, R3, R3 + SUBS $0x10, R14, R14 + BHS copy_5_loop + ADD R14, R13, R13 + ADD $16, R13, R13 + ADD R14, R3, R3 + ADD $16, R3, R3 + ADD $-16, R13, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R3, R15 + VST1 [V0.B16], (R15) + JMP copy_5_end + +copy_5_small: + CMP $0x03, R10 + BEQ copy_5_move_3 + BLO copy_5_move_1or2 + CMP $0x08, R10 + BLO copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVBU (R13), R16 + BFI $0, R16, $8, R14 + ADD R10, R13, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R4 + MOVB R14, (R3) + ADD R10, R3, R15 + MOVB R4, -1(R15) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end + +copy_5_move_3: + MOVHU (R13), R14 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R4 + MOVH R14, (R3) + MOVB R4, 2(R3) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end + +copy_5_move_4through7: + MOVWU (R13), R14 + ADD R10, R13, R15 + MOVWU -4(R15), R4 + MOVW R14, (R3) + ADD R10, R3, R15 + MOVW R4, -4(R15) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end + +copy_5_move_8through16: + MOVD (R13), R14 + ADD R10, R13, R15 + MOVD -8(R15), R4 + MOVD R14, (R3) + ADD R10, R3, R15 + MOVD R4, -8(R15) + ADD R10, R13, R13 + ADD R10, R3, R3 + +copy_5_end: + ADD R10, R6, R6 + SUB R10, R12, R12 + + // Copy match from the current buffer +copy_match: + MOVD R3, R10 + SUB R11, R10, R10 + + // ml <= mo + CMP R11, R12 + BHI copy_overlapping_match + + // Copy non-overlapping match + ADD R12, R6, R6 + MOVD R3, R11 + ADD R12, R3, R3 + +copy_2: + VLD1 (R10), [V0.B16] + VST1 [V0.B16], (R11) + ADD $0x10, R10, R10 + ADD $0x10, R11, R11 + SUBS $0x10, R12, R12 + BHI copy_2 + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADD R12, R6, R6 + +copy_slow_3: + MOVBU (R10), R16 + BFI $0, R16, $8, R11 + MOVB R11, (R3) + ADD $1, R10, R10 + ADD $1, R3, R3 + SUBS $1, R12, R12 + BNE copy_slow_3 + +handle_loop: + ADD $0x18, R0, R0 + ADD $1, R2, R2 + CMP R1, R2 + BLO main_loop + +loop_finished: + // Return value + MOVD $0x01, R16 + MOVB R16, ret+8(FP) + + // Update the context + MOVD ctx+0(FP), R0 + MOVD R2, 24(R0) + MOVD R6, 104(R0) + MOVD 80(R0), R16 + SUB R16, R5, R5 + MOVD R5, 112(R0) + RET + +error_match_off_too_big: + // Return value + MOVD $0x00, R16 + MOVB R16, ret+8(FP) + + // Update the context + MOVD ctx+0(FP), R0 + MOVD R2, 24(R0) + MOVD R6, 104(R0) + MOVD 80(R0), R16 + SUB R16, R5, R5 + MOVD R5, 112(R0) + RET + +empty_seqs: + // Return value + MOVD $0x01, R16 + MOVB R16, ret+8(FP) + RET + +// func sequenceDecs_executeSimple_safe_amd64(ctx *executeAsmContext) bool +// Requires: SSE +TEXT ·sequenceDecs_executeSimple_safe_arm64(SB), $8-9 + MOVD ctx+0(FP), R9 + MOVD 8(R9), R1 + TST R1, R1 + BEQ empty_seqs + MOVD (R9), R0 + MOVD 24(R9), R2 + MOVD 32(R9), R3 + MOVD 80(R9), R5 + MOVD 104(R9), R6 + MOVD 120(R9), R7 + MOVD 56(R9), R8 + MOVD 64(R9), R9 + ADD R9, R8, R8 + + // seqsBase += 24 * seqIndex + ADD R2<<1, R2, R10 + LSL $0x03, R10, R10 + ADD R10, R0, R0 + + // outBase += outPosition + ADD R6, R3, R3 + +main_loop: + MOVD (R0), R10 + MOVD 16(R0), R11 + MOVD 8(R0), R12 + + // Copy literals + TST R10, R10 + BEQ check_offset + MOVD R10, R13 + SUBS $0x10, R13, R13 + BLO copy_1_small + +copy_1_loop: + VLD1 (R5), [V0.B16] + VST1 [V0.B16], (R3) + ADD $0x10, R5, R5 + ADD $0x10, R3, R3 + SUBS $0x10, R13, R13 + BHS copy_1_loop + ADD R13, R5, R5 + ADD $16, R5, R5 + ADD R13, R3, R3 + ADD $16, R3, R3 + ADD $-16, R5, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R3, R15 + VST1 [V0.B16], (R15) + JMP copy_1_end + +copy_1_small: + CMP $0x03, R10 + BEQ copy_1_move_3 + BLO copy_1_move_1or2 + CMP $0x08, R10 + BLO copy_1_move_4through7 + JMP copy_1_move_8through16 + +copy_1_move_1or2: + MOVBU (R5), R16 + BFI $0, R16, $8, R13 + ADD R10, R5, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R14 + MOVB R13, (R3) + ADD R10, R3, R15 + MOVB R14, -1(R15) + ADD R10, R5, R5 + ADD R10, R3, R3 + JMP copy_1_end + +copy_1_move_3: + MOVHU (R5), R13 + MOVBU 2(R5), R16 + BFI $0, R16, $8, R14 + MOVH R13, (R3) + MOVB R14, 2(R3) + ADD R10, R5, R5 + ADD R10, R3, R3 + JMP copy_1_end + +copy_1_move_4through7: + MOVWU (R5), R13 + ADD R10, R5, R15 + MOVWU -4(R15), R14 + MOVW R13, (R3) + ADD R10, R3, R15 + MOVW R14, -4(R15) + ADD R10, R5, R5 + ADD R10, R3, R3 + JMP copy_1_end + +copy_1_move_8through16: + MOVD (R5), R13 + ADD R10, R5, R15 + MOVD -8(R15), R14 + MOVD R13, (R3) + ADD R10, R3, R15 + MOVD R14, -8(R15) + ADD R10, R5, R5 + ADD R10, R3, R3 + +copy_1_end: + ADD R10, R6, R6 + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + ADD R9, R6, R10 + CMP R10, R11 + BGT error_match_off_too_big + CMP R7, R11 + BGT error_match_off_too_big + + // Copy match from history + MOVD R11, R10 + SUBS R6, R10, R10 + BLS copy_match + MOVD R8, R13 + SUB R10, R13, R13 + CMP R10, R12 + BGT copy_all_from_history + MOVD R12, R10 + SUBS $0x10, R10, R10 + BLO copy_4_small + +copy_4_loop: + VLD1 (R13), [V0.B16] + VST1 [V0.B16], (R3) + ADD $0x10, R13, R13 + ADD $0x10, R3, R3 + SUBS $0x10, R10, R10 + BHS copy_4_loop + ADD R10, R13, R13 + ADD $16, R13, R13 + ADD R10, R3, R3 + ADD $16, R3, R3 + ADD $-16, R13, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R3, R15 + VST1 [V0.B16], (R15) + JMP copy_4_end + +copy_4_small: + CMP $0x03, R12 + BEQ copy_4_move_3 + CMP $0x08, R12 + BLO copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVHU (R13), R10 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R11 + MOVH R10, (R3) + MOVB R11, 2(R3) + ADD R12, R13, R13 + ADD R12, R3, R3 + JMP copy_4_end + +copy_4_move_4through7: + MOVWU (R13), R10 + ADD R12, R13, R15 + MOVWU -4(R15), R11 + MOVW R10, (R3) + ADD R12, R3, R15 + MOVW R11, -4(R15) + ADD R12, R13, R13 + ADD R12, R3, R3 + JMP copy_4_end + +copy_4_move_8through16: + MOVD (R13), R10 + ADD R12, R13, R15 + MOVD -8(R15), R11 + MOVD R10, (R3) + ADD R12, R3, R15 + MOVD R11, -8(R15) + ADD R12, R13, R13 + ADD R12, R3, R3 + +copy_4_end: + ADD R12, R6, R6 + ADD $0x18, R0, R0 + ADD $1, R2, R2 + CMP R1, R2 + BLO main_loop + JMP loop_finished + +copy_all_from_history: + MOVD R10, R14 + SUBS $0x10, R14, R14 + BLO copy_5_small + +copy_5_loop: + VLD1 (R13), [V0.B16] + VST1 [V0.B16], (R3) + ADD $0x10, R13, R13 + ADD $0x10, R3, R3 + SUBS $0x10, R14, R14 + BHS copy_5_loop + ADD R14, R13, R13 + ADD $16, R13, R13 + ADD R14, R3, R3 + ADD $16, R3, R3 + ADD $-16, R13, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R3, R15 + VST1 [V0.B16], (R15) + JMP copy_5_end + +copy_5_small: + CMP $0x03, R10 + BEQ copy_5_move_3 + BLO copy_5_move_1or2 + CMP $0x08, R10 + BLO copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVBU (R13), R16 + BFI $0, R16, $8, R14 + ADD R10, R13, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R4 + MOVB R14, (R3) + ADD R10, R3, R15 + MOVB R4, -1(R15) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end + +copy_5_move_3: + MOVHU (R13), R14 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R4 + MOVH R14, (R3) + MOVB R4, 2(R3) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end + +copy_5_move_4through7: + MOVWU (R13), R14 + ADD R10, R13, R15 + MOVWU -4(R15), R4 + MOVW R14, (R3) + ADD R10, R3, R15 + MOVW R4, -4(R15) + ADD R10, R13, R13 + ADD R10, R3, R3 + JMP copy_5_end + +copy_5_move_8through16: + MOVD (R13), R14 + ADD R10, R13, R15 + MOVD -8(R15), R4 + MOVD R14, (R3) + ADD R10, R3, R15 + MOVD R4, -8(R15) + ADD R10, R13, R13 + ADD R10, R3, R3 + +copy_5_end: + ADD R10, R6, R6 + SUB R10, R12, R12 + + // Copy match from the current buffer +copy_match: + MOVD R3, R10 + SUB R11, R10, R10 + + // ml <= mo + CMP R11, R12 + BHI copy_overlapping_match + + // Copy non-overlapping match + ADD R12, R6, R6 + MOVD R12, R11 + SUBS $0x10, R11, R11 + BLO copy_2_small + +copy_2_loop: + VLD1 (R10), [V0.B16] + VST1 [V0.B16], (R3) + ADD $0x10, R10, R10 + ADD $0x10, R3, R3 + SUBS $0x10, R11, R11 + BHS copy_2_loop + ADD R11, R10, R10 + ADD $16, R10, R10 + ADD R11, R3, R3 + ADD $16, R3, R3 + ADD $-16, R10, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R3, R15 + VST1 [V0.B16], (R15) + JMP copy_2_end + +copy_2_small: + CMP $0x03, R12 + BEQ copy_2_move_3 + BLO copy_2_move_1or2 + CMP $0x08, R12 + BLO copy_2_move_4through7 + JMP copy_2_move_8through16 + +copy_2_move_1or2: + MOVBU (R10), R16 + BFI $0, R16, $8, R11 + ADD R12, R10, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R13 + MOVB R11, (R3) + ADD R12, R3, R15 + MOVB R13, -1(R15) + ADD R12, R10, R10 + ADD R12, R3, R3 + JMP copy_2_end + +copy_2_move_3: + MOVHU (R10), R11 + MOVBU 2(R10), R16 + BFI $0, R16, $8, R13 + MOVH R11, (R3) + MOVB R13, 2(R3) + ADD R12, R10, R10 + ADD R12, R3, R3 + JMP copy_2_end + +copy_2_move_4through7: + MOVWU (R10), R11 + ADD R12, R10, R15 + MOVWU -4(R15), R13 + MOVW R11, (R3) + ADD R12, R3, R15 + MOVW R13, -4(R15) + ADD R12, R10, R10 + ADD R12, R3, R3 + JMP copy_2_end + +copy_2_move_8through16: + MOVD (R10), R11 + ADD R12, R10, R15 + MOVD -8(R15), R13 + MOVD R11, (R3) + ADD R12, R3, R15 + MOVD R13, -8(R15) + ADD R12, R10, R10 + ADD R12, R3, R3 + +copy_2_end: + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADD R12, R6, R6 + +copy_slow_3: + MOVBU (R10), R16 + BFI $0, R16, $8, R11 + MOVB R11, (R3) + ADD $1, R10, R10 + ADD $1, R3, R3 + SUBS $1, R12, R12 + BNE copy_slow_3 + +handle_loop: + ADD $0x18, R0, R0 + ADD $1, R2, R2 + CMP R1, R2 + BLO main_loop + +loop_finished: + // Return value + MOVD $0x01, R16 + MOVB R16, ret+8(FP) + + // Update the context + MOVD ctx+0(FP), R0 + MOVD R2, 24(R0) + MOVD R6, 104(R0) + MOVD 80(R0), R16 + SUB R16, R5, R5 + MOVD R5, 112(R0) + RET + +error_match_off_too_big: + // Return value + MOVD $0x00, R16 + MOVB R16, ret+8(FP) + + // Update the context + MOVD ctx+0(FP), R0 + MOVD R2, 24(R0) + MOVD R6, 104(R0) + MOVD 80(R0), R16 + SUB R16, R5, R5 + MOVD R5, 112(R0) + RET + +empty_seqs: + // Return value + MOVD $0x01, R16 + MOVB R16, ret+8(FP) + RET + +// func sequenceDecs_decodeSync_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int +// Requires: CMOV, SSE +TEXT ·sequenceDecs_decodeSync_arm64(SB), $64-32 + MOVD br+8(FP), R1 + MOVD 24(R1), R2 + MOVBU 40(R1), R3 + MOVD (R1), R0 + MOVD 32(R1), R5 + ADD R5, R0, R0 + MOVD R0, 8(RSP) + MOVD ctx+16(FP), R0 + MOVD 72(R0), R6 + MOVD 80(R0), R7 + MOVD 88(R0), R8 + MOVD $0, R1 + MOVD R1, 16(RSP) + MOVD R1, 24(RSP) + MOVD R1, 32(RSP) + MOVD 112(R0), R9 + MOVD 128(R0), R1 + MOVD R1, 40(RSP) + MOVD 144(R0), R10 + MOVD 136(R0), R11 + MOVD 200(R0), R1 + MOVD R1, 64(RSP) + MOVD 176(R0), R1 + MOVD R1, 56(RSP) + MOVD 184(R0), R0 + MOVD R0, 48(RSP) + MOVD 48(RSP), R0 + MOVD 56(RSP), R16 + ADD R0, R16, R16 + MOVD R16, 56(RSP) + + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) + MOVD 40(RSP), R16 + ADD R9, R16, R16 + MOVD R16, 40(RSP) + + // outBase += outPosition + ADD R11, R9, R9 + +sequenceDecs_decodeSync_amd64_main_loop: + MOVD 8(RSP), R12 + + // Fill bitreader to have enough for the offset and match length. + CMP $0x08, R5 + BLT sequenceDecs_decodeSync_amd64_fill_byte_by_byte + MOVD R3, R0 + LSR $0x03, R0, R0 + SUB R0, R12, R12 + MOVD (R12), R2 + SUB R0, R5, R5 + AND $0x07, R3, R3 + JMP sequenceDecs_decodeSync_amd64_fill_end + +sequenceDecs_decodeSync_amd64_fill_byte_by_byte: + CMP $0x00, R5 + BLE sequenceDecs_decodeSync_amd64_fill_check_overread + CMP $0x07, R3 + BLE sequenceDecs_decodeSync_amd64_fill_end + LSL $0x08, R2, R2 + SUB $0x01, R12, R12 + SUB $0x01, R5, R5 + SUB $0x08, R3, R3 + MOVBU (R12), R0 + ORR R0, R2, R2 + JMP sequenceDecs_decodeSync_amd64_fill_byte_by_byte + +sequenceDecs_decodeSync_amd64_fill_check_overread: + CMP $0x40, R3 + BHI error_overread + +sequenceDecs_decodeSync_amd64_fill_end: + // Update offset + MOVD R8, R0 + MOVD R3, R1 + MOVD R2, R13 + LSL R1, R13, R13 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decodeSync_amd64_of_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decodeSync_amd64_of_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decodeSync_amd64_of_update_zero + NEG R1, R1 + LSR R1, R13, R13 + ADD R13, R0, R0 + +sequenceDecs_decodeSync_amd64_of_update_zero: + MOVD R0, 16(RSP) + + // Update match length + MOVD R7, R0 + MOVD R3, R1 + MOVD R2, R13 + LSL R1, R13, R13 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decodeSync_amd64_ml_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decodeSync_amd64_ml_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decodeSync_amd64_ml_update_zero + NEG R1, R1 + LSR R1, R13, R13 + ADD R13, R0, R0 + +sequenceDecs_decodeSync_amd64_ml_update_zero: + MOVD R0, 24(RSP) + + // Fill bitreader to have enough for the remaining + CMP $0x08, R5 + BLT sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte + MOVD R3, R0 + LSR $0x03, R0, R0 + SUB R0, R12, R12 + MOVD (R12), R2 + SUB R0, R5, R5 + AND $0x07, R3, R3 + JMP sequenceDecs_decodeSync_amd64_fill_2_end + +sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte: + CMP $0x00, R5 + BLE sequenceDecs_decodeSync_amd64_fill_2_check_overread + CMP $0x07, R3 + BLE sequenceDecs_decodeSync_amd64_fill_2_end + LSL $0x08, R2, R2 + SUB $0x01, R12, R12 + SUB $0x01, R5, R5 + SUB $0x08, R3, R3 + MOVBU (R12), R0 + ORR R0, R2, R2 + JMP sequenceDecs_decodeSync_amd64_fill_2_byte_by_byte + +sequenceDecs_decodeSync_amd64_fill_2_check_overread: + CMP $0x40, R3 + BHI error_overread + +sequenceDecs_decodeSync_amd64_fill_2_end: + // Update literal length + MOVD R6, R0 + MOVD R3, R1 + MOVD R2, R13 + LSL R1, R13, R13 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decodeSync_amd64_ll_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decodeSync_amd64_ll_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decodeSync_amd64_ll_update_zero + NEG R1, R1 + LSR R1, R13, R13 + ADD R13, R0, R0 + +sequenceDecs_decodeSync_amd64_ll_update_zero: + MOVD R0, 32(RSP) + + // Fill bitreader for state updates + MOVD R12, 8(RSP) + MOVD R8, R0 + LSR $0x08, R0, R0 + MOVBU R0, R0 + MOVD ctx+16(FP), R1 + MOVD 96(R1), R16 + CMP $0x00, R16 + BEQ sequenceDecs_decodeSync_amd64_skip_update + + // Update Literal Length State + MOVBU R6, R12 + LSRW $0x10, R6, R6 + ADD R12, R3, R1 + MOVD R2, R13 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R13, R13 + MOVD $0x00000001, R14 + BFI $0, R12, $8, R1 + LSLW R1, R14, R14 + SUBW $1, R14, R14 + AND R14, R13, R13 + ADD R13, R6, R6 + + // Load ctx.llTable + MOVD ctx+16(FP), R1 + MOVD (R1), R1 + ADD R6<<3, R1, R15 + MOVD (R15), R6 + + // Update Match Length State + MOVBU R7, R12 + LSRW $0x10, R7, R7 + ADD R12, R3, R1 + MOVD R2, R13 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R13, R13 + MOVD $0x00000001, R14 + BFI $0, R12, $8, R1 + LSLW R1, R14, R14 + SUBW $1, R14, R14 + AND R14, R13, R13 + ADD R13, R7, R7 + + // Load ctx.mlTable + MOVD ctx+16(FP), R1 + MOVD 24(R1), R1 + ADD R7<<3, R1, R15 + MOVD (R15), R7 + + // Update Offset State + MOVBU R8, R12 + LSRW $0x10, R8, R8 + ADD R12, R3, R1 + MOVD R2, R13 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R13, R13 + MOVD $0x00000001, R14 + BFI $0, R12, $8, R1 + LSLW R1, R14, R14 + SUBW $1, R14, R14 + AND R14, R13, R13 + ADD R13, R8, R8 + + // Load ctx.ofTable + MOVD ctx+16(FP), R1 + MOVD 48(R1), R1 + ADD R8<<3, R1, R15 + MOVD (R15), R8 + +sequenceDecs_decodeSync_amd64_skip_update: + // Adjust offset + MOVD s+0(FP), R1 + MOVD 16(RSP), R12 + CMP $0x01, R0 + BLS sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0 + ADD $144, R1, R15 + VLD1 (R15), [V0.B16] + MOVD R12, 144(R1) + ADD $152, R1, R15 + VST1 [V0.B16], (R15) + JMP sequenceDecs_decodeSync_amd64_after_adjust + +sequenceDecs_decodeSync_amd64_adjust_offsetB_1_or_0: + MOVD 32(RSP), R16 + CMP $0x00000000, R16 + BNE sequenceDecs_decodeSync_amd64_adjust_offset_maybezero + ADD $1, R12, R12 + JMP sequenceDecs_decodeSync_amd64_adjust_offset_nonzero + +sequenceDecs_decodeSync_amd64_adjust_offset_maybezero: + TST R12, R12 + BNE sequenceDecs_decodeSync_amd64_adjust_offset_nonzero + MOVD 144(R1), R12 + JMP sequenceDecs_decodeSync_amd64_after_adjust + +sequenceDecs_decodeSync_amd64_adjust_offset_nonzero: + MOVD R12, R0 + MOVD $0, R13 + MOVD $-1, R14 + CMP $0x03, R12 + CSEL EQ, R13, R0, R0 + CSEL EQ, R14, R13, R13 + ADD R0<<3, R1, R15 + MOVD 144(R15), R16 + ADDS R16, R13, R13 + BNE sequenceDecs_decodeSync_amd64_adjust_temp_valid + MOVD $0x00000001, R13 + +sequenceDecs_decodeSync_amd64_adjust_temp_valid: + CMP $0x01, R12 + BEQ sequenceDecs_decodeSync_amd64_adjust_skip + MOVD 152(R1), R0 + MOVD R0, 160(R1) + +sequenceDecs_decodeSync_amd64_adjust_skip: + MOVD 144(R1), R0 + MOVD R0, 152(R1) + MOVD R13, 144(R1) + MOVD R13, R12 + +sequenceDecs_decodeSync_amd64_after_adjust: + MOVD R12, 16(RSP) + + // Check values + MOVD 24(RSP), R0 + MOVD 32(RSP), R1 + ADD R1, R0, R13 + MOVD s+0(FP), R14 + MOVD 256(R14), R16 + ADD R13, R16, R16 + MOVD R16, 256(R14) + MOVD ctx+16(FP), R13 + MOVD 104(R13), R16 + SUBS R1, R16, R16 + MOVD R16, 104(R13) + BMI error_not_enough_literals + CMP $0x00020002, R0 + BHI sequenceDecs_decodeSync_amd64_error_match_len_too_big + TST R12, R12 + BNE sequenceDecs_decodeSync_amd64_match_len_ofs_ok + TST R0, R0 + BNE sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch + +sequenceDecs_decodeSync_amd64_match_len_ofs_ok: + MOVD 32(RSP), R0 + MOVD 16(RSP), R1 + MOVD 24(RSP), R12 + + // Check if we have enough space in s.out + ADD R12, R0, R13 + ADD $16, R13, R13 + ADD R9, R13, R13 + MOVD 40(RSP), R16 + CMP R16, R13 + BHI error_not_enough_space + + // Copy literals + TST R0, R0 + BEQ check_offset + MOVD $0, R13 + +copy_1: + ADD R13, R10, R15 + VLD1 (R15), [V0.B16] + ADD R13, R9, R15 + VST1 [V0.B16], (R15) + ADD $0x10, R13, R13 + CMP R0, R13 + BLO copy_1 + ADD R0, R10, R10 + ADD R0, R9, R9 + ADD R0, R11, R11 + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + MOVD R11, R0 + MOVD 48(RSP), R16 + ADD R16, R0, R0 + CMP R0, R1 + BGT error_match_off_too_big + MOVD 64(RSP), R16 + CMP R16, R1 + BGT error_match_off_too_big + + // Copy match from history + MOVD R1, R0 + SUBS R11, R0, R0 + BLS copy_match + MOVD 56(RSP), R13 + SUB R0, R13, R13 + CMP R0, R12 + BGT copy_all_from_history + MOVD R12, R0 + SUBS $0x10, R0, R0 + BLO copy_4_small + +copy_4_loop: + VLD1 (R13), [V0.B16] + VST1 [V0.B16], (R9) + ADD $0x10, R13, R13 + ADD $0x10, R9, R9 + SUBS $0x10, R0, R0 + BHS copy_4_loop + ADD R0, R13, R13 + ADD $16, R13, R13 + ADD R0, R9, R9 + ADD $16, R9, R9 + ADD $-16, R13, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R9, R15 + VST1 [V0.B16], (R15) + JMP copy_4_end + +copy_4_small: + CMP $0x03, R12 + BEQ copy_4_move_3 + CMP $0x08, R12 + BLO copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVHU (R13), R0 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R1 + MOVH R0, (R9) + MOVB R1, 2(R9) + ADD R12, R13, R13 + ADD R12, R9, R9 + JMP copy_4_end + +copy_4_move_4through7: + MOVWU (R13), R0 + ADD R12, R13, R15 + MOVWU -4(R15), R1 + MOVW R0, (R9) + ADD R12, R9, R15 + MOVW R1, -4(R15) + ADD R12, R13, R13 + ADD R12, R9, R9 + JMP copy_4_end + +copy_4_move_8through16: + MOVD (R13), R0 + ADD R12, R13, R15 + MOVD -8(R15), R1 + MOVD R0, (R9) + ADD R12, R9, R15 + MOVD R1, -8(R15) + ADD R12, R13, R13 + ADD R12, R9, R9 + +copy_4_end: + ADD R12, R11, R11 + JMP handle_loop + JMP loop_finished + +copy_all_from_history: + MOVD R0, R14 + SUBS $0x10, R14, R14 + BLO copy_5_small + +copy_5_loop: + VLD1 (R13), [V0.B16] + VST1 [V0.B16], (R9) + ADD $0x10, R13, R13 + ADD $0x10, R9, R9 + SUBS $0x10, R14, R14 + BHS copy_5_loop + ADD R14, R13, R13 + ADD $16, R13, R13 + ADD R14, R9, R9 + ADD $16, R9, R9 + ADD $-16, R13, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R9, R15 + VST1 [V0.B16], (R15) + JMP copy_5_end + +copy_5_small: + CMP $0x03, R0 + BEQ copy_5_move_3 + BLO copy_5_move_1or2 + CMP $0x08, R0 + BLO copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVBU (R13), R16 + BFI $0, R16, $8, R14 + ADD R0, R13, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R4 + MOVB R14, (R9) + ADD R0, R9, R15 + MOVB R4, -1(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end + +copy_5_move_3: + MOVHU (R13), R14 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R4 + MOVH R14, (R9) + MOVB R4, 2(R9) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end + +copy_5_move_4through7: + MOVWU (R13), R14 + ADD R0, R13, R15 + MOVWU -4(R15), R4 + MOVW R14, (R9) + ADD R0, R9, R15 + MOVW R4, -4(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end + +copy_5_move_8through16: + MOVD (R13), R14 + ADD R0, R13, R15 + MOVD -8(R15), R4 + MOVD R14, (R9) + ADD R0, R9, R15 + MOVD R4, -8(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 + +copy_5_end: + ADD R0, R11, R11 + SUB R0, R12, R12 + + // Copy match from the current buffer +copy_match: + MOVD R9, R0 + SUB R1, R0, R0 + + // ml <= mo + CMP R1, R12 + BHI copy_overlapping_match + + // Copy non-overlapping match + ADD R12, R11, R11 + MOVD R9, R1 + ADD R12, R9, R9 + +copy_2: + VLD1 (R0), [V0.B16] + VST1 [V0.B16], (R1) + ADD $0x10, R0, R0 + ADD $0x10, R1, R1 + SUBS $0x10, R12, R12 + BHI copy_2 + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADD R12, R11, R11 + +copy_slow_3: + MOVBU (R0), R16 + BFI $0, R16, $8, R1 + MOVB R1, (R9) + ADD $1, R0, R0 + ADD $1, R9, R9 + SUBS $1, R12, R12 + BNE copy_slow_3 + +handle_loop: + MOVD ctx+16(FP), R0 + MOVD 96(R0), R16 + SUBS $1, R16, R16 + MOVD R16, 96(R0) + BPL sequenceDecs_decodeSync_amd64_main_loop + +loop_finished: + MOVD br+8(FP), R0 + MOVD R2, 24(R0) + MOVB R3, 40(R0) + MOVD R5, 32(R0) + + // Update the context + MOVD ctx+16(FP), R0 + MOVD R11, 136(R0) + MOVD 144(R0), R1 + SUB R1, R10, R10 + MOVD R10, 168(R0) + + // Return success + MOVD $0x00000000, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decodeSync_amd64_error_match_len_ofs_mismatch: + MOVD 24(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 216(R1) + MOVD $0x00000001, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decodeSync_amd64_error_match_len_too_big: + MOVD ctx+16(FP), R0 + MOVD 24(RSP), R1 + MOVD R1, 216(R0) + MOVD $0x00000002, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match offset too long error +error_match_off_too_big: + MOVD ctx+16(FP), R0 + MOVD 16(RSP), R1 + MOVD R1, 224(R0) + MOVD R11, 136(R0) + MOVD $0x00000003, R16 + MOVD R16, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVD ctx+16(FP), R0 + MOVD 32(RSP), R1 + MOVD R1, 208(R0) + MOVD $0x00000004, R16 + MOVD R16, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVD $0x00000006, R16 + MOVD R16, ret+24(FP) + RET + + // Return with not enough output space error +error_not_enough_space: + MOVD ctx+16(FP), R0 + MOVD 32(RSP), R1 + MOVD R1, 208(R0) + MOVD 24(RSP), R1 + MOVD R1, 216(R0) + MOVD R11, 136(R0) + MOVD $0x00000005, R16 + MOVD R16, ret+24(FP) + RET + +// skipped sequenceDecs_decodeSync_bmi2 (generic twin preferred on arm64) + +// func sequenceDecs_decodeSync_safe_amd64(s *sequenceDecs, br *bitReader, ctx *decodeSyncAsmContext) int +// Requires: CMOV, SSE +TEXT ·sequenceDecs_decodeSync_safe_arm64(SB), $64-32 + MOVD br+8(FP), R1 + MOVD 24(R1), R2 + MOVBU 40(R1), R3 + MOVD (R1), R0 + MOVD 32(R1), R5 + ADD R5, R0, R0 + MOVD R0, 8(RSP) + MOVD ctx+16(FP), R0 + MOVD 72(R0), R6 + MOVD 80(R0), R7 + MOVD 88(R0), R8 + MOVD $0, R1 + MOVD R1, 16(RSP) + MOVD R1, 24(RSP) + MOVD R1, 32(RSP) + MOVD 112(R0), R9 + MOVD 128(R0), R1 + MOVD R1, 40(RSP) + MOVD 144(R0), R10 + MOVD 136(R0), R11 + MOVD 200(R0), R1 + MOVD R1, 64(RSP) + MOVD 176(R0), R1 + MOVD R1, 56(RSP) + MOVD 184(R0), R0 + MOVD R0, 48(RSP) + MOVD 48(RSP), R0 + MOVD 56(RSP), R16 + ADD R0, R16, R16 + MOVD R16, 56(RSP) + + // Calculate pointer to s.out[cap(s.out)] (a past-end pointer) + MOVD 40(RSP), R16 + ADD R9, R16, R16 + MOVD R16, 40(RSP) + + // outBase += outPosition + ADD R11, R9, R9 + +sequenceDecs_decodeSync_safe_amd64_main_loop: + MOVD 8(RSP), R12 + + // Fill bitreader to have enough for the offset and match length. + CMP $0x08, R5 + BLT sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte + MOVD R3, R0 + LSR $0x03, R0, R0 + SUB R0, R12, R12 + MOVD (R12), R2 + SUB R0, R5, R5 + AND $0x07, R3, R3 + JMP sequenceDecs_decodeSync_safe_amd64_fill_end + +sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte: + CMP $0x00, R5 + BLE sequenceDecs_decodeSync_safe_amd64_fill_check_overread + CMP $0x07, R3 + BLE sequenceDecs_decodeSync_safe_amd64_fill_end + LSL $0x08, R2, R2 + SUB $0x01, R12, R12 + SUB $0x01, R5, R5 + SUB $0x08, R3, R3 + MOVBU (R12), R0 + ORR R0, R2, R2 + JMP sequenceDecs_decodeSync_safe_amd64_fill_byte_by_byte + +sequenceDecs_decodeSync_safe_amd64_fill_check_overread: + CMP $0x40, R3 + BHI error_overread + +sequenceDecs_decodeSync_safe_amd64_fill_end: + // Update offset + MOVD R8, R0 + MOVD R3, R1 + MOVD R2, R13 + LSL R1, R13, R13 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decodeSync_safe_amd64_of_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decodeSync_safe_amd64_of_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decodeSync_safe_amd64_of_update_zero + NEG R1, R1 + LSR R1, R13, R13 + ADD R13, R0, R0 + +sequenceDecs_decodeSync_safe_amd64_of_update_zero: + MOVD R0, 16(RSP) + + // Update match length + MOVD R7, R0 + MOVD R3, R1 + MOVD R2, R13 + LSL R1, R13, R13 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decodeSync_safe_amd64_ml_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decodeSync_safe_amd64_ml_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decodeSync_safe_amd64_ml_update_zero + NEG R1, R1 + LSR R1, R13, R13 + ADD R13, R0, R0 + +sequenceDecs_decodeSync_safe_amd64_ml_update_zero: + MOVD R0, 24(RSP) + + // Fill bitreader to have enough for the remaining + CMP $0x08, R5 + BLT sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte + MOVD R3, R0 + LSR $0x03, R0, R0 + SUB R0, R12, R12 + MOVD (R12), R2 + SUB R0, R5, R5 + AND $0x07, R3, R3 + JMP sequenceDecs_decodeSync_safe_amd64_fill_2_end + +sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte: + CMP $0x00, R5 + BLE sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread + CMP $0x07, R3 + BLE sequenceDecs_decodeSync_safe_amd64_fill_2_end + LSL $0x08, R2, R2 + SUB $0x01, R12, R12 + SUB $0x01, R5, R5 + SUB $0x08, R3, R3 + MOVBU (R12), R0 + ORR R0, R2, R2 + JMP sequenceDecs_decodeSync_safe_amd64_fill_2_byte_by_byte + +sequenceDecs_decodeSync_safe_amd64_fill_2_check_overread: + CMP $0x40, R3 + BHI error_overread + +sequenceDecs_decodeSync_safe_amd64_fill_2_end: + // Update literal length + MOVD R6, R0 + MOVD R3, R1 + MOVD R2, R13 + LSL R1, R13, R13 + UBFX $8, R0, $8, R16 + BFI $0, R16, $8, R1 + LSR $0x20, R0, R0 + TST R1, R1 + BEQ sequenceDecs_decodeSync_safe_amd64_ll_update_zero + ADD R1, R3, R3 + CMP $0x40, R3 + BHI sequenceDecs_decodeSync_safe_amd64_ll_update_zero + CMP $0x40, R1 + BHS sequenceDecs_decodeSync_safe_amd64_ll_update_zero + NEG R1, R1 + LSR R1, R13, R13 + ADD R13, R0, R0 + +sequenceDecs_decodeSync_safe_amd64_ll_update_zero: + MOVD R0, 32(RSP) + + // Fill bitreader for state updates + MOVD R12, 8(RSP) + MOVD R8, R0 + LSR $0x08, R0, R0 + MOVBU R0, R0 + MOVD ctx+16(FP), R1 + MOVD 96(R1), R16 + CMP $0x00, R16 + BEQ sequenceDecs_decodeSync_safe_amd64_skip_update + + // Update Literal Length State + MOVBU R6, R12 + LSRW $0x10, R6, R6 + ADD R12, R3, R1 + MOVD R2, R13 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R13, R13 + MOVD $0x00000001, R14 + BFI $0, R12, $8, R1 + LSLW R1, R14, R14 + SUBW $1, R14, R14 + AND R14, R13, R13 + ADD R13, R6, R6 + + // Load ctx.llTable + MOVD ctx+16(FP), R1 + MOVD (R1), R1 + ADD R6<<3, R1, R15 + MOVD (R15), R6 + + // Update Match Length State + MOVBU R7, R12 + LSRW $0x10, R7, R7 + ADD R12, R3, R1 + MOVD R2, R13 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R13, R13 + MOVD $0x00000001, R14 + BFI $0, R12, $8, R1 + LSLW R1, R14, R14 + SUBW $1, R14, R14 + AND R14, R13, R13 + ADD R13, R7, R7 + + // Load ctx.mlTable + MOVD ctx+16(FP), R1 + MOVD 24(R1), R1 + ADD R7<<3, R1, R15 + MOVD (R15), R7 + + // Update Offset State + MOVBU R8, R12 + LSRW $0x10, R8, R8 + ADD R12, R3, R1 + MOVD R2, R13 + MOVD R1, R3 + NEG R1, R16 + ROR R16, R13, R13 + MOVD $0x00000001, R14 + BFI $0, R12, $8, R1 + LSLW R1, R14, R14 + SUBW $1, R14, R14 + AND R14, R13, R13 + ADD R13, R8, R8 + + // Load ctx.ofTable + MOVD ctx+16(FP), R1 + MOVD 48(R1), R1 + ADD R8<<3, R1, R15 + MOVD (R15), R8 + +sequenceDecs_decodeSync_safe_amd64_skip_update: + // Adjust offset + MOVD s+0(FP), R1 + MOVD 16(RSP), R12 + CMP $0x01, R0 + BLS sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0 + ADD $144, R1, R15 + VLD1 (R15), [V0.B16] + MOVD R12, 144(R1) + ADD $152, R1, R15 + VST1 [V0.B16], (R15) + JMP sequenceDecs_decodeSync_safe_amd64_after_adjust + +sequenceDecs_decodeSync_safe_amd64_adjust_offsetB_1_or_0: + MOVD 32(RSP), R16 + CMP $0x00000000, R16 + BNE sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero + ADD $1, R12, R12 + JMP sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero + +sequenceDecs_decodeSync_safe_amd64_adjust_offset_maybezero: + TST R12, R12 + BNE sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero + MOVD 144(R1), R12 + JMP sequenceDecs_decodeSync_safe_amd64_after_adjust + +sequenceDecs_decodeSync_safe_amd64_adjust_offset_nonzero: + MOVD R12, R0 + MOVD $0, R13 + MOVD $-1, R14 + CMP $0x03, R12 + CSEL EQ, R13, R0, R0 + CSEL EQ, R14, R13, R13 + ADD R0<<3, R1, R15 + MOVD 144(R15), R16 + ADDS R16, R13, R13 + BNE sequenceDecs_decodeSync_safe_amd64_adjust_temp_valid + MOVD $0x00000001, R13 + +sequenceDecs_decodeSync_safe_amd64_adjust_temp_valid: + CMP $0x01, R12 + BEQ sequenceDecs_decodeSync_safe_amd64_adjust_skip + MOVD 152(R1), R0 + MOVD R0, 160(R1) + +sequenceDecs_decodeSync_safe_amd64_adjust_skip: + MOVD 144(R1), R0 + MOVD R0, 152(R1) + MOVD R13, 144(R1) + MOVD R13, R12 + +sequenceDecs_decodeSync_safe_amd64_after_adjust: + MOVD R12, 16(RSP) + + // Check values + MOVD 24(RSP), R0 + MOVD 32(RSP), R1 + ADD R1, R0, R13 + MOVD s+0(FP), R14 + MOVD 256(R14), R16 + ADD R13, R16, R16 + MOVD R16, 256(R14) + MOVD ctx+16(FP), R13 + MOVD 104(R13), R16 + SUBS R1, R16, R16 + MOVD R16, 104(R13) + BMI error_not_enough_literals + CMP $0x00020002, R0 + BHI sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big + TST R12, R12 + BNE sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok + TST R0, R0 + BNE sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch + +sequenceDecs_decodeSync_safe_amd64_match_len_ofs_ok: + MOVD 32(RSP), R0 + MOVD 16(RSP), R1 + MOVD 24(RSP), R12 + + // Check if we have enough space in s.out + ADD R12, R0, R13 + ADD R9, R13, R13 + MOVD 40(RSP), R16 + CMP R16, R13 + BHI error_not_enough_space + + // Copy literals + TST R0, R0 + BEQ check_offset + MOVD R0, R13 + SUBS $0x10, R13, R13 + BLO copy_1_small + +copy_1_loop: + VLD1 (R10), [V0.B16] + VST1 [V0.B16], (R9) + ADD $0x10, R10, R10 + ADD $0x10, R9, R9 + SUBS $0x10, R13, R13 + BHS copy_1_loop + ADD R13, R10, R10 + ADD $16, R10, R10 + ADD R13, R9, R9 + ADD $16, R9, R9 + ADD $-16, R10, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R9, R15 + VST1 [V0.B16], (R15) + JMP copy_1_end + +copy_1_small: + CMP $0x03, R0 + BEQ copy_1_move_3 + BLO copy_1_move_1or2 + CMP $0x08, R0 + BLO copy_1_move_4through7 + JMP copy_1_move_8through16 + +copy_1_move_1or2: + MOVBU (R10), R16 + BFI $0, R16, $8, R13 + ADD R0, R10, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R14 + MOVB R13, (R9) + ADD R0, R9, R15 + MOVB R14, -1(R15) + ADD R0, R10, R10 + ADD R0, R9, R9 + JMP copy_1_end + +copy_1_move_3: + MOVHU (R10), R13 + MOVBU 2(R10), R16 + BFI $0, R16, $8, R14 + MOVH R13, (R9) + MOVB R14, 2(R9) + ADD R0, R10, R10 + ADD R0, R9, R9 + JMP copy_1_end + +copy_1_move_4through7: + MOVWU (R10), R13 + ADD R0, R10, R15 + MOVWU -4(R15), R14 + MOVW R13, (R9) + ADD R0, R9, R15 + MOVW R14, -4(R15) + ADD R0, R10, R10 + ADD R0, R9, R9 + JMP copy_1_end + +copy_1_move_8through16: + MOVD (R10), R13 + ADD R0, R10, R15 + MOVD -8(R15), R14 + MOVD R13, (R9) + ADD R0, R9, R15 + MOVD R14, -8(R15) + ADD R0, R10, R10 + ADD R0, R9, R9 + +copy_1_end: + ADD R0, R11, R11 + + // Malformed input if seq.mo > t+len(hist) || seq.mo > s.windowSize) +check_offset: + MOVD R11, R0 + MOVD 48(RSP), R16 + ADD R16, R0, R0 + CMP R0, R1 + BGT error_match_off_too_big + MOVD 64(RSP), R16 + CMP R16, R1 + BGT error_match_off_too_big + + // Copy match from history + MOVD R1, R0 + SUBS R11, R0, R0 + BLS copy_match + MOVD 56(RSP), R13 + SUB R0, R13, R13 + CMP R0, R12 + BGT copy_all_from_history + MOVD R12, R0 + SUBS $0x10, R0, R0 + BLO copy_4_small + +copy_4_loop: + VLD1 (R13), [V0.B16] + VST1 [V0.B16], (R9) + ADD $0x10, R13, R13 + ADD $0x10, R9, R9 + SUBS $0x10, R0, R0 + BHS copy_4_loop + ADD R0, R13, R13 + ADD $16, R13, R13 + ADD R0, R9, R9 + ADD $16, R9, R9 + ADD $-16, R13, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R9, R15 + VST1 [V0.B16], (R15) + JMP copy_4_end + +copy_4_small: + CMP $0x03, R12 + BEQ copy_4_move_3 + CMP $0x08, R12 + BLO copy_4_move_4through7 + JMP copy_4_move_8through16 + +copy_4_move_3: + MOVHU (R13), R0 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R1 + MOVH R0, (R9) + MOVB R1, 2(R9) + ADD R12, R13, R13 + ADD R12, R9, R9 + JMP copy_4_end + +copy_4_move_4through7: + MOVWU (R13), R0 + ADD R12, R13, R15 + MOVWU -4(R15), R1 + MOVW R0, (R9) + ADD R12, R9, R15 + MOVW R1, -4(R15) + ADD R12, R13, R13 + ADD R12, R9, R9 + JMP copy_4_end + +copy_4_move_8through16: + MOVD (R13), R0 + ADD R12, R13, R15 + MOVD -8(R15), R1 + MOVD R0, (R9) + ADD R12, R9, R15 + MOVD R1, -8(R15) + ADD R12, R13, R13 + ADD R12, R9, R9 + +copy_4_end: + ADD R12, R11, R11 + JMP handle_loop + JMP loop_finished + +copy_all_from_history: + MOVD R0, R14 + SUBS $0x10, R14, R14 + BLO copy_5_small + +copy_5_loop: + VLD1 (R13), [V0.B16] + VST1 [V0.B16], (R9) + ADD $0x10, R13, R13 + ADD $0x10, R9, R9 + SUBS $0x10, R14, R14 + BHS copy_5_loop + ADD R14, R13, R13 + ADD $16, R13, R13 + ADD R14, R9, R9 + ADD $16, R9, R9 + ADD $-16, R13, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R9, R15 + VST1 [V0.B16], (R15) + JMP copy_5_end + +copy_5_small: + CMP $0x03, R0 + BEQ copy_5_move_3 + BLO copy_5_move_1or2 + CMP $0x08, R0 + BLO copy_5_move_4through7 + JMP copy_5_move_8through16 + +copy_5_move_1or2: + MOVBU (R13), R16 + BFI $0, R16, $8, R14 + ADD R0, R13, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R4 + MOVB R14, (R9) + ADD R0, R9, R15 + MOVB R4, -1(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end + +copy_5_move_3: + MOVHU (R13), R14 + MOVBU 2(R13), R16 + BFI $0, R16, $8, R4 + MOVH R14, (R9) + MOVB R4, 2(R9) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end + +copy_5_move_4through7: + MOVWU (R13), R14 + ADD R0, R13, R15 + MOVWU -4(R15), R4 + MOVW R14, (R9) + ADD R0, R9, R15 + MOVW R4, -4(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 + JMP copy_5_end + +copy_5_move_8through16: + MOVD (R13), R14 + ADD R0, R13, R15 + MOVD -8(R15), R4 + MOVD R14, (R9) + ADD R0, R9, R15 + MOVD R4, -8(R15) + ADD R0, R13, R13 + ADD R0, R9, R9 + +copy_5_end: + ADD R0, R11, R11 + SUB R0, R12, R12 + + // Copy match from the current buffer +copy_match: + MOVD R9, R0 + SUB R1, R0, R0 + + // ml <= mo + CMP R1, R12 + BHI copy_overlapping_match + + // Copy non-overlapping match + ADD R12, R11, R11 + MOVD R12, R1 + SUBS $0x10, R1, R1 + BLO copy_2_small + +copy_2_loop: + VLD1 (R0), [V0.B16] + VST1 [V0.B16], (R9) + ADD $0x10, R0, R0 + ADD $0x10, R9, R9 + SUBS $0x10, R1, R1 + BHS copy_2_loop + ADD R1, R0, R0 + ADD $16, R0, R0 + ADD R1, R9, R9 + ADD $16, R9, R9 + ADD $-16, R0, R15 + VLD1 (R15), [V0.B16] + ADD $-16, R9, R15 + VST1 [V0.B16], (R15) + JMP copy_2_end + +copy_2_small: + CMP $0x03, R12 + BEQ copy_2_move_3 + BLO copy_2_move_1or2 + CMP $0x08, R12 + BLO copy_2_move_4through7 + JMP copy_2_move_8through16 + +copy_2_move_1or2: + MOVBU (R0), R16 + BFI $0, R16, $8, R1 + ADD R12, R0, R15 + MOVBU -1(R15), R16 + BFI $0, R16, $8, R13 + MOVB R1, (R9) + ADD R12, R9, R15 + MOVB R13, -1(R15) + ADD R12, R0, R0 + ADD R12, R9, R9 + JMP copy_2_end + +copy_2_move_3: + MOVHU (R0), R1 + MOVBU 2(R0), R16 + BFI $0, R16, $8, R13 + MOVH R1, (R9) + MOVB R13, 2(R9) + ADD R12, R0, R0 + ADD R12, R9, R9 + JMP copy_2_end + +copy_2_move_4through7: + MOVWU (R0), R1 + ADD R12, R0, R15 + MOVWU -4(R15), R13 + MOVW R1, (R9) + ADD R12, R9, R15 + MOVW R13, -4(R15) + ADD R12, R0, R0 + ADD R12, R9, R9 + JMP copy_2_end + +copy_2_move_8through16: + MOVD (R0), R1 + ADD R12, R0, R15 + MOVD -8(R15), R13 + MOVD R1, (R9) + ADD R12, R9, R15 + MOVD R13, -8(R15) + ADD R12, R0, R0 + ADD R12, R9, R9 + +copy_2_end: + JMP handle_loop + + // Copy overlapping match +copy_overlapping_match: + ADD R12, R11, R11 + +copy_slow_3: + MOVBU (R0), R16 + BFI $0, R16, $8, R1 + MOVB R1, (R9) + ADD $1, R0, R0 + ADD $1, R9, R9 + SUBS $1, R12, R12 + BNE copy_slow_3 + +handle_loop: + MOVD ctx+16(FP), R0 + MOVD 96(R0), R16 + SUBS $1, R16, R16 + MOVD R16, 96(R0) + BPL sequenceDecs_decodeSync_safe_amd64_main_loop + +loop_finished: + MOVD br+8(FP), R0 + MOVD R2, 24(R0) + MOVB R3, 40(R0) + MOVD R5, 32(R0) + + // Update the context + MOVD ctx+16(FP), R0 + MOVD R11, 136(R0) + MOVD 144(R0), R1 + SUB R1, R10, R10 + MOVD R10, 168(R0) + + // Return success + MOVD $0x00000000, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match length error +sequenceDecs_decodeSync_safe_amd64_error_match_len_ofs_mismatch: + MOVD 24(RSP), R0 + MOVD ctx+16(FP), R1 + MOVD R0, 216(R1) + MOVD $0x00000001, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match too long error +sequenceDecs_decodeSync_safe_amd64_error_match_len_too_big: + MOVD ctx+16(FP), R0 + MOVD 24(RSP), R1 + MOVD R1, 216(R0) + MOVD $0x00000002, R16 + MOVD R16, ret+24(FP) + RET + + // Return with match offset too long error +error_match_off_too_big: + MOVD ctx+16(FP), R0 + MOVD 16(RSP), R1 + MOVD R1, 224(R0) + MOVD R11, 136(R0) + MOVD $0x00000003, R16 + MOVD R16, ret+24(FP) + RET + + // Return with not enough literals error +error_not_enough_literals: + MOVD ctx+16(FP), R0 + MOVD 32(RSP), R1 + MOVD R1, 208(R0) + MOVD $0x00000004, R16 + MOVD R16, ret+24(FP) + RET + + // Return with overread error +error_overread: + MOVD $0x00000006, R16 + MOVD R16, ret+24(FP) + RET + + // Return with not enough output space error +error_not_enough_space: + MOVD ctx+16(FP), R0 + MOVD 32(RSP), R1 + MOVD R1, 208(R0) + MOVD 24(RSP), R1 + MOVD R1, 216(R0) + MOVD R11, 136(R0) + MOVD $0x00000005, R16 + MOVD R16, ret+24(FP) + RET + +// skipped sequenceDecs_decodeSync_safe_bmi2 (generic twin preferred on arm64) diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go b/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go new file mode 100644 index 0000000..42ce5de --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_asm.go @@ -0,0 +1,316 @@ +//go:build (amd64 || arm64) && !appengine && !noasm && gc + +package zstd + +import ( + "fmt" + "io" +) + +// This file holds the parts of the assembly sequence decoder that are identical +// across architectures: the context structs exchanged with the asm, the error +// codes, and the decode/decodeSync/executeSimple wrappers. Each architecture +// supplies the small dispatch helpers (decodeAsm, decodeSyncAsm, +// executeSimpleAsm) that select the concrete asm routine — amd64 also chooses a +// BMI2 variant, arm64 has a single implementation. + +type decodeSyncAsmContext struct { + llTable []decSymbol + mlTable []decSymbol + ofTable []decSymbol + llState uint64 + mlState uint64 + ofState uint64 + iteration int + litRemain int + out []byte + outPosition int + literals []byte + litPosition int + history []byte + windowSize int + ll int // set on error (not for all errors, please refer to _generate/gen.go) + ml int // set on error (not for all errors, please refer to _generate/gen.go) + mo int // set on error (not for all errors, please refer to _generate/gen.go) +} + +type decodeAsmContext struct { + llTable []decSymbol + mlTable []decSymbol + ofTable []decSymbol + llState uint64 + mlState uint64 + ofState uint64 + iteration int + seqs []seqVals + litRemain int +} + +type executeAsmContext struct { + seqs []seqVals + seqIndex int + out []byte + history []byte + literals []byte + outPosition int + litPosition int + windowSize int +} + +const noError = 0 + +// error reported when mo == 0 && ml > 0 +const errorMatchLenOfsMismatch = 1 + +// error reported when ml > maxMatchLen +const errorMatchLenTooBig = 2 + +// error reported when mo > available history or mo > s.windowSize +const errorMatchOffTooBig = 3 + +// error reported when the sum of literal lengths exeeceds the literal buffer size +const errorNotEnoughLiterals = 4 + +// error reported when capacity of `out` is too small +const errorNotEnoughSpace = 5 + +// error reported when bits are overread. +const errorOverread = 6 + +// useSafeDecodeSync reports whether decodeSyncSimple must use the bounds-exact +// ("safe") copy variants for the current buffer geometry. +// +// When the output and literal buffers have compressedBlockOverAlloc (16) +// bytes of slack past their logical use, the assembly may use extended +// memory copies that read and write in 16-byte blocks, overrunning the end +// of a literal run or match by up to 15 bytes. Otherwise it must use the +// bounds-exact ("safe") copies. This mirrors the analogous, always-dynamic +// selection in executeSimple below. +// +// The unsafe copies were disabled in #644 (2022) as a mitigation for a +// crash, but that crash's root cause — an unguarded bitReader overread that +// produced out-of-range match offsets/lengths — was fixed three days later +// in #645, which also added the fuzz corpus that has guarded this path since. +// See #1168. An asan-instrumented fuzz job (see .github/workflows/go.yml) +// covers the extended-copy path, which -race and plain fuzzing cannot. +func (s *sequenceDecs) useSafeDecodeSync() bool { + if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSizeAlloc { + return true + } + if s.maxSyncLen > 0 && cap(s.out)-len(s.out)-compressedBlockOverAlloc < int(s.maxSyncLen) { + return true + } + if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc { + return true + } + return false +} + +// decode sequences from the stream with the provided history but without a dictionary. +func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) { + if len(s.dict) > 0 { + return false, nil + } + if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSize { + return false, nil + } + + useSafe := s.useSafeDecodeSync() + + br := s.br + + maxBlockSize := min(s.windowSize, maxCompressedBlockSize) + + ctx := decodeSyncAsmContext{ + llTable: s.litLengths.fse.dt[:maxTablesize], + mlTable: s.matchLengths.fse.dt[:maxTablesize], + ofTable: s.offsets.fse.dt[:maxTablesize], + llState: uint64(s.litLengths.state.state), + mlState: uint64(s.matchLengths.state.state), + ofState: uint64(s.offsets.state.state), + iteration: s.nSeqs - 1, + litRemain: len(s.literals), + out: s.out, + outPosition: len(s.out), + literals: s.literals, + windowSize: s.windowSize, + history: hist, + } + + s.seqSize = 0 + startSize := len(s.out) + + errCode := decodeSyncAsm(s, br, &ctx, useSafe) + switch errCode { + case noError: + break + + case errorMatchLenOfsMismatch: + return true, fmt.Errorf("zero matchoff and matchlen (%d) > 0", ctx.ml) + + case errorMatchLenTooBig: + return true, fmt.Errorf("match len (%d) bigger than max allowed length", ctx.ml) + + case errorMatchOffTooBig: + return true, fmt.Errorf("match offset (%d) bigger than current history (%d)", + ctx.mo, ctx.outPosition+len(hist)-startSize) + + case errorNotEnoughLiterals: + return true, fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", + ctx.ll, ctx.litRemain+ctx.ll) + + case errorOverread: + return true, io.ErrUnexpectedEOF + + case errorNotEnoughSpace: + size := ctx.outPosition + ctx.ll + ctx.ml + if debugDecoder { + println("msl:", s.maxSyncLen, "cap", cap(s.out), "bef:", startSize, "sz:", size-startSize, "mbs:", maxBlockSize, "outsz:", cap(s.out)-startSize) + } + return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) + + default: + return true, fmt.Errorf("sequenceDecs_decode returned erroneous code %d", errCode) + } + + s.seqSize += ctx.litRemain + if s.seqSize > maxBlockSize { + return true, fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) + } + err := br.close() + if err != nil { + printf("Closing sequences: %v, %+v\n", err, *br) + return true, err + } + + s.literals = s.literals[ctx.litPosition:] + t := ctx.outPosition + s.out = s.out[:t] + + // Add final literals + s.out = append(s.out, s.literals...) + if debugDecoder { + t += len(s.literals) + if t != len(s.out) { + panic(fmt.Errorf("length mismatch, want %d, got %d", len(s.out), t)) + } + } + + return true, nil +} + +// decode sequences from the stream without the provided history. +func (s *sequenceDecs) decode(seqs []seqVals) error { + br := s.br + + maxBlockSize := min(s.windowSize, maxCompressedBlockSize) + + ctx := decodeAsmContext{ + llTable: s.litLengths.fse.dt[:maxTablesize], + mlTable: s.matchLengths.fse.dt[:maxTablesize], + ofTable: s.offsets.fse.dt[:maxTablesize], + llState: uint64(s.litLengths.state.state), + mlState: uint64(s.matchLengths.state.state), + ofState: uint64(s.offsets.state.state), + seqs: seqs, + iteration: len(seqs) - 1, + litRemain: len(s.literals), + } + + if debugDecoder { + println("decode: decoding", len(seqs), "sequences", br.remain(), "bits remain on stream") + } + + s.seqSize = 0 + lte56bits := s.maxBits+s.offsets.fse.actualTableLog+s.matchLengths.fse.actualTableLog+s.litLengths.fse.actualTableLog <= 56 + errCode := decodeAsm(s, br, &ctx, lte56bits) + if errCode != 0 { + i := len(seqs) - ctx.iteration - 1 + switch errCode { + case errorMatchLenOfsMismatch: + ml := ctx.seqs[i].ml + return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml) + + case errorMatchLenTooBig: + ml := ctx.seqs[i].ml + return fmt.Errorf("match len (%d) bigger than max allowed length", ml) + + case errorNotEnoughLiterals: + ll := ctx.seqs[i].ll + return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, ctx.litRemain+ll) + case errorOverread: + return io.ErrUnexpectedEOF + } + + return fmt.Errorf("sequenceDecs_decode_amd64 returned erroneous code %d", errCode) + } + + if ctx.litRemain < 0 { + return fmt.Errorf("literal count is too big: total available %d, total requested %d", + len(s.literals), len(s.literals)-ctx.litRemain) + } + + s.seqSize += ctx.litRemain + if s.seqSize > maxBlockSize { + return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) + } + if debugDecoder { + println("decode: ", br.remain(), "bits remain on stream. code:", errCode) + } + err := br.close() + if err != nil { + printf("Closing sequences: %v, %+v\n", err, *br) + } + return err +} + +// executeSimple handles cases when dictionary is not used. +func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error { + // Ensure we have enough output size... + if len(s.out)+s.seqSize+compressedBlockOverAlloc > cap(s.out) { + addBytes := s.seqSize + len(s.out) + compressedBlockOverAlloc + s.out = append(s.out, make([]byte, addBytes)...) + s.out = s.out[:len(s.out)-addBytes] + } + + if debugDecoder { + printf("Execute %d seqs with literals: %d into %d bytes\n", len(seqs), len(s.literals), s.seqSize) + } + + var t = len(s.out) + out := s.out[:t+s.seqSize] + + ctx := executeAsmContext{ + seqs: seqs, + seqIndex: 0, + out: out, + history: hist, + outPosition: t, + litPosition: 0, + literals: s.literals, + windowSize: s.windowSize, + } + // useSafe avoids overwriting the output buffer when the literals slice has + // not been allocated with the required over-allocation slack. + useSafe := cap(s.literals) < len(s.literals)+compressedBlockOverAlloc + + ok := executeSimpleAsm(&ctx, useSafe) + if !ok { + return fmt.Errorf("match offset (%d) bigger than current history (%d)", + seqs[ctx.seqIndex].mo, ctx.outPosition+len(hist)) + } + s.literals = s.literals[ctx.litPosition:] + t = ctx.outPosition + + // Add final literals + copy(out[t:], s.literals) + if debugDecoder { + t += len(s.literals) + if t != len(out) { + panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize)) + } + } + s.out = out + + return nil +} diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go b/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go new file mode 100644 index 0000000..8a3db6b --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/seqdec_generic.go @@ -0,0 +1,236 @@ +//go:build (!amd64 && !arm64) || appengine || !gc || noasm + +package zstd + +import ( + "fmt" + "io" +) + +// decode sequences from the stream with the provided history but without dictionary. +func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) { + return false, nil +} + +// decode sequences from the stream without the provided history. +func (s *sequenceDecs) decode(seqs []seqVals) error { + br := s.br + + // Grab full sizes tables, to avoid bounds checks. + llTable, mlTable, ofTable := s.litLengths.fse.dt[:maxTablesize], s.matchLengths.fse.dt[:maxTablesize], s.offsets.fse.dt[:maxTablesize] + llState, mlState, ofState := s.litLengths.state.state, s.matchLengths.state.state, s.offsets.state.state + s.seqSize = 0 + litRemain := len(s.literals) + + maxBlockSize := maxCompressedBlockSize + if s.windowSize < maxBlockSize { + maxBlockSize = s.windowSize + } + for i := range seqs { + var ll, mo, ml int + if br.cursor > 4+((maxOffsetBits+16+16)>>3) { + // inlined function: + // ll, mo, ml = s.nextFast(br, llState, mlState, ofState) + + // Final will not read from stream. + var llB, mlB, moB uint8 + ll, llB = llState.final() + ml, mlB = mlState.final() + mo, moB = ofState.final() + + // extra bits are stored in reverse order. + br.fillFast() + mo += br.getBits(moB) + if s.maxBits > 32 { + br.fillFast() + } + ml += br.getBits(mlB) + ll += br.getBits(llB) + + if moB > 1 { + s.prevOffset[2] = s.prevOffset[1] + s.prevOffset[1] = s.prevOffset[0] + s.prevOffset[0] = mo + } else { + // mo = s.adjustOffset(mo, ll, moB) + // Inlined for rather big speedup + if ll == 0 { + // There is an exception though, when current sequence's literals_length = 0. + // In this case, repeated offsets are shifted by one, so an offset_value of 1 means Repeated_Offset2, + // an offset_value of 2 means Repeated_Offset3, and an offset_value of 3 means Repeated_Offset1 - 1_byte. + mo++ + } + + if mo == 0 { + mo = s.prevOffset[0] + } else { + var temp int + if mo == 3 { + temp = s.prevOffset[0] - 1 + } else { + temp = s.prevOffset[mo] + } + + if temp == 0 { + // 0 is not valid; input is corrupted; force offset to 1 + println("WARNING: temp was 0") + temp = 1 + } + + if mo != 1 { + s.prevOffset[2] = s.prevOffset[1] + } + s.prevOffset[1] = s.prevOffset[0] + s.prevOffset[0] = temp + mo = temp + } + } + br.fillFast() + } else { + if br.overread() { + if debugDecoder { + printf("reading sequence %d, exceeded available data\n", i) + } + return io.ErrUnexpectedEOF + } + ll, mo, ml = s.next(br, llState, mlState, ofState) + br.fill() + } + + if debugSequences { + println("Seq", i, "Litlen:", ll, "mo:", mo, "(abs) ml:", ml) + } + // Evaluate. + // We might be doing this async, so do it early. + if mo == 0 && ml > 0 { + return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml) + } + if ml > maxMatchLen { + return fmt.Errorf("match len (%d) bigger than max allowed length", ml) + } + s.seqSize += ll + ml + if s.seqSize > maxBlockSize { + return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) + } + litRemain -= ll + if litRemain < 0 { + return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", ll, litRemain+ll) + } + seqs[i] = seqVals{ + ll: ll, + ml: ml, + mo: mo, + } + if i == len(seqs)-1 { + // This is the last sequence, so we shouldn't update state. + break + } + + // Manually inlined, ~ 5-20% faster + // Update all 3 states at once. Approx 20% faster. + nBits := llState.nbBits() + mlState.nbBits() + ofState.nbBits() + if nBits == 0 { + llState = llTable[llState.newState()&maxTableMask] + mlState = mlTable[mlState.newState()&maxTableMask] + ofState = ofTable[ofState.newState()&maxTableMask] + } else { + bits := br.get32BitsFast(nBits) + lowBits := uint16(bits >> ((ofState.nbBits() + mlState.nbBits()) & 31)) + llState = llTable[(llState.newState()+lowBits)&maxTableMask] + + lowBits = uint16(bits >> (ofState.nbBits() & 31)) + lowBits &= bitMask[mlState.nbBits()&15] + mlState = mlTable[(mlState.newState()+lowBits)&maxTableMask] + + lowBits = uint16(bits) & bitMask[ofState.nbBits()&15] + ofState = ofTable[(ofState.newState()+lowBits)&maxTableMask] + } + } + s.seqSize += litRemain + if s.seqSize > maxBlockSize { + return fmt.Errorf("output bigger than max block size (%d)", maxBlockSize) + } + err := br.close() + if err != nil { + printf("Closing sequences: %v, %+v\n", err, *br) + } + return err +} + +// executeSimple handles cases when a dictionary is not used. +func (s *sequenceDecs) executeSimple(seqs []seqVals, hist []byte) error { + // Ensure we have enough output size... + if len(s.out)+s.seqSize > cap(s.out) { + addBytes := s.seqSize + len(s.out) + s.out = append(s.out, make([]byte, addBytes)...) + s.out = s.out[:len(s.out)-addBytes] + } + + if debugDecoder { + printf("Execute %d seqs with literals: %d into %d bytes\n", len(seqs), len(s.literals), s.seqSize) + } + + var t = len(s.out) + out := s.out[:t+s.seqSize] + + for _, seq := range seqs { + // Add literals + copy(out[t:], s.literals[:seq.ll]) + t += seq.ll + s.literals = s.literals[seq.ll:] + + // Malformed input + if seq.mo > t+len(hist) || seq.mo > s.windowSize { + return fmt.Errorf("match offset (%d) bigger than current history (%d)", seq.mo, t+len(hist)) + } + + // Copy from history. + if v := seq.mo - t; v > 0 { + // v is the start position in history from end. + start := len(hist) - v + if seq.ml > v { + // Some goes into the current block. + // Copy remainder of history + copy(out[t:], hist[start:]) + t += v + seq.ml -= v + } else { + copy(out[t:], hist[start:start+seq.ml]) + t += seq.ml + continue + } + } + + // We must be in the current buffer now + if seq.ml > 0 { + start := t - seq.mo + if seq.ml <= t-start { + // No overlap + copy(out[t:], out[start:start+seq.ml]) + t += seq.ml + } else { + // Overlapping copy + // Extend destination slice and copy one byte at the time. + src := out[start : start+seq.ml] + dst := out[t:] + dst = dst[:len(src)] + t += len(src) + // Destination is the space we just added. + for i := range src { + dst[i] = src[i] + } + } + } + } + // Add final literals + copy(out[t:], s.literals) + if debugDecoder { + t += len(s.literals) + if t != len(out) { + panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(out), t, s.seqSize)) + } + } + s.out = out + + return nil +} diff --git a/vendor/github.com/klauspost/compress/zstd/seqenc.go b/vendor/github.com/klauspost/compress/zstd/seqenc.go new file mode 100644 index 0000000..65045ea --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/seqenc.go @@ -0,0 +1,112 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import "math/bits" + +type seqCoders struct { + llEnc, ofEnc, mlEnc *fseEncoder + llPrev, ofPrev, mlPrev *fseEncoder +} + +// swap coders with another (block). +func (s *seqCoders) swap(other *seqCoders) { + *s, *other = *other, *s +} + +// setPrev will update the previous encoders to the actually used ones +// and make sure a fresh one is in the main slot. +func (s *seqCoders) setPrev(ll, ml, of *fseEncoder) { + compareSwap := func(used *fseEncoder, current, prev **fseEncoder) { + // We used the new one, more current to history and reuse the previous history + if *current == used { + *prev, *current = *current, *prev + c := *current + p := *prev + c.reUsed = false + p.reUsed = true + return + } + if used == *prev { + return + } + // Ensure we cannot reuse by accident + prevEnc := *prev + prevEnc.symbolLen = 0 + } + compareSwap(ll, &s.llEnc, &s.llPrev) + compareSwap(ml, &s.mlEnc, &s.mlPrev) + compareSwap(of, &s.ofEnc, &s.ofPrev) +} + +func highBit(val uint32) (n uint32) { + return uint32(bits.Len32(val) - 1) +} + +var llCodeTable = [64]byte{0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 16, 17, 17, 18, 18, 19, 19, + 20, 20, 20, 20, 21, 21, 21, 21, + 22, 22, 22, 22, 22, 22, 22, 22, + 23, 23, 23, 23, 23, 23, 23, 23, + 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24} + +// Up to 6 bits +const maxLLCode = 35 + +// llBitsTable translates from ll code to number of bits. +var llBitsTable = [maxLLCode + 1]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 3, 3, + 4, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16} + +// llCode returns the code that represents the literal length requested. +func llCode(litLength uint32) uint8 { + const llDeltaCode = 19 + if litLength <= 63 { + return llCodeTable[litLength&63] + } + return uint8(highBit(litLength)) + llDeltaCode +} + +var mlCodeTable = [128]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37, + 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42} + +// Up to 6 bits +const maxMLCode = 52 + +// mlBitsTable translates from ml code to number of bits. +var mlBitsTable = [maxMLCode + 1]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16} + +// note : mlBase = matchLength - MINMATCH; +// because it's the format it's stored in seqStore->sequences +func mlCode(mlBase uint32) uint8 { + const mlDeltaCode = 36 + if mlBase <= 127 { + return mlCodeTable[mlBase&127] + } + return uint8(highBit(mlBase)) + mlDeltaCode +} + +func ofCode(offset uint32) uint8 { + // A valid offset will always be > 0. + return uint8(bits.Len32(offset) - 1) +} diff --git a/vendor/github.com/klauspost/compress/zstd/simple_go124.go b/vendor/github.com/klauspost/compress/zstd/simple_go124.go new file mode 100644 index 0000000..2efc049 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/simple_go124.go @@ -0,0 +1,56 @@ +// Copyright 2025+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. + +//go:build go1.24 + +package zstd + +import ( + "errors" + "runtime" + "sync" + "weak" +) + +var weakMu sync.Mutex +var simpleEnc weak.Pointer[Encoder] +var simpleDec weak.Pointer[Decoder] + +// EncodeTo appends the encoded data from src to dst. +func EncodeTo(dst []byte, src []byte) []byte { + weakMu.Lock() + enc := simpleEnc.Value() + if enc == nil { + var err error + enc, err = NewWriter(nil, WithEncoderConcurrency(runtime.NumCPU()), WithWindowSize(1<<20), WithLowerEncoderMem(true), WithZeroFrames(true)) + if err != nil { + panic("failed to create simple encoder: " + err.Error()) + } + simpleEnc = weak.Make(enc) + } + weakMu.Unlock() + + return enc.EncodeAll(src, dst) +} + +// DecodeTo appends the decoded data from src to dst. +// The maximum decoded size is 1GiB, +// not including what may already be in dst. +func DecodeTo(dst []byte, src []byte) ([]byte, error) { + weakMu.Lock() + dec := simpleDec.Value() + if dec == nil { + var err error + dec, err = NewReader(nil, WithDecoderConcurrency(runtime.NumCPU()), WithDecoderLowmem(true), WithDecoderMaxMemory(1<<30)) + if err != nil { + weakMu.Unlock() + return nil, errors.New("failed to create simple decoder: " + err.Error()) + } + runtime.SetFinalizer(dec, func(d *Decoder) { + d.Close() + }) + simpleDec = weak.Make(dec) + } + weakMu.Unlock() + return dec.DecodeAll(src, dst) +} diff --git a/vendor/github.com/klauspost/compress/zstd/snappy.go b/vendor/github.com/klauspost/compress/zstd/snappy.go new file mode 100644 index 0000000..36c56f3 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/snappy.go @@ -0,0 +1,435 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. +// Based on work by Yann Collet, released under BSD License. + +package zstd + +import ( + "encoding/binary" + "errors" + "hash/crc32" + "io" + + "github.com/klauspost/compress/huff0" + snappy "github.com/klauspost/compress/internal/snapref" +) + +const ( + snappyTagLiteral = 0x00 + snappyTagCopy1 = 0x01 + snappyTagCopy2 = 0x02 + snappyTagCopy4 = 0x03 +) + +const ( + snappyChecksumSize = 4 + snappyMagicBody = "sNaPpY" + + // snappyMaxBlockSize is the maximum size of the input to encodeBlock. It is not + // part of the wire format per se, but some parts of the encoder assume + // that an offset fits into a uint16. + // + // Also, for the framing format (Writer type instead of Encode function), + // https://github.com/google/snappy/blob/master/framing_format.txt says + // that "the uncompressed data in a chunk must be no longer than 65536 + // bytes". + snappyMaxBlockSize = 65536 + + // snappyMaxEncodedLenOfMaxBlockSize equals MaxEncodedLen(snappyMaxBlockSize), but is + // hard coded to be a const instead of a variable, so that obufLen can also + // be a const. Their equivalence is confirmed by + // TestMaxEncodedLenOfMaxBlockSize. + snappyMaxEncodedLenOfMaxBlockSize = 76490 +) + +const ( + chunkTypeCompressedData = 0x00 + chunkTypeUncompressedData = 0x01 + chunkTypePadding = 0xfe + chunkTypeStreamIdentifier = 0xff +) + +var ( + // ErrSnappyCorrupt reports that the input is invalid. + ErrSnappyCorrupt = errors.New("snappy: corrupt input") + // ErrSnappyTooLarge reports that the uncompressed length is too large. + ErrSnappyTooLarge = errors.New("snappy: decoded block is too large") + // ErrSnappyUnsupported reports that the input isn't supported. + ErrSnappyUnsupported = errors.New("snappy: unsupported input") + + errUnsupportedLiteralLength = errors.New("snappy: unsupported literal length") +) + +// SnappyConverter can read SnappyConverter-compressed streams and convert them to zstd. +// Conversion is done by converting the stream directly from Snappy without intermediate +// full decoding. +// Therefore the compression ratio is much less than what can be done by a full decompression +// and compression, and a faulty Snappy stream may lead to a faulty Zstandard stream without +// any errors being generated. +// No CRC value is being generated and not all CRC values of the Snappy stream are checked. +// However, it provides really fast recompression of Snappy streams. +// The converter can be reused to avoid allocations, even after errors. +type SnappyConverter struct { + r io.Reader + err error + buf []byte + block *blockEnc +} + +// Convert the Snappy stream supplied in 'in' and write the zStandard stream to 'w'. +// If any error is detected on the Snappy stream it is returned. +// The number of bytes written is returned. +func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) { + initPredefined() + r.err = nil + r.r = in + if r.block == nil { + r.block = &blockEnc{} + r.block.init() + } + r.block.initNewEncode() + if len(r.buf) != snappyMaxEncodedLenOfMaxBlockSize+snappyChecksumSize { + r.buf = make([]byte, snappyMaxEncodedLenOfMaxBlockSize+snappyChecksumSize) + } + r.block.litEnc.Reuse = huff0.ReusePolicyNone + var written int64 + var readHeader bool + { + header := frameHeader{WindowSize: snappyMaxBlockSize}.appendTo(r.buf[:0]) + + var n int + n, r.err = w.Write(header) + if r.err != nil { + return written, r.err + } + written += int64(n) + } + + for { + if !r.readFull(r.buf[:4], true) { + // Add empty last block + r.block.reset(nil) + r.block.last = true + err := r.block.encodeLits(r.block.literals, false) + if err != nil { + return written, err + } + n, err := w.Write(r.block.output) + if err != nil { + return written, err + } + written += int64(n) + + return written, r.err + } + chunkType := r.buf[0] + if !readHeader { + if chunkType != chunkTypeStreamIdentifier { + println("chunkType != chunkTypeStreamIdentifier", chunkType) + r.err = ErrSnappyCorrupt + return written, r.err + } + readHeader = true + } + chunkLen := int(r.buf[1]) | int(r.buf[2])<<8 | int(r.buf[3])<<16 + if chunkLen > len(r.buf) { + println("chunkLen > len(r.buf)", chunkType) + r.err = ErrSnappyUnsupported + return written, r.err + } + + // The chunk types are specified at + // https://github.com/google/snappy/blob/master/framing_format.txt + switch chunkType { + case chunkTypeCompressedData: + // Section 4.2. Compressed data (chunk type 0x00). + if chunkLen < snappyChecksumSize { + println("chunkLen < snappyChecksumSize", chunkLen, snappyChecksumSize) + r.err = ErrSnappyCorrupt + return written, r.err + } + buf := r.buf[:chunkLen] + if !r.readFull(buf, false) { + return written, r.err + } + //checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 + buf = buf[snappyChecksumSize:] + + n, hdr, err := snappyDecodedLen(buf) + if err != nil { + r.err = err + return written, r.err + } + buf = buf[hdr:] + if n > snappyMaxBlockSize { + println("n > snappyMaxBlockSize", n, snappyMaxBlockSize) + r.err = ErrSnappyCorrupt + return written, r.err + } + r.block.reset(nil) + r.block.pushOffsets() + if err := decodeSnappy(r.block, buf); err != nil { + r.err = err + return written, r.err + } + if r.block.size+r.block.extraLits != n { + printf("invalid size, want %d, got %d\n", n, r.block.size+r.block.extraLits) + r.err = ErrSnappyCorrupt + return written, r.err + } + err = r.block.encode(nil, false, false) + switch err { + case errIncompressible: + r.block.popOffsets() + r.block.reset(nil) + r.block.literals, err = snappy.Decode(r.block.literals[:n], r.buf[snappyChecksumSize:chunkLen]) + if err != nil { + return written, err + } + err = r.block.encodeLits(r.block.literals, false) + if err != nil { + return written, err + } + case nil: + default: + return written, err + } + + n, r.err = w.Write(r.block.output) + if r.err != nil { + return written, r.err + } + written += int64(n) + continue + case chunkTypeUncompressedData: + if debugEncoder { + println("Uncompressed, chunklen", chunkLen) + } + // Section 4.3. Uncompressed data (chunk type 0x01). + if chunkLen < snappyChecksumSize { + println("chunkLen < snappyChecksumSize", chunkLen, snappyChecksumSize) + r.err = ErrSnappyCorrupt + return written, r.err + } + r.block.reset(nil) + buf := r.buf[:snappyChecksumSize] + if !r.readFull(buf, false) { + return written, r.err + } + checksum := uint32(buf[0]) | uint32(buf[1])<<8 | uint32(buf[2])<<16 | uint32(buf[3])<<24 + // Read directly into r.decoded instead of via r.buf. + n := chunkLen - snappyChecksumSize + if n > snappyMaxBlockSize { + println("n > snappyMaxBlockSize", n, snappyMaxBlockSize) + r.err = ErrSnappyCorrupt + return written, r.err + } + r.block.literals = r.block.literals[:n] + if !r.readFull(r.block.literals, false) { + return written, r.err + } + if snappyCRC(r.block.literals) != checksum { + println("literals crc mismatch") + r.err = ErrSnappyCorrupt + return written, r.err + } + err := r.block.encodeLits(r.block.literals, false) + if err != nil { + return written, err + } + n, r.err = w.Write(r.block.output) + if r.err != nil { + return written, r.err + } + written += int64(n) + continue + + case chunkTypeStreamIdentifier: + if debugEncoder { + println("stream id", chunkLen, len(snappyMagicBody)) + } + // Section 4.1. Stream identifier (chunk type 0xff). + if chunkLen != len(snappyMagicBody) { + println("chunkLen != len(snappyMagicBody)", chunkLen, len(snappyMagicBody)) + r.err = ErrSnappyCorrupt + return written, r.err + } + if !r.readFull(r.buf[:len(snappyMagicBody)], false) { + return written, r.err + } + for i := range len(snappyMagicBody) { + if r.buf[i] != snappyMagicBody[i] { + println("r.buf[i] != snappyMagicBody[i]", r.buf[i], snappyMagicBody[i], i) + r.err = ErrSnappyCorrupt + return written, r.err + } + } + continue + } + + if chunkType <= 0x7f { + // Section 4.5. Reserved unskippable chunks (chunk types 0x02-0x7f). + println("chunkType <= 0x7f") + r.err = ErrSnappyUnsupported + return written, r.err + } + // Section 4.4 Padding (chunk type 0xfe). + // Section 4.6. Reserved skippable chunks (chunk types 0x80-0xfd). + if !r.readFull(r.buf[:chunkLen], false) { + return written, r.err + } + } +} + +// decodeSnappy writes the decoding of src to dst. It assumes that the varint-encoded +// length of the decompressed bytes has already been read. +func decodeSnappy(blk *blockEnc, src []byte) error { + //decodeRef(make([]byte, snappyMaxBlockSize), src) + var s, length int + lits := blk.extraLits + var offset uint32 + for s < len(src) { + switch src[s] & 0x03 { + case snappyTagLiteral: + x := uint32(src[s] >> 2) + switch { + case x < 60: + s++ + case x == 60: + s += 2 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + println("uint(s) > uint(len(src)", s, src) + return ErrSnappyCorrupt + } + x = uint32(src[s-1]) + case x == 61: + s += 3 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + println("uint(s) > uint(len(src)", s, src) + return ErrSnappyCorrupt + } + x = uint32(src[s-2]) | uint32(src[s-1])<<8 + case x == 62: + s += 4 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + println("uint(s) > uint(len(src)", s, src) + return ErrSnappyCorrupt + } + x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16 + case x == 63: + s += 5 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + println("uint(s) > uint(len(src)", s, src) + return ErrSnappyCorrupt + } + x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24 + } + if x > snappyMaxBlockSize { + println("x > snappyMaxBlockSize", x, snappyMaxBlockSize) + return ErrSnappyCorrupt + } + length = int(x) + 1 + if length <= 0 { + println("length <= 0 ", length) + + return errUnsupportedLiteralLength + } + if length > len(src)-s { + println("length > len(src)-s", length, len(src)-s) + return ErrSnappyCorrupt + } + + blk.literals = append(blk.literals, src[s:s+length]...) + //println(length, "litLen") + lits += length + s += length + continue + + case snappyTagCopy1: + s += 2 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + println("uint(s) > uint(len(src)", s, len(src)) + return ErrSnappyCorrupt + } + length = 4 + int(src[s-2])>>2&0x7 + offset = uint32(src[s-2])&0xe0<<3 | uint32(src[s-1]) + + case snappyTagCopy2: + s += 3 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + println("uint(s) > uint(len(src)", s, len(src)) + return ErrSnappyCorrupt + } + length = 1 + int(src[s-3])>>2 + offset = uint32(src[s-2]) | uint32(src[s-1])<<8 + + case snappyTagCopy4: + s += 5 + if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. + println("uint(s) > uint(len(src)", s, len(src)) + return ErrSnappyCorrupt + } + length = 1 + int(src[s-5])>>2 + offset = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24 + } + + if offset <= 0 || blk.size+lits < int(offset) /*|| length > len(blk)-d */ { + println("offset <= 0 || blk.size+lits < int(offset)", offset, blk.size+lits, int(offset), blk.size, lits) + + return ErrSnappyCorrupt + } + + // Check if offset is one of the recent offsets. + // Adjusts the output offset accordingly. + // Gives a tiny bit of compression, typically around 1%. + if false { + offset = blk.matchOffset(offset, uint32(lits)) + } else { + offset += 3 + } + + blk.sequences = append(blk.sequences, seq{ + litLen: uint32(lits), + offset: offset, + matchLen: uint32(length) - zstdMinMatch, + }) + blk.size += length + lits + lits = 0 + } + blk.extraLits = lits + return nil +} + +func (r *SnappyConverter) readFull(p []byte, allowEOF bool) (ok bool) { + if _, r.err = io.ReadFull(r.r, p); r.err != nil { + if r.err == io.ErrUnexpectedEOF || (r.err == io.EOF && !allowEOF) { + r.err = ErrSnappyCorrupt + } + return false + } + return true +} + +var crcTable = crc32.MakeTable(crc32.Castagnoli) + +// crc implements the checksum specified in section 3 of +// https://github.com/google/snappy/blob/master/framing_format.txt +func snappyCRC(b []byte) uint32 { + c := crc32.Update(0, crcTable, b) + return c>>15 | c<<17 + 0xa282ead8 +} + +// snappyDecodedLen returns the length of the decoded block and the number of bytes +// that the length header occupied. +func snappyDecodedLen(src []byte) (blockLen, headerLen int, err error) { + v, n := binary.Uvarint(src) + if n <= 0 || v > 0xffffffff { + return 0, 0, ErrSnappyCorrupt + } + + const wordSize = 32 << (^uint(0) >> 32 & 1) + if wordSize == 32 && v > 0x7fffffff { + return 0, 0, ErrSnappyTooLarge + } + return int(v), n, nil +} diff --git a/vendor/github.com/klauspost/compress/zstd/zip.go b/vendor/github.com/klauspost/compress/zstd/zip.go new file mode 100644 index 0000000..3198d71 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/zip.go @@ -0,0 +1,141 @@ +// Copyright 2019+ Klaus Post. All rights reserved. +// License information can be found in the LICENSE file. + +package zstd + +import ( + "errors" + "io" + "sync" +) + +// ZipMethodWinZip is the method for Zstandard compressed data inside Zip files for WinZip. +// See https://www.winzip.com/win/en/comp_info.html +const ZipMethodWinZip = 93 + +// ZipMethodPKWare is the original method number used by PKWARE to indicate Zstandard compression. +// Deprecated: This has been deprecated by PKWARE, use ZipMethodWinZip instead for compression. +// See https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT +const ZipMethodPKWare = 20 + +// zipReaderPool is the default reader pool. +var zipReaderPool = sync.Pool{New: func() any { + z, err := NewReader(nil, WithDecoderLowmem(true), WithDecoderMaxWindow(128<<20), WithDecoderConcurrency(1)) + if err != nil { + panic(err) + } + return z +}} + +// newZipReader creates a pooled zip decompressor. +func newZipReader(opts ...DOption) func(r io.Reader) io.ReadCloser { + pool := &zipReaderPool + if len(opts) > 0 { + opts = append([]DOption{WithDecoderLowmem(true), WithDecoderMaxWindow(128 << 20)}, opts...) + // Force concurrency 1 + opts = append(opts, WithDecoderConcurrency(1)) + // Create our own pool + pool = &sync.Pool{} + } + return func(r io.Reader) io.ReadCloser { + dec, ok := pool.Get().(*Decoder) + if ok { + dec.Reset(r) + } else { + d, err := NewReader(r, opts...) + if err != nil { + panic(err) + } + dec = d + } + return &pooledZipReader{dec: dec, pool: pool} + } +} + +type pooledZipReader struct { + mu sync.Mutex // guards Close and Read + pool *sync.Pool + dec *Decoder +} + +func (r *pooledZipReader) Read(p []byte) (n int, err error) { + r.mu.Lock() + defer r.mu.Unlock() + if r.dec == nil { + return 0, errors.New("read after close or EOF") + } + dec, err := r.dec.Read(p) + if err == io.EOF { + r.dec.Reset(nil) + r.pool.Put(r.dec) + r.dec = nil + } + return dec, err +} + +func (r *pooledZipReader) Close() error { + r.mu.Lock() + defer r.mu.Unlock() + var err error + if r.dec != nil { + err = r.dec.Reset(nil) + r.pool.Put(r.dec) + r.dec = nil + } + return err +} + +type pooledZipWriter struct { + mu sync.Mutex // guards Close and Read + enc *Encoder + pool *sync.Pool +} + +func (w *pooledZipWriter) Write(p []byte) (n int, err error) { + w.mu.Lock() + defer w.mu.Unlock() + if w.enc == nil { + return 0, errors.New("Write after Close") + } + return w.enc.Write(p) +} + +func (w *pooledZipWriter) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + var err error + if w.enc != nil { + err = w.enc.Close() + w.pool.Put(w.enc) + w.enc = nil + } + return err +} + +// ZipCompressor returns a compressor that can be registered with zip libraries. +// The provided encoder options will be used on all encodes. +func ZipCompressor(opts ...EOption) func(w io.Writer) (io.WriteCloser, error) { + var pool sync.Pool + return func(w io.Writer) (io.WriteCloser, error) { + enc, ok := pool.Get().(*Encoder) + if ok { + enc.Reset(w) + } else { + var err error + enc, err = NewWriter(w, opts...) + if err != nil { + return nil, err + } + } + return &pooledZipWriter{enc: enc, pool: &pool}, nil + } +} + +// ZipDecompressor returns a decompressor that can be registered with zip libraries. +// See ZipCompressor for example. +// Options can be specified. WithDecoderConcurrency(1) is forced, +// and by default a 128MB maximum decompression window is specified. +// The window size can be overridden if required. +func ZipDecompressor(opts ...DOption) func(r io.Reader) io.ReadCloser { + return newZipReader(opts...) +} diff --git a/vendor/github.com/klauspost/compress/zstd/zstd.go b/vendor/github.com/klauspost/compress/zstd/zstd.go new file mode 100644 index 0000000..1a86971 --- /dev/null +++ b/vendor/github.com/klauspost/compress/zstd/zstd.go @@ -0,0 +1,126 @@ +// Package zstd provides decompression of zstandard files. +// +// For advanced usage and examples, go to the README: https://github.com/klauspost/compress/tree/master/zstd#zstd +package zstd + +import ( + "bytes" + "errors" + "log" + "math" + + "github.com/klauspost/compress/internal/le" +) + +// enable debug printing +const debug = false + +// enable encoding debug printing +const debugEncoder = debug + +// enable decoding debug printing +const debugDecoder = debug + +// Enable extra assertions. +const debugAsserts = debug || false + +// print sequence details +const debugSequences = false + +// print detailed matching information +const debugMatches = false + +// force encoder to use predefined tables. +const forcePreDef = false + +// zstdMinMatch is the minimum zstd match length. +const zstdMinMatch = 3 + +// fcsUnknown is used for unknown frame content size. +const fcsUnknown = math.MaxUint64 + +var ( + // ErrReservedBlockType is returned when a reserved block type is found. + // Typically this indicates wrong or corrupted input. + ErrReservedBlockType = errors.New("invalid input: reserved block type encountered") + + // ErrCompressedSizeTooBig is returned when a block is bigger than allowed. + // Typically this indicates wrong or corrupted input. + ErrCompressedSizeTooBig = errors.New("invalid input: compressed size too big") + + // ErrBlockTooSmall is returned when a block is too small to be decoded. + // Typically returned on invalid input. + ErrBlockTooSmall = errors.New("block too small") + + // ErrUnexpectedBlockSize is returned when a block has unexpected size. + // Typically returned on invalid input. + ErrUnexpectedBlockSize = errors.New("unexpected block size") + + // ErrMagicMismatch is returned when a "magic" number isn't what is expected. + // Typically this indicates wrong or corrupted input. + ErrMagicMismatch = errors.New("invalid input: magic number mismatch") + + // ErrWindowSizeExceeded is returned when a reference exceeds the valid window size. + // Typically this indicates wrong or corrupted input. + ErrWindowSizeExceeded = errors.New("window size exceeded") + + // ErrWindowSizeTooSmall is returned when no window size is specified. + // Typically this indicates wrong or corrupted input. + ErrWindowSizeTooSmall = errors.New("invalid input: window size was too small") + + // ErrDecoderSizeExceeded is returned if decompressed size exceeds the configured limit. + ErrDecoderSizeExceeded = errors.New("decompressed size exceeds configured limit") + + // ErrUnknownDictionary is returned if the dictionary ID is unknown. + ErrUnknownDictionary = errors.New("unknown dictionary") + + // ErrFrameSizeExceeded is returned if the stated frame size is exceeded. + // This is only returned if SingleSegment is specified on the frame. + ErrFrameSizeExceeded = errors.New("frame size exceeded") + + // ErrFrameSizeMismatch is returned if the stated frame size does not match the expected size. + // This is only returned if SingleSegment is specified on the frame. + ErrFrameSizeMismatch = errors.New("frame size does not match size on stream") + + // ErrCRCMismatch is returned if CRC mismatches. + ErrCRCMismatch = errors.New("CRC check failed") + + // ErrDecoderClosed will be returned if the Decoder was used after + // Close has been called. + ErrDecoderClosed = errors.New("decoder used after Close") + + // ErrEncoderClosed will be returned if the Encoder was used after + // Close has been called. + ErrEncoderClosed = errors.New("encoder used after Close") + + // ErrDecoderNilInput is returned when a nil Reader was provided + // and an operation other than Reset/DecodeAll/Close was attempted. + ErrDecoderNilInput = errors.New("nil input provided as reader") +) + +func println(a ...any) { + if debug || debugDecoder || debugEncoder { + log.Println(a...) + } +} + +func printf(format string, a ...any) { + if debug || debugDecoder || debugEncoder { + log.Printf(format, a...) + } +} + +func load3232(b []byte, i int32) uint32 { + return le.Load32(b, i) +} + +func load6432(b []byte, i int32) uint64 { + return le.Load64(b, i) +} + +type byter interface { + Bytes() []byte + Len() int +} + +var _ byter = &bytes.Buffer{} diff --git a/vendor/github.com/tim-st/go-zim/LICENSE b/vendor/github.com/tim-st/go-zim/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/LICENSE @@ -0,0 +1,201 @@ + 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. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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/github.com/tim-st/go-zim/README.md b/vendor/github.com/tim-st/go-zim/README.md new file mode 100644 index 0000000..6f6e85b --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/README.md @@ -0,0 +1,48 @@ +# go-zim + +Package `zim` implements reading support for the ZIM File Format. + +Documentation at . + +Download and install package `zim` and its tools with + +>`go get -u github.com/tim-st/go-zim/...` + +or download a prebuilt binary from the [release](https://github.com/tim-st/go-zim/releases)-section. + +You can download a ZIM file for testing [here](https://download.kiwix.org/zim/). + +## Commands + +The command above installs the tools of this package to `$GOPATH/bin/`. + +### zimserver + +Tool for browsing a ZIM file in your webbrowser via an HTTP interface. + +* Starting a ZIM server at TCP port 8080: `zimserver -filename="filename.zim" -port=8080` +* Browsing the ZIM file via Web Browser is now possible at `http://localhost:8080/` +* The last part of the URL can be used as a basic prefix search by passing the search term after the last `/` in the URL + +### zimindex + +Tool for creating a full text index of a given ZIM file. + +### zimsearch + +Tool that lists search results for a given ZIM file and text query. +If no index file created by `zimindex` is found, a builtin prefix search is used. Otherwise the index file is used to retrieve search results sorted by score, where the search result can be calculated by union or intersection operation. + +### zimtext + +Tool to extract clean texts from a Wikipedia ZIM file. +Each clean HTML paragraph is written on a single line in a text file. + +* Extracting first 1000 clean texts from a ZIM file: `zimtext -zim="filename.zim" -txt="lines.txt" -limit=1000` +* Extracting all clean texts from a ZIM file: `zimtext -zim="filename.zim" -txt="lines.txt"` +* Extracting first 1000 clean sentences (likely a sentence) from a ZIM file: `zimtext -zim="filename.zim" -txt="lines.txt" -limit=1000 -sentences` +* Extracting all clean sentences (likely a sentence) from a ZIM file: `zimtext -zim="filename.zim" -txt="lines.txt" -sentences` +* If you want to support your language or use-case better, it's recommended to define your own Regular Expression to extract only texts you accept. The RE-Syntax is defined [here](https://github.com/google/re2/wiki/Syntax) and can be tested [here](https://regex101.com/) (select Flavor=_Golang_). + +Example: +> `zimtext -zim="wikipedia_de_top_nopic_2019-08.zim" -txt="de.txt" -limit=10000 -regexFilter="^(?:\p{Lu}|\p{N})[ \pL\pN\,\;\:\-]{10,}[\.\)\]\?\"…«»›‹‘“’”]{1}$"` diff --git a/vendor/github.com/tim-st/go-zim/blob_reader.go b/vendor/github.com/tim-st/go-zim/blob_reader.go new file mode 100644 index 0000000..4fa1304 --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/blob_reader.go @@ -0,0 +1,76 @@ +package zim + +import ( + "errors" + "io" + "io/ioutil" +) + +func blobReader(clusterReader io.Reader, offsetSize int64, blobPosition uint32) ( + reader io.Reader, blobSize int64, err error) { + + var seeker, clusterReaderIsSeeker = clusterReader.(io.Seeker) + + var thisBlobIndex = int64(blobPosition) * offsetSize + + // seek to position where we get the relevant start and end positions of the blob + if clusterReaderIsSeeker { + var newOffset int64 + newOffset, err = seeker.Seek(thisBlobIndex, 1) + blobSize = newOffset - thisBlobIndex + } else { + _, err = io.CopyN(ioutil.Discard, clusterReader, thisBlobIndex) + } + if err != nil { + err = errors.New("zim: invalid blob position") + return + } + + // read the start and end positions + var thisBlobPointer int64 + var nextBlobPointer int64 + switch offsetSize { + case extendedOffsetSize: + thisBlobPointer = int64(readUint64R(clusterReader)) + nextBlobPointer = int64(readUint64R(clusterReader)) + default: + thisBlobPointer = int64(readUint32R(clusterReader)) + nextBlobPointer = int64(readUint32R(clusterReader)) + } + + if nextBlobPointer < thisBlobPointer { + err = errors.New("zim: invalid blob index") + return + } + + // seek to the position of blob data start + if clusterReaderIsSeeker { + seeker.Seek(blobSize+thisBlobPointer, 0) + } else { + var alreadyRead = thisBlobIndex + 2*offsetSize + _, err = io.CopyN(ioutil.Discard, clusterReader, thisBlobPointer-alreadyRead) + } + + blobSize = nextBlobPointer - thisBlobPointer + reader = io.LimitReader(clusterReader, blobSize) + return +} + +// BlobReaderAt returns a LimitedReader for the blob data at the given positions. +func (z *File) BlobReaderAt(clusterPosition, blobPosition uint32) ( + reader io.Reader, blobSize int64, err error) { + + var clusterInformation uint8 + reader, clusterInformation, err = z.clusterReader(clusterPosition) + + if err == nil { + reader, blobSize, err = blobReader(reader, int64(clusterOffsetSize(clusterInformation)), blobPosition) + } + return +} + +// BlobReader returns a LimitedReader for the blob data of the given Directory Entry. +func (z *File) BlobReader(e *DirectoryEntry) ( + reader io.Reader, blobSize int64, err error) { + return z.BlobReaderAt(e.ClusterNumber(), e.BlobNumber()) +} diff --git a/vendor/github.com/tim-st/go-zim/checksum.go b/vendor/github.com/tim-st/go-zim/checksum.go new file mode 100644 index 0000000..c185244 --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/checksum.go @@ -0,0 +1,47 @@ +package zim + +import ( + "crypto/md5" + "errors" + "io" +) + +// InternalChecksum is the MD5 checksum for the ZIM file. +// It's precalculated and saved in the header. +func (z *File) InternalChecksum() ([md5.Size]byte, error) { + seek(z.f, int64(z.header.checksumPos)) + var buf, readErr = readSlice(z.f, md5.Size) + var md5sum [md5.Size]byte + if readErr != nil { + return md5sum, errors.New("zim: reading internal checksum failed") + } + copy(md5sum[:], buf) + return md5sum, nil +} + +// CalculateChecksum calculates the MD5 checksum of the ZIM file. +// This could take some time dependent on the size of the file. +func (z *File) CalculateChecksum() ([md5.Size]byte, error) { + var digest = md5.New() + var md5Sum [md5.Size]byte + seek(z.f, 0) + if _, copyErr := io.CopyN(digest, z.f, int64(z.header.checksumPos)); copyErr != nil { + return md5Sum, copyErr + } + copy(md5Sum[:], digest.Sum(nil)[:md5.Size]) + return md5Sum, nil +} + +// ValidateChecksum compares the internal MD5 checksum +// of the ZIM file with the calculated one. +func (z *File) ValidateChecksum() error { + if internal, internalChecksumErr := z.InternalChecksum(); internalChecksumErr != nil { + return internalChecksumErr + } else if calculated, calculatedChecksumErr := z.CalculateChecksum(); calculatedChecksumErr != nil { + return calculatedChecksumErr + } else if internal != calculated { + return errors.New("zim: checksum mismatched") + } else { + return nil + } +} diff --git a/vendor/github.com/tim-st/go-zim/cluster.go b/vendor/github.com/tim-st/go-zim/cluster.go new file mode 100644 index 0000000..f9d1feb --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/cluster.go @@ -0,0 +1,148 @@ +package zim + +import ( + "compress/bzip2" + "encoding/binary" + "errors" + "io" + "io/ioutil" +) + +const ( + defaultOffsetSize = 4 + extendedOffsetSize = 8 + maxClusterLen = 1024 * 1024 * 32 // 32MB +) + +func clusterOffsetSize(clusterInformation uint8) uint8 { + /* + if (clusterInformation & 0b0001_0000) == 0b0001_0000 { + return 8 + } + return 4 + */ + return ((clusterInformation >> 2) & 4) + 4 +} + +func clusterCompression(clusterInformation uint8) uint8 { + return clusterInformation & 15 +} + +func (z *File) clusterReader(clusterPosition uint32) (reader io.Reader, clusterInformation uint8, err error) { + if clusterPosition >= z.ClusterCount() { + err = errors.New("zim: invalid cluster position") + return + } + var clusterPointer = z.clusterPointerAtPos(clusterPosition) + seek(z.f, int64(clusterPointer)) + clusterInformation = readUint8(z.f) + var compression = clusterCompression(clusterInformation) + switch compression { + case 0, 1: // uncompressed + reader = z.f + case 3: // bzip2 compressed + reader = bzip2.NewReader(z.f) + case 4: // xz compressed + if err = z.xzReader.Reset(z.f); err == nil { + z.xzReader.Multistream(false) + reader = z.xzReader + } + case 5: // zstd compressed + if err = z.zstdReader.Reset(z.f); err == nil { + reader = z.zstdReader + } + default: + // 2: zlib compressed (not used anymore) + err = errors.New("zim: unsupported cluster compression") + } + return +} + +func (z *File) lastClusterPosition() uint32 { + return z.header.clusterCount - 1 +} + +// Cluster stores the uncompressed cluster data (blob positions followed by a sequence of blobs). +// Each blob belongs to a Directory Entry. +type Cluster struct { + data []byte // always uncompressed and len(data) <= 32MB + position uint32 // cluster position + information uint8 // cluster information byte; stores information about compression and offset size +} + +// WasCompressed shows if the cluster data was compressed. +// This information can be used as an indicator about the +// cluster contents. +func (c *Cluster) WasCompressed() bool { + return clusterCompression(c.information) > 1 +} + +func (z *File) nextClusterPointer(c *Cluster) uint64 { + if c.position >= z.lastClusterPosition() { + return z.header.checksumPos - 1 + } + return z.clusterPointerAtPos(c.position + 1) +} + +// clusterLen returns the length of the cluster in bytes. +func (z *File) clusterLen(c *Cluster) int64 { + var nextClusterPointer = z.nextClusterPointer(c) + var clusterPointer = z.clusterPointerAtPos(c.position) + seek(z.f, int64(clusterPointer)+1) // file position was (very likely) changed; seek back. + // The +1 is because c.information byte was read afterwards too. + return int64(nextClusterPointer - clusterPointer - 1) +} + +// ClusterAt returns the Cluster of the ZIM file at the given cluster position. +// The complete cluster data is stored uncompressed in memory. +// If the size of the cluster data is more than 32MB an error is returned +// and the data is not read into memory. +// Note: Only use this function, when it's needed to read every single blob of a +// ZIM file into memory (for example when iterating over all contents this improves performance). +func (z *File) ClusterAt(clusterPosition uint32) (Cluster, error) { + var c = Cluster{position: clusterPosition} + var clusterLen = z.clusterLen(&c) + if clusterLen <= 0 || clusterLen > maxClusterLen { + return c, errors.New("zim: invalid cluster size") + } + var clusterReader, clusterInformation, clusterReaderErr = z.clusterReader(clusterPosition) + c.information = clusterInformation + if clusterReaderErr != nil { + return c, clusterReaderErr + } + + var clusterData, clusterDataErr = ioutil.ReadAll(io.LimitReader(clusterReader, int64(maxClusterLen))) + if clusterDataErr != nil { + return c, clusterDataErr + } + + c.data = clusterData + return c, nil +} + +// BlobAt returns the blob data at blob position of a given Cluster. +// This is only useful when iteration over all blobs in a Cluster is done. +// When only a single blob of a Cluster should be retrieved, it's better +// to use z.BlobReaderAt(clusterPosition, blobPosition) instead. +// The blob position starts at 0 and ends if an error is returned. +func (c *Cluster) BlobAt(blobPosition uint32) ([]byte, error) { + var offsetSize = uint64(clusterOffsetSize(c.information)) + var thisBlobIndex = uint64(blobPosition) * offsetSize + var nextBlobIndex = thisBlobIndex + offsetSize + if nextBlobIndex+offsetSize > uint64(len(c.data)) { + return nil, errors.New("zim: invalid blob position") + } + var thisBlobPointer uint64 + var nextBlobPointer uint64 + if offsetSize == defaultOffsetSize { + thisBlobPointer = uint64(binary.LittleEndian.Uint32(c.data[thisBlobIndex : thisBlobIndex+defaultOffsetSize])) + nextBlobPointer = uint64(binary.LittleEndian.Uint32(c.data[nextBlobIndex : nextBlobIndex+defaultOffsetSize])) + } else { + thisBlobPointer = binary.LittleEndian.Uint64(c.data[thisBlobIndex : thisBlobIndex+extendedOffsetSize]) + nextBlobPointer = binary.LittleEndian.Uint64(c.data[nextBlobIndex : nextBlobIndex+extendedOffsetSize]) + } + if nextBlobPointer >= thisBlobPointer && nextBlobPointer <= uint64(len(c.data)) { + return c.data[thisBlobPointer:nextBlobPointer], nil + } + return nil, errors.New("zim: invalid blob index") +} diff --git a/vendor/github.com/tim-st/go-zim/entry.go b/vendor/github.com/tim-st/go-zim/entry.go new file mode 100644 index 0000000..c1465d9 --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/entry.go @@ -0,0 +1,191 @@ +package zim + +import ( + "errors" + "fmt" +) + +// DirectoryEntry holds the information about a specific article, image or other object in a ZIM file. +type DirectoryEntry struct { + mimetype Mimetype + // parameterLen byte + namespace Namespace + revision uint32 + clusterNumber uint32 + blobNumberOrRedirectIndex uint32 + url []byte + title []byte + // parameter []byte // (not used) extra parameters; see `parameterLen` +} + +func (e *DirectoryEntry) String() string { + return fmt.Sprintf("DirectoryEntry{Namespace: %s, Title: %s, URL: %s}", + e.namespace, string(e.title), string(e.url)) +} + +// Mimetype is the Mimetype of the Directory Entry. +func (e *DirectoryEntry) Mimetype() Mimetype { + return e.mimetype +} + +// Namespace defines to which namespace the Directory Entry belongs. +func (e *DirectoryEntry) Namespace() Namespace { + return e.namespace +} + +// Revision identifies a revision of the contents of the Directory Entry, +// needed to identify updates or revisions in the original history. +func (e *DirectoryEntry) Revision() uint32 { + return e.revision +} + +// ClusterNumber in which the data of this Directory Entry is stored. +func (e *DirectoryEntry) ClusterNumber() uint32 { + return e.clusterNumber +} + +// BlobNumber is the blob number inside the uncompressed cluster, where the contents are stored. +func (e *DirectoryEntry) BlobNumber() uint32 { + return e.blobNumberOrRedirectIndex +} + +// RedirectIndex is a pointer to the Directory Entry of the Redirect Target. +func (e *DirectoryEntry) RedirectIndex() uint32 { + return e.blobNumberOrRedirectIndex +} + +// URL is the URL of the Directory Entry, which is unique for the specific Namespace. +func (e *DirectoryEntry) URL() []byte { + return e.url +} + +// Title is the title of the Directory Entry. +func (e *DirectoryEntry) Title() []byte { + if len(e.title) > 0 { + return e.title + } + return e.url +} + +func (z *File) readDirectoryEntry(filePosition uint64, maxRedirects uint8) DirectoryEntry { + var result = DirectoryEntry{} + seek(z.f, int64(filePosition)) + result.mimetype = Mimetype(readUint16(z.f)) + readUint8(z.f) // skip result.parameterLen (currently not used) + result.namespace = Namespace(readUint8(z.f)) + result.revision = readUint32(z.f) + switch result.mimetype { + case MimetypeDeletedEntry, MimetypeLinkTarget: + // no extra fields here + case MimetypeRedirectEntry: + result.blobNumberOrRedirectIndex = readUint32(z.f) // redirectIndex + if maxRedirects > 0 { + return z.readDirectoryEntry(z.urlPointerAtPos(result.RedirectIndex()), maxRedirects-1) + } + default: + // Mimetype: ArticleEntry + result.clusterNumber = readUint32(z.f) + result.blobNumberOrRedirectIndex = readUint32(z.f) // blobNumber + } + result.url = readNullTerminatedSlice(z.f) + result.title = readNullTerminatedSlice(z.f) + //if result.parameterLen > 0 { + //var buf, readErr = readSlice(z.f, int(result.parameterLen)) + //if readErr != nil { + // log.Printf("Error reading parameter data of length %d: %s\n", result.parameterLen, readErr) + //} else { + // result.parameter = string(buf) + //} + //} + return result +} + +// EntryAtURLPosition returns the Directory Entry +// at the position as defined in the ordered URL pointerlist. +// If 0 >= position < z.ArticleCount() the returned error is nil. +// Redirects are not followed automatically. +func (z *File) EntryAtURLPosition(position uint32) (DirectoryEntry, error) { + if position >= z.header.articleCount { + return DirectoryEntry{}, errors.New("zim: position out of range") + } + return z.readDirectoryEntry(z.urlPointerAtPos(position), 0), nil +} + +// EntryAtTitlePosition returns the Directory Entry +// at the position as defined in the ordered title pointerlist. +// If 0 >= position < z.ArticleCount() the returned error is nil. +// Redirects are not followed automatically. +func (z *File) EntryAtTitlePosition(position uint32) (DirectoryEntry, error) { + if position >= z.header.articleCount { + return DirectoryEntry{}, errors.New("zim: position out of range") + } + return z.readDirectoryEntry(z.titlePointerAtPos(position), 0), nil +} + +// IsArticle checks whether the Directory Entry is an Article +func (e *DirectoryEntry) IsArticle() bool { + return e.namespace == NamespaceArticles && e.mimetype < MimetypeDeletedEntry +} + +// IsRedirect checks whether the Directory Entry is a Redirect +// to another Directory Entry +func (e *DirectoryEntry) IsRedirect() bool { + return e.mimetype == MimetypeRedirectEntry +} + +// IsLinkTarget checks whether the Directory Entry is a LinkTarget +func (e *DirectoryEntry) IsLinkTarget() bool { + return e.mimetype == MimetypeLinkTarget +} + +// IsDeletedEntry checks whether the Directory Entry is a DeletedEntry +func (e *DirectoryEntry) IsDeletedEntry() bool { + return e.mimetype == MimetypeDeletedEntry +} + +// FollowRedirect returns the target Directory Entry of the given Redirect Entry +func (z *File) FollowRedirect(redirectEntry *DirectoryEntry) (DirectoryEntry, error) { + if !redirectEntry.IsRedirect() { + return *redirectEntry, errors.New("zim: Directory Entry is not a Redirect Entry") + } + return z.readDirectoryEntry(z.urlPointerAtPos(redirectEntry.RedirectIndex()), 4), nil +} + +// MainPage returns the Directory Entry for the MainPage of the ZIM file +func (z *File) MainPage() (DirectoryEntry, error) { + if z.header.mainPage == NoMainPage { + return DirectoryEntry{ + namespace: NamespaceArticles, + url: []byte("index.html"), + }, errors.New("zim: no main page specified in ZIM file") + } + return z.readDirectoryEntry(z.urlPointerAtPos(z.header.mainPage), 4), nil +} + +// LayoutPage returns the Directory Entry for the LayoutPage of the ZIM file +func (z *File) LayoutPage() (DirectoryEntry, error) { + if z.header.layoutPage == NoLayoutPage { + mainPage, _ := z.MainPage() + return mainPage, errors.New("zim: no layout page specified in ZIM file") + } + return z.readDirectoryEntry(z.urlPointerAtPos(z.header.layoutPage), 4), nil +} + +// Favicon returns the Directory Entry for the Favicon of the ZIM file +func (z *File) Favicon() (entry DirectoryEntry, err error) { + for _, namespace := range [2]Namespace{NamespaceLayout, NamespaceImagesFiles} { + var found bool + entry, _, found = z.EntryWithURL(namespace, []byte("favicon")) + if !found { + entry, _, found = z.EntryWithURL(namespace, []byte("favicon.png")) + } + if found { + if entry.IsRedirect() { + entry, err = z.FollowRedirect(&entry) + } + return + } + } + err = errors.New("zim: favicon not found") + return +} diff --git a/vendor/github.com/tim-st/go-zim/entry_search.go b/vendor/github.com/tim-st/go-zim/entry_search.go new file mode 100644 index 0000000..8609530 --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/entry_search.go @@ -0,0 +1,234 @@ +package zim + +import ( + "bytes" + "hash/fnv" +) + +const defaultLimitEntries = 100 + +// EntryWithURL searches for the Directory Entry with the exact URL. +// If the Directory Entry was found, found is set to true and +// the returned position will be the position in the URL pointerlist. +// This can be used to iterate over the next n Directory Entries using +// z.EntryAtURLPosition(position+n). +func (z *File) EntryWithURL(namespace Namespace, url []byte) ( + entry DirectoryEntry, urlPosition uint32, found bool) { + // more optimized version of entryWithPrefix + var firstURLPosition int64 + var currentURLPos int64 + var lastURLPosition = int64(z.header.articleCount - 1) + for firstURLPosition <= lastURLPosition { + currentURLPos = (firstURLPosition + lastURLPosition) >> 1 + entry = z.readDirectoryEntry(z.urlPointerAtPos(uint32(currentURLPos)), 0) + var c = cmpNs(entry.namespace, namespace) + if c == 0 { + c = bytes.Compare(entry.url, url) + if c == 0 { + found = true + break + } + } + if c < 0 { + firstURLPosition = currentURLPos + 1 + } else { + lastURLPosition = currentURLPos - 1 + } + } + urlPosition = uint32(currentURLPos) + return +} + +// EntryWithURLPrefix searches the first Directory Entry in the namespace +// having the given URL prefix. If it was found, found is set to true and +// the returned position will be the position in the URL pointerlist. +// This can be used to iterate over the next n Directory Entries using +// z.EntryAtURLPosition(position+n). +func (z *File) EntryWithURLPrefix(namespace Namespace, prefix []byte) ( + entry DirectoryEntry, position uint32, found bool) { + return z.entryWithPrefix(z.urlPointerAtPos, chooseURL, namespace, prefix) +} + +// EntryWithNamespace searches the first Directory Entry in the namespace. +// If it was found, found is set to true and the returned position will +// be the position in the URL pointerlist. +// This can be used to iterate over the next n Directory Entries using +// z.EntryAtURLPosition(position+n). +func (z *File) EntryWithNamespace(namespace Namespace) ( + entry DirectoryEntry, position uint32, found bool) { + return z.EntryWithURLPrefix(namespace, nil) +} + +// EntryWithTitlePrefix searches the first Directory Entry in the namespace +// having the given title prefix. If it was found, found is set to true and +// the returned position will be the position in the title pointerlist. +// This can be used to iterate over the next n Directory Entries using +// z.EntryAtTitlePosition(position+n). +func (z *File) EntryWithTitlePrefix(namespace Namespace, prefix []byte) ( + entry DirectoryEntry, position uint32, found bool) { + return z.entryWithPrefix(z.titlePointerAtPos, chooseTitle, namespace, prefix) +} + +// EntriesWithURLPrefix returns all Directory Entries in the Namespace +// that have the same URL prefix like the given. +// When the Limit is set to <= 0 it gets the default value 100. +func (z *File) EntriesWithURLPrefix(namespace Namespace, prefix []byte, limit int) []DirectoryEntry { + return z.entriesWithPrefix(chooseURL, z.urlPointerAtPos, namespace, prefix, limit) +} + +// EntriesWithNamespace returns the first n Directory Entries in the Namespace +// where n <= limit. +// When the Limit is set to <= 0 it gets the default value 100. +func (z *File) EntriesWithNamespace(namespace Namespace, limit int) []DirectoryEntry { + return z.EntriesWithURLPrefix(namespace, nil, limit) +} + +// EntriesWithTitlePrefix returns all Directory Entries in the Namespace +// that have the same Title prefix like the given. +// When the Limit is set to <= 0 it gets the default value 100. +func (z *File) EntriesWithTitlePrefix(namespace Namespace, prefix []byte, limit int) []DirectoryEntry { + return z.entriesWithPrefix(chooseTitle, z.titlePointerAtPos, namespace, prefix, limit) +} + +// EntriesWithSimilarity returns Directory Entries in the Namespace +// that have a similar URL prefix or Title prefix to the given one. +// When the Limit is set to <= 0 it takes the default value 100. +func (z *File) EntriesWithSimilarity(namespace Namespace, prefix []byte, limit int) []DirectoryEntry { + const maxLengthDifference = 15 + type wasSuggested = struct{} + if limit <= 0 { + limit = defaultLimitEntries + } + var alreadySuggested = make(map[uint32]wasSuggested, limit) + var suggestions = make([]DirectoryEntry, 0, limit) + for i := 0; i < maxLengthDifference; i++ { + + for _, prefixFunc := range [2]func(Namespace, []byte, int) []DirectoryEntry{ + z.EntriesWithURLPrefix, z.EntriesWithTitlePrefix} { + var nextSuggestions = prefixFunc(namespace, prefix, limit) + for _, suggestion := range nextSuggestions { + var key = hash(suggestion.url) + var _, suggestedBefore = alreadySuggested[key] + if !suggestedBefore { + suggestions = append(suggestions, suggestion) + alreadySuggested[key] = wasSuggested{} + if len(suggestions) >= limit { + return suggestions + } + } + } + + } + + if len(prefix) == 0 { + return suggestions + } + + // TODO: decrement by runeSize + prefix = prefix[:len(prefix)-1] + } + + return suggestions +} + +func chooseTitle(entry *DirectoryEntry) []byte { return entry.title } + +func chooseURL(entry *DirectoryEntry) []byte { return entry.url } + +func hash(data []byte) uint32 { + h := fnv.New32a() + h.Write(data) + return h.Sum32() +} + +func cmpNs(ns1, ns2 Namespace) int { + if ns1 > ns2 { + return 1 + } + if ns2 > ns1 { + return -1 + } + return 0 +} + +func cmpPrefix(s, prefix []byte) int { + if bytes.HasPrefix(s, prefix) { + return 0 + } + return bytes.Compare(s, prefix) +} + +func (z *File) entryWithPrefix( + pointerAtPosition func(uint32) uint64, + chooseField func(entry *DirectoryEntry) []byte, + namespace Namespace, + prefix []byte) ( + entry DirectoryEntry, position uint32, found bool) { + var firstPosition int64 + var currentPosition int64 + var lastPosition = int64(z.header.articleCount - 1) + for firstPosition <= lastPosition { + currentPosition = (firstPosition + lastPosition) >> 1 + entry = z.readDirectoryEntry(pointerAtPosition(uint32(currentPosition)), 0) + var c = cmpNs(entry.namespace, namespace) + if c == 0 { + c = cmpPrefix(chooseField(&entry), prefix) + if c == 0 { + // we found an entry with the given prefix + if currentPosition == 0 { + // already lowest position + found = true + break + } + var prevEntry = z.readDirectoryEntry(pointerAtPosition(uint32(currentPosition-1)), 0) + if prevEntry.namespace != namespace || !bytes.HasPrefix(chooseField(&prevEntry), prefix) { + // we found the lowest position + found = true + break + } + // the entry below also has the prefix, but maybe much more entries have it too... + c = 1 // so the current entry is greater + } + } + if c < 0 { + firstPosition = currentPosition + 1 + } else { + lastPosition = currentPosition - 1 + } + } + position = uint32(currentPosition) + return +} + +func (z *File) entriesWithPrefix( + chooseField func(*DirectoryEntry) []byte, + pointerAtPosition func(uint32) uint64, + namespace Namespace, + prefix []byte, + limit int) []DirectoryEntry { + var entry, position, found = z.entryWithPrefix(pointerAtPosition, chooseField, namespace, prefix) + var result []DirectoryEntry + if found { + if limit <= 0 { + limit = defaultLimitEntries + } + var capacity = defaultLimitEntries + if limit < defaultLimitEntries { + capacity = limit + } + result = make([]DirectoryEntry, 0, capacity) + result = append(result, entry) + entriesAdded := 1 + lastPosition := z.header.articleCount - 1 + for entriesAdded < limit && position < lastPosition { + position++ + nextEntry := z.readDirectoryEntry(pointerAtPosition(position), 0) + if nextEntry.Namespace() != namespace || !bytes.HasPrefix(chooseField(&nextEntry), prefix) { + break + } + result = append(result, nextEntry) + entriesAdded++ + } + } + return result +} diff --git a/vendor/github.com/tim-st/go-zim/file.go b/vendor/github.com/tim-st/go-zim/file.go new file mode 100644 index 0000000..8f55125 --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/file.go @@ -0,0 +1,91 @@ +// Package zim implements reading support for the ZIM File Format. +package zim + +import ( + "crypto/md5" + "os" + + "github.com/klauspost/compress/zstd" + "github.com/xi2/xz" +) + +// Some useful constants belonging to a ZIM file. +const ( + MagicNumber = uint32(72173914) + NoMainPage = ^uint32(0) + NoLayoutPage = NoMainPage +) + +// File represents a ZIM file and contains the most important +// information that is retrieved once and used again. +type File struct { + f *os.File + xzReader *xz.Reader + zstdReader *zstd.Decoder + header Header + metadata map[string]string + mimetypeList []string +} + +// Open opens the file and checks for a valid ZIM header. +func Open(filename string) (*File, error) { + var f, fileErr = os.Open(filename) + if fileErr != nil { + return nil, fileErr + } + var xzReader, xzReaderErr = xz.NewReader(nil, 0) + if xzReaderErr != nil { + return nil, xzReaderErr + } + var zstdReader, zstdReaderErr = zstd.NewReader(nil) + if zstdReaderErr != nil { + return nil, zstdReaderErr + } + var result = &File{ + f: f, + xzReader: xzReader, + zstdReader: zstdReader, + } + if headerErr := result.readHeader(); headerErr != nil { + return nil, headerErr + } + result.readMimetypeList() + result.readMetadata() + return result, nil +} + +// Close closes the ZIM file. +func (z *File) Close() { + z.f.Close() +} + +// ArticleCount is the total number of articles defined +// in the pointerlists of the ZIM file. +func (z *File) ArticleCount() uint32 { + return z.header.articleCount +} + +// ClusterCount is the number of clusters the ZIM file contains. +func (z *File) ClusterCount() uint32 { + return z.header.clusterCount +} + +// Filename is the filename of the ZIM file on the disk. +func (z *File) Filename() string { + return z.f.Name() +} + +// Filesize is the filesize in Bytes of the ZIM file. +func (z *File) Filesize() int { + return int(z.header.checksumPos) + md5.Size +} + +// UUID is the unique id of a ZIM file. +func (z *File) UUID() UUID { + return z.header.uuid +} + +// Version is the version tuple of the ZIM file. +func (z *File) Version() (majorVersion, minorVersion uint16) { + return z.header.majorVersion, z.header.minorVersion +} diff --git a/vendor/github.com/tim-st/go-zim/file_operations.go b/vendor/github.com/tim-st/go-zim/file_operations.go new file mode 100644 index 0000000..9eb0733 --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/file_operations.go @@ -0,0 +1,93 @@ +package zim + +import ( + "bufio" + "encoding/binary" + "io" + "os" +) + +func readUint8(f *os.File) uint8 { + const byteLen = 1 + var arr [byteLen]byte + f.Read(arr[:byteLen]) + return arr[0] +} + +func readUint16(f *os.File) uint16 { + const byteLen = 2 + var arr [byteLen]byte + f.Read(arr[:byteLen]) + return binary.LittleEndian.Uint16(arr[:byteLen]) +} + +func readUint32(f *os.File) uint32 { + const byteLen = 4 + var arr [byteLen]byte + f.Read(arr[:byteLen]) + return binary.LittleEndian.Uint32(arr[:byteLen]) +} + +func readUint32R(r io.Reader) uint32 { + const byteLen = 4 + var arr [byteLen]byte + r.Read(arr[:byteLen]) + return binary.LittleEndian.Uint32(arr[:byteLen]) +} + +func readUint64(f *os.File) uint64 { + const byteLen = 8 + var arr [byteLen]byte + f.Read(arr[:byteLen]) + return binary.LittleEndian.Uint64(arr[:byteLen]) +} + +func readUint64R(r io.Reader) uint64 { + const byteLen = 8 + var arr [byteLen]byte + r.Read(arr[:byteLen]) + return binary.LittleEndian.Uint64(arr[:byteLen]) +} + +func seek(f *os.File, position int64) { + f.Seek(position, 0) +} + +func currentPosition(f *os.File) int64 { + currentPos, _ := f.Seek(0, 1) + return currentPos +} + +func readSlice(f *os.File, byteLen int) ([]byte, error) { + var buf = make([]byte, byteLen) + var _, readErr = f.Read(buf) + return buf, readErr +} + +func readNullTerminatedSlice(f *os.File) []byte { + const bufferSize = 256 + var prevFilePosition = currentPosition(f) + var bufReader = bufio.NewReaderSize(f, bufferSize) + var result, readBufErr = bufReader.ReadBytes(0) + var dataLen int + if readBufErr == nil { + dataLen = len(result) - 1 + } + seek(f, prevFilePosition+int64(dataLen+1)) + return result[:dataLen] +} + +func (z *File) urlPointerAtPos(position uint32) uint64 { + seek(z.f, int64(z.header.urlPtrPos)+int64(position*8)) + return readUint64(z.f) +} + +func (z *File) titlePointerAtPos(position uint32) uint64 { + seek(z.f, int64(z.header.titlePtrPos)+int64(position*4)) + return z.urlPointerAtPos(readUint32(z.f)) +} + +func (z *File) clusterPointerAtPos(position uint32) uint64 { + seek(z.f, int64(z.header.clusterPtrPos)+int64(position*8)) + return readUint64(z.f) +} diff --git a/vendor/github.com/tim-st/go-zim/header.go b/vendor/github.com/tim-st/go-zim/header.go new file mode 100644 index 0000000..15198fc --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/header.go @@ -0,0 +1,63 @@ +package zim + +import ( + "encoding/hex" + "errors" +) + +const uuidLen = 16 + +// UUID is the unique ID of a ZIM file +type UUID []byte + +func (u UUID) String() string { + return hex.EncodeToString(u) +} + +// Header is the header of a ZIM file +type Header struct { + magicNumber uint32 // Magic number to recognize the file format, must be 72173914 + majorVersion uint16 // Major version of the ZIM file format (5 or 6) + minorVersion uint16 // Minor version of the ZIM file format + uuid UUID // unique ID of the ZIM file + articleCount uint32 // total number of articles + clusterCount uint32 // total number of clusters + urlPtrPos uint64 // position of the directory pointerlist ordered by URL + titlePtrPos uint64 // position of the directory pointerlist ordered by Title + clusterPtrPos uint64 // position of the cluster pointer list + mimeListPos uint64 // position of the MIME type list (also header size) + mainPage uint32 // main page or 0xffffffff if no main page + layoutPage uint32 // layout page or 0xffffffff if no layout page + checksumPos uint64 // pointer to the MD5 checksum of the ZIM file without the checksum itself. This points always 16 bytes before the end of the file. +} + +func (z *File) readHeader() error { + seek(z.f, 0) + z.header.magicNumber = readUint32(z.f) + if z.header.magicNumber != MagicNumber { + return errors.New("zim: file has no ZIM header") + } + z.header.majorVersion = readUint16(z.f) + z.header.minorVersion = readUint16(z.f) + var uuidReadErr error + z.header.uuid, uuidReadErr = readSlice(z.f, uuidLen) + if uuidReadErr != nil { + return uuidReadErr + } + z.header.articleCount = readUint32(z.f) + z.header.clusterCount = readUint32(z.f) + z.header.urlPtrPos = readUint64(z.f) + z.header.titlePtrPos = readUint64(z.f) + z.header.clusterPtrPos = readUint64(z.f) + z.header.mimeListPos = readUint64(z.f) + z.header.mainPage = readUint32(z.f) + z.header.layoutPage = readUint32(z.f) + z.header.checksumPos = readUint64(z.f) + + switch z.header.majorVersion { + case 5, 6: + return nil + default: + return errors.New("zim: version currently not supported") + } +} diff --git a/vendor/github.com/tim-st/go-zim/metadata.go b/vendor/github.com/tim-st/go-zim/metadata.go new file mode 100644 index 0000000..e1d96d5 --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/metadata.go @@ -0,0 +1,73 @@ +package zim + +func (z *File) readMetadata() { + const entryLimit = 256 // we don't want to fill the memory too much + const maxKeySize = 128 + const maxValueSize = 2048 + z.metadata = make(map[string]string) + for _, entry := range z.EntriesWithNamespace(NamespaceZimMetadata, entryLimit) { + if len(entry.url) <= maxKeySize { + var blobReader, blobSize, blobReaderErr = z.BlobReader(&entry) + if blobReaderErr == nil && blobSize <= maxValueSize { + var value = make([]byte, blobSize) + if _, blobReadErr := blobReader.Read(value); blobReadErr == nil { + z.metadata[string(entry.url)] = string(value) + } + } + } + } +} + +// Metadata returns a copy of the internal metadata map of the ZIM file. +func (z *File) Metadata() map[string]string { + var result = make(map[string]string, len(z.metadata)) + for k, v := range z.metadata { + result[k] = v + } + return result +} + +// MetadataFor returns the metadata value for a given key. +// If the key is not set, an empty string is returned. +func (z *File) MetadataFor(key string) string { + return z.metadata[key] +} + +// Name returns the Name of the ZIM file as found in the Metadata. +func (z *File) Name() string { return z.MetadataFor("Name") } + +// Title returns the Title of the ZIM file as found in the Metadata. +func (z *File) Title() string { return z.MetadataFor("Title") } + +// Creator returns the Creator of the ZIM file as found in the Metadata. +func (z *File) Creator() string { return z.MetadataFor("Creator") } + +// Publisher returns the Publisher of the ZIM file as found in the Metadata. +func (z *File) Publisher() string { return z.MetadataFor("Publisher") } + +// Date returns the Date of the ZIM file as found in the Metadata. +func (z *File) Date() string { return z.MetadataFor("Date") } + +// Description returns the Description of the ZIM file as found in the Metadata. +func (z *File) Description() string { return z.MetadataFor("Description") } + +// LongDescription returns the LongDescription of the ZIM file as found in the Metadata. +func (z *File) LongDescription() string { return z.MetadataFor("LongDescription") } + +// Language returns the Language of the ZIM file as found in the Metadata. +func (z *File) Language() string { return z.MetadataFor("Language") } + +// License returns the License of the ZIM file as found in the Metadata. +func (z *File) License() string { return z.MetadataFor("License") } + +// Tags returns the Tags of the ZIM file as found in the Metadata. +func (z *File) Tags() string { return z.MetadataFor("Tags") } + +// Relation returns the Relation of the ZIM file as found in the Metadata. +func (z *File) Relation() string { return z.MetadataFor("Relation") } + +// Source returns the Source of the ZIM file as found in the Metadata. +func (z *File) Source() string { return z.MetadataFor("Source") } + +// Counter returns a String containing the number of Directory Entries per Mimetype. +func (z *File) Counter() string { return z.MetadataFor("Counter") } diff --git a/vendor/github.com/tim-st/go-zim/mimetype.go b/vendor/github.com/tim-st/go-zim/mimetype.go new file mode 100644 index 0000000..1b6953e --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/mimetype.go @@ -0,0 +1,30 @@ +package zim + +import "bytes" + +// Mimetype describes one of the three possible +// fixed Mimetypes for a Directory Entry. +type Mimetype uint16 + +// Possible fixed Mimetype values for Directory Entry. +const ( + MimetypeDeletedEntry = Mimetype(0xFFFD) + MimetypeLinkTarget = Mimetype(0xFFFE) + MimetypeRedirectEntry = Mimetype(0xFFFF) +) + +func (z *File) readMimetypeList() { + seek(z.f, int64(z.header.mimeListPos)) + for { + var mimetype = readNullTerminatedSlice(z.f) + if len(mimetype) == 0 { + break + } + z.mimetypeList = append(z.mimetypeList, string(bytes.ToLower(bytes.TrimSpace(mimetype)))) + } +} + +// MimetypeList returns the internal Mimetype list of the ZIM file. +func (z *File) MimetypeList() []string { + return z.mimetypeList +} diff --git a/vendor/github.com/tim-st/go-zim/namespace.go b/vendor/github.com/tim-st/go-zim/namespace.go new file mode 100644 index 0000000..ef40199 --- /dev/null +++ b/vendor/github.com/tim-st/go-zim/namespace.go @@ -0,0 +1,20 @@ +package zim + +// Namespace is an Ascii-Character representing the category of a Directory Entry. +type Namespace byte + +// Possible values for a Namespace. +const ( + NamespaceLayout = Namespace('-') // layout, eg. the LayoutPage, CSS, favicon.png (48x48), JavaScript and images not related to the articles + NamespaceArticles = Namespace('A') + NamespaceArticleMetadata = Namespace('B') + NamespaceImagesFiles = Namespace('I') + NamespaceImagesText = Namespace('J') + NamespaceZimMetadata = Namespace('M') + NamespaceCategoriesText = Namespace('U') + NamespaceCategoriesArticleList = Namespace('V') + NamespaceCategoriesPerArticleCategoryList = Namespace('W') + NamespaceFulltextIndex = Namespace('X') // Xapian fulltext index +) + +func (n Namespace) String() string { return string(n) } diff --git a/vendor/github.com/xi2/xz/AUTHORS b/vendor/github.com/xi2/xz/AUTHORS new file mode 100644 index 0000000..657330e --- /dev/null +++ b/vendor/github.com/xi2/xz/AUTHORS @@ -0,0 +1,8 @@ +# Package xz authors + +Michael Cross + +# XZ Embedded authors + +Lasse Collin +Igor Pavlov diff --git a/vendor/github.com/xi2/xz/LICENSE b/vendor/github.com/xi2/xz/LICENSE new file mode 100644 index 0000000..b56f2e6 --- /dev/null +++ b/vendor/github.com/xi2/xz/LICENSE @@ -0,0 +1,18 @@ +Licensing of github.com/xi2/xz +============================== + + This Go package is a modified version of + + XZ Embedded + + The contents of the testdata directory are modified versions of + the test files from + + XZ Utils + + All the files in this package have been written by Michael Cross, + Lasse Collin and/or Igor PavLov. All these files have been put + into the public domain. You can do whatever you want with these + files. + + This software is provided "as is", without any warranty. diff --git a/vendor/github.com/xi2/xz/README.md b/vendor/github.com/xi2/xz/README.md new file mode 100644 index 0000000..2190af5 --- /dev/null +++ b/vendor/github.com/xi2/xz/README.md @@ -0,0 +1,10 @@ +# Xz + +Package xz implements XZ decompression natively in Go. + +Documentation at . + +Download and install with `go get github.com/xi2/xz`. + +If you need compression as well as decompression, you might want to +look at . diff --git a/vendor/github.com/xi2/xz/dec_bcj.go b/vendor/github.com/xi2/xz/dec_bcj.go new file mode 100644 index 0000000..a8a3df9 --- /dev/null +++ b/vendor/github.com/xi2/xz/dec_bcj.go @@ -0,0 +1,461 @@ +/* + * Branch/Call/Jump (BCJ) filter decoders + * + * Authors: Lasse Collin + * Igor Pavlov + * + * Translation to Go: Michael Cross + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +package xz + +/* from linux/lib/xz/xz_dec_bcj.c *************************************/ + +type xzDecBCJ struct { + /* Type of the BCJ filter being used */ + typ xzFilterID + /* + * Return value of the next filter in the chain. We need to preserve + * this information across calls, because we must not call the next + * filter anymore once it has returned xzStreamEnd + */ + ret xzRet + /* + * Absolute position relative to the beginning of the uncompressed + * data (in a single .xz Block). + */ + pos int + /* x86 filter state */ + x86PrevMask uint32 + /* Temporary space to hold the variables from xzBuf */ + out []byte + outPos int + temp struct { + /* Amount of already filtered data in the beginning of buf */ + filtered int + /* + * Buffer to hold a mix of filtered and unfiltered data. This + * needs to be big enough to hold Alignment + 2 * Look-ahead: + * + * Type Alignment Look-ahead + * x86 1 4 + * PowerPC 4 0 + * IA-64 16 0 + * ARM 4 0 + * ARM-Thumb 2 2 + * SPARC 4 0 + */ + buf []byte // slice buf will be backed by bufArray + bufArray [16]byte + } +} + +/* + * This is used to test the most significant byte of a memory address + * in an x86 instruction. + */ +func bcjX86TestMSByte(b byte) bool { + return b == 0x00 || b == 0xff +} + +func bcjX86Filter(s *xzDecBCJ, buf []byte) int { + var maskToAllowedStatus = []bool{ + true, true, true, false, true, false, false, false, + } + var maskToBitNum = []byte{0, 1, 2, 2, 3, 3, 3, 3} + var i int + var prevPos int = -1 + var prevMask uint32 = s.x86PrevMask + var src uint32 + var dest uint32 + var j uint32 + var b byte + if len(buf) <= 4 { + return 0 + } + for i = 0; i < len(buf)-4; i++ { + if buf[i]&0xfe != 0xe8 { + continue + } + prevPos = i - prevPos + if prevPos > 3 { + prevMask = 0 + } else { + prevMask = (prevMask << (uint(prevPos) - 1)) & 7 + if prevMask != 0 { + b = buf[i+4-int(maskToBitNum[prevMask])] + if !maskToAllowedStatus[prevMask] || bcjX86TestMSByte(b) { + prevPos = i + prevMask = prevMask<<1 | 1 + continue + } + } + } + prevPos = i + if bcjX86TestMSByte(buf[i+4]) { + src = getLE32(buf[i+1:]) + for { + dest = src - uint32(s.pos+i+5) + if prevMask == 0 { + break + } + j = uint32(maskToBitNum[prevMask]) * 8 + b = byte(dest >> (24 - j)) + if !bcjX86TestMSByte(b) { + break + } + src = dest ^ (1<<(32-j) - 1) + } + dest &= 0x01FFFFFF + dest |= 0 - dest&0x01000000 + putLE32(dest, buf[i+1:]) + i += 4 + } else { + prevMask = prevMask<<1 | 1 + } + } + prevPos = i - prevPos + if prevPos > 3 { + s.x86PrevMask = 0 + } else { + s.x86PrevMask = prevMask << (uint(prevPos) - 1) + } + return i +} + +func bcjPowerPCFilter(s *xzDecBCJ, buf []byte) int { + var i int + var instr uint32 + for i = 0; i+4 <= len(buf); i += 4 { + instr = getBE32(buf[i:]) + if instr&0xFC000003 == 0x48000001 { + instr &= 0x03FFFFFC + instr -= uint32(s.pos + i) + instr &= 0x03FFFFFC + instr |= 0x48000001 + putBE32(instr, buf[i:]) + } + } + return i +} + +var bcjIA64BranchTable = [...]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, + 4, 4, 0, 0, 4, 4, 0, 0, +} + +func bcjIA64Filter(s *xzDecBCJ, buf []byte) int { + var branchTable = bcjIA64BranchTable[:] + /* + * The local variables take a little bit stack space, but it's less + * than what LZMA2 decoder takes, so it doesn't make sense to reduce + * stack usage here without doing that for the LZMA2 decoder too. + */ + /* Loop counters */ + var i int + var j int + /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */ + var slot uint32 + /* Bitwise offset of the instruction indicated by slot */ + var bitPos uint32 + /* bit_pos split into byte and bit parts */ + var bytePos uint32 + var bitRes uint32 + /* Address part of an instruction */ + var addr uint32 + /* Mask used to detect which instructions to convert */ + var mask uint32 + /* 41-bit instruction stored somewhere in the lowest 48 bits */ + var instr uint64 + /* Instruction normalized with bit_res for easier manipulation */ + var norm uint64 + for i = 0; i+16 <= len(buf); i += 16 { + mask = uint32(branchTable[buf[i]&0x1f]) + for slot, bitPos = 0, 5; slot < 3; slot, bitPos = slot+1, bitPos+41 { + if (mask>>slot)&1 == 0 { + continue + } + bytePos = bitPos >> 3 + bitRes = bitPos & 7 + instr = 0 + for j = 0; j < 6; j++ { + instr |= uint64(buf[i+j+int(bytePos)]) << (8 * uint(j)) + } + norm = instr >> bitRes + if (norm>>37)&0x0f == 0x05 && (norm>>9)&0x07 == 0 { + addr = uint32((norm >> 13) & 0x0fffff) + addr |= (uint32(norm>>36) & 1) << 20 + addr <<= 4 + addr -= uint32(s.pos + i) + addr >>= 4 + norm &= ^(uint64(0x8fffff) << 13) + norm |= uint64(addr&0x0fffff) << 13 + norm |= uint64(addr&0x100000) << (36 - 20) + instr &= 1<> (8 * uint(j))) + } + } + } + } + return i +} + +func bcjARMFilter(s *xzDecBCJ, buf []byte) int { + var i int + var addr uint32 + for i = 0; i+4 <= len(buf); i += 4 { + if buf[i+3] == 0xeb { + addr = uint32(buf[i]) | uint32(buf[i+1])<<8 | + uint32(buf[i+2])<<16 + addr <<= 2 + addr -= uint32(s.pos + i + 8) + addr >>= 2 + buf[i] = byte(addr) + buf[i+1] = byte(addr >> 8) + buf[i+2] = byte(addr >> 16) + } + } + return i +} + +func bcjARMThumbFilter(s *xzDecBCJ, buf []byte) int { + var i int + var addr uint32 + for i = 0; i+4 <= len(buf); i += 2 { + if buf[i+1]&0xf8 == 0xf0 && buf[i+3]&0xf8 == 0xf8 { + addr = uint32(buf[i+1]&0x07)<<19 | + uint32(buf[i])<<11 | + uint32(buf[i+3]&0x07)<<8 | + uint32(buf[i+2]) + addr <<= 1 + addr -= uint32(s.pos + i + 4) + addr >>= 1 + buf[i+1] = byte(0xf0 | (addr>>19)&0x07) + buf[i] = byte(addr >> 11) + buf[i+3] = byte(0xf8 | (addr>>8)&0x07) + buf[i+2] = byte(addr) + i += 2 + } + } + return i +} + +func bcjSPARCFilter(s *xzDecBCJ, buf []byte) int { + var i int + var instr uint32 + for i = 0; i+4 <= len(buf); i += 4 { + instr = getBE32(buf[i:]) + if instr>>22 == 0x100 || instr>>22 == 0x1ff { + instr <<= 2 + instr -= uint32(s.pos + i) + instr >>= 2 + instr = (0x40000000 - instr&0x400000) | + 0x40000000 | (instr & 0x3FFFFF) + putBE32(instr, buf[i:]) + } + } + return i +} + +/* + * Apply the selected BCJ filter. Update *pos and s.pos to match the amount + * of data that got filtered. + */ +func bcjApply(s *xzDecBCJ, buf []byte, pos *int) { + var filtered int + buf = buf[*pos:] + switch s.typ { + case idBCJX86: + filtered = bcjX86Filter(s, buf) + case idBCJPowerPC: + filtered = bcjPowerPCFilter(s, buf) + case idBCJIA64: + filtered = bcjIA64Filter(s, buf) + case idBCJARM: + filtered = bcjARMFilter(s, buf) + case idBCJARMThumb: + filtered = bcjARMThumbFilter(s, buf) + case idBCJSPARC: + filtered = bcjSPARCFilter(s, buf) + default: + /* Never reached */ + } + *pos += filtered + s.pos += filtered +} + +/* + * Flush pending filtered data from temp to the output buffer. + * Move the remaining mixture of possibly filtered and unfiltered + * data to the beginning of temp. + */ +func bcjFlush(s *xzDecBCJ, b *xzBuf) { + var copySize int + copySize = len(b.out) - b.outPos + if copySize > s.temp.filtered { + copySize = s.temp.filtered + } + copy(b.out[b.outPos:], s.temp.buf[:copySize]) + b.outPos += copySize + s.temp.filtered -= copySize + copy(s.temp.buf, s.temp.buf[copySize:]) + s.temp.buf = s.temp.buf[:len(s.temp.buf)-copySize] +} + +/* + * Decode raw stream which has a BCJ filter as the first filter. + * + * The BCJ filter functions are primitive in sense that they process the + * data in chunks of 1-16 bytes. To hide this issue, this function does + * some buffering. + */ +func xzDecBCJRun(s *xzDecBCJ, b *xzBuf, chain func(*xzBuf) xzRet) xzRet { + var outStart int + /* + * Flush pending already filtered data to the output buffer. Return + * immediately if we couldn't flush everything, or if the next + * filter in the chain had already returned xzStreamEnd. + */ + if s.temp.filtered > 0 { + bcjFlush(s, b) + if s.temp.filtered > 0 { + return xzOK + } + if s.ret == xzStreamEnd { + return xzStreamEnd + } + } + /* + * If we have more output space than what is currently pending in + * temp, copy the unfiltered data from temp to the output buffer + * and try to fill the output buffer by decoding more data from the + * next filter in the chain. Apply the BCJ filter on the new data + * in the output buffer. If everything cannot be filtered, copy it + * to temp and rewind the output buffer position accordingly. + * + * This needs to be always run when len(temp.buf) == 0 to handle a special + * case where the output buffer is full and the next filter has no + * more output coming but hasn't returned xzStreamEnd yet. + */ + if len(s.temp.buf) < len(b.out)-b.outPos || len(s.temp.buf) == 0 { + outStart = b.outPos + copy(b.out[b.outPos:], s.temp.buf) + b.outPos += len(s.temp.buf) + s.ret = chain(b) + if s.ret != xzStreamEnd && s.ret != xzOK { + return s.ret + } + bcjApply(s, b.out[:b.outPos], &outStart) + /* + * As an exception, if the next filter returned xzStreamEnd, + * we can do that too, since the last few bytes that remain + * unfiltered are meant to remain unfiltered. + */ + if s.ret == xzStreamEnd { + return xzStreamEnd + } + s.temp.buf = s.temp.bufArray[:b.outPos-outStart] + b.outPos -= len(s.temp.buf) + copy(s.temp.buf, b.out[b.outPos:]) + /* + * If there wasn't enough input to the next filter to fill + * the output buffer with unfiltered data, there's no point + * to try decoding more data to temp. + */ + if b.outPos+len(s.temp.buf) < len(b.out) { + return xzOK + } + } + /* + * We have unfiltered data in temp. If the output buffer isn't full + * yet, try to fill the temp buffer by decoding more data from the + * next filter. Apply the BCJ filter on temp. Then we hopefully can + * fill the actual output buffer by copying filtered data from temp. + * A mix of filtered and unfiltered data may be left in temp; it will + * be taken care on the next call to this function. + */ + if b.outPos < len(b.out) { + /* Make b.out temporarily point to s.temp. */ + s.out = b.out + s.outPos = b.outPos + b.out = s.temp.bufArray[:] + b.outPos = len(s.temp.buf) + s.ret = chain(b) + s.temp.buf = s.temp.bufArray[:b.outPos] + b.out = s.out + b.outPos = s.outPos + if s.ret != xzOK && s.ret != xzStreamEnd { + return s.ret + } + bcjApply(s, s.temp.buf, &s.temp.filtered) + /* + * If the next filter returned xzStreamEnd, we mark that + * everything is filtered, since the last unfiltered bytes + * of the stream are meant to be left as is. + */ + if s.ret == xzStreamEnd { + s.temp.filtered = len(s.temp.buf) + } + bcjFlush(s, b) + if s.temp.filtered > 0 { + return xzOK + } + } + return s.ret +} + +/* + * Allocate memory for BCJ decoders. xzDecBCJReset must be used before + * calling xzDecBCJRun. + */ +func xzDecBCJCreate() *xzDecBCJ { + return new(xzDecBCJ) +} + +/* + * Decode the Filter ID of a BCJ filter and check the start offset is + * valid. Returns xzOK if the given Filter ID and offset is + * supported. Otherwise xzOptionsError is returned. + */ +func xzDecBCJReset(s *xzDecBCJ, id xzFilterID, offset int) xzRet { + switch id { + case idBCJX86: + case idBCJPowerPC: + case idBCJIA64: + case idBCJARM: + case idBCJARMThumb: + case idBCJSPARC: + default: + /* Unsupported Filter ID */ + return xzOptionsError + } + // check offset is a multiple of alignment + switch id { + case idBCJPowerPC, idBCJARM, idBCJSPARC: + if offset%4 != 0 { + return xzOptionsError + } + case idBCJIA64: + if offset%16 != 0 { + return xzOptionsError + } + case idBCJARMThumb: + if offset%2 != 0 { + return xzOptionsError + } + } + s.typ = id + s.ret = xzOK + s.pos = offset + s.x86PrevMask = 0 + s.temp.filtered = 0 + s.temp.buf = nil + return xzOK +} diff --git a/vendor/github.com/xi2/xz/dec_delta.go b/vendor/github.com/xi2/xz/dec_delta.go new file mode 100644 index 0000000..19df590 --- /dev/null +++ b/vendor/github.com/xi2/xz/dec_delta.go @@ -0,0 +1,55 @@ +/* + * Delta decoder + * + * Author: Lasse Collin + * + * Translation to Go: Michael Cross + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +package xz + +type xzDecDelta struct { + delta [256]byte + pos byte + distance int // in range [1, 256] +} + +/* + * Decode raw stream which has a delta filter as the first filter. + */ +func xzDecDeltaRun(s *xzDecDelta, b *xzBuf, chain func(*xzBuf) xzRet) xzRet { + outStart := b.outPos + ret := chain(b) + for i := outStart; i < b.outPos; i++ { + tmp := b.out[i] + s.delta[byte(s.distance+int(s.pos))] + s.delta[s.pos] = tmp + b.out[i] = tmp + s.pos-- + } + return ret +} + +/* + * Allocate memory for a delta decoder. xzDecDeltaReset must be used + * before calling xzDecDeltaRun. + */ +func xzDecDeltaCreate() *xzDecDelta { + return new(xzDecDelta) +} + +/* + * Returns xzOK if the given distance is valid. Otherwise + * xzOptionsError is returned. + */ +func xzDecDeltaReset(s *xzDecDelta, distance int) xzRet { + if distance < 1 || distance > 256 { + return xzOptionsError + } + s.delta = [256]byte{} + s.pos = 0 + s.distance = distance + return xzOK +} diff --git a/vendor/github.com/xi2/xz/dec_lzma2.go b/vendor/github.com/xi2/xz/dec_lzma2.go new file mode 100644 index 0000000..fa42e47 --- /dev/null +++ b/vendor/github.com/xi2/xz/dec_lzma2.go @@ -0,0 +1,1235 @@ +/* + * LZMA2 decoder + * + * Authors: Lasse Collin + * Igor Pavlov + * + * Translation to Go: Michael Cross + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +package xz + +/* from linux/lib/xz/xz_lzma2.h ***************************************/ + +/* Range coder constants */ +const ( + rcShiftBits = 8 + rcTopBits = 24 + rcTopValue = 1 << rcTopBits + rcBitModelTotalBits = 11 + rcBitModelTotal = 1 << rcBitModelTotalBits + rcMoveBits = 5 +) + +/* + * Maximum number of position states. A position state is the lowest pb + * number of bits of the current uncompressed offset. In some places there + * are different sets of probabilities for different position states. + */ +const posStatesMax = 1 << 4 + +/* + * lzmaState is used to track which LZMA symbols have occurred most recently + * and in which order. This information is used to predict the next symbol. + * + * Symbols: + * - Literal: One 8-bit byte + * - Match: Repeat a chunk of data at some distance + * - Long repeat: Multi-byte match at a recently seen distance + * - Short repeat: One-byte repeat at a recently seen distance + * + * The symbol names are in from STATE-oldest-older-previous. REP means + * either short or long repeated match, and NONLIT means any non-literal. + */ +type lzmaState int + +const ( + stateLitLit lzmaState = iota + stateMatchLitLit + stateRepLitLit + stateShortrepLitLit + stateMatchLit + stateRepList + stateShortrepLit + stateLitMatch + stateLitLongrep + stateLitShortrep + stateNonlitMatch + stateNonlitRep +) + +/* Total number of states */ +const states = 12 + +/* The lowest 7 states indicate that the previous state was a literal. */ +const litStates = 7 + +/* Indicate that the latest symbol was a literal. */ +func lzmaStateLiteral(state *lzmaState) { + switch { + case *state <= stateShortrepLitLit: + *state = stateLitLit + case *state <= stateLitShortrep: + *state -= 3 + default: + *state -= 6 + } +} + +/* Indicate that the latest symbol was a match. */ +func lzmaStateMatch(state *lzmaState) { + if *state < litStates { + *state = stateLitMatch + } else { + *state = stateNonlitMatch + } +} + +/* Indicate that the latest state was a long repeated match. */ +func lzmaStateLongRep(state *lzmaState) { + if *state < litStates { + *state = stateLitLongrep + } else { + *state = stateNonlitRep + } +} + +/* Indicate that the latest symbol was a short match. */ +func lzmaStateShortRep(state *lzmaState) { + if *state < litStates { + *state = stateLitShortrep + } else { + *state = stateNonlitRep + } +} + +/* Test if the previous symbol was a literal. */ +func lzmaStateIsLiteral(state lzmaState) bool { + return state < litStates +} + +/* Each literal coder is divided in three sections: + * - 0x001-0x0FF: Without match byte + * - 0x101-0x1FF: With match byte; match bit is 0 + * - 0x201-0x2FF: With match byte; match bit is 1 + * + * Match byte is used when the previous LZMA symbol was something else than + * a literal (that is, it was some kind of match). + */ +const literalCoderSize = 0x300 + +/* Maximum number of literal coders */ +const literalCodersMax = 1 << 4 + +/* Minimum length of a match is two bytes. */ +const matchLenMin = 2 + +/* Match length is encoded with 4, 5, or 10 bits. + * + * Length Bits + * 2-9 4 = Choice=0 + 3 bits + * 10-17 5 = Choice=1 + Choice2=0 + 3 bits + * 18-273 10 = Choice=1 + Choice2=1 + 8 bits + */ +const ( + lenLowBits = 3 + lenLowSymbols = 1 << lenLowBits + lenMidBits = 3 + lenMidSymbols = 1 << lenMidBits + lenHighBits = 8 + lenHighSymbols = 1 << lenHighBits +) + +/* + * Different sets of probabilities are used for match distances that have + * very short match length: Lengths of 2, 3, and 4 bytes have a separate + * set of probabilities for each length. The matches with longer length + * use a shared set of probabilities. + */ +const distStates = 4 + +/* + * Get the index of the appropriate probability array for decoding + * the distance slot. + */ +func lzmaGetDistState(len uint32) uint32 { + if len < distStates+matchLenMin { + return len - matchLenMin + } else { + return distStates - 1 + } +} + +/* + * The highest two bits of a 32-bit match distance are encoded using six bits. + * This six-bit value is called a distance slot. This way encoding a 32-bit + * value takes 6-36 bits, larger values taking more bits. + */ +const ( + distSlotBits = 6 + distSlots = 1 << distSlotBits +) + +/* Match distances up to 127 are fully encoded using probabilities. Since + * the highest two bits (distance slot) are always encoded using six bits, + * the distances 0-3 don't need any additional bits to encode, since the + * distance slot itself is the same as the actual distance. distModelStart + * indicates the first distance slot where at least one additional bit is + * needed. + */ +const distModelStart = 4 + +/* + * Match distances greater than 127 are encoded in three pieces: + * - distance slot: the highest two bits + * - direct bits: 2-26 bits below the highest two bits + * - alignment bits: four lowest bits + * + * Direct bits don't use any probabilities. + * + * The distance slot value of 14 is for distances 128-191. + */ +const distModelEnd = 14 + +/* Distance slots that indicate a distance <= 127. */ +const ( + fullDistancesBits = distModelEnd / 2 + fullDistances = 1 << fullDistancesBits +) + +/* + * For match distances greater than 127, only the highest two bits and the + * lowest four bits (alignment) is encoded using probabilities. + */ +const ( + alignBits = 4 + alignSize = 1 << alignBits +) + +/* from linux/lib/xz/xz_dec_lzma2.c ***********************************/ + +/* + * Range decoder initialization eats the first five bytes of each LZMA chunk. + */ +const rcInitBytes = 5 + +/* + * Minimum number of usable input buffer to safely decode one LZMA symbol. + * The worst case is that we decode 22 bits using probabilities and 26 + * direct bits. This may decode at maximum of 20 bytes of input. However, + * lzmaMain does an extra normalization before returning, thus we + * need to put 21 here. + */ +const lzmaInRequired = 21 + +/* + * Dictionary (history buffer) + * + * These are always true: + * start <= pos <= full <= end + * pos <= limit <= end + * end == size + * size <= sizeMax + * len(buf) <= size + */ +type dictionary struct { + /* The history buffer */ + buf []byte + /* Old position in buf (before decoding more data) */ + start uint32 + /* Position in buf */ + pos uint32 + /* + * How full dictionary is. This is used to detect corrupt input that + * would read beyond the beginning of the uncompressed stream. + */ + full uint32 + /* Write limit; we don't write to buf[limit] or later bytes. */ + limit uint32 + /* + * End of the dictionary buffer. This is the same as the + * dictionary size. + */ + end uint32 + /* + * Size of the dictionary as specified in Block Header. This is used + * together with "full" to detect corrupt input that would make us + * read beyond the beginning of the uncompressed stream. + */ + size uint32 + /* Maximum allowed dictionary size. */ + sizeMax uint32 +} + +/* Range decoder */ +type rcDec struct { + rnge uint32 + code uint32 + /* + * Number of initializing bytes remaining to be read + * by rcReadInit. + */ + initBytesLeft uint32 + /* + * Buffer from which we read our input. It can be either + * temp.buf or the caller-provided input buffer. + */ + in []byte + inPos int + inLimit int +} + +/* Probabilities for a length decoder. */ +type lzmaLenDec struct { + /* Probability of match length being at least 10 */ + choice uint16 + /* Probability of match length being at least 18 */ + choice2 uint16 + /* Probabilities for match lengths 2-9 */ + low [posStatesMax][lenLowSymbols]uint16 + /* Probabilities for match lengths 10-17 */ + mid [posStatesMax][lenMidSymbols]uint16 + /* Probabilities for match lengths 18-273 */ + high [lenHighSymbols]uint16 +} + +type lzmaDec struct { + /* Distances of latest four matches */ + rep0 uint32 + rep1 uint32 + rep2 uint32 + rep3 uint32 + /* Types of the most recently seen LZMA symbols */ + state lzmaState + /* + * Length of a match. This is updated so that dictRepeat can + * be called again to finish repeating the whole match. + */ + len uint32 + /* + * LZMA properties or related bit masks (number of literal + * context bits, a mask derived from the number of literal + * position bits, and a mask derived from the number + * position bits) + */ + lc uint32 + literalPosMask uint32 + posMask uint32 + /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ + isMatch [states][posStatesMax]uint16 + /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ + isRep [states]uint16 + /* + * If 0, distance of a repeated match is rep0. + * Otherwise check is_rep1. + */ + isRep0 [states]uint16 + /* + * If 0, distance of a repeated match is rep1. + * Otherwise check is_rep2. + */ + isRep1 [states]uint16 + /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ + isRep2 [states]uint16 + /* + * If 1, the repeated match has length of one byte. Otherwise + * the length is decoded from rep_len_decoder. + */ + isRep0Long [states][posStatesMax]uint16 + /* + * Probability tree for the highest two bits of the match + * distance. There is a separate probability tree for match + * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. + */ + distSlot [distStates][distSlots]uint16 + /* + * Probility trees for additional bits for match distance + * when the distance is in the range [4, 127]. + */ + distSpecial [fullDistances - distModelEnd]uint16 + /* + * Probability tree for the lowest four bits of a match + * distance that is equal to or greater than 128. + */ + distAlign [alignSize]uint16 + /* Length of a normal match */ + matchLenDec lzmaLenDec + /* Length of a repeated match */ + repLenDec lzmaLenDec + /* Probabilities of literals */ + literal [literalCodersMax][literalCoderSize]uint16 +} + +// type of lzma2Dec.sequence +type lzma2Seq int + +const ( + seqControl lzma2Seq = iota + seqUncompressed1 + seqUncompressed2 + seqCompressed0 + seqCompressed1 + seqProperties + seqLZMAPrepare + seqLZMARun + seqCopy +) + +type lzma2Dec struct { + /* Position in xzDecLZMA2Run. */ + sequence lzma2Seq + /* Next position after decoding the compressed size of the chunk. */ + nextSequence lzma2Seq + /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ + uncompressed int + /* + * Compressed size of LZMA chunk or compressed/uncompressed + * size of uncompressed chunk (64 KiB at maximum) + */ + compressed int + /* + * True if dictionary reset is needed. This is false before + * the first chunk (LZMA or uncompressed). + */ + needDictReset bool + /* + * True if new LZMA properties are needed. This is false + * before the first LZMA chunk. + */ + needProps bool +} + +type xzDecLZMA2 struct { + /* + * The order below is important on x86 to reduce code size and + * it shouldn't hurt on other platforms. Everything up to and + * including lzma.pos_mask are in the first 128 bytes on x86-32, + * which allows using smaller instructions to access those + * variables. On x86-64, fewer variables fit into the first 128 + * bytes, but this is still the best order without sacrificing + * the readability by splitting the structures. + */ + rc rcDec + dict dictionary + lzma2 lzma2Dec + lzma lzmaDec + /* + * Temporary buffer which holds small number of input bytes between + * decoder calls. See lzma2LZMA for details. + */ + temp struct { + buf []byte // slice buf will be backed by bufArray + bufArray [3 * lzmaInRequired]byte + } +} + +/************** + * Dictionary * + **************/ + +/* + * Reset the dictionary state. When in single-call mode, set up the beginning + * of the dictionary to point to the actual output buffer. + */ +func dictReset(dict *dictionary, b *xzBuf) { + dict.start = 0 + dict.pos = 0 + dict.limit = 0 + dict.full = 0 +} + +/* Set dictionary write limit */ +func dictLimit(dict *dictionary, outMax int) { + if dict.end-dict.pos <= uint32(outMax) { + dict.limit = dict.end + } else { + dict.limit = dict.pos + uint32(outMax) + } +} + +/* Return true if at least one byte can be written into the dictionary. */ +func dictHasSpace(dict *dictionary) bool { + return dict.pos < dict.limit +} + +/* + * Get a byte from the dictionary at the given distance. The distance is + * assumed to valid, or as a special case, zero when the dictionary is + * still empty. This special case is needed for single-call decoding to + * avoid writing a '\x00' to the end of the destination buffer. + */ +func dictGet(dict *dictionary, dist uint32) uint32 { + var offset uint32 = dict.pos - dist - 1 + if dist >= dict.pos { + offset += dict.end + } + if dict.full > 0 { + return uint32(dict.buf[offset]) + } + return 0 +} + +/* + * Put one byte into the dictionary. It is assumed that there is space for it. + */ +func dictPut(dict *dictionary, byte byte) { + dict.buf[dict.pos] = byte + dict.pos++ + if dict.full < dict.pos { + dict.full = dict.pos + } +} + +/* + * Repeat given number of bytes from the given distance. If the distance is + * invalid, false is returned. On success, true is returned and *len is + * updated to indicate how many bytes were left to be repeated. + */ +func dictRepeat(dict *dictionary, len *uint32, dist uint32) bool { + var back uint32 + var left uint32 + if dist >= dict.full || dist >= dict.size { + return false + } + left = dict.limit - dict.pos + if left > *len { + left = *len + } + *len -= left + back = dict.pos - dist - 1 + if dist >= dict.pos { + back += dict.end + } + for { + dict.buf[dict.pos] = dict.buf[back] + dict.pos++ + back++ + if back == dict.end { + back = 0 + } + left-- + if !(left > 0) { + break + } + } + if dict.full < dict.pos { + dict.full = dict.pos + } + return true +} + +/* Copy uncompressed data as is from input to dictionary and output buffers. */ +func dictUncompressed(dict *dictionary, b *xzBuf, left *int) { + var copySize int + for *left > 0 && b.inPos < len(b.in) && b.outPos < len(b.out) { + copySize = len(b.in) - b.inPos + if copySize > len(b.out)-b.outPos { + copySize = len(b.out) - b.outPos + } + if copySize > int(dict.end-dict.pos) { + copySize = int(dict.end - dict.pos) + } + if copySize > *left { + copySize = *left + } + *left -= copySize + copy(dict.buf[dict.pos:], b.in[b.inPos:b.inPos+copySize]) + dict.pos += uint32(copySize) + if dict.full < dict.pos { + dict.full = dict.pos + } + if dict.pos == dict.end { + dict.pos = 0 + } + copy(b.out[b.outPos:], b.in[b.inPos:b.inPos+copySize]) + dict.start = dict.pos + b.outPos += copySize + b.inPos += copySize + } +} + +/* + * Flush pending data from dictionary to b.out. It is assumed that there is + * enough space in b.out. This is guaranteed because caller uses dictLimit + * before decoding data into the dictionary. + */ +func dictFlush(dict *dictionary, b *xzBuf) int { + var copySize int = int(dict.pos - dict.start) + if dict.pos == dict.end { + dict.pos = 0 + } + copy(b.out[b.outPos:], dict.buf[dict.start:dict.start+uint32(copySize)]) + dict.start = dict.pos + b.outPos += copySize + return copySize +} + +/***************** + * Range decoder * + *****************/ + +/* Reset the range decoder. */ +func rcReset(rc *rcDec) { + rc.rnge = ^uint32(0) + rc.code = 0 + rc.initBytesLeft = rcInitBytes +} + +/* + * Read the first five initial bytes into rc->code if they haven't been + * read already. (Yes, the first byte gets completely ignored.) + */ +func rcReadInit(rc *rcDec, b *xzBuf) bool { + for rc.initBytesLeft > 0 { + if b.inPos == len(b.in) { + return false + } + rc.code = rc.code<<8 + uint32(b.in[b.inPos]) + b.inPos++ + rc.initBytesLeft-- + } + return true +} + +/* Return true if there may not be enough input for the next decoding loop. */ +func rcLimitExceeded(rc *rcDec) bool { + return rc.inPos > rc.inLimit +} + +/* + * Return true if it is possible (from point of view of range decoder) that + * we have reached the end of the LZMA chunk. + */ +func rcIsFinished(rc *rcDec) bool { + return rc.code == 0 +} + +/* Read the next input byte if needed. */ +func rcNormalize(rc *rcDec) { + if rc.rnge < rcTopValue { + rc.rnge <<= rcShiftBits + rc.code = rc.code<> rcBitModelTotalBits) * uint32(*prob) + if rc.code < bound { + rc.rnge = bound + *prob += (rcBitModelTotal - *prob) >> rcMoveBits + bit = false + } else { + rc.rnge -= bound + rc.code -= bound + *prob -= *prob >> rcMoveBits + bit = true + } + return bit +} + +/* Decode a bittree starting from the most significant bit. */ +func rcBittree(rc *rcDec, probs []uint16, limit uint32) uint32 { + var symbol uint32 = 1 + for { + if rcBit(rc, &probs[symbol-1]) { + symbol = symbol<<1 + 1 + } else { + symbol <<= 1 + } + if !(symbol < limit) { + break + } + } + return symbol +} + +/* Decode a bittree starting from the least significant bit. */ +func rcBittreeReverse(rc *rcDec, probs []uint16, dest *uint32, limit uint32) { + var symbol uint32 = 1 + var i uint32 = 0 + for { + if rcBit(rc, &probs[symbol-1]) { + symbol = symbol<<1 + 1 + *dest += 1 << i + } else { + symbol <<= 1 + } + i++ + if !(i < limit) { + break + } + } +} + +/* Decode direct bits (fixed fifty-fifty probability) */ +func rcDirect(rc *rcDec, dest *uint32, limit uint32) { + var mask uint32 + for { + rcNormalize(rc) + rc.rnge >>= 1 + rc.code -= rc.rnge + mask = 0 - rc.code>>31 + rc.code += rc.rnge & mask + *dest = *dest<<1 + mask + 1 + limit-- + if !(limit > 0) { + break + } + } +} + +/******** + * LZMA * + ********/ + +/* Get pointer to literal coder probability array. */ +func lzmaLiteralProbs(s *xzDecLZMA2) []uint16 { + var prevByte uint32 = dictGet(&s.dict, 0) + var low uint32 = prevByte >> (8 - s.lzma.lc) + var high uint32 = (s.dict.pos & s.lzma.literalPosMask) << s.lzma.lc + return s.lzma.literal[low+high][:] +} + +/* Decode a literal (one 8-bit byte) */ +func lzmaLiteral(s *xzDecLZMA2) { + var probs []uint16 + var symbol uint32 + var matchByte uint32 + var matchBit uint32 + var offset uint32 + var i uint32 + probs = lzmaLiteralProbs(s) + if lzmaStateIsLiteral(s.lzma.state) { + symbol = rcBittree(&s.rc, probs[1:], 0x100) + } else { + symbol = 1 + matchByte = dictGet(&s.dict, s.lzma.rep0) << 1 + offset = 0x100 + for { + matchBit = matchByte & offset + matchByte <<= 1 + i = offset + matchBit + symbol + if rcBit(&s.rc, &probs[i]) { + symbol = symbol<<1 + 1 + offset &= matchBit + } else { + symbol <<= 1 + offset &= ^matchBit + } + if !(symbol < 0x100) { + break + } + } + } + dictPut(&s.dict, byte(symbol)) + lzmaStateLiteral(&s.lzma.state) +} + +/* Decode the length of the match into s.lzma.len. */ +func lzmaLen(s *xzDecLZMA2, l *lzmaLenDec, posState uint32) { + var probs []uint16 + var limit uint32 + switch { + case !rcBit(&s.rc, &l.choice): + probs = l.low[posState][:] + limit = lenLowSymbols + s.lzma.len = matchLenMin + case !rcBit(&s.rc, &l.choice2): + probs = l.mid[posState][:] + limit = lenMidSymbols + s.lzma.len = matchLenMin + lenLowSymbols + default: + probs = l.high[:] + limit = lenHighSymbols + s.lzma.len = matchLenMin + lenLowSymbols + lenMidSymbols + } + s.lzma.len += rcBittree(&s.rc, probs[1:], limit) - limit +} + +/* Decode a match. The distance will be stored in s.lzma.rep0. */ +func lzmaMatch(s *xzDecLZMA2, posState uint32) { + var probs []uint16 + var distSlot uint32 + var limit uint32 + lzmaStateMatch(&s.lzma.state) + s.lzma.rep3 = s.lzma.rep2 + s.lzma.rep2 = s.lzma.rep1 + s.lzma.rep1 = s.lzma.rep0 + lzmaLen(s, &s.lzma.matchLenDec, posState) + probs = s.lzma.distSlot[lzmaGetDistState(s.lzma.len)][:] + distSlot = rcBittree(&s.rc, probs[1:], distSlots) - distSlots + if distSlot < distModelStart { + s.lzma.rep0 = distSlot + } else { + limit = distSlot>>1 - 1 + s.lzma.rep0 = 2 + distSlot&1 + if distSlot < distModelEnd { + s.lzma.rep0 <<= limit + probs = s.lzma.distSpecial[s.lzma.rep0-distSlot:] + rcBittreeReverse(&s.rc, probs, &s.lzma.rep0, limit) + } else { + rcDirect(&s.rc, &s.lzma.rep0, limit-alignBits) + s.lzma.rep0 <<= alignBits + rcBittreeReverse( + &s.rc, s.lzma.distAlign[1:], &s.lzma.rep0, alignBits) + } + } +} + +/* + * Decode a repeated match. The distance is one of the four most recently + * seen matches. The distance will be stored in s.lzma.rep0. + */ +func lzmaRepMatch(s *xzDecLZMA2, posState uint32) { + var tmp uint32 + if !rcBit(&s.rc, &s.lzma.isRep0[s.lzma.state]) { + if !rcBit(&s.rc, &s.lzma.isRep0Long[s.lzma.state][posState]) { + lzmaStateShortRep(&s.lzma.state) + s.lzma.len = 1 + return + } + } else { + if !rcBit(&s.rc, &s.lzma.isRep1[s.lzma.state]) { + tmp = s.lzma.rep1 + } else { + if !rcBit(&s.rc, &s.lzma.isRep2[s.lzma.state]) { + tmp = s.lzma.rep2 + } else { + tmp = s.lzma.rep3 + s.lzma.rep3 = s.lzma.rep2 + } + s.lzma.rep2 = s.lzma.rep1 + } + s.lzma.rep1 = s.lzma.rep0 + s.lzma.rep0 = tmp + } + lzmaStateLongRep(&s.lzma.state) + lzmaLen(s, &s.lzma.repLenDec, posState) +} + +/* LZMA decoder core */ +func lzmaMain(s *xzDecLZMA2) bool { + var posState uint32 + /* + * If the dictionary was reached during the previous call, try to + * finish the possibly pending repeat in the dictionary. + */ + if dictHasSpace(&s.dict) && s.lzma.len > 0 { + dictRepeat(&s.dict, &s.lzma.len, s.lzma.rep0) + } + /* + * Decode more LZMA symbols. One iteration may consume up to + * lzmaInRequired - 1 bytes. + */ + for dictHasSpace(&s.dict) && !rcLimitExceeded(&s.rc) { + posState = s.dict.pos & s.lzma.posMask + if !rcBit(&s.rc, &s.lzma.isMatch[s.lzma.state][posState]) { + lzmaLiteral(s) + } else { + if rcBit(&s.rc, &s.lzma.isRep[s.lzma.state]) { + lzmaRepMatch(s, posState) + } else { + lzmaMatch(s, posState) + } + if !dictRepeat(&s.dict, &s.lzma.len, s.lzma.rep0) { + return false + } + } + } + /* + * Having the range decoder always normalized when we are outside + * this function makes it easier to correctly handle end of the chunk. + */ + rcNormalize(&s.rc) + return true +} + +/* + * Reset the LZMA decoder and range decoder state. Dictionary is not reset + * here, because LZMA state may be reset without resetting the dictionary. + */ +func lzmaReset(s *xzDecLZMA2) { + s.lzma.state = stateLitLit + s.lzma.rep0 = 0 + s.lzma.rep1 = 0 + s.lzma.rep2 = 0 + s.lzma.rep3 = 0 + /* All probabilities are initialized to the same value, v */ + v := uint16(rcBitModelTotal / 2) + s.lzma.matchLenDec.choice = v + s.lzma.matchLenDec.choice2 = v + s.lzma.repLenDec.choice = v + s.lzma.repLenDec.choice2 = v + for _, m := range [][]uint16{ + s.lzma.isRep[:], s.lzma.isRep0[:], s.lzma.isRep1[:], + s.lzma.isRep2[:], s.lzma.distSpecial[:], s.lzma.distAlign[:], + s.lzma.matchLenDec.high[:], s.lzma.repLenDec.high[:], + } { + for j := range m { + m[j] = v + } + } + for i := range s.lzma.isMatch { + for j := range s.lzma.isMatch[i] { + s.lzma.isMatch[i][j] = v + } + } + for i := range s.lzma.isRep0Long { + for j := range s.lzma.isRep0Long[i] { + s.lzma.isRep0Long[i][j] = v + } + } + for i := range s.lzma.distSlot { + for j := range s.lzma.distSlot[i] { + s.lzma.distSlot[i][j] = v + } + } + for i := range s.lzma.literal { + for j := range s.lzma.literal[i] { + s.lzma.literal[i][j] = v + } + } + for i := range s.lzma.matchLenDec.low { + for j := range s.lzma.matchLenDec.low[i] { + s.lzma.matchLenDec.low[i][j] = v + } + } + for i := range s.lzma.matchLenDec.mid { + for j := range s.lzma.matchLenDec.mid[i] { + s.lzma.matchLenDec.mid[i][j] = v + } + } + for i := range s.lzma.repLenDec.low { + for j := range s.lzma.repLenDec.low[i] { + s.lzma.repLenDec.low[i][j] = v + } + } + for i := range s.lzma.repLenDec.mid { + for j := range s.lzma.repLenDec.mid[i] { + s.lzma.repLenDec.mid[i][j] = v + } + } + rcReset(&s.rc) +} + +/* + * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks + * from the decoded lp and pb values. On success, the LZMA decoder state is + * reset and true is returned. + */ +func lzmaProps(s *xzDecLZMA2, props byte) bool { + if props > (4*5+4)*9+8 { + return false + } + s.lzma.posMask = 0 + for props >= 9*5 { + props -= 9 * 5 + s.lzma.posMask++ + } + s.lzma.posMask = 1<= 9 { + props -= 9 + s.lzma.literalPosMask++ + } + s.lzma.lc = uint32(props) + if s.lzma.lc+s.lzma.literalPosMask > 4 { + return false + } + s.lzma.literalPosMask = 1< 0 || s.lzma2.compressed == 0 { + tmp = 2*lzmaInRequired - len(s.temp.buf) + if tmp > s.lzma2.compressed-len(s.temp.buf) { + tmp = s.lzma2.compressed - len(s.temp.buf) + } + if tmp > inAvail { + tmp = inAvail + } + copy(s.temp.bufArray[len(s.temp.buf):], b.in[b.inPos:b.inPos+tmp]) + switch { + case len(s.temp.buf)+tmp == s.lzma2.compressed: + for i := len(s.temp.buf) + tmp; i < len(s.temp.bufArray); i++ { + s.temp.bufArray[i] = 0 + } + s.rc.inLimit = len(s.temp.buf) + tmp + case len(s.temp.buf)+tmp < lzmaInRequired: + s.temp.buf = s.temp.bufArray[:len(s.temp.buf)+tmp] + b.inPos += tmp + return true + default: + s.rc.inLimit = len(s.temp.buf) + tmp - lzmaInRequired + } + s.rc.in = s.temp.bufArray[:] + s.rc.inPos = 0 + if !lzmaMain(s) || s.rc.inPos > len(s.temp.buf)+tmp { + return false + } + s.lzma2.compressed -= s.rc.inPos + if s.rc.inPos < len(s.temp.buf) { + copy(s.temp.buf, s.temp.buf[s.rc.inPos:]) + s.temp.buf = s.temp.buf[:len(s.temp.buf)-s.rc.inPos] + return true + } + b.inPos += s.rc.inPos - len(s.temp.buf) + s.temp.buf = nil + } + inAvail = len(b.in) - b.inPos + if inAvail >= lzmaInRequired { + s.rc.in = b.in + s.rc.inPos = b.inPos + if inAvail >= s.lzma2.compressed+lzmaInRequired { + s.rc.inLimit = b.inPos + s.lzma2.compressed + } else { + s.rc.inLimit = len(b.in) - lzmaInRequired + } + if !lzmaMain(s) { + return false + } + inAvail = s.rc.inPos - b.inPos + if inAvail > s.lzma2.compressed { + return false + } + s.lzma2.compressed -= inAvail + b.inPos = s.rc.inPos + } + inAvail = len(b.in) - b.inPos + if inAvail < lzmaInRequired { + if inAvail > s.lzma2.compressed { + inAvail = s.lzma2.compressed + } + s.temp.buf = s.temp.bufArray[:inAvail] + copy(s.temp.buf, b.in[b.inPos:]) + b.inPos += inAvail + } + return true +} + +/* + * Take care of the LZMA2 control layer, and forward the job of actual LZMA + * decoding or copying of uncompressed chunks to other functions. + */ +func xzDecLZMA2Run(s *xzDecLZMA2, b *xzBuf) xzRet { + var tmp int + for b.inPos < len(b.in) || s.lzma2.sequence == seqLZMARun { + switch s.lzma2.sequence { + case seqControl: + /* + * LZMA2 control byte + * + * Exact values: + * 0x00 End marker + * 0x01 Dictionary reset followed by + * an uncompressed chunk + * 0x02 Uncompressed chunk (no dictionary reset) + * + * Highest three bits (s.control & 0xE0): + * 0xE0 Dictionary reset, new properties and state + * reset, followed by LZMA compressed chunk + * 0xC0 New properties and state reset, followed + * by LZMA compressed chunk (no dictionary + * reset) + * 0xA0 State reset using old properties, + * followed by LZMA compressed chunk (no + * dictionary reset) + * 0x80 LZMA chunk (no dictionary or state reset) + * + * For LZMA compressed chunks, the lowest five bits + * (s.control & 1F) are the highest bits of the + * uncompressed size (bits 16-20). + * + * A new LZMA2 stream must begin with a dictionary + * reset. The first LZMA chunk must set new + * properties and reset the LZMA state. + * + * Values that don't match anything described above + * are invalid and we return xzDataError. + */ + tmp = int(b.in[b.inPos]) + b.inPos++ + if tmp == 0x00 { + return xzStreamEnd + } + switch { + case tmp >= 0xe0 || tmp == 0x01: + s.lzma2.needProps = true + s.lzma2.needDictReset = false + dictReset(&s.dict, b) + case s.lzma2.needDictReset: + return xzDataError + } + if tmp >= 0x80 { + s.lzma2.uncompressed = (tmp & 0x1f) << 16 + s.lzma2.sequence = seqUncompressed1 + switch { + case tmp >= 0xc0: + /* + * When there are new properties, + * state reset is done at + * seqProperties. + */ + s.lzma2.needProps = false + s.lzma2.nextSequence = seqProperties + case s.lzma2.needProps: + return xzDataError + default: + s.lzma2.nextSequence = seqLZMAPrepare + if tmp >= 0xa0 { + lzmaReset(s) + } + } + } else { + if tmp > 0x02 { + return xzDataError + } + s.lzma2.sequence = seqCompressed0 + s.lzma2.nextSequence = seqCopy + } + case seqUncompressed1: + s.lzma2.uncompressed += int(b.in[b.inPos]) << 8 + b.inPos++ + s.lzma2.sequence = seqUncompressed2 + case seqUncompressed2: + s.lzma2.uncompressed += int(b.in[b.inPos]) + 1 + b.inPos++ + s.lzma2.sequence = seqCompressed0 + case seqCompressed0: + s.lzma2.compressed += int(b.in[b.inPos]) << 8 + b.inPos++ + s.lzma2.sequence = seqCompressed1 + case seqCompressed1: + s.lzma2.compressed += int(b.in[b.inPos]) + 1 + b.inPos++ + s.lzma2.sequence = s.lzma2.nextSequence + case seqProperties: + if !lzmaProps(s, b.in[b.inPos]) { + return xzDataError + } + b.inPos++ + s.lzma2.sequence = seqLZMAPrepare + fallthrough + case seqLZMAPrepare: + if s.lzma2.compressed < rcInitBytes { + return xzDataError + } + if !rcReadInit(&s.rc, b) { + return xzOK + } + s.lzma2.compressed -= rcInitBytes + s.lzma2.sequence = seqLZMARun + fallthrough + case seqLZMARun: + /* + * Set dictionary limit to indicate how much we want + * to be encoded at maximum. Decode new data into the + * dictionary. Flush the new data from dictionary to + * b.out. Check if we finished decoding this chunk. + * In case the dictionary got full but we didn't fill + * the output buffer yet, we may run this loop + * multiple times without changing s.lzma2.sequence. + */ + outMax := len(b.out) - b.outPos + if outMax > s.lzma2.uncompressed { + outMax = s.lzma2.uncompressed + } + dictLimit(&s.dict, outMax) + if !lzma2LZMA(s, b) { + return xzDataError + } + s.lzma2.uncompressed -= dictFlush(&s.dict, b) + switch { + case s.lzma2.uncompressed == 0: + if s.lzma2.compressed > 0 || s.lzma.len > 0 || + !rcIsFinished(&s.rc) { + return xzDataError + } + rcReset(&s.rc) + s.lzma2.sequence = seqControl + case b.outPos == len(b.out) || + b.inPos == len(b.in) && + len(s.temp.buf) < s.lzma2.compressed: + return xzOK + } + case seqCopy: + dictUncompressed(&s.dict, b, &s.lzma2.compressed) + if s.lzma2.compressed > 0 { + return xzOK + } + s.lzma2.sequence = seqControl + } + } + return xzOK +} + +/* + * Allocate memory for LZMA2 decoder. xzDecLZMA2Reset must be used + * before calling xzDecLZMA2Run. + */ +func xzDecLZMA2Create(dictMax uint32) *xzDecLZMA2 { + s := new(xzDecLZMA2) + s.dict.sizeMax = dictMax + return s +} + +/* + * Decode the LZMA2 properties (one byte) and reset the decoder. Return + * xzOK on success, xzMemlimitError if the preallocated dictionary is not + * big enough, and xzOptionsError if props indicates something that this + * decoder doesn't support. + */ +func xzDecLZMA2Reset(s *xzDecLZMA2, props byte) xzRet { + if props > 40 { + return xzOptionsError // Bigger than 4 GiB + } + if props == 40 { + s.dict.size = ^uint32(0) + } else { + s.dict.size = uint32(2 + props&1) + s.dict.size <<= props>>1 + 11 + } + if s.dict.size > s.dict.sizeMax { + return xzMemlimitError + } + s.dict.end = s.dict.size + if len(s.dict.buf) < int(s.dict.size) { + s.dict.buf = make([]byte, s.dict.size) + } + s.lzma.len = 0 + s.lzma2.sequence = seqControl + s.lzma2.compressed = 0 + s.lzma2.uncompressed = 0 + s.lzma2.needDictReset = true + s.temp.buf = nil + return xzOK +} diff --git a/vendor/github.com/xi2/xz/dec_stream.go b/vendor/github.com/xi2/xz/dec_stream.go new file mode 100644 index 0000000..9381a3c --- /dev/null +++ b/vendor/github.com/xi2/xz/dec_stream.go @@ -0,0 +1,932 @@ +/* + * .xz Stream decoder + * + * Author: Lasse Collin + * + * Translation to Go: Michael Cross + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +package xz + +import ( + "bytes" + "crypto/sha256" + "hash" + "hash/crc32" + "hash/crc64" +) + +/* from linux/lib/xz/xz_stream.h **************************************/ + +/* + * See the .xz file format specification at + * http://tukaani.org/xz/xz-file-format.txt + * to understand the container format. + */ +const ( + streamHeaderSize = 12 + headerMagic = "\xfd7zXZ\x00" + footerMagic = "YZ" +) + +/* + * Variable-length integer can hold a 63-bit unsigned integer or a special + * value indicating that the value is unknown. + */ +type vliType uint64 + +const ( + vliUnknown vliType = ^vliType(0) + /* Maximum encoded size of a VLI */ + vliBytesMax = 8 * 8 / 7 // (Sizeof(vliType) * 8 / 7) +) + +/* from linux/lib/xz/xz_dec_stream.c **********************************/ + +/* Hash used to validate the Index field */ +type xzDecHash struct { + unpadded vliType + uncompressed vliType + sha256 hash.Hash +} + +// type of xzDec.sequence +type xzDecSeq int + +const ( + seqStreamHeader xzDecSeq = iota + seqBlockStart + seqBlockHeader + seqBlockUncompress + seqBlockPadding + seqBlockCheck + seqIndex + seqIndexPadding + seqIndexCRC32 + seqStreamFooter +) + +// type of xzDec.index.sequence +type xzDecIndexSeq int + +const ( + seqIndexCount xzDecIndexSeq = iota + seqIndexUnpadded + seqIndexUncompressed +) + +/** + * xzDec - Opaque type to hold the XZ decoder state + */ +type xzDec struct { + /* Position in decMain */ + sequence xzDecSeq + /* Position in variable-length integers and Check fields */ + pos int + /* Variable-length integer decoded by decVLI */ + vli vliType + /* Saved inPos and outPos */ + inStart int + outStart int + /* CRC32 checksum hash used in Index */ + crc32 hash.Hash + /* Hashes used in Blocks */ + checkCRC32 hash.Hash + checkCRC64 hash.Hash + checkSHA256 hash.Hash + /* for checkTypes CRC32/CRC64/SHA256, check is one of the above 3 hashes */ + check hash.Hash + /* Embedded stream header struct containing CheckType */ + *Header + /* + * True if the next call to xzDecRun is allowed to return + * xzBufError. + */ + allowBufError bool + /* Information stored in Block Header */ + blockHeader struct { + /* + * Value stored in the Compressed Size field, or + * vliUnknown if Compressed Size is not present. + */ + compressed vliType + /* + * Value stored in the Uncompressed Size field, or + * vliUnknown if Uncompressed Size is not present. + */ + uncompressed vliType + /* Size of the Block Header field */ + size int + } + /* Information collected when decoding Blocks */ + block struct { + /* Observed compressed size of the current Block */ + compressed vliType + /* Observed uncompressed size of the current Block */ + uncompressed vliType + /* Number of Blocks decoded so far */ + count vliType + /* + * Hash calculated from the Block sizes. This is used to + * validate the Index field. + */ + hash xzDecHash + } + /* Variables needed when verifying the Index field */ + index struct { + /* Position in decIndex */ + sequence xzDecIndexSeq + /* Size of the Index in bytes */ + size vliType + /* Number of Records (matches block.count in valid files) */ + count vliType + /* + * Hash calculated from the Records (matches block.hash in + * valid files). + */ + hash xzDecHash + } + /* + * Temporary buffer needed to hold Stream Header, Block Header, + * and Stream Footer. The Block Header is the biggest (1 KiB) + * so we reserve space according to that. bufArray has to be aligned + * to a multiple of four bytes; the variables before it + * should guarantee this. + */ + temp struct { + pos int + buf []byte // slice buf will be backed by bufArray + bufArray [1024]byte + } + // chain is the function (or to be more precise, closure) which + // does the decompression and will call into the lzma2 and other + // filter code as needed. It is constructed by decBlockHeader + chain func(b *xzBuf) xzRet + // lzma2 holds the state of the last filter (which must be LZMA2) + lzma2 *xzDecLZMA2 + // pointers to allocated BCJ/Delta filters + bcjs []*xzDecBCJ + deltas []*xzDecDelta + // number of currently in use BCJ/Delta filters from the above + bcjsUsed int + deltasUsed int +} + +/* Sizes of the Check field with different Check IDs */ +var checkSizes = [...]byte{ + 0, + 4, 4, 4, + 8, 8, 8, + 16, 16, 16, + 32, 32, 32, + 64, 64, 64, +} + +/* + * Fill s.temp by copying data starting from b.in[b.inPos]. Caller + * must have set s.temp.pos to indicate how much data we are supposed + * to copy into s.temp.buf. Return true once s.temp.pos has reached + * len(s.temp.buf). + */ +func fillTemp(s *xzDec, b *xzBuf) bool { + copySize := len(b.in) - b.inPos + tempRemaining := len(s.temp.buf) - s.temp.pos + if copySize > tempRemaining { + copySize = tempRemaining + } + copy(s.temp.buf[s.temp.pos:], b.in[b.inPos:]) + b.inPos += copySize + s.temp.pos += copySize + if s.temp.pos == len(s.temp.buf) { + s.temp.pos = 0 + return true + } + return false +} + +/* Decode a variable-length integer (little-endian base-128 encoding) */ +func decVLI(s *xzDec, in []byte, inPos *int) xzRet { + var byte byte + if s.pos == 0 { + s.vli = 0 + } + for *inPos < len(in) { + byte = in[*inPos] + *inPos++ + s.vli |= vliType(byte&0x7f) << uint(s.pos) + if byte&0x80 == 0 { + /* Don't allow non-minimal encodings. */ + if byte == 0 && s.pos != 0 { + return xzDataError + } + s.pos = 0 + return xzStreamEnd + } + s.pos += 7 + if s.pos == 7*vliBytesMax { + return xzDataError + } + } + return xzOK +} + +/* + * Decode the Compressed Data field from a Block. Update and validate + * the observed compressed and uncompressed sizes of the Block so that + * they don't exceed the values possibly stored in the Block Header + * (validation assumes that no integer overflow occurs, since vliType + * is uint64). Update s.check if presence of the CRC32/CRC64/SHA256 + * field was indicated in Stream Header. + * + * Once the decoding is finished, validate that the observed sizes match + * the sizes possibly stored in the Block Header. Update the hash and + * Block count, which are later used to validate the Index field. + */ +func decBlock(s *xzDec, b *xzBuf) xzRet { + var ret xzRet + s.inStart = b.inPos + s.outStart = b.outPos + ret = s.chain(b) + s.block.compressed += vliType(b.inPos - s.inStart) + s.block.uncompressed += vliType(b.outPos - s.outStart) + /* + * There is no need to separately check for vliUnknown since + * the observed sizes are always smaller than vliUnknown. + */ + if s.block.compressed > s.blockHeader.compressed || + s.block.uncompressed > s.blockHeader.uncompressed { + return xzDataError + } + switch s.CheckType { + case CheckCRC32, CheckCRC64, CheckSHA256: + _, _ = s.check.Write(b.out[s.outStart:b.outPos]) + } + if ret == xzStreamEnd { + if s.blockHeader.compressed != vliUnknown && + s.blockHeader.compressed != s.block.compressed { + return xzDataError + } + if s.blockHeader.uncompressed != vliUnknown && + s.blockHeader.uncompressed != s.block.uncompressed { + return xzDataError + } + s.block.hash.unpadded += + vliType(s.blockHeader.size) + s.block.compressed + s.block.hash.unpadded += vliType(checkSizes[s.CheckType]) + s.block.hash.uncompressed += s.block.uncompressed + var buf [2 * 8]byte // 2*Sizeof(vliType) + putLE64(uint64(s.block.hash.unpadded), buf[:]) + putLE64(uint64(s.block.hash.uncompressed), buf[8:]) + _, _ = s.block.hash.sha256.Write(buf[:]) + s.block.count++ + } + return ret +} + +/* Update the Index size and the CRC32 hash. */ +func indexUpdate(s *xzDec, b *xzBuf) { + inUsed := b.inPos - s.inStart + s.index.size += vliType(inUsed) + _, _ = s.crc32.Write(b.in[s.inStart : s.inStart+inUsed]) +} + +/* + * Decode the Number of Records, Unpadded Size, and Uncompressed Size + * fields from the Index field. That is, Index Padding and CRC32 are not + * decoded by this function. + * + * This can return xzOK (more input needed), xzStreamEnd (everything + * successfully decoded), or xzDataError (input is corrupt). + */ +func decIndex(s *xzDec, b *xzBuf) xzRet { + var ret xzRet + for { + ret = decVLI(s, b.in, &b.inPos) + if ret != xzStreamEnd { + indexUpdate(s, b) + return ret + } + switch s.index.sequence { + case seqIndexCount: + s.index.count = s.vli + /* + * Validate that the Number of Records field + * indicates the same number of Records as + * there were Blocks in the Stream. + */ + if s.index.count != s.block.count { + return xzDataError + } + s.index.sequence = seqIndexUnpadded + case seqIndexUnpadded: + s.index.hash.unpadded += s.vli + s.index.sequence = seqIndexUncompressed + case seqIndexUncompressed: + s.index.hash.uncompressed += s.vli + var buf [2 * 8]byte // 2*Sizeof(vliType) + putLE64(uint64(s.index.hash.unpadded), buf[:]) + putLE64(uint64(s.index.hash.uncompressed), buf[8:]) + _, _ = s.index.hash.sha256.Write(buf[:]) + s.index.count-- + s.index.sequence = seqIndexUnpadded + } + if !(s.index.count > 0) { + break + } + } + return xzStreamEnd +} + +/* + * Validate that the next 4 bytes match s.crc32.Sum(nil). s.pos must + * be zero when starting to validate the first byte. + */ +func crcValidate(s *xzDec, b *xzBuf) xzRet { + sum := s.crc32.Sum(nil) + // CRC32 - reverse slice + sum[0], sum[1], sum[2], sum[3] = sum[3], sum[2], sum[1], sum[0] + for { + if b.inPos == len(b.in) { + return xzOK + } + if sum[s.pos] != b.in[b.inPos] { + return xzDataError + } + b.inPos++ + s.pos++ + if !(s.pos < 4) { + break + } + } + s.crc32.Reset() + s.pos = 0 + return xzStreamEnd +} + +/* + * Validate that the next 4/8/32 bytes match s.check.Sum(nil). s.pos + * must be zero when starting to validate the first byte. + */ +func checkValidate(s *xzDec, b *xzBuf) xzRet { + sum := s.check.Sum(nil) + if s.CheckType == CheckCRC32 || s.CheckType == CheckCRC64 { + // CRC32/64 - reverse slice + for i, j := 0, len(sum)-1; i < j; i, j = i+1, j-1 { + sum[i], sum[j] = sum[j], sum[i] + } + } + for { + if b.inPos == len(b.in) { + return xzOK + } + if sum[s.pos] != b.in[b.inPos] { + return xzDataError + } + b.inPos++ + s.pos++ + if !(s.pos < len(sum)) { + break + } + } + s.check.Reset() + s.pos = 0 + return xzStreamEnd +} + +/* + * Skip over the Check field when the Check ID is not supported. + * Returns true once the whole Check field has been skipped over. + */ +func checkSkip(s *xzDec, b *xzBuf) bool { + for s.pos < int(checkSizes[s.CheckType]) { + if b.inPos == len(b.in) { + return false + } + b.inPos++ + s.pos++ + } + s.pos = 0 + return true +} + +/* polynomial table used in decStreamHeader below */ +var xzCRC64Table = crc64.MakeTable(crc64.ECMA) + +/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */ +func decStreamHeader(s *xzDec) xzRet { + if string(s.temp.buf[:len(headerMagic)]) != headerMagic { + return xzFormatError + } + if crc32.ChecksumIEEE(s.temp.buf[len(headerMagic):len(headerMagic)+2]) != + getLE32(s.temp.buf[len(headerMagic)+2:]) { + return xzDataError + } + if s.temp.buf[len(headerMagic)] != 0 { + return xzOptionsError + } + /* + * Of integrity checks, we support none (Check ID = 0), + * CRC32 (Check ID = 1), CRC64 (Check ID = 4) and SHA256 (Check ID = 10) + * However, we will accept other check types too, but then the check + * won't be verified and a warning (xzUnsupportedCheck) will be given. + */ + s.CheckType = CheckID(s.temp.buf[len(headerMagic)+1]) + if s.CheckType > checkMax { + return xzOptionsError + } + switch s.CheckType { + case CheckNone: + // CheckNone: no action needed + case CheckCRC32: + if s.checkCRC32 == nil { + s.checkCRC32 = crc32.NewIEEE() + } else { + s.checkCRC32.Reset() + } + s.check = s.checkCRC32 + case CheckCRC64: + if s.checkCRC64 == nil { + s.checkCRC64 = crc64.New(xzCRC64Table) + } else { + s.checkCRC64.Reset() + } + s.check = s.checkCRC64 + case CheckSHA256: + if s.checkSHA256 == nil { + s.checkSHA256 = sha256.New() + } else { + s.checkSHA256.Reset() + } + s.check = s.checkSHA256 + default: + return xzUnsupportedCheck + } + return xzOK +} + +/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */ +func decStreamFooter(s *xzDec) xzRet { + if string(s.temp.buf[10:10+len(footerMagic)]) != footerMagic { + return xzDataError + } + if crc32.ChecksumIEEE(s.temp.buf[4:10]) != getLE32(s.temp.buf) { + return xzDataError + } + /* + * Validate Backward Size. Note that we never added the size of the + * Index CRC32 field to s->index.size, thus we use s->index.size / 4 + * instead of s->index.size / 4 - 1. + */ + if s.index.size>>2 != vliType(getLE32(s.temp.buf[4:])) { + return xzDataError + } + if s.temp.buf[8] != 0 || CheckID(s.temp.buf[9]) != s.CheckType { + return xzDataError + } + /* + * Use xzStreamEnd instead of xzOK to be more convenient + * for the caller. + */ + return xzStreamEnd +} + +/* Decode the Block Header and initialize the filter chain. */ +func decBlockHeader(s *xzDec) xzRet { + var ret xzRet + /* + * Validate the CRC32. We know that the temp buffer is at least + * eight bytes so this is safe. + */ + crc := getLE32(s.temp.buf[len(s.temp.buf)-4:]) + s.temp.buf = s.temp.buf[:len(s.temp.buf)-4] + if crc32.ChecksumIEEE(s.temp.buf) != crc { + return xzDataError + } + s.temp.pos = 2 + /* + * Catch unsupported Block Flags. + */ + if s.temp.buf[1]&0x3C != 0 { + return xzOptionsError + } + /* Compressed Size */ + if s.temp.buf[1]&0x40 != 0 { + if decVLI(s, s.temp.buf, &s.temp.pos) != xzStreamEnd { + return xzDataError + } + if s.vli >= 1<<63-8 { + // the whole block must stay smaller than 2^63 bytes + // the block header cannot be smaller than 8 bytes + return xzDataError + } + if s.vli == 0 { + // compressed size must be non-zero + return xzDataError + } + s.blockHeader.compressed = s.vli + } else { + s.blockHeader.compressed = vliUnknown + } + /* Uncompressed Size */ + if s.temp.buf[1]&0x80 != 0 { + if decVLI(s, s.temp.buf, &s.temp.pos) != xzStreamEnd { + return xzDataError + } + s.blockHeader.uncompressed = s.vli + } else { + s.blockHeader.uncompressed = vliUnknown + } + // get total number of filters (1-4) + filterTotal := int(s.temp.buf[1]&0x03) + 1 + // slice to hold decoded filters + filterList := make([]struct { + id xzFilterID + props uint32 + }, filterTotal) + // decode the non-last filters which cannot be LZMA2 + for i := 0; i < filterTotal-1; i++ { + /* Valid Filter Flags always take at least two bytes. */ + if len(s.temp.buf)-s.temp.pos < 2 { + return xzDataError + } + s.temp.pos += 2 + switch id := xzFilterID(s.temp.buf[s.temp.pos-2]); id { + case idDelta: + // delta filter + if s.temp.buf[s.temp.pos-1] != 0x01 { + return xzOptionsError + } + /* Filter Properties contains distance - 1 */ + if len(s.temp.buf)-s.temp.pos < 1 { + return xzDataError + } + props := uint32(s.temp.buf[s.temp.pos]) + s.temp.pos++ + filterList[i] = struct { + id xzFilterID + props uint32 + }{id: id, props: props} + case idBCJX86, idBCJPowerPC, idBCJIA64, + idBCJARM, idBCJARMThumb, idBCJSPARC: + // bcj filter + var props uint32 + switch s.temp.buf[s.temp.pos-1] { + case 0x00: + props = 0 + case 0x04: + if len(s.temp.buf)-s.temp.pos < 4 { + return xzDataError + } + props = getLE32(s.temp.buf[s.temp.pos:]) + s.temp.pos += 4 + default: + return xzOptionsError + } + filterList[i] = struct { + id xzFilterID + props uint32 + }{id: id, props: props} + default: + return xzOptionsError + } + } + /* + * decode the last filter which must be LZMA2 + */ + if len(s.temp.buf)-s.temp.pos < 2 { + return xzDataError + } + /* Filter ID = LZMA2 */ + if xzFilterID(s.temp.buf[s.temp.pos]) != idLZMA2 { + return xzOptionsError + } + s.temp.pos++ + /* Size of Properties = 1-byte Filter Properties */ + if s.temp.buf[s.temp.pos] != 0x01 { + return xzOptionsError + } + s.temp.pos++ + /* Filter Properties contains LZMA2 dictionary size. */ + if len(s.temp.buf)-s.temp.pos < 1 { + return xzDataError + } + props := uint32(s.temp.buf[s.temp.pos]) + s.temp.pos++ + filterList[filterTotal-1] = struct { + id xzFilterID + props uint32 + }{id: idLZMA2, props: props} + /* + * Process the filter list and create s.chain, going from last + * filter (LZMA2) to first filter + * + * First, LZMA2. + */ + ret = xzDecLZMA2Reset(s.lzma2, byte(filterList[filterTotal-1].props)) + if ret != xzOK { + return ret + } + s.chain = func(b *xzBuf) xzRet { + return xzDecLZMA2Run(s.lzma2, b) + } + /* + * Now the non-last filters + */ + for i := filterTotal - 2; i >= 0; i-- { + switch id := filterList[i].id; id { + case idDelta: + // delta filter + var delta *xzDecDelta + if s.deltasUsed < len(s.deltas) { + delta = s.deltas[s.deltasUsed] + } else { + delta = xzDecDeltaCreate() + s.deltas = append(s.deltas, delta) + } + s.deltasUsed++ + ret = xzDecDeltaReset(delta, int(filterList[i].props)+1) + if ret != xzOK { + return ret + } + chain := s.chain + s.chain = func(b *xzBuf) xzRet { + return xzDecDeltaRun(delta, b, chain) + } + case idBCJX86, idBCJPowerPC, idBCJIA64, + idBCJARM, idBCJARMThumb, idBCJSPARC: + // bcj filter + var bcj *xzDecBCJ + if s.bcjsUsed < len(s.bcjs) { + bcj = s.bcjs[s.bcjsUsed] + } else { + bcj = xzDecBCJCreate() + s.bcjs = append(s.bcjs, bcj) + } + s.bcjsUsed++ + ret = xzDecBCJReset(bcj, id, int(filterList[i].props)) + if ret != xzOK { + return ret + } + chain := s.chain + s.chain = func(b *xzBuf) xzRet { + return xzDecBCJRun(bcj, b, chain) + } + } + } + /* The rest must be Header Padding. */ + for s.temp.pos < len(s.temp.buf) { + if s.temp.buf[s.temp.pos] != 0x00 { + return xzOptionsError + } + s.temp.pos++ + } + s.temp.pos = 0 + s.block.compressed = 0 + s.block.uncompressed = 0 + return xzOK +} + +func decMain(s *xzDec, b *xzBuf) xzRet { + var ret xzRet + /* + * Store the start position for the case when we are in the middle + * of the Index field. + */ + s.inStart = b.inPos + for { + switch s.sequence { + case seqStreamHeader: + /* + * Stream Header is copied to s.temp, and then + * decoded from there. This way if the caller + * gives us only little input at a time, we can + * still keep the Stream Header decoding code + * simple. Similar approach is used in many places + * in this file. + */ + if !fillTemp(s, b) { + return xzOK + } + /* + * If decStreamHeader returns + * xzUnsupportedCheck, it is still possible + * to continue decoding. Thus, update s.sequence + * before calling decStreamHeader. + */ + s.sequence = seqBlockStart + ret = decStreamHeader(s) + if ret != xzOK { + return ret + } + fallthrough + case seqBlockStart: + /* We need one byte of input to continue. */ + if b.inPos == len(b.in) { + return xzOK + } + /* See if this is the beginning of the Index field. */ + if b.in[b.inPos] == 0 { + s.inStart = b.inPos + b.inPos++ + s.sequence = seqIndex + break + } + /* + * Calculate the size of the Block Header and + * prepare to decode it. + */ + s.blockHeader.size = (int(b.in[b.inPos]) + 1) * 4 + s.temp.buf = s.temp.bufArray[:s.blockHeader.size] + s.temp.pos = 0 + s.sequence = seqBlockHeader + fallthrough + case seqBlockHeader: + if !fillTemp(s, b) { + return xzOK + } + ret = decBlockHeader(s) + if ret != xzOK { + return ret + } + s.sequence = seqBlockUncompress + fallthrough + case seqBlockUncompress: + ret = decBlock(s, b) + if ret != xzStreamEnd { + return ret + } + s.sequence = seqBlockPadding + fallthrough + case seqBlockPadding: + /* + * Size of Compressed Data + Block Padding + * must be a multiple of four. We don't need + * s->block.compressed for anything else + * anymore, so we use it here to test the size + * of the Block Padding field. + */ + for s.block.compressed&3 != 0 { + if b.inPos == len(b.in) { + return xzOK + } + if b.in[b.inPos] != 0 { + return xzDataError + } + b.inPos++ + s.block.compressed++ + } + s.sequence = seqBlockCheck + fallthrough + case seqBlockCheck: + switch s.CheckType { + case CheckCRC32, CheckCRC64, CheckSHA256: + ret = checkValidate(s, b) + if ret != xzStreamEnd { + return ret + } + default: + if !checkSkip(s, b) { + return xzOK + } + } + s.sequence = seqBlockStart + case seqIndex: + ret = decIndex(s, b) + if ret != xzStreamEnd { + return ret + } + s.sequence = seqIndexPadding + fallthrough + case seqIndexPadding: + for (s.index.size+vliType(b.inPos-s.inStart))&3 != 0 { + if b.inPos == len(b.in) { + indexUpdate(s, b) + return xzOK + } + if b.in[b.inPos] != 0 { + return xzDataError + } + b.inPos++ + } + /* Finish the CRC32 value and Index size. */ + indexUpdate(s, b) + /* Compare the hashes to validate the Index field. */ + if !bytes.Equal( + s.block.hash.sha256.Sum(nil), s.index.hash.sha256.Sum(nil)) { + return xzDataError + } + s.sequence = seqIndexCRC32 + fallthrough + case seqIndexCRC32: + ret = crcValidate(s, b) + if ret != xzStreamEnd { + return ret + } + s.temp.buf = s.temp.bufArray[:streamHeaderSize] + s.sequence = seqStreamFooter + fallthrough + case seqStreamFooter: + if !fillTemp(s, b) { + return xzOK + } + return decStreamFooter(s) + } + } + /* Never reached */ +} + +/** + * xzDecRun - Run the XZ decoder + * @s: Decoder state allocated using xzDecInit + * @b: Input and output buffers + * + * See xzRet for details of return values. + * + * xzDecRun is a wrapper for decMain to handle some special cases. + * + * We must return xzBufError when it seems clear that we are not + * going to make any progress anymore. This is to prevent the caller + * from calling us infinitely when the input file is truncated or + * otherwise corrupt. Since zlib-style API allows that the caller + * fills the input buffer only when the decoder doesn't produce any + * new output, we have to be careful to avoid returning xzBufError + * too easily: xzBufError is returned only after the second + * consecutive call to xzDecRun that makes no progress. + */ +func xzDecRun(s *xzDec, b *xzBuf) xzRet { + inStart := b.inPos + outStart := b.outPos + ret := decMain(s, b) + if ret == xzOK && inStart == b.inPos && outStart == b.outPos { + if s.allowBufError { + ret = xzBufError + } + s.allowBufError = true + } else { + s.allowBufError = false + } + return ret +} + +/** + * xzDecInit - Allocate and initialize a XZ decoder state + * @dictMax: Maximum size of the LZMA2 dictionary (history buffer) for + * decoding. LZMA2 dictionary is always 2^n bytes + * or 2^n + 2^(n-1) bytes (the latter sizes are less common + * in practice), so other values for dictMax don't make sense. + * + * dictMax specifies the maximum allowed dictionary size that xzDecRun + * may allocate once it has parsed the dictionary size from the stream + * headers. This way excessive allocations can be avoided while still + * limiting the maximum memory usage to a sane value to prevent running the + * system out of memory when decompressing streams from untrusted sources. + * + * xzDecInit returns a pointer to an xzDec, which is ready to be used with + * xzDecRun. + */ +func xzDecInit(dictMax uint32, header *Header) *xzDec { + s := new(xzDec) + s.crc32 = crc32.NewIEEE() + s.Header = header + s.block.hash.sha256 = sha256.New() + s.index.hash.sha256 = sha256.New() + s.lzma2 = xzDecLZMA2Create(dictMax) + xzDecReset(s) + return s +} + +/** + * xzDecReset - Reset an already allocated decoder state + * @s: Decoder state allocated using xzDecInit + * + * This function can be used to reset the decoder state without + * reallocating memory with xzDecInit. + */ +func xzDecReset(s *xzDec) { + s.sequence = seqStreamHeader + s.allowBufError = false + s.pos = 0 + s.crc32.Reset() + s.check = nil + s.CheckType = checkUnset + s.block.compressed = 0 + s.block.uncompressed = 0 + s.block.count = 0 + s.block.hash.unpadded = 0 + s.block.hash.uncompressed = 0 + s.block.hash.sha256.Reset() + s.index.sequence = seqIndexCount + s.index.size = 0 + s.index.count = 0 + s.index.hash.unpadded = 0 + s.index.hash.uncompressed = 0 + s.index.hash.sha256.Reset() + s.temp.pos = 0 + s.temp.buf = s.temp.bufArray[:streamHeaderSize] + s.chain = nil + s.bcjsUsed = 0 + s.deltasUsed = 0 +} diff --git a/vendor/github.com/xi2/xz/dec_util.go b/vendor/github.com/xi2/xz/dec_util.go new file mode 100644 index 0000000..c422752 --- /dev/null +++ b/vendor/github.com/xi2/xz/dec_util.go @@ -0,0 +1,52 @@ +/* + * XZ decompressor utility functions + * + * Author: Michael Cross + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +package xz + +func getLE32(buf []byte) uint32 { + return uint32(buf[0]) | + uint32(buf[1])<<8 | + uint32(buf[2])<<16 | + uint32(buf[3])<<24 +} + +func getBE32(buf []byte) uint32 { + return uint32(buf[0])<<24 | + uint32(buf[1])<<16 | + uint32(buf[2])<<8 | + uint32(buf[3]) +} + +func putLE32(val uint32, buf []byte) { + buf[0] = byte(val) + buf[1] = byte(val >> 8) + buf[2] = byte(val >> 16) + buf[3] = byte(val >> 24) + return +} + +func putBE32(val uint32, buf []byte) { + buf[0] = byte(val >> 24) + buf[1] = byte(val >> 16) + buf[2] = byte(val >> 8) + buf[3] = byte(val) + return +} + +func putLE64(val uint64, buf []byte) { + buf[0] = byte(val) + buf[1] = byte(val >> 8) + buf[2] = byte(val >> 16) + buf[3] = byte(val >> 24) + buf[4] = byte(val >> 32) + buf[5] = byte(val >> 40) + buf[6] = byte(val >> 48) + buf[7] = byte(val >> 56) + return +} diff --git a/vendor/github.com/xi2/xz/dec_xz.go b/vendor/github.com/xi2/xz/dec_xz.go new file mode 100644 index 0000000..1b18a83 --- /dev/null +++ b/vendor/github.com/xi2/xz/dec_xz.go @@ -0,0 +1,124 @@ +/* + * XZ decompressor + * + * Authors: Lasse Collin + * Igor Pavlov + * + * Translation to Go: Michael Cross + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +package xz + +/* from linux/include/linux/xz.h **************************************/ + +/** + * xzRet - Return codes + * @xzOK: Everything is OK so far. More input or more + * output space is required to continue. + * @xzStreamEnd: Operation finished successfully. + * @xzUnSupportedCheck: Integrity check type is not supported. Decoding + * is still possible by simply calling xzDecRun + * again. + * @xzMemlimitError: A bigger LZMA2 dictionary would be needed than + * allowed by the dictMax argument given to + * xzDecInit. + * @xzFormatError: File format was not recognized (wrong magic + * bytes). + * @xzOptionsError: This implementation doesn't support the requested + * compression options. In the decoder this means + * that the header CRC32 matches, but the header + * itself specifies something that we don't support. + * @xzDataError: Compressed data is corrupt. + * @xzBufError: Cannot make any progress. + * + * xzBufError is returned when two consecutive calls to XZ code cannot + * consume any input and cannot produce any new output. This happens + * when there is no new input available, or the output buffer is full + * while at least one output byte is still pending. Assuming your code + * is not buggy, you can get this error only when decoding a + * compressed stream that is truncated or otherwise corrupt. + */ +type xzRet int + +const ( + xzOK xzRet = iota + xzStreamEnd + xzUnsupportedCheck + xzMemlimitError + xzFormatError + xzOptionsError + xzDataError + xzBufError +) + +/** + * xzBuf - Passing input and output buffers to XZ code + * @in: Input buffer. + * @inPos: Current position in the input buffer. This must not exceed + * input buffer size. + * @out: Output buffer. + * @outPos: Current position in the output buffer. This must not exceed + * output buffer size. + * + * Only the contents of the output buffer from out[outPos] onward, and + * the variables inPos and outPos are modified by the XZ code. + */ +type xzBuf struct { + in []byte + inPos int + out []byte + outPos int +} + +/* All XZ filter IDs */ +type xzFilterID int64 + +const ( + idDelta xzFilterID = 0x03 + idBCJX86 xzFilterID = 0x04 + idBCJPowerPC xzFilterID = 0x05 + idBCJIA64 xzFilterID = 0x06 + idBCJARM xzFilterID = 0x07 + idBCJARMThumb xzFilterID = 0x08 + idBCJSPARC xzFilterID = 0x09 + idLZMA2 xzFilterID = 0x21 +) + +// CheckID is the type of the data integrity check in an XZ stream +// calculated from the uncompressed data. +type CheckID int + +func (id CheckID) String() string { + switch id { + case CheckNone: + return "None" + case CheckCRC32: + return "CRC32" + case CheckCRC64: + return "CRC64" + case CheckSHA256: + return "SHA256" + default: + return "Unknown" + } +} + +const ( + CheckNone CheckID = 0x00 + CheckCRC32 CheckID = 0x01 + CheckCRC64 CheckID = 0x04 + CheckSHA256 CheckID = 0x0A + checkMax CheckID = 0x0F + checkUnset CheckID = -1 +) + +// An XZ stream contains a stream header which holds information about +// the stream. That information is exposed as fields of the +// Reader. Currently it contains only the stream's data integrity +// check type. +type Header struct { + CheckType CheckID // type of the stream's data integrity check +} diff --git a/vendor/github.com/xi2/xz/doc.go b/vendor/github.com/xi2/xz/doc.go new file mode 100644 index 0000000..f8c62e6 --- /dev/null +++ b/vendor/github.com/xi2/xz/doc.go @@ -0,0 +1,35 @@ +// Package xz implements XZ decompression natively in Go. +// +// Usage +// +// For ease of use, this package is designed to have a similar API to +// compress/gzip. See the examples for further details. +// +// Implementation +// +// This package is a translation from C to Go of XZ Embedded +// (http://tukaani.org/xz/embedded.html) with enhancements made so as +// to implement all mandatory and optional parts of the XZ file format +// specification v1.0.4. It supports all filters and block check +// types, supports multiple streams, and performs index verification +// using SHA-256 as recommended by the specification. +// +// Speed +// +// On the author's Intel Ivybridge i5, decompression speed is about +// half that of the standard XZ Utils (tested with a recent linux +// kernel tarball). +// +// Thanks +// +// Thanks are due to Lasse Collin and Igor Pavlov, the authors of XZ +// Embedded, on whose code package xz is based. It would not exist +// without their decision to allow others to modify and reuse their +// code. +// +// Bug reports +// +// For bug reports relating to this package please contact the author +// through https://github.com/xi2/xz/issues, and not the authors of XZ +// Embedded. +package xz diff --git a/vendor/github.com/xi2/xz/reader.go b/vendor/github.com/xi2/xz/reader.go new file mode 100644 index 0000000..e321d75 --- /dev/null +++ b/vendor/github.com/xi2/xz/reader.go @@ -0,0 +1,256 @@ +/* + * Package xz Go Reader API + * + * Author: Michael Cross + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +package xz + +import ( + "errors" + "io" +) + +// Package specific errors. +var ( + ErrUnsupportedCheck = errors.New("xz: integrity check type not supported") + ErrMemlimit = errors.New("xz: LZMA2 dictionary size exceeds max") + ErrFormat = errors.New("xz: file format not recognized") + ErrOptions = errors.New("xz: compression options not supported") + ErrData = errors.New("xz: data is corrupt") + ErrBuf = errors.New("xz: data is truncated or corrupt") +) + +// DefaultDictMax is the default maximum dictionary size in bytes used +// by the decoder. This value is sufficient to decompress files +// created with XZ Utils "xz -9". +const DefaultDictMax = 1 << 26 // 64 MiB + +// inBufSize is the input buffer size used by the decoder. +const inBufSize = 1 << 13 // 8 KiB + +// A Reader is an io.Reader that can be used to retrieve uncompressed +// data from an XZ file. +// +// In general, an XZ file can be a concatenation of other XZ +// files. Reads from the Reader return the concatenation of the +// uncompressed data of each. +type Reader struct { + Header + r io.Reader // the wrapped io.Reader + multistream bool // true if reader is in multistream mode + rEOF bool // true after io.EOF received on r + dEOF bool // true after decoder has completed + padding int // bytes of stream padding read (or -1) + in [inBufSize]byte // backing array for buf.in + buf *xzBuf // decoder input/output buffers + dec *xzDec // decoder state + err error // the result of the last decoder call +} + +// NewReader creates a new Reader reading from r. The decompressor +// will use an LZMA2 dictionary size up to dictMax bytes in +// size. Passing a value of zero sets dictMax to DefaultDictMax. If +// an individual XZ stream requires a dictionary size greater than +// dictMax in order to decompress, Read will return ErrMemlimit. +// +// If NewReader is passed a value of nil for r then a Reader is +// created such that all read attempts will return io.EOF. This is +// useful if you just want to allocate memory for a Reader which will +// later be initialized with Reset. +// +// Due to internal buffering, the Reader may read more data than +// necessary from r. +func NewReader(r io.Reader, dictMax uint32) (*Reader, error) { + if dictMax == 0 { + dictMax = DefaultDictMax + } + z := &Reader{ + r: r, + multistream: true, + padding: -1, + buf: &xzBuf{}, + } + if r == nil { + z.rEOF, z.dEOF = true, true + } + z.dec = xzDecInit(dictMax, &z.Header) + var err error + if r != nil { + _, err = z.Read(nil) // read stream header + } + return z, err +} + +// decode is a wrapper around xzDecRun that additionally handles +// stream padding. It treats the padding as a kind of stream that +// decodes to nothing. +// +// When decoding padding, z.padding >= 0 +// When decoding a real stream, z.padding == -1 +func (z *Reader) decode() (ret xzRet) { + if z.padding >= 0 { + // read all padding in input buffer + for z.buf.inPos < len(z.buf.in) && + z.buf.in[z.buf.inPos] == 0 { + z.buf.inPos++ + z.padding++ + } + switch { + case z.buf.inPos == len(z.buf.in) && z.rEOF: + // case: out of padding. no more input data available + if z.padding%4 != 0 { + ret = xzDataError + } else { + ret = xzStreamEnd + } + case z.buf.inPos == len(z.buf.in): + // case: read more padding next loop iteration + ret = xzOK + default: + // case: out of padding. more input data available + if z.padding%4 != 0 { + ret = xzDataError + } else { + xzDecReset(z.dec) + ret = xzStreamEnd + } + } + } else { + ret = xzDecRun(z.dec, z.buf) + } + return +} + +func (z *Reader) Read(p []byte) (n int, err error) { + // restore err + err = z.err + // set decoder output buffer to p + z.buf.out = p + z.buf.outPos = 0 + for { + // update n + n = z.buf.outPos + // if last call to decoder ended with an error, return that error + if err != nil { + break + } + // if decoder has finished, return with err == io.EOF + if z.dEOF { + err = io.EOF + break + } + // if p full, return with err == nil, unless we have not yet + // read the stream header with Read(nil) + if n == len(p) && z.CheckType != checkUnset { + break + } + // if needed, read more data from z.r + if z.buf.inPos == len(z.buf.in) && !z.rEOF { + rn, e := z.r.Read(z.in[:]) + if e != nil && e != io.EOF { + // read error + err = e + break + } + if e == io.EOF { + z.rEOF = true + } + // set new input buffer in z.buf + z.buf.in = z.in[:rn] + z.buf.inPos = 0 + } + // decode more data + ret := z.decode() + switch ret { + case xzOK: + // no action needed + case xzStreamEnd: + if z.padding >= 0 { + z.padding = -1 + if !z.multistream || z.rEOF { + z.dEOF = true + } + } else { + z.padding = 0 + } + case xzUnsupportedCheck: + err = ErrUnsupportedCheck + case xzMemlimitError: + err = ErrMemlimit + case xzFormatError: + err = ErrFormat + case xzOptionsError: + err = ErrOptions + case xzDataError: + err = ErrData + case xzBufError: + err = ErrBuf + } + // save err + z.err = err + } + return +} + +// Multistream controls whether the reader is operating in multistream +// mode. +// +// If enabled (the default), the Reader expects the input to be a +// sequence of XZ streams, possibly interspersed with stream padding, +// which it reads one after another. The effect is that the +// concatenation of a sequence of XZ streams or XZ files is +// treated as equivalent to the compressed result of the concatenation +// of the sequence. This is standard behaviour for XZ readers. +// +// Calling Multistream(false) disables this behaviour; disabling the +// behaviour can be useful when reading file formats that distinguish +// individual XZ streams. In this mode, when the Reader reaches the +// end of the stream, Read returns io.EOF. To start the next stream, +// call z.Reset(nil) followed by z.Multistream(false). If there is no +// next stream, z.Reset(nil) will return io.EOF. +func (z *Reader) Multistream(ok bool) { + z.multistream = ok +} + +// Reset, for non-nil values of io.Reader r, discards the Reader z's +// state and makes it equivalent to the result of its original state +// from NewReader, but reading from r instead. This permits reusing a +// Reader rather than allocating a new one. +// +// If you wish to leave r unchanged use z.Reset(nil). This keeps r +// unchanged and ensures internal buffering is preserved. If the +// Reader was at the end of a stream it is then ready to read any +// follow on streams. If there are no follow on streams z.Reset(nil) +// returns io.EOF. If the Reader was not at the end of a stream then +// z.Reset(nil) does nothing. +func (z *Reader) Reset(r io.Reader) error { + switch { + case r == nil: + z.multistream = true + if !z.dEOF { + return nil + } + if z.rEOF { + return io.EOF + } + z.dEOF = false + _, err := z.Read(nil) // read stream header + return err + default: + z.r = r + z.multistream = true + z.rEOF = false + z.dEOF = false + z.padding = -1 + z.buf.in = nil + z.buf.inPos = 0 + xzDecReset(z.dec) + z.err = nil + _, err := z.Read(nil) // read stream header + return err + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 1036645..54d0d3d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -79,6 +79,16 @@ github.com/huandu/xstrings ## explicit; go 1.10 github.com/jmoiron/sqlx github.com/jmoiron/sqlx/reflectx +# github.com/klauspost/compress v1.19.2 +## explicit; go 1.24 +github.com/klauspost/compress +github.com/klauspost/compress/fse +github.com/klauspost/compress/huff0 +github.com/klauspost/compress/internal/cpuinfo +github.com/klauspost/compress/internal/le +github.com/klauspost/compress/internal/snapref +github.com/klauspost/compress/zstd +github.com/klauspost/compress/zstd/internal/xxhash # github.com/lib/pq v1.10.9 ## explicit; go 1.13 github.com/lib/pq @@ -139,6 +149,12 @@ github.com/tamerh/xml-stream-parser # github.com/tamerh/xpath v1.0.0 ## explicit github.com/tamerh/xpath +# github.com/tim-st/go-zim v0.1.3 +## explicit +github.com/tim-st/go-zim +# github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 +## explicit +github.com/xi2/xz # golang.org/x/crypto v0.31.0 ## explicit; go 1.20 golang.org/x/crypto/bcrypt diff --git a/zim.go b/zim.go new file mode 100644 index 0000000..f08cbd5 --- /dev/null +++ b/zim.go @@ -0,0 +1,108 @@ +package main + +import ( + "fmt" + "io" + "log" + "strings" + + zim "github.com/tim-st/go-zim" +) + +// epubMimetype is the ZIM directory-entry mimetype for a Project Gutenberg book. +const epubMimetype = "application/epub+zip" + +// readZIMBooks enumerates every EPUB entry in a ZIM archive (e.g. a Project +// Gutenberg library) and returns one BookMetadata per book. FileType, FilePath +// and SubFilepath are populated so the entry can be reopened on download. +func readZIMBooks(path string) ([]*BookMetadata, error) { + z, err := zim.Open(path) + if err != nil { + return nil, fmt.Errorf("error opening zim %q: %w", path, err) + } + defer z.Close() + + mimes := z.MimetypeList() + + // The library seeks a single shared file handle per read, so entries must be + // read sequentially rather than concurrently. + var mds []*BookMetadata + for i := range z.ArticleCount() { + e, err := z.EntryAtURLPosition(i) + if err != nil { + continue + } + if e.IsRedirect() { + continue + } + if mt := e.Mimetype(); int(mt) >= len(mimes) || mimes[mt] != epubMimetype { + continue + } + + r, _, err := z.BlobReader(&e) + if err != nil { + log.Printf("[zim] error reading blob for %q in %q: %v", string(e.URL()), path, err) + continue + } + buf, err := io.ReadAll(r) + if err != nil { + log.Printf("[zim] error reading epub bytes for %q in %q: %v", string(e.URL()), path, err) + continue + } + + md, err := readEPUBMetadataFromBytes(buf) + if err != nil { + log.Printf("[zim] error reading metadata for %q in %q: %v", string(e.URL()), path, err) + continue + } + md.FileType = ZIM + md.FilePath = path + md.SubFilepath = zimEntryRef(&e) + mds = append(mds, md) + } + + return mds, nil +} + +// openZIMEntry reopens the EPUB blob for a stored entry reference and returns +// its bytes. +func openZIMEntry(path, ref string) ([]byte, error) { + ns, url := parseZimEntryRef(ref) + + z, err := zim.Open(path) + if err != nil { + return nil, fmt.Errorf("error opening zim %q: %w", path, err) + } + defer z.Close() + + entry, _, found := z.EntryWithURL(zim.Namespace(ns), []byte(url)) + if !found { + return nil, fmt.Errorf("zim: entry %q not found in %q", ref, path) + } + if entry.IsRedirect() { + if entry, err = z.FollowRedirect(&entry); err != nil { + return nil, fmt.Errorf("zim: following redirect for %q: %w", ref, err) + } + } + + r, _, err := z.BlobReader(&entry) + if err != nil { + return nil, fmt.Errorf("zim: reading blob for %q: %w", ref, err) + } + return io.ReadAll(r) +} + +// zimEntryRef encodes an entry's namespace and URL as "/" so it +// can be looked up again later, independent of its position in the archive. +func zimEntryRef(e *zim.DirectoryEntry) string { + return fmt.Sprintf("%s/%s", e.Namespace().String(), string(e.URL())) +} + +func parseZimEntryRef(ref string) (namespace byte, url string) { + // The namespace is a single character followed by '/', then the URL (which + // may itself contain '/'). + if i := strings.IndexByte(ref, '/'); i > 0 { + return ref[0], ref[i+1:] + } + return 'C', ref +} diff --git a/zim_test.go b/zim_test.go new file mode 100644 index 0000000..676e5cb --- /dev/null +++ b/zim_test.go @@ -0,0 +1,147 @@ +package main + +import ( + "context" + "io" + "os" + "path/filepath" + "strings" + "testing" + "time" + "unicode" + + "github.com/jmoiron/sqlx" + _ "github.com/mattn/go-sqlite3" + migrate "github.com/rubenv/sql-migrate" +) + +// zimFixture is a small Project Gutenberg ZIM archive kept in testdata. See +// testdata/README.md for provenance. +const zimFixture = "testdata/gutenberg_csb_all_2025-10.zim" + +func TestReadZIMBooks(t *testing.T) { + books, err := readZIMBooks(zimFixture) + if err != nil { + t.Fatalf("readZIMBooks: %v", err) + } + if len(books) == 0 { + t.Fatalf("no books found in %q", zimFixture) + } + t.Logf("indexed %d books", len(books)) + + for _, b := range books { + if b.FileType != ZIM { + t.Errorf("book %q: FileType = %q, want %q", b.Title, b.FileType, ZIM) + } + if b.Title == "" { + t.Errorf("book with ref %q has empty title", b.SubFilepath) + } + if !strings.Contains(b.SubFilepath, "/") { + t.Errorf("book %q: SubFilepath %q missing namespace prefix", b.Title, b.SubFilepath) + } + } + + // Round-trip: reopen the first book's blob and confirm it is a zip (EPUB). + buf, err := openZIMEntry(zimFixture, books[0].SubFilepath) + if err != nil { + t.Fatalf("openZIMEntry(%q): %v", books[0].SubFilepath, err) + } + if len(buf) < 4 || string(buf[:2]) != "PK" { + t.Fatalf("book blob is not a zip/epub (head=%x)", buf[:min(4, len(buf))]) + } +} + +func TestServiceIndexesZIM(t *testing.T) { + books, err := readZIMBooks(zimFixture) + if err != nil { + t.Fatalf("readZIMBooks: %v", err) + } + token, want := searchableToken(books) + if token == "" { + t.Fatalf("fixture has no book with a searchable title word") + } + + db := sqlx.MustConnect("sqlite3", ":memory:") + store := NewSqliteStore(db) + if _, err := migrate.Exec(db.DB, "sqlite3", &migrate.FileMigrationSource{Dir: "./db/migrations"}, migrate.Up); err != nil { + t.Fatalf("migrations: %v", err) + } + + // Copy the fixture into an isolated dir so the scanner sees only the ZIM. + tempDir := t.TempDir() + copyFile(t, zimFixture, filepath.Join(tempDir, "gutenberg.zim")) + + svc, err := NewService(tempDir, store) + if err != nil { + t.Fatalf("NewService: %v", err) + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + if err := svc.Run(ctx); err != nil { + t.Fatalf("Run: %v", err) + } + if err := svc.Scan(ctx); err != nil { + t.Fatalf("Scan: %v", err) + } + + var found *BookMetadata + eventually(t, 10*time.Second, 200*time.Millisecond, func() (bool, error) { + res, err := svc.Search(ctx, token) + if err != nil { + return false, err + } + for _, b := range res { + if b.Title == want { + found = b + return true, nil + } + } + return false, nil + }) + + reader, cleanup, err := svc.GetBook(ctx, found.ID, EPUB) + if err != nil { + t.Fatalf("GetBook: %v", err) + } + defer cleanup() + head := make([]byte, 4) + if _, err := io.ReadFull(reader, head); err != nil { + t.Fatalf("read book: %v", err) + } + if string(head[:2]) != "PK" { + t.Fatalf("served book is not an epub (head=%x)", head) + } +} + +func copyFile(t *testing.T, src, dst string) { + t.Helper() + b, err := os.ReadFile(src) + if err != nil { + t.Fatalf("read %q: %v", src, err) + } + if err := os.WriteFile(dst, b, 0o644); err != nil { + t.Fatalf("write %q: %v", dst, err) + } +} + +// searchableToken finds a book whose title contains an ASCII-letter word of at +// least 4 characters and returns that word plus the book's full title. +func searchableToken(books []*BookMetadata) (token, title string) { + for _, b := range books { + for _, word := range strings.FieldsFunc(b.Title, func(r rune) bool { return !unicode.IsLetter(r) }) { + if len(word) >= 4 && isASCIILetters(word) { + return word, b.Title + } + } + } + return "", "" +} + +func isASCIILetters(s string) bool { + for _, r := range s { + if r > unicode.MaxASCII || !unicode.IsLetter(r) { + return false + } + } + return true +} From 3dcd57e1c19a4fab2e1d8591c2dba1d62312801d Mon Sep 17 00:00:00 2001 From: Andrew Zhu Date: Wed, 12 Aug 2026 02:21:36 +0400 Subject: [PATCH 03/14] Add script to sync English Gutenberg ZIM archives from Kiwix scripts/sync_gutenberg_en.py (stdlib only) reads the Kiwix Gutenberg directory listing and downloads the English archives you are missing: - English (gutenberg_en_*) only, newest version of each variant. - Skips archives already present locally. - Skips an lcc-* split when a same-or-newer -all archive is present (or will be downloaded this run), since a full -all already contains it; pass --include-superseded to fetch them anyway. - Resumable downloads (.part file + HTTP Range), which survives the mirror redirect. Supports --dir, --base-url, --dry-run, --include-superseded, --timeout. Co-Authored-By: Claude Opus 4.8 --- scripts/sync_gutenberg_en.py | 251 +++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100755 scripts/sync_gutenberg_en.py diff --git a/scripts/sync_gutenberg_en.py b/scripts/sync_gutenberg_en.py new file mode 100755 index 0000000..94e9c57 --- /dev/null +++ b/scripts/sync_gutenberg_en.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 +"""Download English Project Gutenberg ZIM archives from the Kiwix mirror. + +Standard library only. + +It looks at the Kiwix Gutenberg directory listing and, for the English +(``gutenberg_en_*``) archives, downloads what you are missing according to a +few rules: + +* English only (``gutenberg_en_all_*`` and ``gutenberg_en_lcc-*``). +* Only the newest version of each archive (e.g. ``lcc-p_2026-03`` supersedes + ``lcc-p_2025-12``). +* Skip anything already present in the target directory. +* Skip an ``lcc-*`` split when a ``-all`` archive you already have (or are about + to download in this run) is at least as new, because a full ``-all`` archive + already contains that split's books. In other words: an ``lcc-*`` split is + only worth downloading if it is *newer* than your newest ``-all``. + + (If you actually want the superseded splits too, pass ``--include-superseded``.) + +Downloads are resumable: interrupted files land in ``.zim.part`` and are +continued via an HTTP Range request on the next run. + +Examples: + # Preview what would be downloaded into the current directory: + ./sync_gutenberg_en.py --dry-run + + # Download missing English archives into /data/zim: + ./sync_gutenberg_en.py --dir /data/zim +""" + +import argparse +import os +import re +import sys +import urllib.request + +BASE_URL = "https://lb.download.kiwix.org/zim/gutenberg/" +LANG = "en" +USER_AGENT = "bookworm-gutenberg-sync/1.0" + +# gutenberg___.zim where variant is "all" or "lcc-" +NAME_RE = re.compile(r"^gutenberg_([a-z0-9-]+)_(all|lcc-[a-z]+)_(\d{4}-\d{2})\.zim$") + + +class Archive: + __slots__ = ("filename", "lang", "variant", "date") + + def __init__(self, filename, lang, variant, date): + self.filename = filename + self.lang = lang + self.variant = variant + self.date = date # "YYYY-MM"; lexicographic order == chronological order + + def __repr__(self): + return self.filename + + +def parse_name(filename): + m = NAME_RE.match(filename) + if not m: + return None + return Archive(filename, m.group(1), m.group(2), m.group(3)) + + +def http_get(url, timeout=60): + req = urllib.request.Request(url, headers={"User-Agent": USER_AGENT}) + return urllib.request.urlopen(req, timeout=timeout) + + +def list_remote(base_url, timeout=60): + """Return {variant: Archive} keeping only the newest English archive per variant.""" + with http_get(base_url, timeout=timeout) as resp: + html = resp.read().decode("utf-8", "replace") + + latest = {} + for filename in re.findall(r'href="(gutenberg_[^"]+\.zim)"', html): + arc = parse_name(filename) + if arc is None or arc.lang != LANG: + continue + cur = latest.get(arc.variant) + if cur is None or arc.date > cur.date: + latest[arc.variant] = arc + return latest + + +def scan_local(directory): + """Scan the target directory for English archives already on disk. + + Return ``(present_filenames, local_newest)`` where ``local_newest`` maps each + variant to the newest date present locally (so a remote archive can be + recognised as superseded by a newer local copy of the same variant). + """ + present = set() + local_newest = {} + try: + entries = os.listdir(directory) + except FileNotFoundError: + entries = [] + for name in entries: + arc = parse_name(name) + if arc is None or arc.lang != LANG: + continue + present.add(name) + cur = local_newest.get(arc.variant) + if cur is None or arc.date > cur: + local_newest[arc.variant] = arc.date + return present, local_newest + + +def plan(remote, present, local_newest, include_superseded): + """Yield (action, archive, reason) for every candidate, action in {download, skip}.""" + remote_all = remote.get("all") + + # The best -all we will have after this run: the newest of what's on disk and + # the newest -all we're going to download. + effective_all = local_newest.get("all") + if remote_all is not None and (effective_all is None or remote_all.date > effective_all): + effective_all = remote_all.date + + for variant in sorted(remote): + arc = remote[variant] + if arc.filename in present: + yield "skip", arc, "already present" + continue + have_date = local_newest.get(variant) + if have_date is not None and have_date >= arc.date: + # A same-or-newer copy of this exact variant is already on disk. + yield "skip", arc, "newer local copy (%s)" % have_date + continue + if ( + variant != "all" + and not include_superseded + and effective_all is not None + and arc.date <= effective_all + ): + yield "skip", arc, "covered by newer -all (%s)" % effective_all + continue + yield "download", arc, "missing" + + +def human(nbytes): + n = float(nbytes) + for unit in ("B", "KiB", "MiB", "GiB", "TiB"): + if n < 1024 or unit == "TiB": + return "%.1f %s" % (n, unit) + n /= 1024 + + +def download(url, dst, timeout=60): + """Download url to dst with resume support via a .part file.""" + part = dst + ".part" + have = os.path.getsize(part) if os.path.exists(part) else 0 + + headers = {"User-Agent": USER_AGENT} + if have: + headers["Range"] = "bytes=%d-" % have + + req = urllib.request.Request(url, headers=headers) + with urllib.request.urlopen(req, timeout=timeout) as resp: + resuming = resp.status == 206 and resp.headers.get("Content-Range") + if have and not resuming: + # Server ignored our Range; start over from scratch. + have = 0 + + remaining = resp.headers.get("Content-Length") + total = (have + int(remaining)) if remaining is not None else None + + mode = "ab" if have else "wb" + downloaded = have + with open(part, mode) as f: + while True: + chunk = resp.read(1024 * 256) + if not chunk: + break + f.write(chunk) + downloaded += len(chunk) + if total: + pct = 100.0 * downloaded / total + msg = "\r %s / %s (%.1f%%)" % (human(downloaded), human(total), pct) + else: + msg = "\r %s" % human(downloaded) + sys.stderr.write(msg) + sys.stderr.flush() + sys.stderr.write("\n") + os.replace(part, dst) + + +def main(argv=None): + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--dir", default=os.getcwd(), + help="target directory for the archives (default: current dir)") + parser.add_argument("--base-url", default=BASE_URL, + help="Kiwix Gutenberg directory URL") + parser.add_argument("--dry-run", action="store_true", + help="print the plan without downloading anything") + parser.add_argument("--include-superseded", action="store_true", + help="also download lcc-* splits older than a local -all " + "(by default those are skipped)") + parser.add_argument("--timeout", type=int, default=60, + help="socket timeout in seconds (default: 60)") + args = parser.parse_args(argv) + + try: + remote = list_remote(args.base_url, timeout=args.timeout) + except OSError as e: + print("error: could not fetch listing from %s: %s" % (args.base_url, e), file=sys.stderr) + return 1 + + if not remote: + print("no English archives found at %s" % args.base_url, file=sys.stderr) + return 1 + + present, local_newest = scan_local(args.dir) + if local_newest.get("all"): + print("newest local -all: %s" % local_newest["all"]) + + to_download = [] + for action, arc, reason in plan(remote, present, local_newest, args.include_superseded): + mark = "DOWNLOAD" if action == "download" else "skip " + print("%s %-40s %s" % (mark, arc.filename, reason)) + if action == "download": + to_download.append(arc) + + if not to_download: + print("\nnothing to download.") + return 0 + + if args.dry_run: + print("\n%d archive(s) would be downloaded (dry run)." % len(to_download)) + return 0 + + os.makedirs(args.dir, exist_ok=True) + print("\ndownloading %d archive(s) into %s" % (len(to_download), args.dir)) + failures = 0 + for arc in to_download: + url = args.base_url.rstrip("/") + "/" + arc.filename + dst = os.path.join(args.dir, arc.filename) + print("%s" % arc.filename) + try: + download(url, dst, timeout=args.timeout) + except OSError as e: + failures += 1 + print(" failed: %s" % e, file=sys.stderr) + + return 1 if failures else 0 + + +if __name__ == "__main__": + sys.exit(main()) From e8f22dbfad3c4ca01f9ebbb7fb98d941d7b3a939 Mon Sep 17 00:00:00 2001 From: Andrew Zhu Date: Wed, 12 Aug 2026 02:38:06 +0400 Subject: [PATCH 04/14] Bump all dependencies to latest Run `go get -u ./...` + tidy + vendor. Notable direct/indirect bumps: mattn/go-sqlite3 1.14.24->1.14.49, rubenv/sql-migrate 1.7.1->1.8.1, golang.org/x/crypto 0.31->0.55, go-sql-driver/mysql 1.8.1->1.10.0, google.golang.org/protobuf 1.35.2->1.36.12. The `go` directive stays at 1.26.5 (no dependency requires newer). Build, vet, fmt and the non-conversion test suite pass. Co-Authored-By: Claude Opus 4.8 --- go.mod | 53 +- go.sum | 118 +- vendor/dario.cat/mergo/FUNDING.json | 7 + vendor/dario.cat/mergo/README.md | 5 - vendor/dario.cat/mergo/SECURITY.md | 4 +- vendor/filippo.io/edwards25519/README.md | 6 +- vendor/filippo.io/edwards25519/doc.go | 6 +- vendor/filippo.io/edwards25519/extra.go | 68 +- vendor/filippo.io/edwards25519/field/fe.go | 34 +- .../filippo.io/edwards25519/field/fe_amd64.go | 3 +- .../filippo.io/edwards25519/field/fe_amd64.s | 203 +- .../edwards25519/field/fe_amd64_noasm.go | 3 +- .../filippo.io/edwards25519/field/fe_arm64.go | 16 - .../filippo.io/edwards25519/field/fe_arm64.s | 42 - .../edwards25519/field/fe_arm64_noasm.go | 12 - .../edwards25519/field/fe_generic.go | 170 +- vendor/filippo.io/edwards25519/pull.sh | 53 + vendor/filippo.io/edwards25519/scalar.go | 27 +- vendor/filippo.io/edwards25519/tables.go | 4 +- .../Masterminds/semver/v3/.gitignore | 3 +- .../Masterminds/semver/v3/.golangci.yml | 55 +- .../Masterminds/semver/v3/CHANGELOG.md | 28 +- .../Masterminds/semver/v3/README.md | 18 +- .../Masterminds/semver/v3/constraints.go | 217 +- .../Masterminds/semver/v3/version.go | 202 +- .../VictoriaMetrics/easyproto/LICENSE | 190 + .../VictoriaMetrics/easyproto/README.md | 232 + .../VictoriaMetrics/easyproto/doc.go | 3 + .../VictoriaMetrics/easyproto/reader.go | 1233 + .../VictoriaMetrics/easyproto/writer.go | 718 + .../github.com/cespare/xxhash/v2/LICENSE.txt | 22 + vendor/github.com/cespare/xxhash/v2/README.md | 74 + .../github.com/cespare/xxhash/v2/testall.sh | 10 + vendor/github.com/cespare/xxhash/v2/xxhash.go | 243 + .../cespare/xxhash/v2/xxhash_amd64.s | 209 + .../cespare/xxhash/v2/xxhash_arm64.s | 183 + .../cespare/xxhash/v2/xxhash_asm.go | 15 + .../cespare/xxhash/v2/xxhash_other.go | 76 + .../cespare/xxhash/v2/xxhash_safe.go | 16 + .../cespare/xxhash/v2/xxhash_unsafe.go | 58 + .../clipperhouse/displaywidth/.gitignore | 3 + .../clipperhouse/displaywidth/AGENTS.md | 51 + .../clipperhouse/displaywidth/CHANGELOG.md | 129 + .../displaywidth/LICENSE} | 2 +- .../clipperhouse/displaywidth/README.md | 190 + .../clipperhouse/displaywidth/gen.go | 3 + .../clipperhouse/displaywidth/graphemes.go | 73 + .../clipperhouse/displaywidth/options.go | 30 + .../clipperhouse/displaywidth/trie.go | 1699 + .../clipperhouse/displaywidth/truncate.go | 149 + .../clipperhouse/displaywidth/width.go | 239 + .../github.com/clipperhouse/uax29/v2/LICENSE | 21 + .../clipperhouse/uax29/v2/graphemes/README.md | 120 + .../clipperhouse/uax29/v2/graphemes/ansi.go | 138 + .../clipperhouse/uax29/v2/graphemes/ansi8.go | 79 + .../uax29/v2/graphemes/iterator.go | 144 + .../clipperhouse/uax29/v2/graphemes/reader.go | 25 + .../uax29/v2/graphemes/splitfunc.go | 205 + .../clipperhouse/uax29/v2/graphemes/trie.go | 1717 + vendor/github.com/fatih/color/color.go | 112 +- .../github.com/fatih/color/color_windows.go | 3 + .../github.com/fsnotify/fsnotify/.cirrus.yml | 14 - .../github.com/fsnotify/fsnotify/CHANGELOG.md | 84 +- .../fsnotify/fsnotify/CONTRIBUTING.md | 3 + vendor/github.com/fsnotify/fsnotify/README.md | 58 +- .../fsnotify/fsnotify/backend_fen.go | 111 +- .../fsnotify/fsnotify/backend_inotify.go | 465 +- .../fsnotify/fsnotify/backend_kqueue.go | 180 +- .../fsnotify/fsnotify/backend_other.go | 5 +- .../fsnotify/fsnotify/backend_windows.go | 100 +- .../github.com/fsnotify/fsnotify/fsnotify.go | 82 +- .../fsnotify/fsnotify/internal/darwin.go | 23 +- .../fsnotify/internal/debug_darwin.go | 42 - .../fsnotify/internal/debug_dragonfly.go | 18 - .../fsnotify/internal/debug_freebsd.go | 34 +- .../fsnotify/internal/debug_kqueue.go | 2 +- .../fsnotify/internal/debug_netbsd.go | 10 - .../fsnotify/internal/debug_openbsd.go | 12 - .../fsnotify/fsnotify/internal/freebsd.go | 15 +- .../fsnotify/fsnotify/internal/unix.go | 17 +- .../fsnotify/fsnotify/internal/unix2.go | 18 + .../fsnotify/fsnotify/internal/windows.go | 5 +- vendor/github.com/fsnotify/fsnotify/shared.go | 64 + .../fsnotify/fsnotify/staticcheck.conf | 3 + .../github.com/go-logfmt/logfmt/CHANGELOG.md | 10 + vendor/github.com/go-logfmt/logfmt/encode.go | 24 +- .../github.com/go-logfmt/logfmt/jsonstring.go | 8 +- vendor/github.com/go-sql-driver/mysql/AUTHORS | 21 +- .../go-sql-driver/mysql/CHANGELOG.md | 65 + .../github.com/go-sql-driver/mysql/README.md | 21 +- .../go-sql-driver/mysql/atomic_bool.go | 19 - .../go-sql-driver/mysql/atomic_bool_go118.go | 47 - vendor/github.com/go-sql-driver/mysql/auth.go | 2 +- .../github.com/go-sql-driver/mysql/buffer.go | 139 +- .../go-sql-driver/mysql/collations.go | 2 +- .../go-sql-driver/mysql/compress.go | 213 + .../go-sql-driver/mysql/conncheck.go | 1 - .../go-sql-driver/mysql/conncheck_dummy.go | 1 - .../go-sql-driver/mysql/connection.go | 450 +- .../go-sql-driver/mysql/connector.go | 76 +- .../github.com/go-sql-driver/mysql/const.go | 28 +- vendor/github.com/go-sql-driver/mysql/dsn.go | 65 +- .../github.com/go-sql-driver/mysql/errors.go | 4 +- .../github.com/go-sql-driver/mysql/fields.go | 42 +- .../github.com/go-sql-driver/mysql/infile.go | 21 +- .../github.com/go-sql-driver/mysql/packets.go | 657 +- .../github.com/go-sql-driver/mysql/result.go | 6 +- vendor/github.com/go-sql-driver/mysql/rows.go | 17 +- .../go-sql-driver/mysql/statement.go | 47 +- .../go-sql-driver/mysql/transaction.go | 18 +- .../github.com/go-sql-driver/mysql/utils.go | 198 +- 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 | 86 + vendor/github.com/goccy/go-json/CHANGELOG.md | 425 + 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 | 263 + .../goccy/go-json/docker-compose.yml | 13 + vendor/github.com/goccy/go-json/encode.go | 326 + vendor/github.com/goccy/go-json/error.go | 41 + .../internal/decoder/anonymous_field.go | 41 + .../goccy/go-json/internal/decoder/array.go | 176 + .../goccy/go-json/internal/decoder/assign.go | 438 + .../goccy/go-json/internal/decoder/bool.go | 83 + .../goccy/go-json/internal/decoder/bytes.go | 118 + .../goccy/go-json/internal/decoder/compile.go | 493 + .../internal/decoder/compile_norace.go | 30 + .../go-json/internal/decoder/compile_race.go | 38 + .../goccy/go-json/internal/decoder/context.go | 254 + .../goccy/go-json/internal/decoder/float.go | 170 + .../goccy/go-json/internal/decoder/func.go | 146 + .../goccy/go-json/internal/decoder/int.go | 246 + .../go-json/internal/decoder/interface.go | 528 + .../goccy/go-json/internal/decoder/invalid.go | 55 + .../goccy/go-json/internal/decoder/map.go | 280 + .../goccy/go-json/internal/decoder/number.go | 123 + .../goccy/go-json/internal/decoder/option.go | 17 + .../goccy/go-json/internal/decoder/path.go | 670 + .../goccy/go-json/internal/decoder/ptr.go | 97 + .../goccy/go-json/internal/decoder/slice.go | 380 + .../goccy/go-json/internal/decoder/stream.go | 556 + .../goccy/go-json/internal/decoder/string.go | 452 + .../goccy/go-json/internal/decoder/struct.go | 845 + .../goccy/go-json/internal/decoder/type.go | 30 + .../goccy/go-json/internal/decoder/uint.go | 194 + .../internal/decoder/unmarshal_json.go | 104 + .../internal/decoder/unmarshal_text.go | 285 + .../internal/decoder/wrapped_string.go | 73 + .../goccy/go-json/internal/encoder/code.go | 1024 + .../goccy/go-json/internal/encoder/compact.go | 286 + .../go-json/internal/encoder/compiler.go | 939 + .../internal/encoder/compiler_norace.go | 33 + .../go-json/internal/encoder/compiler_race.go | 46 + .../goccy/go-json/internal/encoder/context.go | 105 + .../go-json/internal/encoder/decode_rune.go | 126 + .../goccy/go-json/internal/encoder/encoder.go | 601 + .../goccy/go-json/internal/encoder/indent.go | 211 + .../goccy/go-json/internal/encoder/int.go | 176 + .../goccy/go-json/internal/encoder/map112.go | 9 + .../goccy/go-json/internal/encoder/map113.go | 9 + .../goccy/go-json/internal/encoder/opcode.go | 752 + .../goccy/go-json/internal/encoder/option.go | 48 + .../goccy/go-json/internal/encoder/optype.go | 932 + .../goccy/go-json/internal/encoder/query.go | 135 + .../goccy/go-json/internal/encoder/string.go | 483 + .../go-json/internal/encoder/string_table.go | 415 + .../go-json/internal/encoder/vm/debug_vm.go | 41 + .../goccy/go-json/internal/encoder/vm/hack.go | 9 + .../goccy/go-json/internal/encoder/vm/util.go | 207 + .../goccy/go-json/internal/encoder/vm/vm.go | 4859 +++ .../internal/encoder/vm_color/debug_vm.go | 35 + .../go-json/internal/encoder/vm_color/hack.go | 9 + .../go-json/internal/encoder/vm_color/util.go | 274 + .../go-json/internal/encoder/vm_color/vm.go | 4859 +++ .../encoder/vm_color_indent/debug_vm.go | 35 + .../internal/encoder/vm_color_indent/util.go | 297 + .../internal/encoder/vm_color_indent/vm.go | 4859 +++ .../internal/encoder/vm_indent/debug_vm.go | 35 + .../internal/encoder/vm_indent/hack.go | 9 + .../internal/encoder/vm_indent/util.go | 230 + .../go-json/internal/encoder/vm_indent/vm.go | 4859 +++ .../goccy/go-json/internal/errors/error.go | 183 + .../goccy/go-json/internal/runtime/rtype.go | 262 + .../go-json/internal/runtime/struct_field.go | 91 + .../goccy/go-json/internal/runtime/type.go | 98 + vendor/github.com/goccy/go-json/json.go | 368 + vendor/github.com/goccy/go-json/option.go | 79 + vendor/github.com/goccy/go-json/path.go | 84 + vendor/github.com/goccy/go-json/query.go | 47 + vendor/github.com/godror/godror/CHANGELOG.md | 80 +- vendor/github.com/godror/godror/LICENSE.md | 2 +- vendor/github.com/godror/godror/README.md | 28 +- vendor/github.com/godror/godror/batch.go | 38 +- vendor/github.com/godror/godror/conn.go | 157 +- vendor/github.com/godror/godror/data.go | 75 +- vendor/github.com/godror/godror/drv.go | 108 +- vendor/github.com/godror/godror/drv_go24.go | 228 + vendor/github.com/godror/godror/dsn/dsn.go | 281 +- vendor/github.com/godror/godror/json.go | 118 +- vendor/github.com/godror/godror/lob.go | 124 +- vendor/github.com/godror/godror/log.go | 2 +- vendor/github.com/godror/godror/number.go | 2 +- vendor/github.com/godror/godror/obj.go | 853 +- .../github.com/godror/godror/odpi/LICENSE.txt | 2 +- .../godror/godror/odpi/include/dpi.h | 85 +- .../godror/godror/odpi/src/dpiConn.c | 459 +- .../godror/godror/odpi/src/dpiContext.c | 85 +- .../godror/godror/odpi/src/dpiData.c | 19 +- .../godror/godror/odpi/src/dpiDeqOptions.c | 25 +- .../godror/godror/odpi/src/dpiError.c | 21 +- .../godror/godror/odpi/src/dpiErrorMessages.h | 4 +- .../godror/godror/odpi/src/dpiGen.c | 4 +- .../godror/godror/odpi/src/dpiGlobal.c | 28 +- .../godror/godror/odpi/src/dpiHandleList.c | 25 +- .../godror/godror/odpi/src/dpiImpl.h | 118 +- .../godror/godror/odpi/src/dpiLob.c | 5 +- .../godror/godror/odpi/src/dpiMsgProps.c | 23 +- .../godror/godror/odpi/src/dpiObject.c | 12 +- .../godror/godror/odpi/src/dpiObjectAttr.c | 14 +- .../godror/godror/odpi/src/dpiObjectType.c | 26 +- .../godror/godror/odpi/src/dpiOci.c | 511 +- .../godror/godror/odpi/src/dpiOracleType.c | 9 +- .../godror/godror/odpi/src/dpiQueue.c | 6 +- .../godror/godror/odpi/src/dpiSodaDb.c | 22 +- .../godror/godror/odpi/src/dpiStmt.c | 116 +- .../godror/godror/odpi/src/dpiSubscr.c | 19 +- .../godror/godror/odpi/src/dpiUtils.c | 55 + .../godror/godror/odpi/src/dpiVar.c | 75 +- .../godror/godror/odpi/src/dpiVector.c | 47 +- vendor/github.com/godror/godror/orahlp.go | 38 +- vendor/github.com/godror/godror/queue.go | 285 +- vendor/github.com/godror/godror/rows.go | 79 +- .../godror/godror/slog/expslog_go1.21.go | 1 + vendor/github.com/godror/godror/stmt.go | 1069 +- vendor/github.com/godror/godror/subscr.go | 20 +- vendor/github.com/godror/godror/tznames.go | 147 + .../godror/godror/tznames_generated.txt | 4 +- vendor/github.com/godror/godror/vector.go | 159 + vendor/github.com/godror/godror/version.go | 21 +- .../godror/knownpb/timestamppb/timestamp.go | 168 +- .../knownpb/timestamppb/timestamp_vtproto.go | 162 - vendor/github.com/lib/pq/.gitattributes | 1 + vendor/github.com/lib/pq/CHANGELOG.md | 265 + vendor/github.com/lib/pq/LICENSE | 21 + vendor/github.com/lib/pq/LICENSE.md | 8 - vendor/github.com/lib/pq/README.md | 328 +- vendor/github.com/lib/pq/TESTS.md | 33 - vendor/github.com/lib/pq/array.go | 72 +- vendor/github.com/lib/pq/as.go | 26 + vendor/github.com/lib/pq/as_go126.go | 23 + vendor/github.com/lib/pq/buf.go | 19 +- vendor/github.com/lib/pq/compose.yaml | 89 + vendor/github.com/lib/pq/conn.go | 2182 +- vendor/github.com/lib/pq/conn_go115.go | 8 - vendor/github.com/lib/pq/conn_go18.go | 97 +- vendor/github.com/lib/pq/connector.go | 1175 +- vendor/github.com/lib/pq/copy.go | 195 +- vendor/github.com/lib/pq/deprecated.go | 133 + vendor/github.com/lib/pq/doc.go | 269 +- vendor/github.com/lib/pq/encode.go | 590 +- vendor/github.com/lib/pq/error.go | 659 +- .../lib/pq/internal/pgpass/pgpass.go | 70 + .../lib/pq/internal/pgservice/pgservice.go | 70 + .../github.com/lib/pq/internal/pqsql/copy.go | 37 + .../github.com/lib/pq/internal/pqtime/loc.go | 37 + .../lib/pq/internal/pqtime/pqtime.go | 190 + .../github.com/lib/pq/internal/pqutil/path.go | 91 + .../github.com/lib/pq/internal/pqutil/perm.go | 64 + .../pq/internal/pqutil/perm_unsupported.go | 12 + .../lib/pq/internal/pqutil/pqutil.go | 32 + .../lib/pq/internal/pqutil/user_other.go | 9 + .../lib/pq/internal/pqutil/user_posix.go | 25 + .../lib/pq/internal/pqutil/user_windows.go | 28 + .../github.com/lib/pq/internal/proto/proto.go | 186 + .../github.com/lib/pq/internal/proto/sz_32.go | 7 + .../github.com/lib/pq/internal/proto/sz_64.go | 7 + vendor/github.com/lib/pq/notice.go | 9 +- vendor/github.com/lib/pq/notify.go | 372 +- vendor/github.com/lib/pq/oid/doc.go | 5 +- vendor/github.com/lib/pq/pqerror/codes.go | 581 + vendor/github.com/lib/pq/pqerror/pqerror.go | 35 + vendor/github.com/lib/pq/quote.go | 71 + vendor/github.com/lib/pq/rows.go | 202 +- vendor/github.com/lib/pq/scram/scram.go | 27 +- vendor/github.com/lib/pq/ssl.go | 340 +- vendor/github.com/lib/pq/ssl_permissions.go | 93 - vendor/github.com/lib/pq/ssl_windows.go | 10 - vendor/github.com/lib/pq/staticcheck.conf | 5 + vendor/github.com/lib/pq/stmt.go | 150 + vendor/github.com/lib/pq/url.go | 76 - vendor/github.com/lib/pq/user_other.go | 10 - vendor/github.com/lib/pq/user_posix.go | 25 - vendor/github.com/lib/pq/user_windows.go | 27 - vendor/github.com/lib/pq/uuid.go | 23 - .../mattn/go-colorable/colorable_appengine.go | 38 - .../mattn/go-colorable/colorable_others.go | 4 +- .../mattn/go-colorable/colorable_windows.go | 44 +- .../mattn/go-isatty/isatty_others.go | 4 +- ...{isatty_tcgets.go => isatty_tiocgwinsz.go} | 6 +- .../mattn/go-isatty/isatty_windows.go | 15 +- .../github.com/mattn/go-runewidth/SECURITY.md | 25 + .../mattn/go-runewidth/benchstat.txt | 43 + vendor/github.com/mattn/go-runewidth/new.txt | 54 + vendor/github.com/mattn/go-runewidth/old.txt | 54 + .../mattn/go-runewidth/runewidth.go | 367 +- .../mattn/go-runewidth/runewidth_table.go | 758 +- .../mattn/go-runewidth/runewidth_windows.go | 6 + .../mattn/go-sqlite3/.coderabbit.yaml | 15 + vendor/github.com/mattn/go-sqlite3/README.md | 27 +- .../github.com/mattn/go-sqlite3/SECURITY.md | 33 + .../github.com/mattn/go-sqlite3/callback.go | 135 +- .../mattn/go-sqlite3/sqlite3-binding.c | 31621 +++++++++++----- .../mattn/go-sqlite3/sqlite3-binding.h | 1716 +- vendor/github.com/mattn/go-sqlite3/sqlite3.go | 917 +- .../mattn/go-sqlite3/sqlite3_context.go | 13 +- .../go-sqlite3/sqlite3_load_extension.go | 6 +- .../go-sqlite3/sqlite3_opt_column_metadata.go | 2 +- .../mattn/go-sqlite3/sqlite3_opt_dbstat.go | 15 + .../go-sqlite3/sqlite3_opt_percentile.go | 15 + .../go-sqlite3/sqlite3_opt_preupdate_hook.go | 8 +- .../mattn/go-sqlite3/sqlite3_opt_serialize.go | 21 +- .../go-sqlite3/sqlite3_opt_unlock_notify.c | 4 + .../go-sqlite3/sqlite3_opt_unlock_notify.go | 7 +- .../mattn/go-sqlite3/sqlite3_opt_userauth.go | 153 +- .../mattn/go-sqlite3/sqlite3_opt_vtable.go | 105 +- .../{sqlite3_go18.go => sqlite3_sql.go} | 7 +- .../github.com/mattn/go-sqlite3/sqlite3ext.h | 20 + vendor/github.com/olekukonko/cat/.gitignore | 3 + vendor/github.com/olekukonko/cat/LICENSE | 21 + vendor/github.com/olekukonko/cat/README.md | 168 + vendor/github.com/olekukonko/cat/builder.go | 124 + vendor/github.com/olekukonko/cat/cat.go | 117 + vendor/github.com/olekukonko/cat/concat.go | 590 + vendor/github.com/olekukonko/cat/fn.go | 376 + vendor/github.com/olekukonko/cat/sql.go | 161 + .../github.com/olekukonko/errors/.gitignore | 3 + vendor/github.com/olekukonko/errors/LICENSE | 21 + vendor/github.com/olekukonko/errors/README.md | 613 + vendor/github.com/olekukonko/errors/base.go | 178 + vendor/github.com/olekukonko/errors/chain.go | 645 + vendor/github.com/olekukonko/errors/chan.go | 309 + vendor/github.com/olekukonko/errors/errors.go | 1403 + .../github.com/olekukonko/errors/generic.go | 150 + vendor/github.com/olekukonko/errors/group.go | 119 + vendor/github.com/olekukonko/errors/helper.go | 464 + vendor/github.com/olekukonko/errors/http.go | 117 + .../github.com/olekukonko/errors/inspect.go | 215 + .../olekukonko/errors/multi_error.go | 433 + vendor/github.com/olekukonko/errors/pool.go | 79 + .../olekukonko/errors/pool_above_1_24.go | 30 + .../olekukonko/errors/pool_below_1_24.go | 30 + vendor/github.com/olekukonko/errors/retry.go | 368 + .../github.com/olekukonko/errors/sentinel.go | 135 + vendor/github.com/olekukonko/errors/utils.go | 170 + vendor/github.com/olekukonko/ll/.gitignore | 5 + .../github.com/olekukonko/ll/.goreleaser.yaml | 37 + vendor/github.com/olekukonko/ll/LICENSE | 21 + vendor/github.com/olekukonko/ll/Makefile | 99 + vendor/github.com/olekukonko/ll/README.md | 417 + vendor/github.com/olekukonko/ll/comb.hcl | 12 + .../github.com/olekukonko/ll/conditional.go | 475 + vendor/github.com/olekukonko/ll/dbg.go | 282 + vendor/github.com/olekukonko/ll/field.go | 370 + vendor/github.com/olekukonko/ll/global.go | 707 + vendor/github.com/olekukonko/ll/inspector.go | 239 + vendor/github.com/olekukonko/ll/lc.go | 48 + .../github.com/olekukonko/ll/lh/buffered.go | 331 + .../github.com/olekukonko/ll/lh/colorized.go | 999 + .../olekukonko/ll/lh/colorized_unix.go | 10 + .../olekukonko/ll/lh/colorized_windows.go | 47 + vendor/github.com/olekukonko/ll/lh/dedup.go | 248 + vendor/github.com/olekukonko/ll/lh/json.go | 263 + vendor/github.com/olekukonko/ll/lh/lh.go | 75 + vendor/github.com/olekukonko/ll/lh/memory.go | 114 + vendor/github.com/olekukonko/ll/lh/multi.go | 80 + vendor/github.com/olekukonko/ll/lh/pipe.go | 76 + vendor/github.com/olekukonko/ll/lh/rotate.go | 235 + vendor/github.com/olekukonko/ll/lh/slog.go | 99 + vendor/github.com/olekukonko/ll/lh/text.go | 248 + vendor/github.com/olekukonko/ll/ll.go | 1466 + vendor/github.com/olekukonko/ll/lx/field.go | 140 + .../github.com/olekukonko/ll/lx/interface.go | 72 + vendor/github.com/olekukonko/ll/lx/lx.go | 90 + .../github.com/olekukonko/ll/lx/namespace.go | 107 + vendor/github.com/olekukonko/ll/lx/types.go | 145 + vendor/github.com/olekukonko/ll/middleware.go | 126 + vendor/github.com/olekukonko/ll/options.go | 69 + vendor/github.com/olekukonko/ll/since.go | 388 + vendor/github.com/olekukonko/ll/writer.go | 53 + .../olekukonko/tablewriter/.gitignore | 22 +- .../olekukonko/tablewriter/.golangci.yml | 55 + .../olekukonko/tablewriter/.travis.yml | 22 - .../olekukonko/tablewriter/MIGRATION.md | 3280 ++ .../olekukonko/tablewriter/README.md | 1310 +- .../olekukonko/tablewriter/README_LEGACY.md | 466 + .../olekukonko/tablewriter/comb.hcl | 10 + .../olekukonko/tablewriter/config.go | 1105 + .../github.com/olekukonko/tablewriter/csv.go | 88 +- .../olekukonko/tablewriter/deprecated.go | 235 + .../olekukonko/tablewriter/option.go | 991 + .../tablewriter/pkg/twcache/cache.go | 12 + .../olekukonko/tablewriter/pkg/twcache/lru.go | 289 + .../olekukonko/tablewriter/pkg/twwarp/wrap.go | 229 + .../tablewriter/pkg/twwidth/cache.go | 26 + .../olekukonko/tablewriter/pkg/twwidth/ea.go | 424 + .../olekukonko/tablewriter/pkg/twwidth/tab.go | 288 + .../tablewriter/pkg/twwidth/width.go | 419 + .../tablewriter/renderer/blueprint.go | 608 + .../tablewriter/renderer/colorized.go | 702 + .../olekukonko/tablewriter/renderer/fn.go | 236 + .../olekukonko/tablewriter/renderer/html.go | 442 + .../tablewriter/renderer/junction.go | 273 + .../tablewriter/renderer/markdown.go | 415 + .../olekukonko/tablewriter/renderer/ocean.go | 462 + .../olekukonko/tablewriter/renderer/svg.go | 702 + .../olekukonko/tablewriter/renderer/tint.go | 25 + .../olekukonko/tablewriter/stream.go | 1164 + .../olekukonko/tablewriter/table.go | 967 - .../tablewriter/table_with_color.go | 136 - .../olekukonko/tablewriter/tablewriter.go | 2333 ++ .../olekukonko/tablewriter/tw/cell.go | 79 + .../olekukonko/tablewriter/tw/deprecated.go | 137 + .../olekukonko/tablewriter/tw/fn.go | 237 + .../olekukonko/tablewriter/tw/mapper.go | 245 + .../olekukonko/tablewriter/tw/preset.go | 15 + .../olekukonko/tablewriter/tw/renderer.go | 133 + .../olekukonko/tablewriter/tw/slicer.go | 134 + .../olekukonko/tablewriter/tw/state.go | 51 + .../olekukonko/tablewriter/tw/symbols.go | 1012 + .../olekukonko/tablewriter/tw/tw.go | 109 + .../olekukonko/tablewriter/tw/types.go | 244 + .../github.com/olekukonko/tablewriter/util.go | 93 - .../github.com/olekukonko/tablewriter/wrap.go | 99 - .../github.com/olekukonko/tablewriter/zoo.go | 1736 + .../github.com/planetscale/vtprotobuf/LICENSE | 29 - .../vtprotobuf/protohelpers/protohelpers.go | 122 - vendor/github.com/rivo/uniseg/README.md | 137 - vendor/github.com/rivo/uniseg/doc.go | 108 - .../github.com/rivo/uniseg/eastasianwidth.go | 2588 -- .../rivo/uniseg/emojipresentation.go | 295 - .../github.com/rivo/uniseg/gen_breaktest.go | 215 - .../github.com/rivo/uniseg/gen_properties.go | 261 - vendor/github.com/rivo/uniseg/grapheme.go | 331 - .../rivo/uniseg/graphemeproperties.go | 1915 - .../github.com/rivo/uniseg/graphemerules.go | 176 - vendor/github.com/rivo/uniseg/line.go | 134 - .../github.com/rivo/uniseg/lineproperties.go | 3554 -- vendor/github.com/rivo/uniseg/linerules.go | 626 - vendor/github.com/rivo/uniseg/properties.go | 208 - vendor/github.com/rivo/uniseg/sentence.go | 90 - .../rivo/uniseg/sentenceproperties.go | 2845 -- .../github.com/rivo/uniseg/sentencerules.go | 276 - vendor/github.com/rivo/uniseg/step.go | 242 - vendor/github.com/rivo/uniseg/width.go | 61 - vendor/github.com/rivo/uniseg/word.go | 89 - .../github.com/rivo/uniseg/wordproperties.go | 1883 - vendor/github.com/rivo/uniseg/wordrules.go | 282 - .../rubenv/sql-migrate/.golangci.yaml | 204 +- .../github.com/rubenv/sql-migrate/migrate.go | 14 +- .../sql-migrate/sql-migrate/command_common.go | 7 +- vendor/github.com/spf13/cast/.editorconfig | 15 + vendor/github.com/spf13/cast/.golangci.yaml | 39 + vendor/github.com/spf13/cast/README.md | 12 +- vendor/github.com/spf13/cast/alias.go | 69 + vendor/github.com/spf13/cast/basic.go | 131 + vendor/github.com/spf13/cast/cast.go | 232 +- vendor/github.com/spf13/cast/caste.go | 1510 - vendor/github.com/spf13/cast/indirect.go | 37 + vendor/github.com/spf13/cast/internal/time.go | 79 + .../cast/internal/timeformattype_string.go | 27 + vendor/github.com/spf13/cast/map.go | 212 + vendor/github.com/spf13/cast/number.go | 549 + vendor/github.com/spf13/cast/slice.go | 106 + vendor/github.com/spf13/cast/time.go | 116 + .../spf13/cast/timeformattype_string.go | 27 - vendor/github.com/spf13/cast/zz_generated.go | 261 + vendor/golang.org/x/crypto/bcrypt/bcrypt.go | 2 +- vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go | 73 +- vendor/golang.org/x/crypto/scrypt/scrypt.go | 3 + .../x/exp/constraints/constraints.go | 50 - vendor/golang.org/x/exp/slices/cmp.go | 44 - vendor/golang.org/x/exp/slices/slices.go | 447 +- vendor/golang.org/x/exp/slices/sort.go | 162 +- .../golang.org/x/exp/slices/zsortanyfunc.go | 479 - .../golang.org/x/exp/slices/zsortordered.go | 481 - .../golang.org/x/sys/unix/affinity_linux.go | 135 +- vendor/golang.org/x/sys/unix/auxv.go | 36 + .../golang.org/x/sys/unix/auxv_unsupported.go | 13 + vendor/golang.org/x/sys/unix/fdset.go | 4 +- vendor/golang.org/x/sys/unix/ifreq_linux.go | 4 +- vendor/golang.org/x/sys/unix/ioctl_signed.go | 11 +- .../golang.org/x/sys/unix/ioctl_unsigned.go | 11 +- vendor/golang.org/x/sys/unix/mkall.sh | 3 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 11 +- vendor/golang.org/x/sys/unix/readv_unix.go | 103 + .../golang.org/x/sys/unix/syscall_darwin.go | 4 + .../x/sys/unix/syscall_dragonfly.go | 12 + vendor/golang.org/x/sys/unix/syscall_linux.go | 159 +- .../x/sys/unix/syscall_linux_386.go | 1 - .../x/sys/unix/syscall_linux_amd64.go | 1 - .../x/sys/unix/syscall_linux_arm.go | 4 +- .../x/sys/unix/syscall_linux_arm64.go | 4 +- .../x/sys/unix/syscall_linux_loong64.go | 4 +- .../x/sys/unix/syscall_linux_mips64x.go | 1 - .../x/sys/unix/syscall_linux_mipsx.go | 1 - .../x/sys/unix/syscall_linux_ppc.go | 1 - .../x/sys/unix/syscall_linux_ppc64x.go | 1 - .../x/sys/unix/syscall_linux_riscv64.go | 4 +- .../x/sys/unix/syscall_linux_s390x.go | 1 - .../x/sys/unix/syscall_linux_sparc64.go | 1 - .../golang.org/x/sys/unix/syscall_netbsd.go | 17 + .../golang.org/x/sys/unix/syscall_openbsd.go | 4 + .../golang.org/x/sys/unix/syscall_solaris.go | 97 +- vendor/golang.org/x/sys/unix/syscall_unix.go | 10 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 509 +- .../x/sys/unix/zerrors_linux_386.go | 15 +- .../x/sys/unix/zerrors_linux_amd64.go | 15 +- .../x/sys/unix/zerrors_linux_arm.go | 15 +- .../x/sys/unix/zerrors_linux_arm64.go | 16 +- .../x/sys/unix/zerrors_linux_loong64.go | 15 +- .../x/sys/unix/zerrors_linux_mips.go | 15 +- .../x/sys/unix/zerrors_linux_mips64.go | 15 +- .../x/sys/unix/zerrors_linux_mips64le.go | 15 +- .../x/sys/unix/zerrors_linux_mipsle.go | 15 +- .../x/sys/unix/zerrors_linux_ppc.go | 15 +- .../x/sys/unix/zerrors_linux_ppc64.go | 15 +- .../x/sys/unix/zerrors_linux_ppc64le.go | 15 +- .../x/sys/unix/zerrors_linux_riscv64.go | 1106 +- .../x/sys/unix/zerrors_linux_s390x.go | 15 +- .../x/sys/unix/zerrors_linux_sparc64.go | 15 +- .../x/sys/unix/zsyscall_darwin_amd64.go | 84 + .../x/sys/unix/zsyscall_darwin_amd64.s | 20 + .../x/sys/unix/zsyscall_darwin_arm64.go | 84 + .../x/sys/unix/zsyscall_darwin_arm64.s | 20 + .../golang.org/x/sys/unix/zsyscall_linux.go | 35 +- .../x/sys/unix/zsyscall_linux_386.go | 17 - .../x/sys/unix/zsyscall_linux_amd64.go | 17 - .../x/sys/unix/zsyscall_linux_arm.go | 17 - .../x/sys/unix/zsyscall_linux_arm64.go | 17 - .../x/sys/unix/zsyscall_linux_loong64.go | 17 - .../x/sys/unix/zsyscall_linux_mips.go | 17 - .../x/sys/unix/zsyscall_linux_mips64.go | 17 - .../x/sys/unix/zsyscall_linux_mips64le.go | 17 - .../x/sys/unix/zsyscall_linux_mipsle.go | 17 - .../x/sys/unix/zsyscall_linux_ppc.go | 17 - .../x/sys/unix/zsyscall_linux_ppc64.go | 17 - .../x/sys/unix/zsyscall_linux_ppc64le.go | 17 - .../x/sys/unix/zsyscall_linux_riscv64.go | 17 - .../x/sys/unix/zsyscall_linux_s390x.go | 17 - .../x/sys/unix/zsyscall_linux_sparc64.go | 17 - .../x/sys/unix/zsyscall_openbsd_386.go | 84 + .../x/sys/unix/zsyscall_openbsd_386.s | 20 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 84 + .../x/sys/unix/zsyscall_openbsd_amd64.s | 20 + .../x/sys/unix/zsyscall_openbsd_arm.go | 84 + .../x/sys/unix/zsyscall_openbsd_arm.s | 20 + .../x/sys/unix/zsyscall_openbsd_arm64.go | 84 + .../x/sys/unix/zsyscall_openbsd_arm64.s | 20 + .../x/sys/unix/zsyscall_openbsd_mips64.go | 84 + .../x/sys/unix/zsyscall_openbsd_mips64.s | 20 + .../x/sys/unix/zsyscall_openbsd_ppc64.go | 84 + .../x/sys/unix/zsyscall_openbsd_ppc64.s | 24 + .../x/sys/unix/zsyscall_openbsd_riscv64.go | 84 + .../x/sys/unix/zsyscall_openbsd_riscv64.s | 20 + .../x/sys/unix/zsyscall_solaris_amd64.go | 122 +- .../x/sys/unix/zsysnum_linux_386.go | 9 + .../x/sys/unix/zsysnum_linux_amd64.go | 10 + .../x/sys/unix/zsysnum_linux_arm.go | 9 + .../x/sys/unix/zsysnum_linux_arm64.go | 9 + .../x/sys/unix/zsysnum_linux_loong64.go | 10 + .../x/sys/unix/zsysnum_linux_mips.go | 9 + .../x/sys/unix/zsysnum_linux_mips64.go | 9 + .../x/sys/unix/zsysnum_linux_mips64le.go | 9 + .../x/sys/unix/zsysnum_linux_mipsle.go | 9 + .../x/sys/unix/zsysnum_linux_ppc.go | 9 + .../x/sys/unix/zsysnum_linux_ppc64.go | 9 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 9 + .../x/sys/unix/zsysnum_linux_riscv64.go | 9 + .../x/sys/unix/zsysnum_linux_s390x.go | 9 + .../x/sys/unix/zsysnum_linux_sparc64.go | 10 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 549 +- .../golang.org/x/sys/unix/ztypes_linux_386.go | 30 +- .../x/sys/unix/ztypes_linux_amd64.go | 28 + .../golang.org/x/sys/unix/ztypes_linux_arm.go | 32 +- .../x/sys/unix/ztypes_linux_arm64.go | 28 + .../x/sys/unix/ztypes_linux_loong64.go | 28 + .../x/sys/unix/ztypes_linux_mips.go | 30 +- .../x/sys/unix/ztypes_linux_mips64.go | 28 + .../x/sys/unix/ztypes_linux_mips64le.go | 28 + .../x/sys/unix/ztypes_linux_mipsle.go | 30 +- .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 32 +- .../x/sys/unix/ztypes_linux_ppc64.go | 28 + .../x/sys/unix/ztypes_linux_ppc64le.go | 28 + .../x/sys/unix/ztypes_linux_riscv64.go | 28 + .../x/sys/unix/ztypes_linux_s390x.go | 28 + .../x/sys/unix/ztypes_linux_sparc64.go | 28 + .../x/sys/unix/ztypes_netbsd_arm.go | 2 +- vendor/golang.org/x/sys/windows/aliases.go | 1 + .../golang.org/x/sys/windows/dll_windows.go | 48 +- .../x/sys/windows/security_windows.go | 91 +- .../x/sys/windows/syscall_windows.go | 62 +- .../golang.org/x/sys/windows/types_windows.go | 456 +- .../x/sys/windows/zsyscall_windows.go | 1106 +- .../protobuf/encoding/prototext/decode.go | 23 +- .../protobuf/encoding/protowire/wire.go | 26 +- .../protobuf/internal/descfmt/stringer.go | 269 +- .../editiondefaults/editions_defaults.binpb | Bin 99 -> 191 bytes .../internal/encoding/defval/default.go | 8 +- .../protobuf/internal/encoding/tag/tag.go | 19 +- .../protobuf/internal/encoding/text/decode.go | 115 +- .../protobuf/internal/errors/is_go112.go | 40 - .../protobuf/internal/errors/is_go113.go | 13 - .../protobuf/internal/filedesc/desc.go | 65 +- .../protobuf/internal/filedesc/desc_init.go | 14 + .../protobuf/internal/filedesc/desc_lazy.go | 51 +- .../protobuf/internal/filedesc/editions.go | 22 +- .../protobuf/internal/filedesc/presence.go | 33 + .../protobuf/internal/filetype/build.go | 2 +- .../protobuf/internal/flags/flags.go | 2 +- .../protobuf/internal/genid/api_gen.go | 6 + .../protobuf/internal/genid/descriptor_gen.go | 106 +- .../internal/genid/go_features_gen.go | 17 + .../protobuf/internal/genid/goname.go | 5 - .../protobuf/internal/genid/name.go | 12 + .../internal/impl/api_export_opaque.go | 128 + .../protobuf/internal/impl/bitmap.go | 34 + .../protobuf/internal/impl/bitmap_race.go | 126 + .../protobuf/internal/impl/checkinit.go | 33 + .../protobuf/internal/impl/codec_field.go | 75 - .../internal/impl/codec_field_opaque.go | 264 + .../protobuf/internal/impl/codec_map.go | 20 +- .../protobuf/internal/impl/codec_map_go111.go | 38 - .../protobuf/internal/impl/codec_map_go112.go | 12 - .../protobuf/internal/impl/codec_message.go | 20 +- .../internal/impl/codec_message_opaque.go | 154 + .../protobuf/internal/impl/convert_map.go | 2 +- .../protobuf/internal/impl/decode.go | 59 +- .../protobuf/internal/impl/encode.go | 78 + .../protobuf/internal/impl/lazy.go | 433 + .../protobuf/internal/impl/legacy_message.go | 5 +- .../protobuf/internal/impl/merge.go | 27 + .../protobuf/internal/impl/message.go | 31 +- .../protobuf/internal/impl/message_opaque.go | 598 + .../internal/impl/message_opaque_gen.go | 132 + .../protobuf/internal/impl/message_reflect.go | 10 +- .../internal/impl/message_reflect_field.go | 160 +- .../impl/message_reflect_field_gen.go | 273 + .../protobuf/internal/impl/pointer_unsafe.go | 12 +- .../internal/impl/pointer_unsafe_opaque.go | 42 + .../protobuf/internal/impl/presence.go | 139 + .../protobuf/internal/impl/validate.go | 66 +- .../protobuf/internal/impl/weak.go | 74 - .../internal/protolazy/bufferreader.go | 364 + .../protobuf/internal/protolazy/lazy.go | 359 + .../internal/protolazy/pointer_unsafe.go | 17 + ...ings_unsafe_go121.go => strings_unsafe.go} | 2 - .../internal/strs/strings_unsafe_go120.go | 94 - .../protobuf/internal/version/version.go | 4 +- .../protobuf/proto/decode.go | 31 +- .../protobuf/proto/encode.go | 3 +- .../google.golang.org/protobuf/proto/merge.go | 6 + .../google.golang.org/protobuf/proto/size.go | 8 + .../protobuf/proto/wrapperopaque.go | 80 + .../reflect/protoreflect/source_gen.go | 12 + .../protobuf/reflect/protoreflect/type.go | 12 +- .../protobuf/reflect/protoreflect/value.go | 2 +- ...{value_unsafe_go121.go => value_unsafe.go} | 2 - .../protoreflect/value_unsafe_go120.go | 98 - .../protobuf/runtime/protoiface/methods.go | 16 + .../protobuf/runtime/protoimpl/impl.go | 4 + .../types/known/timestamppb/timestamp.pb.go | 59 +- vendor/modules.txt | 135 +- 675 files changed, 129653 insertions(+), 43126 deletions(-) create mode 100644 vendor/dario.cat/mergo/FUNDING.json delete mode 100644 vendor/filippo.io/edwards25519/field/fe_arm64.go delete mode 100644 vendor/filippo.io/edwards25519/field/fe_arm64.s delete mode 100644 vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go create mode 100644 vendor/filippo.io/edwards25519/pull.sh create mode 100644 vendor/github.com/VictoriaMetrics/easyproto/LICENSE create mode 100644 vendor/github.com/VictoriaMetrics/easyproto/README.md create mode 100644 vendor/github.com/VictoriaMetrics/easyproto/doc.go create mode 100644 vendor/github.com/VictoriaMetrics/easyproto/reader.go create mode 100644 vendor/github.com/VictoriaMetrics/easyproto/writer.go create mode 100644 vendor/github.com/cespare/xxhash/v2/LICENSE.txt create mode 100644 vendor/github.com/cespare/xxhash/v2/README.md create mode 100644 vendor/github.com/cespare/xxhash/v2/testall.sh create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash.go create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_asm.go create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_other.go create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_safe.go create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go create mode 100644 vendor/github.com/clipperhouse/displaywidth/.gitignore create mode 100644 vendor/github.com/clipperhouse/displaywidth/AGENTS.md create mode 100644 vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md rename vendor/github.com/{rivo/uniseg/LICENSE.txt => clipperhouse/displaywidth/LICENSE} (96%) create mode 100644 vendor/github.com/clipperhouse/displaywidth/README.md create mode 100644 vendor/github.com/clipperhouse/displaywidth/gen.go create mode 100644 vendor/github.com/clipperhouse/displaywidth/graphemes.go create mode 100644 vendor/github.com/clipperhouse/displaywidth/options.go create mode 100644 vendor/github.com/clipperhouse/displaywidth/trie.go create mode 100644 vendor/github.com/clipperhouse/displaywidth/truncate.go create mode 100644 vendor/github.com/clipperhouse/displaywidth/width.go create mode 100644 vendor/github.com/clipperhouse/uax29/v2/LICENSE create mode 100644 vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md create mode 100644 vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go create mode 100644 vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go create mode 100644 vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go create mode 100644 vendor/github.com/clipperhouse/uax29/v2/graphemes/reader.go create mode 100644 vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go create mode 100644 vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go delete mode 100644 vendor/github.com/fsnotify/fsnotify/.cirrus.yml create mode 100644 vendor/github.com/fsnotify/fsnotify/shared.go create mode 100644 vendor/github.com/fsnotify/fsnotify/staticcheck.conf delete mode 100644 vendor/github.com/go-sql-driver/mysql/atomic_bool.go delete mode 100644 vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go create mode 100644 vendor/github.com/go-sql-driver/mysql/compress.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/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/assign.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/invalid.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/path.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/code.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/decode_rune.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/query.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/string_table.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/goccy/go-json/path.go create mode 100644 vendor/github.com/goccy/go-json/query.go create mode 100644 vendor/github.com/godror/godror/drv_go24.go create mode 100644 vendor/github.com/godror/godror/tznames.go create mode 100644 vendor/github.com/godror/godror/vector.go delete mode 100644 vendor/github.com/godror/knownpb/timestamppb/timestamp_vtproto.go create mode 100644 vendor/github.com/lib/pq/.gitattributes create mode 100644 vendor/github.com/lib/pq/CHANGELOG.md create mode 100644 vendor/github.com/lib/pq/LICENSE delete mode 100644 vendor/github.com/lib/pq/LICENSE.md delete mode 100644 vendor/github.com/lib/pq/TESTS.md create mode 100644 vendor/github.com/lib/pq/as.go create mode 100644 vendor/github.com/lib/pq/as_go126.go create mode 100644 vendor/github.com/lib/pq/compose.yaml delete mode 100644 vendor/github.com/lib/pq/conn_go115.go create mode 100644 vendor/github.com/lib/pq/deprecated.go create mode 100644 vendor/github.com/lib/pq/internal/pgpass/pgpass.go create mode 100644 vendor/github.com/lib/pq/internal/pgservice/pgservice.go create mode 100644 vendor/github.com/lib/pq/internal/pqsql/copy.go create mode 100644 vendor/github.com/lib/pq/internal/pqtime/loc.go create mode 100644 vendor/github.com/lib/pq/internal/pqtime/pqtime.go create mode 100644 vendor/github.com/lib/pq/internal/pqutil/path.go create mode 100644 vendor/github.com/lib/pq/internal/pqutil/perm.go create mode 100644 vendor/github.com/lib/pq/internal/pqutil/perm_unsupported.go create mode 100644 vendor/github.com/lib/pq/internal/pqutil/pqutil.go create mode 100644 vendor/github.com/lib/pq/internal/pqutil/user_other.go create mode 100644 vendor/github.com/lib/pq/internal/pqutil/user_posix.go create mode 100644 vendor/github.com/lib/pq/internal/pqutil/user_windows.go create mode 100644 vendor/github.com/lib/pq/internal/proto/proto.go create mode 100644 vendor/github.com/lib/pq/internal/proto/sz_32.go create mode 100644 vendor/github.com/lib/pq/internal/proto/sz_64.go create mode 100644 vendor/github.com/lib/pq/pqerror/codes.go create mode 100644 vendor/github.com/lib/pq/pqerror/pqerror.go create mode 100644 vendor/github.com/lib/pq/quote.go delete mode 100644 vendor/github.com/lib/pq/ssl_permissions.go delete mode 100644 vendor/github.com/lib/pq/ssl_windows.go create mode 100644 vendor/github.com/lib/pq/staticcheck.conf create mode 100644 vendor/github.com/lib/pq/stmt.go delete mode 100644 vendor/github.com/lib/pq/url.go delete mode 100644 vendor/github.com/lib/pq/user_other.go delete mode 100644 vendor/github.com/lib/pq/user_posix.go delete mode 100644 vendor/github.com/lib/pq/user_windows.go delete mode 100644 vendor/github.com/lib/pq/uuid.go delete mode 100644 vendor/github.com/mattn/go-colorable/colorable_appengine.go rename vendor/github.com/mattn/go-isatty/{isatty_tcgets.go => isatty_tiocgwinsz.go} (62%) create mode 100644 vendor/github.com/mattn/go-runewidth/SECURITY.md create mode 100644 vendor/github.com/mattn/go-runewidth/benchstat.txt create mode 100644 vendor/github.com/mattn/go-runewidth/new.txt create mode 100644 vendor/github.com/mattn/go-runewidth/old.txt create mode 100644 vendor/github.com/mattn/go-sqlite3/.coderabbit.yaml create mode 100644 vendor/github.com/mattn/go-sqlite3/SECURITY.md create mode 100644 vendor/github.com/mattn/go-sqlite3/sqlite3_opt_dbstat.go create mode 100644 vendor/github.com/mattn/go-sqlite3/sqlite3_opt_percentile.go rename vendor/github.com/mattn/go-sqlite3/{sqlite3_go18.go => sqlite3_sql.go} (97%) create mode 100644 vendor/github.com/olekukonko/cat/.gitignore create mode 100644 vendor/github.com/olekukonko/cat/LICENSE create mode 100644 vendor/github.com/olekukonko/cat/README.md create mode 100644 vendor/github.com/olekukonko/cat/builder.go create mode 100644 vendor/github.com/olekukonko/cat/cat.go create mode 100644 vendor/github.com/olekukonko/cat/concat.go create mode 100644 vendor/github.com/olekukonko/cat/fn.go create mode 100644 vendor/github.com/olekukonko/cat/sql.go create mode 100644 vendor/github.com/olekukonko/errors/.gitignore create mode 100644 vendor/github.com/olekukonko/errors/LICENSE create mode 100644 vendor/github.com/olekukonko/errors/README.md create mode 100644 vendor/github.com/olekukonko/errors/base.go create mode 100644 vendor/github.com/olekukonko/errors/chain.go create mode 100644 vendor/github.com/olekukonko/errors/chan.go create mode 100644 vendor/github.com/olekukonko/errors/errors.go create mode 100644 vendor/github.com/olekukonko/errors/generic.go create mode 100644 vendor/github.com/olekukonko/errors/group.go create mode 100644 vendor/github.com/olekukonko/errors/helper.go create mode 100644 vendor/github.com/olekukonko/errors/http.go create mode 100644 vendor/github.com/olekukonko/errors/inspect.go create mode 100644 vendor/github.com/olekukonko/errors/multi_error.go create mode 100644 vendor/github.com/olekukonko/errors/pool.go create mode 100644 vendor/github.com/olekukonko/errors/pool_above_1_24.go create mode 100644 vendor/github.com/olekukonko/errors/pool_below_1_24.go create mode 100644 vendor/github.com/olekukonko/errors/retry.go create mode 100644 vendor/github.com/olekukonko/errors/sentinel.go create mode 100644 vendor/github.com/olekukonko/errors/utils.go create mode 100644 vendor/github.com/olekukonko/ll/.gitignore create mode 100644 vendor/github.com/olekukonko/ll/.goreleaser.yaml create mode 100644 vendor/github.com/olekukonko/ll/LICENSE create mode 100644 vendor/github.com/olekukonko/ll/Makefile create mode 100644 vendor/github.com/olekukonko/ll/README.md create mode 100644 vendor/github.com/olekukonko/ll/comb.hcl create mode 100644 vendor/github.com/olekukonko/ll/conditional.go create mode 100644 vendor/github.com/olekukonko/ll/dbg.go create mode 100644 vendor/github.com/olekukonko/ll/field.go create mode 100644 vendor/github.com/olekukonko/ll/global.go create mode 100644 vendor/github.com/olekukonko/ll/inspector.go create mode 100644 vendor/github.com/olekukonko/ll/lc.go create mode 100644 vendor/github.com/olekukonko/ll/lh/buffered.go create mode 100644 vendor/github.com/olekukonko/ll/lh/colorized.go create mode 100644 vendor/github.com/olekukonko/ll/lh/colorized_unix.go create mode 100644 vendor/github.com/olekukonko/ll/lh/colorized_windows.go create mode 100644 vendor/github.com/olekukonko/ll/lh/dedup.go create mode 100644 vendor/github.com/olekukonko/ll/lh/json.go create mode 100644 vendor/github.com/olekukonko/ll/lh/lh.go create mode 100644 vendor/github.com/olekukonko/ll/lh/memory.go create mode 100644 vendor/github.com/olekukonko/ll/lh/multi.go create mode 100644 vendor/github.com/olekukonko/ll/lh/pipe.go create mode 100644 vendor/github.com/olekukonko/ll/lh/rotate.go create mode 100644 vendor/github.com/olekukonko/ll/lh/slog.go create mode 100644 vendor/github.com/olekukonko/ll/lh/text.go create mode 100644 vendor/github.com/olekukonko/ll/ll.go create mode 100644 vendor/github.com/olekukonko/ll/lx/field.go create mode 100644 vendor/github.com/olekukonko/ll/lx/interface.go create mode 100644 vendor/github.com/olekukonko/ll/lx/lx.go create mode 100644 vendor/github.com/olekukonko/ll/lx/namespace.go create mode 100644 vendor/github.com/olekukonko/ll/lx/types.go create mode 100644 vendor/github.com/olekukonko/ll/middleware.go create mode 100644 vendor/github.com/olekukonko/ll/options.go create mode 100644 vendor/github.com/olekukonko/ll/since.go create mode 100644 vendor/github.com/olekukonko/ll/writer.go create mode 100644 vendor/github.com/olekukonko/tablewriter/.golangci.yml delete mode 100644 vendor/github.com/olekukonko/tablewriter/.travis.yml create mode 100644 vendor/github.com/olekukonko/tablewriter/MIGRATION.md create mode 100644 vendor/github.com/olekukonko/tablewriter/README_LEGACY.md create mode 100644 vendor/github.com/olekukonko/tablewriter/comb.hcl create mode 100644 vendor/github.com/olekukonko/tablewriter/config.go create mode 100644 vendor/github.com/olekukonko/tablewriter/deprecated.go create mode 100644 vendor/github.com/olekukonko/tablewriter/option.go create mode 100644 vendor/github.com/olekukonko/tablewriter/pkg/twcache/cache.go create mode 100644 vendor/github.com/olekukonko/tablewriter/pkg/twcache/lru.go create mode 100644 vendor/github.com/olekukonko/tablewriter/pkg/twwarp/wrap.go create mode 100644 vendor/github.com/olekukonko/tablewriter/pkg/twwidth/cache.go create mode 100644 vendor/github.com/olekukonko/tablewriter/pkg/twwidth/ea.go create mode 100644 vendor/github.com/olekukonko/tablewriter/pkg/twwidth/tab.go create mode 100644 vendor/github.com/olekukonko/tablewriter/pkg/twwidth/width.go create mode 100644 vendor/github.com/olekukonko/tablewriter/renderer/blueprint.go create mode 100644 vendor/github.com/olekukonko/tablewriter/renderer/colorized.go create mode 100644 vendor/github.com/olekukonko/tablewriter/renderer/fn.go create mode 100644 vendor/github.com/olekukonko/tablewriter/renderer/html.go create mode 100644 vendor/github.com/olekukonko/tablewriter/renderer/junction.go create mode 100644 vendor/github.com/olekukonko/tablewriter/renderer/markdown.go create mode 100644 vendor/github.com/olekukonko/tablewriter/renderer/ocean.go create mode 100644 vendor/github.com/olekukonko/tablewriter/renderer/svg.go create mode 100644 vendor/github.com/olekukonko/tablewriter/renderer/tint.go create mode 100644 vendor/github.com/olekukonko/tablewriter/stream.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/table.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/table_with_color.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tablewriter.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/cell.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/deprecated.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/fn.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/mapper.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/preset.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/renderer.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/slicer.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/state.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/symbols.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/tw.go create mode 100644 vendor/github.com/olekukonko/tablewriter/tw/types.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/util.go delete mode 100644 vendor/github.com/olekukonko/tablewriter/wrap.go create mode 100644 vendor/github.com/olekukonko/tablewriter/zoo.go delete mode 100644 vendor/github.com/planetscale/vtprotobuf/LICENSE delete mode 100644 vendor/github.com/planetscale/vtprotobuf/protohelpers/protohelpers.go delete mode 100644 vendor/github.com/rivo/uniseg/README.md delete mode 100644 vendor/github.com/rivo/uniseg/doc.go delete mode 100644 vendor/github.com/rivo/uniseg/eastasianwidth.go delete mode 100644 vendor/github.com/rivo/uniseg/emojipresentation.go delete mode 100644 vendor/github.com/rivo/uniseg/gen_breaktest.go delete mode 100644 vendor/github.com/rivo/uniseg/gen_properties.go delete mode 100644 vendor/github.com/rivo/uniseg/grapheme.go delete mode 100644 vendor/github.com/rivo/uniseg/graphemeproperties.go delete mode 100644 vendor/github.com/rivo/uniseg/graphemerules.go delete mode 100644 vendor/github.com/rivo/uniseg/line.go delete mode 100644 vendor/github.com/rivo/uniseg/lineproperties.go delete mode 100644 vendor/github.com/rivo/uniseg/linerules.go delete mode 100644 vendor/github.com/rivo/uniseg/properties.go delete mode 100644 vendor/github.com/rivo/uniseg/sentence.go delete mode 100644 vendor/github.com/rivo/uniseg/sentenceproperties.go delete mode 100644 vendor/github.com/rivo/uniseg/sentencerules.go delete mode 100644 vendor/github.com/rivo/uniseg/step.go delete mode 100644 vendor/github.com/rivo/uniseg/width.go delete mode 100644 vendor/github.com/rivo/uniseg/word.go delete mode 100644 vendor/github.com/rivo/uniseg/wordproperties.go delete mode 100644 vendor/github.com/rivo/uniseg/wordrules.go create mode 100644 vendor/github.com/spf13/cast/.editorconfig create mode 100644 vendor/github.com/spf13/cast/.golangci.yaml create mode 100644 vendor/github.com/spf13/cast/alias.go create mode 100644 vendor/github.com/spf13/cast/basic.go delete mode 100644 vendor/github.com/spf13/cast/caste.go create mode 100644 vendor/github.com/spf13/cast/indirect.go create mode 100644 vendor/github.com/spf13/cast/internal/time.go create mode 100644 vendor/github.com/spf13/cast/internal/timeformattype_string.go create mode 100644 vendor/github.com/spf13/cast/map.go create mode 100644 vendor/github.com/spf13/cast/number.go create mode 100644 vendor/github.com/spf13/cast/slice.go create mode 100644 vendor/github.com/spf13/cast/time.go delete mode 100644 vendor/github.com/spf13/cast/timeformattype_string.go create mode 100644 vendor/github.com/spf13/cast/zz_generated.go delete mode 100644 vendor/golang.org/x/exp/constraints/constraints.go delete mode 100644 vendor/golang.org/x/exp/slices/cmp.go delete mode 100644 vendor/golang.org/x/exp/slices/zsortanyfunc.go delete mode 100644 vendor/golang.org/x/exp/slices/zsortordered.go create mode 100644 vendor/golang.org/x/sys/unix/auxv.go create mode 100644 vendor/golang.org/x/sys/unix/auxv_unsupported.go create mode 100644 vendor/golang.org/x/sys/unix/readv_unix.go delete mode 100644 vendor/google.golang.org/protobuf/internal/errors/is_go112.go delete mode 100644 vendor/google.golang.org/protobuf/internal/errors/is_go113.go create mode 100644 vendor/google.golang.org/protobuf/internal/filedesc/presence.go create mode 100644 vendor/google.golang.org/protobuf/internal/genid/name.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/api_export_opaque.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/bitmap.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/bitmap_race.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/codec_field_opaque.go delete mode 100644 vendor/google.golang.org/protobuf/internal/impl/codec_map_go111.go delete mode 100644 vendor/google.golang.org/protobuf/internal/impl/codec_map_go112.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/codec_message_opaque.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/lazy.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/message_opaque.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/message_opaque_gen.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/message_reflect_field_gen.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/pointer_unsafe_opaque.go create mode 100644 vendor/google.golang.org/protobuf/internal/impl/presence.go delete mode 100644 vendor/google.golang.org/protobuf/internal/impl/weak.go create mode 100644 vendor/google.golang.org/protobuf/internal/protolazy/bufferreader.go create mode 100644 vendor/google.golang.org/protobuf/internal/protolazy/lazy.go create mode 100644 vendor/google.golang.org/protobuf/internal/protolazy/pointer_unsafe.go rename vendor/google.golang.org/protobuf/internal/strs/{strings_unsafe_go121.go => strings_unsafe.go} (99%) delete mode 100644 vendor/google.golang.org/protobuf/internal/strs/strings_unsafe_go120.go create mode 100644 vendor/google.golang.org/protobuf/proto/wrapperopaque.go rename vendor/google.golang.org/protobuf/reflect/protoreflect/{value_unsafe_go121.go => value_unsafe.go} (99%) delete mode 100644 vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go120.go diff --git a/go.mod b/go.mod index ccdabc4..3165b3a 100644 --- a/go.mod +++ b/go.mod @@ -3,31 +3,36 @@ module github.com/dir01/bookworm go 1.26.5 require ( - github.com/fsnotify/fsnotify v1.8.0 + github.com/fsnotify/fsnotify v1.10.1 github.com/jmoiron/sqlx v1.4.0 - github.com/mattn/go-sqlite3 v1.14.24 - github.com/rubenv/sql-migrate v1.7.1 + github.com/mattn/go-sqlite3 v1.14.49 + github.com/rubenv/sql-migrate v1.8.1 github.com/tamerh/xml-stream-parser v1.5.0 github.com/tim-st/go-zim v0.1.3 gopkg.in/telebot.v3 v3.3.8 ) require ( - dario.cat/mergo v1.0.1 // indirect - filippo.io/edwards25519 v1.1.0 // indirect + dario.cat/mergo v1.0.2 // indirect + filippo.io/edwards25519 v1.2.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.3.1 // indirect + github.com/Masterminds/semver/v3 v3.5.0 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect + github.com/VictoriaMetrics/easyproto v1.2.0 // indirect github.com/antchfx/xpath v1.2.5 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/clipperhouse/displaywidth v0.11.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/denisenkom/go-mssqldb v0.12.3 // indirect - github.com/fatih/color v1.18.0 // indirect + github.com/fatih/color v1.19.0 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect - github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/godror/godror v0.45.2 // indirect - github.com/godror/knownpb v0.2.0 // indirect + github.com/go-logfmt/logfmt v0.6.1 // indirect + github.com/go-sql-driver/mysql v1.10.0 // indirect + github.com/goccy/go-json v0.10.6 // indirect + github.com/godror/godror v0.51.0 // indirect + github.com/godror/knownpb v0.3.0 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/google/uuid v1.6.0 // indirect @@ -35,25 +40,27 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/klauspost/compress v1.19.2 // indirect - github.com/lib/pq v1.10.9 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/lib/pq v1.12.3 // indirect + github.com/mattn/go-colorable v0.1.15 // indirect + github.com/mattn/go-isatty v0.0.24 // indirect github.com/mattn/go-oci8 v0.1.1 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mattn/go-runewidth v0.0.27 // indirect github.com/mitchellh/cli v1.1.5 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/planetscale/vtprotobuf v0.6.0 // indirect + github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect + github.com/olekukonko/errors v1.3.0 // indirect + github.com/olekukonko/ll v0.1.8 // indirect + github.com/olekukonko/tablewriter v1.1.4 // indirect github.com/posener/complete v1.2.3 // indirect - github.com/rivo/uniseg v0.4.7 // indirect github.com/shopspring/decimal v1.4.0 // indirect - github.com/spf13/cast v1.7.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect github.com/tamerh/xpath v1.0.0 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect - golang.org/x/crypto v0.31.0 // indirect - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect - golang.org/x/sys v0.28.0 // indirect - google.golang.org/protobuf v1.35.2 // indirect + golang.org/x/crypto v0.55.0 // indirect + golang.org/x/exp v0.0.0-20260811152304-ee035b5b010f // indirect + golang.org/x/sys v0.47.0 // indirect + google.golang.org/protobuf v1.36.12 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 119d96a..8741aa2 100644 --- a/go.sum +++ b/go.sum @@ -53,11 +53,12 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= +filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= @@ -67,14 +68,16 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= -github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= +github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/UNO-SOFT/zlog v0.8.1 h1:TEFkGJHtUfTRgMkLZiAjLSHALjwSBdw6/zByMC5GJt4= github.com/UNO-SOFT/zlog v0.8.1/go.mod h1:yqFOjn3OhvJ4j7ArJqQNA+9V+u6t9zSAyIZdWdMweWc= +github.com/VictoriaMetrics/easyproto v1.2.0 h1:FJT9uNXA2isppFuJErbLqD306KoFlehl7Wn2dg/6oIE= +github.com/VictoriaMetrics/easyproto v1.2.0/go.mod h1:QlGlzaJnDfFd8Lk6Ci/fuLxfTo3/GThPs2KH23mv710= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -98,12 +101,18 @@ github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= +github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -137,14 +146,14 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -157,23 +166,26 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= -github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE= +github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw= +github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU= +github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godror/godror v0.45.2 h1:rkXxmD+/QdKz0PTOuSfEmWNFCHnKpWS8b8HUl+5V7us= -github.com/godror/godror v0.45.2/go.mod h1:44hxVDzvFSwc+yGyRM+riCLNAY5SwZkUfLzVTh5MXCg= -github.com/godror/knownpb v0.2.0 h1:RJLntksFiKUHoUz3wCCJ8+DBjxSLYHYDNl1xRz0/gXI= -github.com/godror/knownpb v0.2.0/go.mod h1:kRahRJBwqTenpVPleymQ4k433Xz2Wuy7dOeFSuEpmkI= +github.com/godror/godror v0.51.0 h1:lowQJLgaRxTpWIUK0ozB9xdVC0Ar8bdzdPM+8lHjOUc= +github.com/godror/godror v0.51.0/go.mod h1:dnzB1y3mXcHH81sFbnB2N+MXR05sL7CDiIkiaHBpwvA= +github.com/godror/knownpb v0.3.0 h1:+caUdy8hTtl7X05aPl3tdL540TvCcaQA6woZQroLZMw= +github.com/godror/knownpb v0.3.0/go.mod h1:PpTyfJwiOEAzQl7NtVCM8kdPCnp3uhxsZYIzZ5PV4zU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -229,8 +241,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -335,8 +347,9 @@ 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/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= +github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -344,25 +357,23 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= +github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= github.com/mattn/go-oci8 v0.1.1 h1:aEUDxNAyDG0tv8CA3TArnDQNyc4EhnWlsfxRgDHABHM= github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.27 h1:Feg/Oou5zI/wnpgDF6omIU0OokC9GxLC/WRknhVlIR0= +github.com/mattn/go-runewidth v0.0.27/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= -github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.49 h1:B8jBHC3xhxZgxztrgruTuLucebnULQnx4W7cF7SAE9w= +github.com/mattn/go-sqlite3 v1.14.49/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -391,8 +402,14 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid/v2 v2.0.2 h1:r4fFzBm+bv0wNKNh5eXTwU7i85y5x+uwkxCUTNVQqLc= github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc= +github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0= +github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U= +github.com/olekukonko/errors v1.3.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y= +github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8= +github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw= +github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I= +github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -402,8 +419,6 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA= -github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -429,16 +444,13 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rubenv/sql-migrate v1.7.1 h1:f/o0WgfO/GqNuVg+6801K/KW3WdDSupzSjDYODmiUq4= -github.com/rubenv/sql-migrate v1.7.1/go.mod h1:Ob2Psprc0/3ggbM6wCzyYVFFuc6FyZrb2AS+ezLDFb4= +github.com/rubenv/sql-migrate v1.8.1 h1:EPNwCvjAowHI3TnZ+4fQu3a915OpnQoPAjTXCGOy2U0= +github.com/rubenv/sql-migrate v1.8.1/go.mod h1:BTIKBORjzyxZDS6dzoiw6eAFYJ1iNlGAtjn4LGeVjS8= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -452,8 +464,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= -github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= @@ -515,8 +527,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -527,8 +539,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= -golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/exp v0.0.0-20260811152304-ee035b5b010f h1:iXpLj9sdDH/RLYsnOMpbETK6KWtrHwvegcc4psWJHV8= +golang.org/x/exp v0.0.0-20260811152304-ee035b5b010f/go.mod h1:EdfpwwqSu+0Li0mzskwHU6FWDV3t9Q+RZDo3QMUtL3Q= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -634,8 +646,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/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-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -714,14 +726,12 @@ golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= 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.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -964,8 +974,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= +google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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= diff --git a/vendor/dario.cat/mergo/FUNDING.json b/vendor/dario.cat/mergo/FUNDING.json new file mode 100644 index 0000000..0585e1f --- /dev/null +++ b/vendor/dario.cat/mergo/FUNDING.json @@ -0,0 +1,7 @@ +{ + "drips": { + "ethereum": { + "ownedBy": "0x6160020e7102237aC41bdb156e94401692D76930" + } + } +} diff --git a/vendor/dario.cat/mergo/README.md b/vendor/dario.cat/mergo/README.md index 0b3c488..0e4a59a 100644 --- a/vendor/dario.cat/mergo/README.md +++ b/vendor/dario.cat/mergo/README.md @@ -85,7 +85,6 @@ Mergo is used by [thousands](https://deps.dev/go/dario.cat%2Fmergo/v1.0.0/depend * [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser) * [go-micro/go-micro](https://github.com/go-micro/go-micro) * [grafana/loki](https://github.com/grafana/loki) -* [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) * [masterminds/sprig](github.com/Masterminds/sprig) * [moby/moby](https://github.com/moby/moby) * [slackhq/nebula](https://github.com/slackhq/nebula) @@ -191,10 +190,6 @@ func main() { } ``` -Note: if test are failing due missing package, please execute: - - go get gopkg.in/yaml.v3 - ### Transformers Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`? diff --git a/vendor/dario.cat/mergo/SECURITY.md b/vendor/dario.cat/mergo/SECURITY.md index a5de61f..3788fcc 100644 --- a/vendor/dario.cat/mergo/SECURITY.md +++ b/vendor/dario.cat/mergo/SECURITY.md @@ -4,8 +4,8 @@ | Version | Supported | | ------- | ------------------ | -| 0.3.x | :white_check_mark: | -| < 0.3 | :x: | +| 1.x.x | :white_check_mark: | +| < 1.0 | :x: | ## Security contact information diff --git a/vendor/filippo.io/edwards25519/README.md b/vendor/filippo.io/edwards25519/README.md index 24e2457..dcdd8d8 100644 --- a/vendor/filippo.io/edwards25519/README.md +++ b/vendor/filippo.io/edwards25519/README.md @@ -7,8 +7,10 @@ import "filippo.io/edwards25519" This library implements the edwards25519 elliptic curve, exposing the necessary APIs to build a wide array of higher-level primitives. Read the docs at [pkg.go.dev/filippo.io/edwards25519](https://pkg.go.dev/filippo.io/edwards25519). -The code is originally derived from Adam Langley's internal implementation in the Go standard library, and includes George Tankersley's [performance improvements](https://golang.org/cl/71950). It was then further developed by Henry de Valence for use in ristretto255, and was finally [merged back into the Go standard library](https://golang.org/cl/276272) as of Go 1.17. It now tracks the upstream codebase and extends it with additional functionality. +The package tracks the upstream standard library package `crypto/internal/fips140/edwards25519` and extends it with additional functionality. -Most users don't need this package, and should instead use `crypto/ed25519` for signatures, `golang.org/x/crypto/curve25519` for Diffie-Hellman, or `github.com/gtank/ristretto255` for prime order group logic. However, for anyone currently using a fork of `crypto/internal/edwards25519`/`crypto/ed25519/internal/edwards25519` or `github.com/agl/edwards25519`, this package should be a safer, faster, and more powerful alternative. +The code is originally derived from Adam Langley's internal implementation in the Go standard library, and includes George Tankersley's [performance improvements](https://golang.org/cl/71950). It was then further developed by Henry de Valence for use in ristretto255, and was finally [merged back into the Go standard library](https://golang.org/cl/276272) as of Go 1.17. + +Most users don't need this package, and should instead use `crypto/ed25519` for signatures, `crypto/ecdh` for Diffie-Hellman, or `github.com/gtank/ristretto255` for prime order group logic. However, for anyone currently using a fork of the internal `edwards25519` package or of `github.com/agl/edwards25519`, this package should be a safer, faster, and more powerful alternative. Since this package is meant to curb proliferation of edwards25519 implementations in the Go ecosystem, it welcomes requests for new APIs or reviewable performance improvements. diff --git a/vendor/filippo.io/edwards25519/doc.go b/vendor/filippo.io/edwards25519/doc.go index ab6aaeb..dd2deb6 100644 --- a/vendor/filippo.io/edwards25519/doc.go +++ b/vendor/filippo.io/edwards25519/doc.go @@ -10,11 +10,11 @@ // the curve used by the Ed25519 signature scheme. // // Most users don't need this package, and should instead use crypto/ed25519 for -// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or -// github.com/gtank/ristretto255 for prime order group logic. +// signatures, crypto/ecdh for Diffie-Hellman, or github.com/gtank/ristretto255 +// for prime order group logic. // // However, developers who do need to interact with low-level edwards25519 // operations can use this package, which is an extended version of -// crypto/internal/edwards25519 from the standard library repackaged as +// crypto/internal/fips140/edwards25519 from the standard library repackaged as // an importable module. package edwards25519 diff --git a/vendor/filippo.io/edwards25519/extra.go b/vendor/filippo.io/edwards25519/extra.go index d152d68..ee9b5ca 100644 --- a/vendor/filippo.io/edwards25519/extra.go +++ b/vendor/filippo.io/edwards25519/extra.go @@ -9,6 +9,7 @@ package edwards25519 import ( "errors" + "slices" "filippo.io/edwards25519/field" ) @@ -100,13 +101,15 @@ func (v *Point) bytesMontgomery(buf *[32]byte) []byte { // // u = (1 + y) / (1 - y) // - // where y = Y / Z. + // where y = Y / Z and therefore + // + // u = (Z + Y) / (Z - Y) - var y, recip, u field.Element + var n, r, u field.Element - y.Multiply(&v.y, y.Invert(&v.z)) // y = Y / Z - recip.Invert(recip.Subtract(feOne, &y)) // r = 1/(1 - y) - u.Multiply(u.Add(feOne, &y), &recip) // u = (1 + y)*r + n.Add(&v.z, &v.y) // n = Z + Y + r.Invert(r.Subtract(&v.z, &v.y)) // r = 1 / (Z - Y) + u.Multiply(&n, &r) // u = n * r return copyFieldElement(buf, &u) } @@ -124,7 +127,7 @@ func (v *Point) MultByCofactor(p *Point) *Point { return v.fromP1xP1(&result) } -// Given k > 0, set s = s**(2*i). +// Given k > 0, set s = s**(2*k). func (s *Scalar) pow2k(k int) { for i := 0; i < k; i++ { s.Multiply(s, s) @@ -250,12 +253,14 @@ func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point { // between each point in the multiscalar equation. // Build lookup tables for each point - tables := make([]projLookupTable, len(points)) + tables := make([]projLookupTable, 0, 2) // avoid allocation for small sizes + tables = slices.Grow(tables, len(points))[:len(points)] for i := range tables { tables[i].FromP3(points[i]) } // Compute signed radix-16 digits for each scalar - digits := make([][64]int8, len(scalars)) + digits := make([][64]int8, 0, 2) // avoid allocation for small sizes + digits = slices.Grow(digits, len(scalars))[:len(scalars)] for i := range digits { digits[i] = scalars[i].signedRadix16() } @@ -265,6 +270,7 @@ func (v *Point) MultiScalarMult(scalars []*Scalar, points []*Point) *Point { tmp1 := &projP1xP1{} tmp2 := &projP2{} // Lookup-and-add the appropriate multiple of each input point + v.Set(NewIdentityPoint()) for j := range tables { tables[j].SelectInto(multiple, digits[j][63]) tmp1.Add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords @@ -347,3 +353,49 @@ func (v *Point) VarTimeMultiScalarMult(scalars []*Scalar, points []*Point) *Poin v.fromP2(tmp2) return v } + +// Select sets v to a if cond == 1 and to b if cond == 0. +func (v *Point) Select(a, b *Point, cond int) *Point { + checkInitialized(a, b) + v.x.Select(&a.x, &b.x, cond) + v.y.Select(&a.y, &b.y, cond) + v.z.Select(&a.z, &b.z, cond) + v.t.Select(&a.t, &b.t, cond) + return v +} + +// Double sets v = p + p, and returns v. +func (v *Point) Double(p *Point) *Point { + checkInitialized(p) + + pp := new(projP2).FromP3(p) + p1 := new(projP1xP1).Double(pp) + return v.fromP1xP1(p1) +} + +func (v *Point) addCached(p *Point, qCached *projCached) *Point { + result := new(projP1xP1).Add(p, qCached) + return v.fromP1xP1(result) +} + +// ScalarMultSlow sets v = x * q, and returns v. It doesn't precompute a large +// table, so it is considerably slower, but requires less memory. +// +// The scalar multiplication is done in constant time. +func (v *Point) ScalarMultSlow(x *Scalar, q *Point) *Point { + checkInitialized(q) + + s := x.Bytes() + qCached := new(projCached).FromP3(q) + v.Set(NewIdentityPoint()) + t := new(Point) + + for i := 255; i >= 0; i-- { + v.Double(v) + t.addCached(v, qCached) + cond := (s[i/8] >> (i % 8)) & 1 + v.Select(t, v, int(cond)) + } + + return v +} diff --git a/vendor/filippo.io/edwards25519/field/fe.go b/vendor/filippo.io/edwards25519/field/fe.go index 5518ef2..4d52cc1 100644 --- a/vendor/filippo.io/edwards25519/field/fe.go +++ b/vendor/filippo.io/edwards25519/field/fe.go @@ -90,11 +90,7 @@ func (v *Element) Add(a, b *Element) *Element { v.l2 = a.l2 + b.l2 v.l3 = a.l3 + b.l3 v.l4 = a.l4 + b.l4 - // Using the generic implementation here is actually faster than the - // assembly. Probably because the body of this function is so simple that - // the compiler can figure out better optimizations by inlining the carry - // propagation. - return v.carryPropagateGeneric() + return v.carryPropagate() } // Subtract sets v = a - b, and returns v. @@ -232,18 +228,22 @@ func (v *Element) bytes(out *[32]byte) []byte { t := *v t.reduce() - var buf [8]byte - for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { - bitsOffset := i * 51 - binary.LittleEndian.PutUint64(buf[:], l<= len(out) { - break - } - out[off] |= bb - } - } + // Pack five 51-bit limbs into four 64-bit words: + // + // 255 204 153 102 51 0 + // ├──l4──┼──l3──┼──l2──┼──l1──┼──l0──┤ + // ├───u3───┼───u2───┼───u1───┼───u0───┤ + // 256 192 128 64 0 + + u0 := t.l1<<51 | t.l0 + u1 := t.l2<<(102-64) | t.l1>>(64-51) + u2 := t.l3<<(153-128) | t.l2>>(128-102) + u3 := t.l4<<(204-192) | t.l3>>(192-153) + + binary.LittleEndian.PutUint64(out[0*8:], u0) + binary.LittleEndian.PutUint64(out[1*8:], u1) + binary.LittleEndian.PutUint64(out[2*8:], u2) + binary.LittleEndian.PutUint64(out[3*8:], u3) return out[:] } diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64.go b/vendor/filippo.io/edwards25519/field/fe_amd64.go index edcf163..00bf8f4 100644 --- a/vendor/filippo.io/edwards25519/field/fe_amd64.go +++ b/vendor/filippo.io/edwards25519/field/fe_amd64.go @@ -1,7 +1,6 @@ // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. -//go:build amd64 && gc && !purego -// +build amd64,gc,!purego +//go:build !purego package field diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64.s b/vendor/filippo.io/edwards25519/field/fe_amd64.s index 293f013..5e06e24 100644 --- a/vendor/filippo.io/edwards25519/field/fe_amd64.s +++ b/vendor/filippo.io/edwards25519/field/fe_amd64.s @@ -1,7 +1,6 @@ // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. -//go:build amd64 && gc && !purego -// +build amd64,gc,!purego +//go:build !purego #include "textflag.h" @@ -17,32 +16,36 @@ TEXT ·feMul(SB), NOSPLIT, $0-24 MOVQ DX, SI // r0 += 19×a1×b4 - MOVQ 8(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, DI - ADCQ DX, SI + MOVQ 8(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 32(BX) + ADDQ AX, DI + ADCQ DX, SI // r0 += 19×a2×b3 - MOVQ 16(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(BX) - ADDQ AX, DI - ADCQ DX, SI + MOVQ 16(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 24(BX) + ADDQ AX, DI + ADCQ DX, SI // r0 += 19×a3×b2 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 16(BX) - ADDQ AX, DI - ADCQ DX, SI + MOVQ 24(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 16(BX) + ADDQ AX, DI + ADCQ DX, SI // r0 += 19×a4×b1 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 8(BX) - ADDQ AX, DI - ADCQ DX, SI + MOVQ 32(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 8(BX) + ADDQ AX, DI + ADCQ DX, SI // r1 = a0×b1 MOVQ (CX), AX @@ -57,25 +60,28 @@ TEXT ·feMul(SB), NOSPLIT, $0-24 ADCQ DX, R8 // r1 += 19×a2×b4 - MOVQ 16(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, R9 - ADCQ DX, R8 + MOVQ 16(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 32(BX) + ADDQ AX, R9 + ADCQ DX, R8 // r1 += 19×a3×b3 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(BX) - ADDQ AX, R9 - ADCQ DX, R8 + MOVQ 24(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 24(BX) + ADDQ AX, R9 + ADCQ DX, R8 // r1 += 19×a4×b2 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 16(BX) - ADDQ AX, R9 - ADCQ DX, R8 + MOVQ 32(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 16(BX) + ADDQ AX, R9 + ADCQ DX, R8 // r2 = a0×b2 MOVQ (CX), AX @@ -96,18 +102,20 @@ TEXT ·feMul(SB), NOSPLIT, $0-24 ADCQ DX, R10 // r2 += 19×a3×b4 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, R11 - ADCQ DX, R10 + MOVQ 24(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 32(BX) + ADDQ AX, R11 + ADCQ DX, R10 // r2 += 19×a4×b3 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(BX) - ADDQ AX, R11 - ADCQ DX, R10 + MOVQ 32(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 24(BX) + ADDQ AX, R11 + ADCQ DX, R10 // r3 = a0×b3 MOVQ (CX), AX @@ -134,11 +142,12 @@ TEXT ·feMul(SB), NOSPLIT, $0-24 ADCQ DX, R12 // r3 += 19×a4×b4 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(BX) - ADDQ AX, R13 - ADCQ DX, R12 + MOVQ 32(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 32(BX) + ADDQ AX, R13 + ADCQ DX, R12 // r4 = a0×b4 MOVQ (CX), AX @@ -232,18 +241,22 @@ TEXT ·feSquare(SB), NOSPLIT, $0-16 MOVQ DX, BX // r0 += 38×l1×l4 - MOVQ 8(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 32(CX) - ADDQ AX, SI - ADCQ DX, BX + MOVQ 8(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + SHLQ $0x01, AX + MULQ 32(CX) + ADDQ AX, SI + ADCQ DX, BX // r0 += 38×l2×l3 - MOVQ 16(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 24(CX) - ADDQ AX, SI - ADCQ DX, BX + MOVQ 16(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + SHLQ $0x01, AX + MULQ 24(CX) + ADDQ AX, SI + ADCQ DX, BX // r1 = 2×l0×l1 MOVQ (CX), AX @@ -253,18 +266,21 @@ TEXT ·feSquare(SB), NOSPLIT, $0-16 MOVQ DX, DI // r1 += 38×l2×l4 - MOVQ 16(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 32(CX) - ADDQ AX, R8 - ADCQ DX, DI + MOVQ 16(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + SHLQ $0x01, AX + MULQ 32(CX) + ADDQ AX, R8 + ADCQ DX, DI // r1 += 19×l3×l3 - MOVQ 24(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 24(CX) - ADDQ AX, R8 - ADCQ DX, DI + MOVQ 24(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 24(CX) + ADDQ AX, R8 + ADCQ DX, DI // r2 = 2×l0×l2 MOVQ (CX), AX @@ -280,11 +296,13 @@ TEXT ·feSquare(SB), NOSPLIT, $0-16 ADCQ DX, R9 // r2 += 38×l3×l4 - MOVQ 24(CX), AX - IMUL3Q $0x26, AX, AX - MULQ 32(CX) - ADDQ AX, R10 - ADCQ DX, R9 + MOVQ 24(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + SHLQ $0x01, AX + MULQ 32(CX) + ADDQ AX, R10 + ADCQ DX, R9 // r3 = 2×l0×l3 MOVQ (CX), AX @@ -294,18 +312,19 @@ TEXT ·feSquare(SB), NOSPLIT, $0-16 MOVQ DX, R11 // r3 += 2×l1×l2 - MOVQ 8(CX), AX - IMUL3Q $0x02, AX, AX - MULQ 16(CX) - ADDQ AX, R12 - ADCQ DX, R11 + MOVQ 8(CX), AX + SHLQ $0x01, AX + MULQ 16(CX) + ADDQ AX, R12 + ADCQ DX, R11 // r3 += 19×l4×l4 - MOVQ 32(CX), AX - IMUL3Q $0x13, AX, AX - MULQ 32(CX) - ADDQ AX, R12 - ADCQ DX, R11 + MOVQ 32(CX), DX + LEAQ (DX)(DX*8), AX + LEAQ (DX)(AX*2), AX + MULQ 32(CX) + ADDQ AX, R12 + ADCQ DX, R11 // r4 = 2×l0×l4 MOVQ (CX), AX @@ -315,11 +334,11 @@ TEXT ·feSquare(SB), NOSPLIT, $0-16 MOVQ DX, R13 // r4 += 2×l1×l3 - MOVQ 8(CX), AX - IMUL3Q $0x02, AX, AX - MULQ 24(CX) - ADDQ AX, R14 - ADCQ DX, R13 + MOVQ 8(CX), AX + SHLQ $0x01, AX + MULQ 24(CX) + ADDQ AX, R14 + ADCQ DX, R13 // r4 += l2×l2 MOVQ 16(CX), AX diff --git a/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go b/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go index ddb6c9b..4b81f25 100644 --- a/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go +++ b/vendor/filippo.io/edwards25519/field/fe_amd64_noasm.go @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 || !gc || purego -// +build !amd64 !gc purego +//go:build !amd64 || purego package field diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64.go b/vendor/filippo.io/edwards25519/field/fe_arm64.go deleted file mode 100644 index af459ef..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_arm64.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2020 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. - -//go:build arm64 && gc && !purego -// +build arm64,gc,!purego - -package field - -//go:noescape -func carryPropagate(v *Element) - -func (v *Element) carryPropagate() *Element { - carryPropagate(v) - return v -} diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64.s b/vendor/filippo.io/edwards25519/field/fe_arm64.s deleted file mode 100644 index 3126a43..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_arm64.s +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2020 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. - -//go:build arm64 && gc && !purego - -#include "textflag.h" - -// carryPropagate works exactly like carryPropagateGeneric and uses the -// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but -// avoids loading R0-R4 twice and uses LDP and STP. -// -// See https://golang.org/issues/43145 for the main compiler issue. -// -// func carryPropagate(v *Element) -TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8 - MOVD v+0(FP), R20 - - LDP 0(R20), (R0, R1) - LDP 16(R20), (R2, R3) - MOVD 32(R20), R4 - - AND $0x7ffffffffffff, R0, R10 - AND $0x7ffffffffffff, R1, R11 - AND $0x7ffffffffffff, R2, R12 - AND $0x7ffffffffffff, R3, R13 - AND $0x7ffffffffffff, R4, R14 - - ADD R0>>51, R11, R11 - ADD R1>>51, R12, R12 - ADD R2>>51, R13, R13 - ADD R3>>51, R14, R14 - // R4>>51 * 19 + R10 -> R10 - LSR $51, R4, R21 - MOVD $19, R22 - MADD R22, R10, R21, R10 - - STP (R10, R11), 0(R20) - STP (R12, R13), 16(R20) - MOVD R14, 32(R20) - - RET diff --git a/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go b/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go deleted file mode 100644 index 234a5b2..0000000 --- a/vendor/filippo.io/edwards25519/field/fe_arm64_noasm.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2021 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. - -//go:build !arm64 || !gc || purego -// +build !arm64 !gc purego - -package field - -func (v *Element) carryPropagate() *Element { - return v.carryPropagateGeneric() -} diff --git a/vendor/filippo.io/edwards25519/field/fe_generic.go b/vendor/filippo.io/edwards25519/field/fe_generic.go index 86f5fd9..ef1f15a 100644 --- a/vendor/filippo.io/edwards25519/field/fe_generic.go +++ b/vendor/filippo.io/edwards25519/field/fe_generic.go @@ -12,20 +12,42 @@ type uint128 struct { lo, hi uint64 } -// mul64 returns a * b. -func mul64(a, b uint64) uint128 { +// mul returns a * b. +func mul(a, b uint64) uint128 { hi, lo := bits.Mul64(a, b) return uint128{lo, hi} } -// addMul64 returns v + a * b. -func addMul64(v uint128, a, b uint64) uint128 { +// addMul returns v + a * b. +func addMul(v uint128, a, b uint64) uint128 { hi, lo := bits.Mul64(a, b) lo, c := bits.Add64(lo, v.lo, 0) hi, _ = bits.Add64(hi, v.hi, c) return uint128{lo, hi} } +// mul19 returns v * 19. +func mul19(v uint64) uint64 { + // Using this approach seems to yield better optimizations than *19. + return v + (v+v<<3)<<1 +} + +// addMul19 returns v + 19 * a * b, where a and b are at most 52 bits. +func addMul19(v uint128, a, b uint64) uint128 { + hi, lo := bits.Mul64(mul19(a), b) + lo, c := bits.Add64(lo, v.lo, 0) + hi, _ = bits.Add64(hi, v.hi, c) + return uint128{lo, hi} +} + +// addMul38 returns v + 38 * a * b, where a and b are at most 52 bits. +func addMul38(v uint128, a, b uint64) uint128 { + hi, lo := bits.Mul64(mul19(a), b*2) + lo, c := bits.Add64(lo, v.lo, 0) + hi, _ = bits.Add64(hi, v.hi, c) + return uint128{lo, hi} +} + // shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits. func shiftRightBy51(a uint128) uint64 { return (a.hi << (64 - 51)) | (a.lo >> 51) @@ -76,45 +98,40 @@ func feMulGeneric(v, a, b *Element) { // // Finally we add up the columns into wide, overlapping limbs. - a1_19 := a1 * 19 - a2_19 := a2 * 19 - a3_19 := a3 * 19 - a4_19 := a4 * 19 - // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1) - r0 := mul64(a0, b0) - r0 = addMul64(r0, a1_19, b4) - r0 = addMul64(r0, a2_19, b3) - r0 = addMul64(r0, a3_19, b2) - r0 = addMul64(r0, a4_19, b1) + r0 := mul(a0, b0) + r0 = addMul19(r0, a1, b4) + r0 = addMul19(r0, a2, b3) + r0 = addMul19(r0, a3, b2) + r0 = addMul19(r0, a4, b1) // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2) - r1 := mul64(a0, b1) - r1 = addMul64(r1, a1, b0) - r1 = addMul64(r1, a2_19, b4) - r1 = addMul64(r1, a3_19, b3) - r1 = addMul64(r1, a4_19, b2) + r1 := mul(a0, b1) + r1 = addMul(r1, a1, b0) + r1 = addMul19(r1, a2, b4) + r1 = addMul19(r1, a3, b3) + r1 = addMul19(r1, a4, b2) // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3) - r2 := mul64(a0, b2) - r2 = addMul64(r2, a1, b1) - r2 = addMul64(r2, a2, b0) - r2 = addMul64(r2, a3_19, b4) - r2 = addMul64(r2, a4_19, b3) + r2 := mul(a0, b2) + r2 = addMul(r2, a1, b1) + r2 = addMul(r2, a2, b0) + r2 = addMul19(r2, a3, b4) + r2 = addMul19(r2, a4, b3) // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4 - r3 := mul64(a0, b3) - r3 = addMul64(r3, a1, b2) - r3 = addMul64(r3, a2, b1) - r3 = addMul64(r3, a3, b0) - r3 = addMul64(r3, a4_19, b4) + r3 := mul(a0, b3) + r3 = addMul(r3, a1, b2) + r3 = addMul(r3, a2, b1) + r3 = addMul(r3, a3, b0) + r3 = addMul19(r3, a4, b4) // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0 - r4 := mul64(a0, b4) - r4 = addMul64(r4, a1, b3) - r4 = addMul64(r4, a2, b2) - r4 = addMul64(r4, a3, b1) - r4 = addMul64(r4, a4, b0) + r4 := mul(a0, b4) + r4 = addMul(r4, a1, b3) + r4 = addMul(r4, a2, b2) + r4 = addMul(r4, a3, b1) + r4 = addMul(r4, a4, b0) // After the multiplication, we need to reduce (carry) the five coefficients // to obtain a result with limbs that are at most slightly larger than 2⁵¹, @@ -149,7 +166,7 @@ func feMulGeneric(v, a, b *Element) { c3 := shiftRightBy51(r3) c4 := shiftRightBy51(r4) - rr0 := r0.lo&maskLow51Bits + c4*19 + rr0 := r0.lo&maskLow51Bits + mul19(c4) rr1 := r1.lo&maskLow51Bits + c0 rr2 := r2.lo&maskLow51Bits + c1 rr3 := r3.lo&maskLow51Bits + c2 @@ -158,8 +175,12 @@ func feMulGeneric(v, a, b *Element) { // Now all coefficients fit into 64-bit registers but are still too large to // be passed around as an Element. We therefore do one last carry chain, // where the carries will be small enough to fit in the wiggle room above 2⁵¹. - *v = Element{rr0, rr1, rr2, rr3, rr4} - v.carryPropagate() + + v.l0 = rr0&maskLow51Bits + mul19(rr4>>51) + v.l1 = rr1&maskLow51Bits + rr0>>51 + v.l2 = rr2&maskLow51Bits + rr1>>51 + v.l3 = rr3&maskLow51Bits + rr2>>51 + v.l4 = rr4&maskLow51Bits + rr3>>51 } func feSquareGeneric(v, a *Element) { @@ -190,44 +211,31 @@ func feSquareGeneric(v, a *Element) { // l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 = // -------------------------------------- // r4 r3 r2 r1 r0 - // - // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with - // only three Mul64 and four Add64, instead of five and eight. - - l0_2 := l0 * 2 - l1_2 := l1 * 2 - - l1_38 := l1 * 38 - l2_38 := l2 * 38 - l3_38 := l3 * 38 - - l3_19 := l3 * 19 - l4_19 := l4 * 19 // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3) - r0 := mul64(l0, l0) - r0 = addMul64(r0, l1_38, l4) - r0 = addMul64(r0, l2_38, l3) + r0 := mul(l0, l0) + r0 = addMul38(r0, l1, l4) + r0 = addMul38(r0, l2, l3) // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3 - r1 := mul64(l0_2, l1) - r1 = addMul64(r1, l2_38, l4) - r1 = addMul64(r1, l3_19, l3) + r1 := mul(l0*2, l1) + r1 = addMul38(r1, l2, l4) + r1 = addMul19(r1, l3, l3) // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4 - r2 := mul64(l0_2, l2) - r2 = addMul64(r2, l1, l1) - r2 = addMul64(r2, l3_38, l4) + r2 := mul(l0*2, l2) + r2 = addMul(r2, l1, l1) + r2 = addMul38(r2, l3, l4) // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4 - r3 := mul64(l0_2, l3) - r3 = addMul64(r3, l1_2, l2) - r3 = addMul64(r3, l4_19, l4) + r3 := mul(l0*2, l3) + r3 = addMul(r3, l1*2, l2) + r3 = addMul19(r3, l4, l4) // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2 - r4 := mul64(l0_2, l4) - r4 = addMul64(r4, l1_2, l3) - r4 = addMul64(r4, l2, l2) + r4 := mul(l0*2, l4) + r4 = addMul(r4, l1*2, l3) + r4 = addMul(r4, l2, l2) c0 := shiftRightBy51(r0) c1 := shiftRightBy51(r1) @@ -235,32 +243,30 @@ func feSquareGeneric(v, a *Element) { c3 := shiftRightBy51(r3) c4 := shiftRightBy51(r4) - rr0 := r0.lo&maskLow51Bits + c4*19 + rr0 := r0.lo&maskLow51Bits + mul19(c4) rr1 := r1.lo&maskLow51Bits + c0 rr2 := r2.lo&maskLow51Bits + c1 rr3 := r3.lo&maskLow51Bits + c2 rr4 := r4.lo&maskLow51Bits + c3 - *v = Element{rr0, rr1, rr2, rr3, rr4} - v.carryPropagate() + v.l0 = rr0&maskLow51Bits + mul19(rr4>>51) + v.l1 = rr1&maskLow51Bits + rr0>>51 + v.l2 = rr2&maskLow51Bits + rr1>>51 + v.l3 = rr3&maskLow51Bits + rr2>>51 + v.l4 = rr4&maskLow51Bits + rr3>>51 } -// carryPropagateGeneric brings the limbs below 52 bits by applying the reduction +// carryPropagate brings the limbs below 52 bits by applying the reduction // identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. -func (v *Element) carryPropagateGeneric() *Element { - c0 := v.l0 >> 51 - c1 := v.l1 >> 51 - c2 := v.l2 >> 51 - c3 := v.l3 >> 51 - c4 := v.l4 >> 51 - - // c4 is at most 64 - 51 = 13 bits, so c4*19 is at most 18 bits, and +func (v *Element) carryPropagate() *Element { + // (l4>>51) is at most 64 - 51 = 13 bits, so (l4>>51)*19 is at most 18 bits, and // the final l0 will be at most 52 bits. Similarly for the rest. - v.l0 = v.l0&maskLow51Bits + c4*19 - v.l1 = v.l1&maskLow51Bits + c0 - v.l2 = v.l2&maskLow51Bits + c1 - v.l3 = v.l3&maskLow51Bits + c2 - v.l4 = v.l4&maskLow51Bits + c3 + l0 := v.l0 + v.l0 = v.l0&maskLow51Bits + mul19(v.l4>>51) + v.l4 = v.l4&maskLow51Bits + v.l3>>51 + v.l3 = v.l3&maskLow51Bits + v.l2>>51 + v.l2 = v.l2&maskLow51Bits + v.l1>>51 + v.l1 = v.l1&maskLow51Bits + l0>>51 return v } diff --git a/vendor/filippo.io/edwards25519/pull.sh b/vendor/filippo.io/edwards25519/pull.sh new file mode 100644 index 0000000..f6217c9 --- /dev/null +++ b/vendor/filippo.io/edwards25519/pull.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +TAG="$1" +TMPDIR="$(mktemp -d)" + +cleanup() { + rm -rf "$TMPDIR" +} +trap cleanup EXIT + +command -v git >/dev/null +command -v git-filter-repo >/dev/null + +if [ -d "$HOME/go/.git" ]; then + REFERENCE=(--reference "$HOME/go" --dissociate) +else + REFERENCE=() +fi + +git -c advice.detachedHead=false clone --no-checkout "${REFERENCE[@]}" \ + -b "$TAG" https://go.googlesource.com/go.git "$TMPDIR" + +# Simplify the history graph by removing the dev.boringcrypto branches, whose +# merges end up empty after grafting anyway. This also fixes a weird quirk +# (maybe a git-filter-repo bug?) where only one file from an old path, +# src/crypto/ed25519/internal/edwards25519/const.go, would still exist in the +# filtered repo. +git -C "$TMPDIR" replace --graft f771edd7f9 99f1bf54eb +git -C "$TMPDIR" replace --graft 109c13b64f c2f96e686f +git -C "$TMPDIR" replace --graft aa4da4f189 912f075047 + +git -C "$TMPDIR" filter-repo --force \ + --paths-from-file /dev/stdin \ + --prune-empty always \ + --prune-degenerate always \ + --tag-callback 'tag.skip()' <<'EOF' +src/crypto/internal/fips140/edwards25519 +src/crypto/internal/edwards25519 +src/crypto/ed25519/internal/edwards25519 +EOF + +git fetch "$TMPDIR" +git update-ref "refs/heads/upstream/$TAG" FETCH_HEAD + +echo +echo "Fetched upstream history up to $TAG. Merge with:" +echo -e "\tgit merge --no-ff --no-commit --allow-unrelated-histories upstream/$TAG" diff --git a/vendor/filippo.io/edwards25519/scalar.go b/vendor/filippo.io/edwards25519/scalar.go index 3fd1653..f08b262 100644 --- a/vendor/filippo.io/edwards25519/scalar.go +++ b/vendor/filippo.io/edwards25519/scalar.go @@ -7,6 +7,7 @@ package edwards25519 import ( "encoding/binary" "errors" + "math/bits" ) // A Scalar is an integer modulo @@ -179,15 +180,23 @@ func isReduced(s []byte) bool { return false } - for i := len(s) - 1; i >= 0; i-- { - switch { - case s[i] > scalarMinusOneBytes[i]: - return false - case s[i] < scalarMinusOneBytes[i]: - return true - } - } - return true + s0 := binary.LittleEndian.Uint64(s[:8]) + s1 := binary.LittleEndian.Uint64(s[8:16]) + s2 := binary.LittleEndian.Uint64(s[16:24]) + s3 := binary.LittleEndian.Uint64(s[24:]) + + l0 := binary.LittleEndian.Uint64(scalarMinusOneBytes[:8]) + l1 := binary.LittleEndian.Uint64(scalarMinusOneBytes[8:16]) + l2 := binary.LittleEndian.Uint64(scalarMinusOneBytes[16:24]) + l3 := binary.LittleEndian.Uint64(scalarMinusOneBytes[24:]) + + // Do a constant time subtraction chain scalarMinusOneBytes - s. If there is + // a borrow at the end, then s > scalarMinusOneBytes. + _, b := bits.Sub64(l0, s0, 0) + _, b = bits.Sub64(l1, s1, b) + _, b = bits.Sub64(l2, s2, b) + _, b = bits.Sub64(l3, s3, b) + return b == 0 } // SetBytesWithClamping applies the buffer pruning described in RFC 8032, diff --git a/vendor/filippo.io/edwards25519/tables.go b/vendor/filippo.io/edwards25519/tables.go index 83234bb..4a2b54e 100644 --- a/vendor/filippo.io/edwards25519/tables.go +++ b/vendor/filippo.io/edwards25519/tables.go @@ -4,9 +4,7 @@ package edwards25519 -import ( - "crypto/subtle" -) +import "crypto/subtle" // A dynamic lookup table for variable-base, constant-time scalar muls. type projLookupTable struct { diff --git a/vendor/github.com/Masterminds/semver/v3/.gitignore b/vendor/github.com/Masterminds/semver/v3/.gitignore index 6b061e6..35f0e5a 100644 --- a/vendor/github.com/Masterminds/semver/v3/.gitignore +++ b/vendor/github.com/Masterminds/semver/v3/.gitignore @@ -1 +1,2 @@ -_fuzz/ \ No newline at end of file +_fuzz/ +.devcontainer/ \ No newline at end of file diff --git a/vendor/github.com/Masterminds/semver/v3/.golangci.yml b/vendor/github.com/Masterminds/semver/v3/.golangci.yml index fbc6332..24277f3 100644 --- a/vendor/github.com/Masterminds/semver/v3/.golangci.yml +++ b/vendor/github.com/Masterminds/semver/v3/.golangci.yml @@ -1,27 +1,42 @@ -run: - deadline: 2m - +version: "2" linters: - disable-all: true + default: none enable: - - misspell - - govet - - staticcheck + - dupl - errcheck - - unparam + - gocyclo + - gosec + - govet - ineffassign + - misspell - nakedret - - gocyclo - - dupl - - goimports - revive - - gosec - - gosimple - - typecheck + - staticcheck + - unparam - unused - -linters-settings: - gofmt: - simplify: true - dupl: - threshold: 600 + settings: + dupl: + threshold: 600 + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - goimports + settings: + gofmt: + simplify: true + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md b/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md index f95a504..fabe5e4 100644 --- a/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md +++ b/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## 3.4.0 (2025-06-27) + +### Added + +- #268: Added property to Constraints to include prereleases for Check and Validate + +### Changed + +- #263: Updated Go testing for 1.24, 1.23, and 1.22 +- #269: Updated the error message handling for message case and wrapping errors +- #266: Restore the ability to have leading 0's when parsing with NewVersion. + Opt-out of this by setting CoerceNewVersion to false. + +### Fixed + +- #257: Fixed the CodeQL link (thanks @dmitris) +- #262: Restored detailed errors when failed to parse with NewVersion. Opt-out + of this by setting DetailedNewVersionErrors to false for faster performance. +- #267: Handle pre-releases for an "and" group if one constraint includes them + +## 3.3.1 (2024-11-19) + +### Fixed + +- #253: Fix for allowing some version that were invalid + ## 3.3.0 (2024-08-27) ### Added @@ -137,7 +163,7 @@ functions. These are described in the added and changed sections below. - #78: Fix unchecked error in example code (thanks @ravron) - #70: Fix the handling of pre-releases and the 0.0.0 release edge case - #97: Fixed copyright file for proper display on GitHub -- #107: Fix handling prerelease when sorting alphanum and num +- #107: Fix handling prerelease when sorting alphanum and num - #109: Fixed where Validate sometimes returns wrong message on error ## 1.4.2 (2018-04-10) diff --git a/vendor/github.com/Masterminds/semver/v3/README.md b/vendor/github.com/Masterminds/semver/v3/README.md index ed56936..2f56c67 100644 --- a/vendor/github.com/Masterminds/semver/v3/README.md +++ b/vendor/github.com/Masterminds/semver/v3/README.md @@ -50,6 +50,18 @@ other versions, convert the version back into a string, and get the original string. Getting the original string is useful if the semantic version was coerced into a valid form. +There are package level variables that affect how `NewVersion` handles parsing. + +- `CoerceNewVersion` is `true` by default. When set to `true` it coerces non-compliant + versions into SemVer. For example, allowing a leading 0 in a major, minor, or patch + part. This enables the use of CalVer in versions even when not compliant with SemVer. + When set to `false` less coercion work is done. +- `DetailedNewVersionErrors` provides more detailed errors. It only has an affect when + `CoerceNewVersion` is set to `false`. When `DetailedNewVersionErrors` is set to `true` + it can provide some more insight into why a version is invalid. Setting + `DetailedNewVersionErrors` to `false` is faster on performance but provides less + detailed error messages if a version fails to parse. + ## Sorting Semantic Versions A set of versions can be sorted using the `sort` package from the standard library. @@ -160,6 +172,10 @@ means `>=1.2.3-BETA` will return `1.2.3-alpha`. What you might expect from case sensitivity doesn't apply here. This is due to ASCII sort ordering which is what the spec specifies. +The `Constraints` instance returned from `semver.NewConstraint()` has a property +`IncludePrerelease` that, when set to true, will return prerelease versions when calls +to `Check()` and `Validate()` are made. + ### Hyphen Range Comparisons There are multiple methods to handle ranges and the first is hyphens ranges. @@ -250,7 +266,7 @@ or [create a pull request](https://github.com/Masterminds/semver/pulls). Security is an important consideration for this project. The project currently uses the following tools to help discover security issues: -* [CodeQL](https://github.com/Masterminds/semver) +* [CodeQL](https://codeql.github.com) * [gosec](https://github.com/securego/gosec) * Daily Fuzz testing diff --git a/vendor/github.com/Masterminds/semver/v3/constraints.go b/vendor/github.com/Masterminds/semver/v3/constraints.go index 8461c7e..e8353bc 100644 --- a/vendor/github.com/Masterminds/semver/v3/constraints.go +++ b/vendor/github.com/Masterminds/semver/v3/constraints.go @@ -12,24 +12,52 @@ import ( // checked against. type Constraints struct { constraints [][]*constraint + containsPre []bool + + // IncludePrerelease specifies if pre-releases should be included in + // the results. Note, if a constraint range has a prerelease than + // prereleases will be included for that AND group even if this is + // set to false. + IncludePrerelease bool } +// MaxConstraintLen is the maximum allowed length of a constraint string. +const MaxConstraintLen = 512 + +// MaxConstraintGroups is the maximum number of OR groups allowed in a +// constraint string. +const MaxConstraintGroups = 32 + +// ErrConstraintTooLong is returned when a constraint string exceeds the +// maximum allowed length. +var ErrConstraintTooLong = fmt.Errorf("constraint string is too long (max %d bytes)", MaxConstraintLen) + +// ErrTooManyConstraintGroups is returned when a constraint string contains +// too many OR groups. +var ErrTooManyConstraintGroups = fmt.Errorf("too many constraint groups (max %d)", MaxConstraintGroups) + // NewConstraint returns a Constraints instance that a Version instance can // be checked against. If there is a parse error it will be returned. func NewConstraint(c string) (*Constraints, error) { + if len(c) > MaxConstraintLen { + return nil, ErrConstraintTooLong + } + // Rewrite - ranges into a comparison operation. c = rewriteRange(c) ors := strings.Split(c, "||") - or := make([][]*constraint, len(ors)) + if len(ors) > MaxConstraintGroups { + return nil, ErrTooManyConstraintGroups + } + lenors := len(ors) + or := make([][]*constraint, lenors) + hasPre := make([]bool, lenors) for k, v := range ors { - - // TODO: Find a way to validate and fetch all the constraints in a simpler form - // Validate the segment if !validConstraintRegex.MatchString(v) { - return nil, fmt.Errorf("improper constraint: %s", v) + return nil, fmt.Errorf("improper constraint: %q", v) } cs := findConstraintRegex.FindAllString(v, -1) @@ -43,12 +71,22 @@ func NewConstraint(c string) (*Constraints, error) { return nil, err } + // If one of the constraints has a prerelease record this. + // This information is used when checking all in an "and" + // group to ensure they all check for prereleases. + if pc.con.pre != "" { + hasPre[k] = true + } + result[i] = pc } or[k] = result } - o := &Constraints{constraints: or} + o := &Constraints{ + constraints: or, + containsPre: hasPre, + } return o, nil } @@ -57,10 +95,10 @@ func (cs Constraints) Check(v *Version) bool { // TODO(mattfarina): For v4 of this library consolidate the Check and Validate // functions as the underlying functions make that possible now. // loop over the ORs and check the inner ANDs - for _, o := range cs.constraints { + for i, o := range cs.constraints { joy := true for _, c := range o { - if check, _ := c.check(v); !check { + if check, _ := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); !check { joy = false break } @@ -83,14 +121,14 @@ func (cs Constraints) Validate(v *Version) (bool, []error) { // Capture the prerelease message only once. When it happens the first time // this var is marked var prerelesase bool - for _, o := range cs.constraints { + for i, o := range cs.constraints { joy := true for _, c := range o { // Before running the check handle the case there the version is // a prerelease and the check is not searching for prereleases. - if c.con.pre == "" && v.pre != "" { + if !cs.IncludePrerelease && !cs.containsPre[i] && v.pre != "" { if !prerelesase { - em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + em := fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v) e = append(e, em) prerelesase = true } @@ -98,7 +136,7 @@ func (cs Constraints) Validate(v *Version) (bool, []error) { } else { - if _, err := c.check(v); err != nil { + if _, err := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); err != nil { e = append(e, err) joy = false } @@ -227,8 +265,8 @@ type constraint struct { } // Check if a version meets the constraint -func (c *constraint) check(v *Version) (bool, error) { - return constraintOps[c.origfunc](v, c) +func (c *constraint) check(v *Version, includePre bool) (bool, error) { + return constraintOps[c.origfunc](v, c, includePre) } // String prints an individual constraint into a string @@ -236,13 +274,13 @@ func (c *constraint) string() string { return c.origfunc + c.orig } -type cfunc func(v *Version, c *constraint) (bool, error) +type cfunc func(v *Version, c *constraint, includePre bool) (bool, error) func parseConstraint(c string) (*constraint, error) { if len(c) > 0 { m := constraintRegex.FindStringSubmatch(c) if m == nil { - return nil, fmt.Errorf("improper constraint: %s", c) + return nil, fmt.Errorf("improper constraint: %q", c) } cs := &constraint{ @@ -272,7 +310,7 @@ func parseConstraint(c string) (*constraint, error) { // The constraintRegex should catch any regex parsing errors. So, // we should never get here. - return nil, errors.New("constraint Parser Error") + return nil, errors.New("constraint parser error") } cs.con = con @@ -290,7 +328,7 @@ func parseConstraint(c string) (*constraint, error) { // The constraintRegex should catch any regex parsing errors. So, // we should never get here. - return nil, errors.New("constraint Parser Error") + return nil, errors.New("constraint parser error") } cs := &constraint{ @@ -305,23 +343,21 @@ func parseConstraint(c string) (*constraint, error) { } // Constraint functions -func constraintNotEqual(v *Version, c *constraint) (bool, error) { - if c.dirty { - - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) - } +func constraintNotEqual(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { + return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v) + } + if c.dirty { if c.con.Major() != v.Major() { return true, nil } if c.con.Minor() != v.Minor() && !c.minorDirty { return true, nil } else if c.minorDirty { - return false, fmt.Errorf("%s is equal to %s", v, c.orig) + return false, fmt.Errorf("%q is equal to %q", v, c.orig) } else if c.con.Patch() != v.Patch() && !c.patchDirty { return true, nil } else if c.patchDirty { @@ -331,27 +367,26 @@ func constraintNotEqual(v *Version, c *constraint) (bool, error) { if eq { return true, nil } - return false, fmt.Errorf("%s is equal to %s", v, c.orig) + return false, fmt.Errorf("%q is equal to %q", v, c.orig) } - return false, fmt.Errorf("%s is equal to %s", v, c.orig) + return false, fmt.Errorf("%q is equal to %q", v, c.orig) } } eq := v.Equal(c.con) if eq { - return false, fmt.Errorf("%s is equal to %s", v, c.orig) + return false, fmt.Errorf("%q is equal to %q", v, c.orig) } return true, nil } -func constraintGreaterThan(v *Version, c *constraint) (bool, error) { +func constraintGreaterThan(v *Version, c *constraint, includePre bool) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { + return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v) } var eq bool @@ -361,17 +396,17 @@ func constraintGreaterThan(v *Version, c *constraint) (bool, error) { if eq { return true, nil } - return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) + return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig) } if v.Major() > c.con.Major() { return true, nil } else if v.Major() < c.con.Major() { - return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) + return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig) } else if c.minorDirty { // This is a range case such as >11. When the version is something like // 11.1.0 is it not > 11. For that we would need 12 or higher - return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) + return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig) } else if c.patchDirty { // This is for ranges such as >11.1. A version of 11.1.1 is not greater // which one of 11.2.1 is greater @@ -379,7 +414,7 @@ func constraintGreaterThan(v *Version, c *constraint) (bool, error) { if eq { return true, nil } - return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) + return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig) } // If we have gotten here we are not comparing pre-preleases and can use the @@ -388,46 +423,43 @@ func constraintGreaterThan(v *Version, c *constraint) (bool, error) { if eq { return true, nil } - return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) + return false, fmt.Errorf("%q is less than or equal to %q", v, c.orig) } -func constraintLessThan(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) +func constraintLessThan(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { + return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v) } eq := v.Compare(c.con) < 0 if eq { return true, nil } - return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig) + return false, fmt.Errorf("%q is greater than or equal to %q", v, c.orig) } -func constraintGreaterThanEqual(v *Version, c *constraint) (bool, error) { +func constraintGreaterThanEqual(v *Version, c *constraint, includePre bool) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { + return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v) } eq := v.Compare(c.con) >= 0 if eq { return true, nil } - return false, fmt.Errorf("%s is less than %s", v, c.orig) + return false, fmt.Errorf("%q is less than %q", v, c.orig) } -func constraintLessThanEqual(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) +func constraintLessThanEqual(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { + return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v) } var eq bool @@ -437,13 +469,13 @@ func constraintLessThanEqual(v *Version, c *constraint) (bool, error) { if eq { return true, nil } - return false, fmt.Errorf("%s is greater than %s", v, c.orig) + return false, fmt.Errorf("%q is greater than %q", v, c.orig) } if v.Major() > c.con.Major() { - return false, fmt.Errorf("%s is greater than %s", v, c.orig) + return false, fmt.Errorf("%q is greater than %q", v, c.orig) } else if v.Major() == c.con.Major() && v.Minor() > c.con.Minor() && !c.minorDirty { - return false, fmt.Errorf("%s is greater than %s", v, c.orig) + return false, fmt.Errorf("%q is greater than %q", v, c.orig) } return true, nil @@ -455,16 +487,15 @@ func constraintLessThanEqual(v *Version, c *constraint) (bool, error) { // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0 // ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0 // ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0 -func constraintTilde(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) +func constraintTilde(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { + return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v) } if v.LessThan(c.con) { - return false, fmt.Errorf("%s is less than %s", v, c.orig) + return false, fmt.Errorf("%q is less than %q", v, c.orig) } // ~0.0.0 is a special case where all constraints are accepted. It's @@ -475,11 +506,11 @@ func constraintTilde(v *Version, c *constraint) (bool, error) { } if v.Major() != c.con.Major() { - return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig) + return false, fmt.Errorf("%q does not have same major version as %q", v, c.orig) } if v.Minor() != c.con.Minor() && !c.minorDirty { - return false, fmt.Errorf("%s does not have same major and minor version as %s", v, c.orig) + return false, fmt.Errorf("%q does not have same major and minor version as %q", v, c.orig) } return true, nil @@ -487,16 +518,15 @@ func constraintTilde(v *Version, c *constraint) (bool, error) { // When there is a .x (dirty) status it automatically opts in to ~. Otherwise // it's a straight = -func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) +func constraintTildeOrEqual(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { + return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v) } if c.dirty { - return constraintTilde(v, c) + return constraintTilde(v, c, includePre) } eq := v.Equal(c.con) @@ -504,7 +534,7 @@ func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) { return true, nil } - return false, fmt.Errorf("%s is not equal to %s", v, c.orig) + return false, fmt.Errorf("%q is not equal to %q", v, c.orig) } // ^* --> (any) @@ -516,17 +546,16 @@ func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) { // ^0.0.3 --> >=0.0.3 <0.0.4 // ^0.0 --> >=0.0.0 <0.1.0 // ^0 --> >=0.0.0 <1.0.0 -func constraintCaret(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) +func constraintCaret(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { + return false, fmt.Errorf("%q is a prerelease version and the constraint is only looking for release versions", v) } // This less than handles prereleases if v.LessThan(c.con) { - return false, fmt.Errorf("%s is less than %s", v, c.orig) + return false, fmt.Errorf("%q is less than %q", v, c.orig) } var eq bool @@ -541,12 +570,12 @@ func constraintCaret(v *Version, c *constraint) (bool, error) { if eq { return true, nil } - return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig) + return false, fmt.Errorf("%q does not have same major version as %q", v, c.orig) } // ^ when the major is 0 and minor > 0 is >=0.y.z < 0.y+1 if c.con.Major() == 0 && v.Major() > 0 { - return false, fmt.Errorf("%s does not have same major version as %s", v, c.orig) + return false, fmt.Errorf("%q does not have same major version as %q", v, c.orig) } // If the con Minor is > 0 it is not dirty if c.con.Minor() > 0 || c.patchDirty { @@ -554,11 +583,11 @@ func constraintCaret(v *Version, c *constraint) (bool, error) { if eq { return true, nil } - return false, fmt.Errorf("%s does not have same minor version as %s. Expected minor versions to match when constraint major version is 0", v, c.orig) + return false, fmt.Errorf("%q does not have same minor version as %q. Expected minor versions to match when constraint major version is 0", v, c.orig) } // ^ when the minor is 0 and minor > 0 is =0.0.z if c.con.Minor() == 0 && v.Minor() > 0 { - return false, fmt.Errorf("%s does not have same minor version as %s", v, c.orig) + return false, fmt.Errorf("%q does not have same minor version as %q", v, c.orig) } // At this point the major is 0 and the minor is 0 and not dirty. The patch @@ -567,7 +596,7 @@ func constraintCaret(v *Version, c *constraint) (bool, error) { if eq { return true, nil } - return false, fmt.Errorf("%s does not equal %s. Expect version and constraint to equal when major and minor versions are 0", v, c.orig) + return false, fmt.Errorf("%q does not equal %q. Expect version and constraint to equal when major and minor versions are 0", v, c.orig) } func isX(x string) bool { diff --git a/vendor/github.com/Masterminds/semver/v3/version.go b/vendor/github.com/Masterminds/semver/v3/version.go index 304edc3..da42876 100644 --- a/vendor/github.com/Masterminds/semver/v3/version.go +++ b/vendor/github.com/Masterminds/semver/v3/version.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "regexp" "strconv" "strings" @@ -14,30 +15,50 @@ import ( // The compiled version of the regex created at init() is cached here so it // only needs to be created once. var versionRegex *regexp.Regexp +var looseVersionRegex *regexp.Regexp + +// CoerceNewVersion sets if leading 0's are allowd in the version part. Leading 0's are +// not allowed in a valid semantic version. When set to true, NewVersion will coerce +// leading 0's into a valid version. +var CoerceNewVersion = true + +// DetailedNewVersionErrors specifies if detailed errors are returned from the NewVersion +// function. This is used when CoerceNewVersion is set to false. If set to false +// ErrInvalidSemVer is returned for an invalid version. This does not apply to +// StrictNewVersion. Setting this function to false returns errors more quickly. +var DetailedNewVersionErrors = true var ( // ErrInvalidSemVer is returned a version is found to be invalid when // being parsed. - ErrInvalidSemVer = errors.New("Invalid Semantic Version") + ErrInvalidSemVer = errors.New("invalid semantic version") // ErrEmptyString is returned when an empty string is passed in for parsing. - ErrEmptyString = errors.New("Version string empty") + ErrEmptyString = errors.New("version string empty") // ErrInvalidCharacters is returned when invalid characters are found as // part of a version - ErrInvalidCharacters = errors.New("Invalid characters in version") + ErrInvalidCharacters = errors.New("invalid characters in version") // ErrSegmentStartsZero is returned when a version segment starts with 0. // This is invalid in SemVer. - ErrSegmentStartsZero = errors.New("Version segment starts with 0") + ErrSegmentStartsZero = errors.New("version segment starts with 0") // ErrInvalidMetadata is returned when the metadata is an invalid format - ErrInvalidMetadata = errors.New("Invalid Metadata string") + ErrInvalidMetadata = errors.New("invalid metadata string") // ErrInvalidPrerelease is returned when the pre-release is an invalid format - ErrInvalidPrerelease = errors.New("Invalid Prerelease string") + ErrInvalidPrerelease = errors.New("invalid prerelease string") + + // ErrVersionTooLong is returned when a version string exceeds the + // maximum allowed length. + ErrVersionTooLong = fmt.Errorf("version string is too long (max %d bytes)", MaxVersionLen) ) +// MaxVersionLen is the maximum allowed length of a version string. This guards +// against unbounded input causing excessive memory allocations during parsing. +const MaxVersionLen = 256 + // semVerRegex is the regular expression used to parse a semantic version. // This is not the official regex from the semver spec. It has been modified to allow for loose handling // where versions like 2.1 are detected. @@ -45,6 +66,12 @@ const semVerRegex string = `v?(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:\.(0|[1-9]\d*))? `(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?` + `(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?` +// looseSemVerRegex is a regular expression that lets invalid semver expressions through +// with enough detail that certain errors can be checked for. +const looseSemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` + + `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + + `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + // Version represents a single semantic version. type Version struct { major, minor, patch uint64 @@ -55,6 +82,7 @@ type Version struct { func init() { versionRegex = regexp.MustCompile("^" + semVerRegex + "$") + looseVersionRegex = regexp.MustCompile("^" + looseSemVerRegex + "$") } const ( @@ -75,6 +103,10 @@ func StrictNewVersion(v string) (*Version, error) { return nil, ErrEmptyString } + if len(v) > MaxVersionLen { + return nil, ErrVersionTooLong + } + // Split the parts into [0]major, [1]minor, and [2]patch,prerelease,build parts := strings.SplitN(v, ".", 3) if len(parts) != 3 { @@ -142,8 +174,30 @@ func StrictNewVersion(v string) (*Version, error) { // attempts to convert it to SemVer. If you want to validate it was a strict // semantic version at parse time see StrictNewVersion(). func NewVersion(v string) (*Version, error) { + if len(v) > MaxVersionLen { + return nil, ErrVersionTooLong + } + if CoerceNewVersion { + return coerceNewVersion(v) + } m := versionRegex.FindStringSubmatch(v) if m == nil { + + // Disabling detailed errors is first so that it is in the fast path. + if !DetailedNewVersionErrors { + return nil, ErrInvalidSemVer + } + + // Check for specific errors with the semver string and return a more detailed + // error. + m = looseVersionRegex.FindStringSubmatch(v) + if m == nil { + return nil, ErrInvalidSemVer + } + err := validateVersion(m) + if err != nil { + return nil, err + } return nil, ErrInvalidSemVer } @@ -156,13 +210,13 @@ func NewVersion(v string) (*Version, error) { var err error sv.major, err = strconv.ParseUint(m[1], 10, 64) if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) + return nil, fmt.Errorf("error parsing version segment: %w", err) } if m[2] != "" { sv.minor, err = strconv.ParseUint(m[2], 10, 64) if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) + return nil, fmt.Errorf("error parsing version segment: %w", err) } } else { sv.minor = 0 @@ -171,7 +225,61 @@ func NewVersion(v string) (*Version, error) { if m[3] != "" { sv.patch, err = strconv.ParseUint(m[3], 10, 64) if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) + return nil, fmt.Errorf("error parsing version segment: %w", err) + } + } else { + sv.patch = 0 + } + + // Perform some basic due diligence on the extra parts to ensure they are + // valid. + + if sv.pre != "" { + if err = validatePrerelease(sv.pre); err != nil { + return nil, err + } + } + + if sv.metadata != "" { + if err = validateMetadata(sv.metadata); err != nil { + return nil, err + } + } + + return sv, nil +} + +func coerceNewVersion(v string) (*Version, error) { + m := looseVersionRegex.FindStringSubmatch(v) + if m == nil { + return nil, ErrInvalidSemVer + } + + sv := &Version{ + metadata: m[8], + pre: m[5], + original: v, + } + + var err error + sv.major, err = strconv.ParseUint(m[1], 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing version segment: %w", err) + } + + if m[2] != "" { + sv.minor, err = strconv.ParseUint(strings.TrimPrefix(m[2], "."), 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing version segment: %w", err) + } + } else { + sv.minor = 0 + } + + if m[3] != "" { + sv.patch, err = strconv.ParseUint(strings.TrimPrefix(m[3], "."), 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing version segment: %w", err) } } else { sv.patch = 0 @@ -197,6 +305,8 @@ func NewVersion(v string) (*Version, error) { // New creates a new instance of Version with each of the parts passed in as // arguments instead of parsing a version string. +// Note, New does not validate prerelease or metadata. Incorrect information can +// be passed in. func New(major, minor, patch uint64, pre, metadata string) *Version { v := Version{ major: major, @@ -209,6 +319,7 @@ func New(major, minor, patch uint64, pre, metadata string) *Version { v.original = v.String() + // TODO: In the next semver major version validate the pre and metadata. Return error if there is one. return &v } @@ -296,6 +407,9 @@ func (v Version) IncPatch() Version { } else { vNext.metadata = "" vNext.pre = "" + if v.patch == math.MaxUint64 { + panic("patch version increment would overflow uint64") + } vNext.patch = v.patch + 1 } vNext.original = v.originalVPrefix() + "" + vNext.String() @@ -312,6 +426,9 @@ func (v Version) IncMinor() Version { vNext.metadata = "" vNext.pre = "" vNext.patch = 0 + if v.minor == math.MaxUint64 { + panic("minor version increment would overflow uint64") + } vNext.minor = v.minor + 1 vNext.original = v.originalVPrefix() + "" + vNext.String() return vNext @@ -329,6 +446,9 @@ func (v Version) IncMajor() Version { vNext.pre = "" vNext.patch = 0 vNext.minor = 0 + if v.major == math.MaxUint64 { + panic("major version increment would overflow uint64") + } vNext.major = v.major + 1 vNext.original = v.originalVPrefix() + "" + vNext.String() return vNext @@ -476,7 +596,16 @@ func (v Version) MarshalText() ([]byte, error) { // Scan implements the SQL.Scanner interface. func (v *Version) Scan(value interface{}) error { var s string - s, _ = value.(string) + switch t := value.(type) { + case string: + s = t + case []byte: + s = string(t) + case nil: + return fmt.Errorf("cannot scan nil into Version") + default: + return fmt.Errorf("unsupported Scan type %T", value) + } temp, err := NewVersion(s) if err != nil { return err @@ -615,7 +744,7 @@ func validatePrerelease(p string) error { eparts := strings.Split(p, ".") for _, p := range eparts { if p == "" { - return ErrInvalidMetadata + return ErrInvalidPrerelease } else if containsOnly(p, num) { if len(p) > 1 && p[0] == '0' { return ErrSegmentStartsZero @@ -643,3 +772,54 @@ func validateMetadata(m string) error { } return nil } + +// validateVersion checks for common validation issues but may not catch all errors +func validateVersion(m []string) error { + var err error + var v string + if m[1] != "" { + if len(m[1]) > 1 && m[1][0] == '0' { + return ErrSegmentStartsZero + } + _, err = strconv.ParseUint(m[1], 10, 64) + if err != nil { + return fmt.Errorf("error parsing version segment: %w", err) + } + } + + if m[2] != "" { + v = strings.TrimPrefix(m[2], ".") + if len(v) > 1 && v[0] == '0' { + return ErrSegmentStartsZero + } + _, err = strconv.ParseUint(v, 10, 64) + if err != nil { + return fmt.Errorf("error parsing version segment: %w", err) + } + } + + if m[3] != "" { + v = strings.TrimPrefix(m[3], ".") + if len(v) > 1 && v[0] == '0' { + return ErrSegmentStartsZero + } + _, err = strconv.ParseUint(v, 10, 64) + if err != nil { + return fmt.Errorf("error parsing version segment: %w", err) + } + } + + if m[5] != "" { + if err = validatePrerelease(m[5]); err != nil { + return err + } + } + + if m[8] != "" { + if err = validateMetadata(m[8]); err != nil { + return err + } + } + + return nil +} diff --git a/vendor/github.com/VictoriaMetrics/easyproto/LICENSE b/vendor/github.com/VictoriaMetrics/easyproto/LICENSE new file mode 100644 index 0000000..c6b28e5 --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/easyproto/LICENSE @@ -0,0 +1,190 @@ + 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. + + END OF TERMS AND CONDITIONS + + Copyright 2023-2024 VictoriaMetrics, Inc. + + 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/github.com/VictoriaMetrics/easyproto/README.md b/vendor/github.com/VictoriaMetrics/easyproto/README.md new file mode 100644 index 0000000..4f164f6 --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/easyproto/README.md @@ -0,0 +1,232 @@ +[![GoDoc](https://godoc.org/github.com/VictoriaMetrics/easyproto?status.svg)](http://godoc.org/github.com/VictoriaMetrics/easyproto) + +# easyproto + +Package [github.com/VictoriaMetrics/easyproto](http://godoc.org/github.com/VictoriaMetrics/easyproto) provides simple building blocks +for marshaling and unmarshaling of [protobuf](https://protobuf.dev/) messages with [proto3 encoding](https://protobuf.dev/programming-guides/encoding/). + +## Features + +- There is no need in [protoc](https://grpc.io/docs/protoc-installation/) or [go generate](https://go.dev/blog/generate) - + just write simple maintainable code for marshaling and unmarshaling protobuf messages. +- `easyproto` doesn't increase your binary size by tens of megabytes unlike traditional `protoc`-compiled code may do. +- `easyproto` allows writing zero-alloc code for marshaling and unmarshaling of arbitrary complex protobuf messages. See [examples](#examples). + +## Restrictions + +- It supports only [proto3 encoding](https://protobuf.dev/programming-guides/encoding/), e.g. it doesn't support `proto2` encoding + features such as [proto2 groups](https://protobuf.dev/programming-guides/proto2/#groups). +- It doesn't provide helpers for marshaling and unmarshaling of [well-known types](https://protobuf.dev/reference/protobuf/google.protobuf/), + since they aren't used too much in practice. + +## Examples + +Suppose you need marshaling and unmarshaling of the following `timeseries` message: + +```proto +message timeseries { + string name = 1; + repeated sample samples = 2; +} + +message sample { + double value = 1; + int64 timestamp = 2; +} +``` + +At first let's create the corresponding data structures in Go: + +```go +type Timeseries struct { + Name string + Samples []Sample +} + +type Sample struct { + Value float64 + Timestamp int64 +} +``` + +Since you write the code on yourself without any `go generate` and `protoc` invocations, +you are free to use arbitrary fields and methods in these structs. You can also specify the most suitable types for these fields. +For example, the `Sample` struct may be written as the following if you need an ability to detect empty values and timestamps: + +```go +type Sample struct { + Value *float64 + Timestamp *int64 +} +``` + +* [How to marshal `Timeseries` struct to protobuf message](#marshaling) +* [How to unmarshal protobuf message to `Timeseries` struct](#unmarshaling) + +### Marshaling + +The following code can be used for marshaling `Timeseries` struct to protobuf message: + +```go +import ( + "github.com/VictoriaMetrics/easyproto" +) + +// MarshalProtobuf marshals ts into protobuf message, appends this message to dst and returns the result. +// +// This function doesn't allocate memory on repeated calls. +func (ts *Timeseries) MarshalProtobuf(dst []byte) []byte { + m := mp.Get() + ts.marshalProtobuf(m.MessageMarshaler()) + dst = m.Marshal(dst) + mp.Put(m) + return dst +} + +func (ts *Timeseries) marshalProtobuf(mm *easyproto.MessageMarshaler) { + mm.AppendString(1, ts.Name) + for _, s := range ts.Samples { + s.marshalProtobuf(mm.AppendMessage(2)) + } +} + +func (s *Sample) marshalProtobuf(mm *easyproto.MessageMarshaler) { + mm.AppendDouble(1, s.Value) + mm.AppendInt64(2, s.Timestamp) +} + +var mp easyproto.MarshalerPool +``` + +Note that you are free to modify this code according to your needs, since you write and maintain it. +For example, you can construct arbitrary protobuf messages on the fly without the need to prepare the source struct for marshaling: + +```go +func CreateProtobufMessageOnTheFly() []byte { + // Dynamically construct timeseries message with 10 samples + var m easyproto.Marshaler + mm := m.MessageMarshaler() + mm.AppendString(1, "foo") + for i := 0; i < 10; i++ { + mmSample := mm.AppendMessage(2) + mmSample.AppendDouble(1, float64(i)/10) + mmSample.AppendInt64(2, int64(i)*1000) + } + return m.Marshal(nil) +} +``` + +This may be useful in tests. + +### Unmarshaling + +The following code can be used for unmarshaling [`timeseries` message](#examples) into `Timeseries` struct: + +```go +// UnmarshalProtobuf unmarshals ts from protobuf message at src. +func (ts *Timeseries) UnmarshalProtobuf(src []byte) (err error) { + // Set default Timeseries values + ts.Name = "" + ts.Samples = ts.Samples[:0] + + // Parse Timeseries message at src + var fc easyproto.FieldContext + for len(src) > 0 { + src, err = fc.NextField(src) + if err != nil { + return fmt.Errorf("cannot read next field in Timeseries message") + } + switch fc.FieldNum { + case 1: + name, ok := fc.String() + if !ok { + return fmt.Errorf("cannot read Timeseries name") + } + // name refers to src. This means that the name changes when src changes. + // Make a copy with strings.Clone(name) if needed. + ts.Name = name + case 2: + data, ok := fc.MessageData() + if !ok { + return fmt.Errorf("cannot read Timeseries sample data") + } + ts.Samples = append(ts.Samples, Sample{}) + s := &ts.Samples[len(ts.Samples)-1] + if err := s.UnmarshalProtobuf(data); err != nil { + return fmt.Errorf("cannot unmarshal sample: %w", err) + } + } + } + return nil +} + +// UnmarshalProtobuf unmarshals s from protobuf message at src. +func (s *Sample) UnmarshalProtobuf(src []byte) (err error) { + // Set default Sample values + s.Value = 0 + s.Timestamp = 0 + + // Parse Sample message at src + var fc easyproto.FieldContext + for len(src) > 0 { + src, err = fc.NextField(src) + if err != nil { + return fmt.Errorf("cannot read next field in sample") + } + switch fc.FieldNum { + case 1: + value, ok := fc.Double() + if !ok { + return fmt.Errorf("cannot read sample value") + } + s.Value = value + case 2: + timestamp, ok := fc.Int64() + if !ok { + return fmt.Errorf("cannot read sample timestamp") + } + s.Timestamp = timestamp + } + } + return nil +} +``` + +You are free to modify this code according to your needs, since you wrote it and you maintain it. + +It is possible to extract the needed data from arbitrary protobuf messages without the need to create a destination struct. +For example, the following code extracts `timeseries` name from protobuf message, while ignoring all the other fields: + +```go +func GetTimeseriesName(src []byte) (name string, err error) { + var fc easyproto.FieldContext + for len(src) > 0 { + src, err = fc.NextField(src) + if src != nil { + return "", fmt.Errorf("cannot read the next field") + } + if fc.FieldNum == 1 { + name, ok := fc.String() + if !ok { + return "", fmt.Errorf("cannot read timeseries name") + } + // Return a copy of name, since name refers to src. + return strings.Clone(name), nil + } + } + return "", fmt.Errorf("timeseries name isn't found in the message") +} +``` + +## Users + +`easyproto` is used in the following projects: + +- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics): + - [Prometheus `remote_write` protocol parser](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/9bc7a17d80b8fa8e497532b51cf25bbe36ef9c3f/lib/prompb/write_request_unmarshaler.go#L62) + - [OpenTelemetry parser for metrics](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/9bc7a17d80b8fa8e497532b51cf25bbe36ef9c3f/lib/protoparser/opentelemetry/pb/pb.go#L76) +- [VictoriaLogs](https://github.com/VictoriaMetrics/VictoriaLogs): + - [Loki protocol parser](https://github.com/VictoriaMetrics/VictoriaLogs/blob/ff579585998fe1506863acd5e3c0307743736f77/app/vlinsert/loki/pb.go#L22) + - [OpenTelemetry parser for logs](https://github.com/VictoriaMetrics/VictoriaLogs/blob/ff579585998fe1506863acd5e3c0307743736f77/app/vlinsert/opentelemetry/pb.go#L21) +- [VictoriaTraces](https://github.com/VictoriaMetrics/VictoriaTraces): + - [OpenTelemetry parser for trace spans](https://github.com/VictoriaMetrics/VictoriaTraces/blob/24f90c84665e42a77f07720d79b6667bfaa766b2/lib/protoparser/opentelemetry/pb/traces.go#L46) diff --git a/vendor/github.com/VictoriaMetrics/easyproto/doc.go b/vendor/github.com/VictoriaMetrics/easyproto/doc.go new file mode 100644 index 0000000..036f825 --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/easyproto/doc.go @@ -0,0 +1,3 @@ +// Package easyproto provides building blocks for marshaling and unmarshaling protobuf v3 messages +// according to https://protobuf.dev/programming-guides/encoding/ . +package easyproto diff --git a/vendor/github.com/VictoriaMetrics/easyproto/reader.go b/vendor/github.com/VictoriaMetrics/easyproto/reader.go new file mode 100644 index 0000000..0adf468 --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/easyproto/reader.go @@ -0,0 +1,1233 @@ +package easyproto + +import ( + "encoding/binary" + "fmt" + "math" + "sync" + "unsafe" +) + +// FieldContext represents a single protobuf-encoded field after NextField() or FieldByNum() call. +type FieldContext struct { + // FieldNum is the number of protobuf field read after NextField() or FieldByNum() call. + FieldNum uint32 + + // wireType is the wire type for the given field + wireType wireType + + // data is probobuf-encoded field data for wireType=wireTypeLen + data []byte + + // intValue contains int value for wireType!=wireTypeLen + intValue uint64 +} + +// FieldByNum sets fc to the field with the given fieldNum at protobuf-encoded src. +// +// false is returned if src doesn't contain a field with the given fieldNum. +// +// It is unsafe modifying src while FieldContext is in use. +// +// See also NextField(). +func (fc *FieldContext) FieldByNum(src []byte, fieldNum uint32) (bool, error) { + for len(src) > 0 { + var err error + src, err = fc.NextField(src) + if err != nil { + return false, fmt.Errorf("cannot read the next field while searching for fieldNum=%d: %w", fieldNum, err) + } + if fc.FieldNum != fieldNum { + continue + } + return true, nil + } + return false, nil +} + +// NextField reads the next field from protobuf-encoded src. +// +// It returns the tail left after reading the next field from src. +// +// It is unsafe modifying src while FieldContext is in use. +// +// See also FieldByNum(). +func (fc *FieldContext) NextField(src []byte) ([]byte, error) { + if len(src) >= 2 { + n := uint16(src[0])<<8 | uint16(src[1]) + if (n&0x8080 == 0) && (n&0x0700 == (uint16(wireTypeLen) << 8)) { + // Fast path - read message with the length smaller than 0x80 bytes. + msgLen := int(n & 0xff) + src = src[2:] + if len(src) < msgLen { + return src, fmt.Errorf("cannot read field from %d bytes; need at least %d bytes", len(src), msgLen) + } + fc.FieldNum = uint32(n >> (8 + 3)) + fc.wireType = wireTypeLen + fc.data = src[:msgLen] + src = src[msgLen:] + return src, nil + } + } + + // Read field tag. See https://protobuf.dev/programming-guides/encoding/#structure + if len(src) == 0 { + return src, fmt.Errorf("cannot unmarshal field from empty message") + } + + var fieldNum uint64 + tag := uint64(src[0]) + if tag < 0x80 { + src = src[1:] + fieldNum = tag >> 3 + } else { + var offset int + tag, offset = binary.Uvarint(src) + if offset <= 0 { + return src, fmt.Errorf("cannot unmarshal field tag from uvarint") + } + src = src[offset:] + fieldNum = tag >> 3 + if fieldNum > math.MaxUint32 { + return src, fmt.Errorf("fieldNum=%d is bigger than uint32max=%d", fieldNum, uint64(math.MaxUint32)) + } + } + + wt := wireType(tag & 0x07) + + fc.FieldNum = uint32(fieldNum) + fc.wireType = wt + + // Read the remaining data + if wt == wireTypeLen { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return src, fmt.Errorf("cannot read message length for field #%d", fieldNum) + } + src = src[offset:] + if uint64(len(src)) < u64 { + return src, fmt.Errorf("cannot read data for field #%d from %d bytes; need at least %d bytes", fieldNum, len(src), u64) + } + fc.data = src[:u64] + src = src[u64:] + return src, nil + } + if wt == wireTypeVarint { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return src, fmt.Errorf("cannot read varint after field tag for field #%d", fieldNum) + } + src = src[offset:] + fc.intValue = u64 + return src, nil + } + if wt == wireTypeI64 { + if len(src) < 8 { + return src, fmt.Errorf("cannot read i64 for field #%d", fieldNum) + } + u64 := binary.LittleEndian.Uint64(src) + src = src[8:] + fc.intValue = u64 + return src, nil + } + if wt == wireTypeI32 { + if len(src) < 4 { + return src, fmt.Errorf("cannot read i32 for field #%d", fieldNum) + } + u32 := binary.LittleEndian.Uint32(src) + src = src[4:] + fc.intValue = uint64(u32) + return src, nil + } + return src, fmt.Errorf("unknown wireType=%d", wt) +} + +// UnmarshalMessageLen unmarshals protobuf message length from src. +// +// It returns the tail left after unmarshaling message length from src. +// +// It is expected that src is marshaled with Marshaler.MarshalWithLen(). +// +// False is returned if message length cannot be unmarshaled from src. +func UnmarshalMessageLen(src []byte) (int, []byte, bool) { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return 0, src, false + } + src = src[offset:] + if u64 > math.MaxInt32 { + return 0, src, false + } + return int(u64), src, true +} + +// wireType is the type of of protobuf-encoded field +// +// See https://protobuf.dev/programming-guides/encoding/#structure +type wireType byte + +const ( + // VARINT type - one of int32, int64, uint32, uint64, sint32, sint64, bool, enum + wireTypeVarint = wireType(0) + + // I64 type + wireTypeI64 = wireType(1) + + // Len type + wireTypeLen = wireType(2) + + // I32 type + wireTypeI32 = wireType(5) +) + +func (wt wireType) String() string { + switch wt { + case wireTypeVarint: + return "varint" + case wireTypeI64: + return "i64" + case wireTypeLen: + return "len" + case wireTypeI32: + return "i32" + default: + return fmt.Sprintf("unknown (%d)", int(wt)) + } +} + +// Int32 returns int32 value for fc. +// +// False is returned if fc doesn't contain int32 value. +func (fc *FieldContext) Int32() (int32, bool) { + if fc.wireType != wireTypeVarint { + return 0, false + } + return getInt32(fc.intValue) +} + +// Int64 returns int64 value for fc. +// +// False is returned if fc doesn't contain int64 value. +func (fc *FieldContext) Int64() (int64, bool) { + if fc.wireType != wireTypeVarint { + return 0, false + } + return int64(fc.intValue), true +} + +// Uint32 returns uint32 value for fc. +// +// False is returned if fc doesn't contain uint32 value. +func (fc *FieldContext) Uint32() (uint32, bool) { + if fc.wireType != wireTypeVarint { + return 0, false + } + return getUint32(fc.intValue) +} + +// Uint64 returns uint64 value for fc. +// +// False is returned if fc doesn't contain uint64 value. +func (fc *FieldContext) Uint64() (uint64, bool) { + if fc.wireType != wireTypeVarint { + return 0, false + } + return fc.intValue, true +} + +// Sint32 returns sint32 value for fc. +// +// False is returned if fc doesn't contain sint32 value. +func (fc *FieldContext) Sint32() (int32, bool) { + if fc.wireType != wireTypeVarint { + return 0, false + } + u32, ok := getUint32(fc.intValue) + if !ok { + return 0, false + } + i32 := decodeZigZagInt32(u32) + return i32, true +} + +// Sint64 returns sint64 value for fc. +// +// False is returned if fc doesn't contain sint64 value. +func (fc *FieldContext) Sint64() (int64, bool) { + if fc.wireType != wireTypeVarint { + return 0, false + } + i64 := decodeZigZagInt64(fc.intValue) + return i64, true +} + +// Bool returns bool value for fc. +// +// False is returned in the second result if fc doesn't contain bool value. +func (fc *FieldContext) Bool() (bool, bool) { + if fc.wireType != wireTypeVarint { + return false, false + } + return getBool(fc.intValue) +} + +// Enum returns enum value for fc. +// +// False is returned if fc doesn't contain enum value. +func (fc *FieldContext) Enum() (int32, bool) { + if fc.wireType != wireTypeVarint { + return 0, false + } + return getInt32(fc.intValue) +} + +// Fixed64 returns fixed64 value for fc. +// +// False is returned if fc doesn't contain fixed64 value. +func (fc *FieldContext) Fixed64() (uint64, bool) { + if fc.wireType != wireTypeI64 { + return 0, false + } + return fc.intValue, true +} + +// Sfixed64 returns sfixed64 value for fc. +// +// False is returned if fc doesn't contain sfixed64 value. +func (fc *FieldContext) Sfixed64() (int64, bool) { + if fc.wireType != wireTypeI64 { + return 0, false + } + return int64(fc.intValue), true +} + +// Double returns dobule value for fc. +// +// False is returned if fc doesn't contain double value. +func (fc *FieldContext) Double() (float64, bool) { + if fc.wireType != wireTypeI64 { + return 0, false + } + v := math.Float64frombits(fc.intValue) + return v, true +} + +// String returns string value for fc. +// +// The returned string is valid while the underlying buffer isn't changed. +// +// False is returned if fc doesn't contain string value. +func (fc *FieldContext) String() (string, bool) { + if fc.wireType != wireTypeLen { + return "", false + } + s := unsafeBytesToString(fc.data) + return s, true +} + +// Bytes returns bytes value for fc. +// +// The returned byte slice is valid while the underlying buffer isn't changed. +// +// False is returned if fc doesn't contain bytes value. +func (fc *FieldContext) Bytes() ([]byte, bool) { + if fc.wireType != wireTypeLen { + return nil, false + } + return fc.data, true +} + +// MessageData returns protobuf message data for fc. +// +// False is returned if fc doesn't contain message data. +func (fc *FieldContext) MessageData() ([]byte, bool) { + if fc.wireType != wireTypeLen { + return nil, false + } + return fc.data, true +} + +// Fixed32 returns fixed32 value for fc. +// +// False is returned if fc doesn't contain fixed32 value. +func (fc *FieldContext) Fixed32() (uint32, bool) { + if fc.wireType != wireTypeI32 { + return 0, false + } + u32 := mustGetUint32(fc.intValue) + return u32, true +} + +// Sfixed32 returns sfixed32 value for fc. +// +// False is returned if fc doesn't contain sfixed value. +func (fc *FieldContext) Sfixed32() (int32, bool) { + if fc.wireType != wireTypeI32 { + return 0, false + } + i32 := mustGetInt32(fc.intValue) + return i32, true +} + +// Float returns float value for fc. +// +// False is returned if fc doesn't contain float value. +func (fc *FieldContext) Float() (float32, bool) { + if fc.wireType != wireTypeI32 { + return 0, false + } + u32 := mustGetUint32(fc.intValue) + v := math.Float32frombits(u32) + return v, true +} + +// UnpackInt32s unpacks int32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackInt32s(src []byte, fieldNum uint32, dst []int32) ([]int32, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackInt32s) +} + +// UnpackInt32s unpacks int32 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain int32 values. +func (fc *FieldContext) UnpackInt32s(dst []int32) ([]int32, bool) { + if fc.wireType == wireTypeVarint { + i32, ok := getInt32(fc.intValue) + if !ok { + return dst, false + } + dst = append(dst, i32) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return dstOrig, false + } + src = src[offset:] + i32, ok := getInt32(u64) + if !ok { + return dstOrig, false + } + dst = append(dst, i32) + } + return dst, true +} + +// UnpackInt64s unpacks int64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackInt64s(src []byte, fieldNum uint32, dst []int64) ([]int64, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackInt64s) +} + +// UnpackInt64s unpacks int64 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain int64 values. +func (fc *FieldContext) UnpackInt64s(dst []int64) ([]int64, bool) { + if fc.wireType == wireTypeVarint { + dst = append(dst, int64(fc.intValue)) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return dstOrig, false + } + src = src[offset:] + dst = append(dst, int64(u64)) + } + return dst, true +} + +// UnpackUint32s unpacks uint32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackUint32s(src []byte, fieldNum uint32, dst []uint32) ([]uint32, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackUint32s) +} + +// UnpackUint32s unpacks uint32 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain uint32 values. +func (fc *FieldContext) UnpackUint32s(dst []uint32) ([]uint32, bool) { + if fc.wireType == wireTypeVarint { + u32, ok := getUint32(fc.intValue) + if !ok { + return dst, false + } + dst = append(dst, u32) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return dstOrig, false + } + src = src[offset:] + u32, ok := getUint32(u64) + if !ok { + return dstOrig, false + } + dst = append(dst, u32) + } + return dst, true +} + +// UnpackUint64s unpacks uint64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackUint64s(src []byte, fieldNum uint32, dst []uint64) ([]uint64, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackUint64s) +} + +// UnpackUint64s unpacks uint64 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain uint64 values. +func (fc *FieldContext) UnpackUint64s(dst []uint64) ([]uint64, bool) { + if fc.wireType == wireTypeVarint { + dst = append(dst, fc.intValue) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return dstOrig, false + } + src = src[offset:] + dst = append(dst, u64) + } + return dst, true +} + +// UnpackSint32s unpacks sint32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackSint32s(src []byte, fieldNum uint32, dst []int32) ([]int32, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackSint32s) +} + +// UnpackSint32s unpacks sint32 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain sint32 values. +func (fc *FieldContext) UnpackSint32s(dst []int32) ([]int32, bool) { + if fc.wireType == wireTypeVarint { + u32, ok := getUint32(fc.intValue) + if !ok { + return dst, false + } + i32 := decodeZigZagInt32(u32) + dst = append(dst, i32) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return dstOrig, false + } + src = src[offset:] + u32, ok := getUint32(u64) + if !ok { + return dstOrig, false + } + i32 := decodeZigZagInt32(u32) + dst = append(dst, i32) + } + return dst, true +} + +// UnpackSint64s unpacks sint64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackSint64s(src []byte, fieldNum uint32, dst []int64) ([]int64, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackSint64s) +} + +// UnpackSint64s unpacks sint64 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain sint64 values. +func (fc *FieldContext) UnpackSint64s(dst []int64) ([]int64, bool) { + if fc.wireType == wireTypeVarint { + i64 := decodeZigZagInt64(fc.intValue) + dst = append(dst, i64) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return dstOrig, false + } + src = src[offset:] + i64 := decodeZigZagInt64(u64) + dst = append(dst, i64) + } + return dst, true +} + +// UnpackBools unpacks bool values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackBools(src []byte, fieldNum uint32, dst []bool) ([]bool, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackBools) +} + +// UnpackBools unpacks bool values from fc, appends them to dst and returns the result. +// +// False is returned in the second result if fc doesn't contain bool values. +func (fc *FieldContext) UnpackBools(dst []bool) ([]bool, bool) { + if fc.wireType == wireTypeVarint { + v, ok := getBool(fc.intValue) + if !ok { + return dst, false + } + dst = append(dst, v) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + u64, offset := binary.Uvarint(src) + if offset <= 0 { + return dstOrig, false + } + src = src[offset:] + v, ok := getBool(u64) + if !ok { + return dst, false + } + dst = append(dst, v) + } + return dst, true +} + +// UnpackFixed64s unpacks fixed64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackFixed64s(src []byte, fieldNum uint32, dst []uint64) ([]uint64, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackFixed64s) +} + +// UnpackFixed64s unpacks fixed64 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain fixed64 values. +func (fc *FieldContext) UnpackFixed64s(dst []uint64) ([]uint64, bool) { + if fc.wireType == wireTypeI64 { + u64 := fc.intValue + dst = append(dst, u64) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + if len(src) < 8 { + return dstOrig, false + } + u64 := binary.LittleEndian.Uint64(src) + src = src[8:] + dst = append(dst, u64) + } + return dst, true +} + +// UnpackSfixed64s unpacks sfixed64 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackSfixed64s(src []byte, fieldNum uint32, dst []int64) ([]int64, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackSfixed64s) +} + +// UnpackSfixed64s unpacks sfixed64 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain sfixed64 values. +func (fc *FieldContext) UnpackSfixed64s(dst []int64) ([]int64, bool) { + if fc.wireType == wireTypeI64 { + u64 := fc.intValue + dst = append(dst, int64(u64)) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + if len(src) < 8 { + return dstOrig, false + } + u64 := binary.LittleEndian.Uint64(src) + src = src[8:] + dst = append(dst, int64(u64)) + } + return dst, true +} + +// UnpackDoubles unpacks double values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackDoubles(src []byte, fieldNum uint32, dst []float64) ([]float64, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackDoubles) +} + +// UnpackDoubles unpacks double values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain double values. +func (fc *FieldContext) UnpackDoubles(dst []float64) ([]float64, bool) { + if fc.wireType == wireTypeI64 { + v := math.Float64frombits(fc.intValue) + dst = append(dst, v) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + if len(src) < 8 { + return dstOrig, false + } + u64 := binary.LittleEndian.Uint64(src) + src = src[8:] + v := math.Float64frombits(u64) + dst = append(dst, v) + } + return dst, true +} + +// UnpackFixed32s unpacks fixed32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackFixed32s(src []byte, fieldNum uint32, dst []uint32) ([]uint32, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackFixed32s) +} + +// UnpackFixed32s unpacks fixed32 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain fixed32 values. +func (fc *FieldContext) UnpackFixed32s(dst []uint32) ([]uint32, bool) { + if fc.wireType == wireTypeI32 { + u32 := mustGetUint32(fc.intValue) + dst = append(dst, u32) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + if len(src) < 4 { + return dstOrig, false + } + u32 := binary.LittleEndian.Uint32(src) + src = src[4:] + dst = append(dst, u32) + } + return dst, true +} + +// UnpackSfixed32s unpacks sfixed32 values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackSfixed32s(src []byte, fieldNum uint32, dst []int32) ([]int32, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackSfixed32s) +} + +// UnpackSfixed32s unpacks sfixed32 values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain sfixed32 values. +func (fc *FieldContext) UnpackSfixed32s(dst []int32) ([]int32, bool) { + if fc.wireType == wireTypeI32 { + i32 := mustGetInt32(fc.intValue) + dst = append(dst, i32) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + if len(src) < 4 { + return dstOrig, false + } + u32 := binary.LittleEndian.Uint32(src) + src = src[4:] + dst = append(dst, int32(u32)) + } + return dst, true +} + +// UnpackFloats unpacks float values from protobuf-encoded fields at src with the given fieldNum, appends them to dst and returns the result. +func UnpackFloats(src []byte, fieldNum uint32, dst []float32) ([]float32, error) { + return unpackArray(src, fieldNum, dst, (*FieldContext).UnpackFloats) +} + +// UnpackFloats unpacks float values from fc, appends them to dst and returns the result. +// +// False is returned if fc doesn't contain float values. +func (fc *FieldContext) UnpackFloats(dst []float32) ([]float32, bool) { + if fc.wireType == wireTypeI32 { + u32 := mustGetUint32(fc.intValue) + v := math.Float32frombits(u32) + dst = append(dst, v) + return dst, true + } + if fc.wireType != wireTypeLen { + return dst, false + } + src := fc.data + dstOrig := dst + for len(src) > 0 { + if len(src) < 4 { + return dstOrig, false + } + u32 := binary.LittleEndian.Uint32(src) + src = src[4:] + v := math.Float32frombits(u32) + dst = append(dst, v) + } + return dst, true +} + +func (fc *FieldContext) getField(src []byte, fieldNum uint32, neededWireType wireType) (bool, error) { + ok, err := fc.FieldByNum(src, fieldNum) + if err != nil { + return false, err + } + if !ok { + return false, nil + } + if fc.wireType != neededWireType { + return false, fmt.Errorf("fieldNum=%d contains unexpected wireType; got %s; want %s", fieldNum, fc.wireType, neededWireType) + } + return true, nil +} + +func unpackArray[T any](src []byte, fieldNum uint32, dst []T, unpackFunc func(fc *FieldContext, dst []T) ([]T, bool)) ([]T, error) { + v := fieldContextPool.Get() + if v == nil { + v = &FieldContext{} + } + defer fieldContextPool.Put(v) + + fc := v.(*FieldContext) + for len(src) > 0 { + var err error + src, err = fc.NextField(src) + if err != nil { + return dst, fmt.Errorf("cannot read the next field while searching for fieldNum=%d: %w", fieldNum, err) + } + if fc.FieldNum != fieldNum { + continue + } + + var ok bool + dst, ok = unpackFunc(fc, dst) + if !ok { + return dst, fmt.Errorf("cannot unpack bools from field with fieldNum=%d", fieldNum) + } + } + return dst, nil +} + +var fieldContextPool sync.Pool + +// GetInt32 returns the int32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetInt32(src []byte, fieldNum uint32) (n int32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n, ok = getInt32(fc.intValue) + if !ok { + return 0, false, fmt.Errorf("fieldNum=%d contains too big integer %d, which cannot be converted to int32", fieldNum, fc.intValue) + } + return n, true, nil +} + +// GetInt64 returns the int64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetInt64(src []byte, fieldNum uint32) (n int64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + return int64(fc.intValue), true, nil +} + +// GetUint32 returns the uint32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetUint32(src []byte, fieldNum uint32) (n uint32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n, ok = getUint32(fc.intValue) + if !ok { + return 0, false, fmt.Errorf("fieldNum=%d contains too big integer %d, which cannot be converted to uint32", fieldNum, fc.intValue) + } + return n, true, nil +} + +// GetUint64 returns the int64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetUint64(src []byte, fieldNum uint32) (n uint64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + return fc.intValue, true, nil +} + +// GetSint32 returns sint32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetSint32(src []byte, fieldNum uint32) (n int32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + u32, ok := getUint32(fc.intValue) + if !ok { + return 0, false, fmt.Errorf("fieldNum=%d contains too big integer %d, which cannot be converted to uint32", fieldNum, fc.intValue) + } + n = decodeZigZagInt32(u32) + return n, true, nil +} + +// GetSint64 returns sint64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetSint64(src []byte, fieldNum uint32) (n int64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n = decodeZigZagInt64(fc.intValue) + return n, true, nil +} + +// GetBool returns bool value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetBool(src []byte, fieldNum uint32) (b bool, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return false, false, err + } + if !ok { + return false, false, nil + } + b, ok = getBool(fc.intValue) + if !ok { + return false, false, fmt.Errorf("fieldNum=%d contains invalid integer %d, which cannot be converted to bool", fieldNum, fc.intValue) + } + return b, true, nil +} + +// GetEnum returns enum value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetEnum(src []byte, fieldNum uint32) (n int32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeVarint) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n, ok = getInt32(fc.intValue) + if !ok { + return 0, false, fmt.Errorf("fieldNum=%d contains invalid integer %d, which cannot be converted to enum", fieldNum, fc.intValue) + } + return n, true, nil +} + +// GetFixed64 returns fixed64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetFixed64(src []byte, fieldNum uint32) (n uint64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI64) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + return fc.intValue, true, nil +} + +// GetSfixed64 returns sfixed64 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetSfixed64(src []byte, fieldNum uint32) (n int64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI64) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + return int64(fc.intValue), true, nil +} + +// GetDouble returns double value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetDouble(src []byte, fieldNum uint32) (f float64, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI64) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + f = math.Float64frombits(fc.intValue) + return f, true, nil +} + +// GetString returns string value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// The returned string is valid until src is changed. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetString(src []byte, fieldNum uint32) (s string, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeLen) + if err != nil { + return "", false, err + } + if !ok { + return "", false, nil + } + return unsafeBytesToString(fc.data), true, nil +} + +// GetBytes returns bytes slice for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// The returned bytes slice is valid until src is changed. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetBytes(src []byte, fieldNum uint32) (b []byte, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeLen) + if err != nil { + return nil, false, err + } + if !ok { + return nil, false, nil + } + return fc.data, true, nil +} + +// GetMessageData returns message data for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// The returned message data is valid until src is changed. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetMessageData(src []byte, fieldNum uint32) (data []byte, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeLen) + if err != nil { + return nil, false, err + } + if !ok { + return nil, false, nil + } + return fc.data, true, nil +} + +// GetFixed32 returns fixed32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetFixed32(src []byte, fieldNum uint32) (n uint32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI32) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n = mustGetUint32(fc.intValue) + return n, true, nil +} + +// GetSfixed32 returns sfixed32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetSfixed32(src []byte, fieldNum uint32) (n int32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI32) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + n = mustGetInt32(fc.intValue) + return n, true, nil +} + +// GetFloat returns float32 value for the given fieldNum from protobuf-encoded message at src. +// +// ok=false is returned if src doesn't contain the given fieldNum. +// +// This function is useful when only a single message with the given fieldNum must be obtained from protobuf-encoded src. +// Otherwise use FieldContext for obtaining multiple message from protobuf-encoded src. +func GetFloat(src []byte, fieldNum uint32) (f float32, ok bool, err error) { + var fc FieldContext + ok, err = fc.getField(src, fieldNum, wireTypeI32) + if err != nil { + return 0, false, err + } + if !ok { + return 0, false, nil + } + u32 := mustGetUint32(fc.intValue) + f = math.Float32frombits(u32) + return f, true, nil +} + +func decodeZigZagInt64(u64 uint64) int64 { + return int64(u64>>1) ^ (int64(u64<<63) >> 63) +} + +func decodeZigZagInt32(u32 uint32) int32 { + return int32(u32>>1) ^ (int32(u32<<31) >> 31) +} + +func unsafeBytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +func getInt32(u64 uint64) (int32, bool) { + u32, ok := getUint32(u64) + if !ok { + return 0, false + } + return int32(u32), true +} + +func getUint32(u64 uint64) (uint32, bool) { + if u64 > math.MaxUint32 { + return 0, false + } + return uint32(u64), true +} + +func mustGetInt32(u64 uint64) int32 { + u32 := mustGetUint32(u64) + return int32(u32) +} + +func mustGetUint32(u64 uint64) uint32 { + u32, ok := getUint32(u64) + if !ok { + panic(fmt.Errorf("BUG: cannot get uint32 from %d", u64)) + } + return u32 +} + +func getBool(u64 uint64) (bool, bool) { + if u64 == 0 { + return false, true + } + if u64 == 1 { + return true, true + } + return false, false +} diff --git a/vendor/github.com/VictoriaMetrics/easyproto/writer.go b/vendor/github.com/VictoriaMetrics/easyproto/writer.go new file mode 100644 index 0000000..edde7ad --- /dev/null +++ b/vendor/github.com/VictoriaMetrics/easyproto/writer.go @@ -0,0 +1,718 @@ +package easyproto + +import ( + "encoding/binary" + "math" + "math/bits" + "sync" +) + +// MarshalerPool is a pool of Marshaler structs. +type MarshalerPool struct { + p sync.Pool +} + +// Get obtains a Marshaler from the pool. +// +// The returned Marshaler can be returned to the pool via Put after it is no longer needed. +func (mp *MarshalerPool) Get() *Marshaler { + v := mp.p.Get() + if v == nil { + return &Marshaler{} + } + return v.(*Marshaler) +} + +// Put returns the given m to the pool. +// +// m cannot be used after returning to the pool. +func (mp *MarshalerPool) Put(m *Marshaler) { + m.Reset() + mp.p.Put(m) +} + +// Marshaler helps marshaling arbitrary protobuf messages. +// +// Construct message with Append* functions at MessageMarshaler() and then call Marshal* for marshaling the constructed message. +// +// It is unsafe to use a single Marshaler instance from multiple concurrently running goroutines. +// +// It is recommended re-cycling Marshaler via MarshalerPool in order to reduce memory allocations. +type Marshaler struct { + // mm contains the root MessageMarshaler. + mm *MessageMarshaler + + // buf contains temporary data needed for marshaling the protobuf message. + buf []byte + + // fs contains fields for the currently marshaled message. + fs []field + + // mms contains MessageMarshaler structs for the currently marshaled message. + mms []MessageMarshaler +} + +// MessageMarshaler helps constructing protobuf message for marshaling. +// +// MessageMarshaler must be obtained via Marshaler.MessageMarshaler(). +type MessageMarshaler struct { + // m is the parent Marshaler for the given MessageMarshaler. + m *Marshaler + + // tag contains protobuf message tag for the given MessageMarshaler. + tag uint64 + + // firstFieldIdx contains the index of the first field in the Marshaler.fs, which belongs to MessageMarshaler. + firstFieldIdx int + + // lastFieldIdx is the index of the last field in the Marshaler.fs, which belongs to MessageMarshaler. + lastFieldIdx int +} + +func (mm *MessageMarshaler) reset() { + mm.m = nil + mm.tag = 0 + mm.firstFieldIdx = -1 + mm.lastFieldIdx = -1 +} + +type field struct { + // messageSize is the size of marshaled protobuf message for the given field. + messageSize uint64 + + // dataStart is the start offset of field data at Marshaler.buf. + dataStart int + + // dataEnd is the end offset of field data at Marshaler.buf. + dataEnd int + + // nextFieldIdx contains an index of the next field in Marshaler.fs. + nextFieldIdx int + + // childMessageMarshalerIdx contains an index of child MessageMarshaler in Marshaler.mms. + childMessageMarshalerIdx int +} + +func (f *field) reset() { + f.messageSize = 0 + f.dataStart = 0 + f.dataEnd = 0 + f.nextFieldIdx = -1 + f.childMessageMarshalerIdx = -1 +} + +// Reset resets m, so it can be re-used. +func (m *Marshaler) Reset() { + m.mm = nil + m.buf = m.buf[:0] + + // There is no need in resetting individual fields, since they are reset in newFieldIndex() + m.fs = m.fs[:0] + + // There is no need in resetting individual MessageMarshaler items, since they are reset in newMessageMarshalerIndex() + m.mms = m.mms[:0] +} + +// MarshalWithLen marshals m, appends its length together with the marshaled m to dst and returns the result. +// +// I.e. it appends length-delimited protobuf message to dst. +// The length of the resulting message can be read via UnmarshalMessageLen() function. +// +// See also Marshal. +func (m *Marshaler) MarshalWithLen(dst []byte) []byte { + if m.mm == nil { + dst = marshalVarUint64(dst, 0) + return dst + } + if firstFieldIdx := m.mm.firstFieldIdx; firstFieldIdx >= 0 { + f := &m.fs[firstFieldIdx] + messageSize := f.initMessageSize(m) + if cap(dst) == 0 { + dst = make([]byte, messageSize+10) + dst = dst[:0] + } + dst = marshalVarUint64(dst, messageSize) + dst = f.marshal(dst, m) + } + return dst +} + +// Marshal appends marshaled protobuf m to dst and returns the result. +// +// The marshaled message can be read via FieldContext.NextField(). +// +// See also MarshalWithLen. +func (m *Marshaler) Marshal(dst []byte) []byte { + if m.mm == nil { + // Nothing to marshal + return dst + } + if firstFieldIdx := m.mm.firstFieldIdx; firstFieldIdx >= 0 { + f := &m.fs[firstFieldIdx] + messageSize := f.initMessageSize(m) + if cap(dst) == 0 { + dst = make([]byte, messageSize) + dst = dst[:0] + } + dst = f.marshal(dst, m) + } + return dst +} + +// MessageMarshaler returns message marshaler for the given m. +func (m *Marshaler) MessageMarshaler() *MessageMarshaler { + if mm := m.mm; mm != nil { + return mm + } + idx := m.newMessageMarshalerIndex() + mm := &m.mms[idx] + m.mm = mm + return mm +} + +func (m *Marshaler) newMessageMarshalerIndex() int { + mms := m.mms + mmsLen := len(mms) + if cap(mms) > mmsLen { + mms = mms[:mmsLen+1] + } else { + mms = append(mms, MessageMarshaler{}) + } + m.mms = mms + mm := &mms[mmsLen] + mm.reset() + mm.m = m + return mmsLen +} + +func (m *Marshaler) newFieldIndex() int { + fs := m.fs + fsLen := len(fs) + if cap(fs) > fsLen { + fs = fs[:fsLen+1] + } else { + fs = append(fs, field{}) + } + m.fs = fs + fs[fsLen].reset() + return fsLen +} + +// AppendInt32 appends the given int32 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendInt32(fieldNum uint32, i32 int32) { + mm.AppendUint64(fieldNum, uint64(uint32(i32))) +} + +// AppendInt64 appends the given int64 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendInt64(fieldNum uint32, i64 int64) { + mm.AppendUint64(fieldNum, uint64(i64)) +} + +// AppendUint32 appends the given uint32 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendUint32(fieldNum, u32 uint32) { + mm.AppendUint64(fieldNum, uint64(u32)) +} + +// AppendUint64 appends the given uint64 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendUint64(fieldNum uint32, u64 uint64) { + tag := makeTag(fieldNum, wireTypeVarint) + + m := mm.m + dst := m.buf + dstLen := len(dst) + if tag < 0x80 { + dst = append(dst, byte(tag)) + } else { + dst = marshalVarUint64(dst, tag) + } + dst = marshalVarUint64(dst, u64) + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +// AppendSint32 appends the given sint32 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendSint32(fieldNum uint32, i32 int32) { + u64 := uint64(encodeZigZagInt32(i32)) + mm.AppendUint64(fieldNum, u64) +} + +// AppendSint64 appends the given sint64 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendSint64(fieldNum uint32, i64 int64) { + u64 := encodeZigZagInt64(i64) + mm.AppendUint64(fieldNum, u64) +} + +// AppendBool appends the given bool value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendBool(fieldNum uint32, v bool) { + u64 := uint64(0) + if v { + u64 = 1 + } + mm.AppendUint64(fieldNum, u64) +} + +// AppendFixed64 appends fixed64 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendFixed64(fieldNum uint32, u64 uint64) { + tag := makeTag(fieldNum, wireTypeI64) + + m := mm.m + dst := m.buf + dstLen := len(dst) + if tag < 0x80 { + dst = append(dst, byte(tag)) + } else { + dst = marshalVarUint64(dst, tag) + } + dst = marshalUint64(dst, u64) + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +// AppendSfixed64 appends sfixed64 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendSfixed64(fieldNum uint32, i64 int64) { + mm.AppendFixed64(fieldNum, uint64(i64)) +} + +// AppendDouble appends double value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendDouble(fieldNum uint32, f float64) { + u64 := math.Float64bits(f) + mm.AppendFixed64(fieldNum, u64) +} + +// AppendString appends string value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendString(fieldNum uint32, s string) { + tag := makeTag(fieldNum, wireTypeLen) + + m := mm.m + dst := m.buf + dstLen := len(dst) + sLen := len(s) + if tag < 0x80 && sLen < 0x80 { + dst = append(dst, byte(tag), byte(sLen)) + } else { + dst = marshalVarUint64(dst, tag) + dst = marshalVarUint64(dst, uint64(sLen)) + } + dst = append(dst, s...) + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +// AppendBytes appends bytes value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendBytes(fieldNum uint32, b []byte) { + s := unsafeBytesToString(b) + mm.AppendString(fieldNum, s) +} + +// AppendMessage appends protobuf message with the given fieldNum to m. +// +// The function returns the MessageMarshaler for constructing the appended message. +func (mm *MessageMarshaler) AppendMessage(fieldNum uint32) *MessageMarshaler { + tag := makeTag(fieldNum, wireTypeLen) + + f := mm.newField() + m := mm.m + f.childMessageMarshalerIdx = m.newMessageMarshalerIndex() + mmChild := &m.mms[f.childMessageMarshalerIdx] + mmChild.tag = tag + return mmChild +} + +// AppendFixed32 appends fixed32 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendFixed32(fieldNum, u32 uint32) { + tag := makeTag(fieldNum, wireTypeI32) + + m := mm.m + dst := m.buf + dstLen := len(dst) + if tag < 0x80 { + dst = append(dst, byte(tag)) + } else { + dst = marshalVarUint64(dst, tag) + } + dst = marshalUint32(dst, u32) + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +// AppendSfixed32 appends sfixed32 value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendSfixed32(fieldNum uint32, i32 int32) { + mm.AppendFixed32(fieldNum, uint32(i32)) +} + +// AppendFloat appends float value under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendFloat(fieldNum uint32, f float32) { + u32 := math.Float32bits(f) + mm.AppendFixed32(fieldNum, u32) +} + +// AppendInt32s appends the given int32 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendInt32s(fieldNum uint32, i32s []int32) { + child := mm.AppendMessage(fieldNum) + child.appendInt32s(i32s) +} + +// AppendInt64s appends the given int64 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendInt64s(fieldNum uint32, i64s []int64) { + child := mm.AppendMessage(fieldNum) + child.appendInt64s(i64s) +} + +// AppendUint32s appends the given uint32 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendUint32s(fieldNum uint32, u32s []uint32) { + child := mm.AppendMessage(fieldNum) + child.appendUint32s(u32s) +} + +// AppendUint64s appends the given uint64 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendUint64s(fieldNum uint32, u64s []uint64) { + child := mm.AppendMessage(fieldNum) + child.appendUint64s(u64s) +} + +// AppendSint32s appends the given sint32 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendSint32s(fieldNum uint32, i32s []int32) { + child := mm.AppendMessage(fieldNum) + child.appendSint32s(i32s) +} + +// AppendSint64s appends the given sint64 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendSint64s(fieldNum uint32, i64s []int64) { + child := mm.AppendMessage(fieldNum) + child.appendSint64s(i64s) +} + +// AppendBools appends the given bool values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendBools(fieldNum uint32, bs []bool) { + child := mm.AppendMessage(fieldNum) + child.appendBools(bs) +} + +// AppendFixed64s appends the given fixed64 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendFixed64s(fieldNum uint32, u64s []uint64) { + child := mm.AppendMessage(fieldNum) + child.appendFixed64s(u64s) +} + +// AppendSfixed64s appends the given sfixed64 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendSfixed64s(fieldNum uint32, i64s []int64) { + child := mm.AppendMessage(fieldNum) + child.appendSfixed64s(i64s) +} + +// AppendDoubles appends the given double values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendDoubles(fieldNum uint32, fs []float64) { + child := mm.AppendMessage(fieldNum) + child.appendDoubles(fs) +} + +// AppendFixed32s appends the given fixed32 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendFixed32s(fieldNum uint32, u32s []uint32) { + child := mm.AppendMessage(fieldNum) + child.appendFixed32s(u32s) +} + +// AppendSfixed32s appends the given sfixed32 values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendSfixed32s(fieldNum uint32, i32s []int32) { + child := mm.AppendMessage(fieldNum) + child.appendSfixed32s(i32s) +} + +// AppendFloats appends the given float values under the given fieldNum to mm. +func (mm *MessageMarshaler) AppendFloats(fieldNum uint32, fs []float32) { + child := mm.AppendMessage(fieldNum) + child.appendFloats(fs) +} + +func (mm *MessageMarshaler) appendInt32s(i32s []int32) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, i32 := range i32s { + dst = marshalVarUint64(dst, uint64(uint32(i32))) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendUint32s(u32s []uint32) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, u32 := range u32s { + dst = marshalVarUint64(dst, uint64(u32)) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendSint32s(i32s []int32) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, i32 := range i32s { + u64 := uint64(encodeZigZagInt32(i32)) + dst = marshalVarUint64(dst, u64) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendInt64s(i64s []int64) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, i64 := range i64s { + dst = marshalVarUint64(dst, uint64(i64)) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendUint64s(u64s []uint64) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, u64 := range u64s { + dst = marshalVarUint64(dst, u64) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendSint64s(i64s []int64) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, i64 := range i64s { + u64 := encodeZigZagInt64(i64) + dst = marshalVarUint64(dst, u64) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendBools(bs []bool) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, b := range bs { + u64 := uint64(0) + if b { + u64 = 1 + } + dst = marshalVarUint64(dst, u64) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendFixed64s(u64s []uint64) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, u64 := range u64s { + dst = marshalUint64(dst, u64) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendSfixed64s(i64s []int64) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, i64 := range i64s { + dst = marshalUint64(dst, uint64(i64)) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendFixed32s(u32s []uint32) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, u32 := range u32s { + dst = marshalUint32(dst, u32) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendSfixed32s(i32s []int32) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, i32 := range i32s { + dst = marshalUint32(dst, uint32(i32)) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendDoubles(fs []float64) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, f := range fs { + u64 := math.Float64bits(f) + dst = marshalUint64(dst, u64) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendFloats(fs []float32) { + m := mm.m + dst := m.buf + dstLen := len(dst) + for _, f := range fs { + u32 := math.Float32bits(f) + dst = marshalUint32(dst, u32) + } + m.buf = dst + + mm.appendField(m, dstLen, len(dst)) +} + +func (mm *MessageMarshaler) appendField(m *Marshaler, dataStart, dataEnd int) { + if lastFieldIdx := mm.lastFieldIdx; lastFieldIdx >= 0 { + if f := &m.fs[lastFieldIdx]; f.childMessageMarshalerIdx == -1 && f.dataEnd == dataStart { + f.dataEnd = dataEnd + return + } + } + f := mm.newField() + f.dataStart = dataStart + f.dataEnd = dataEnd +} + +func (mm *MessageMarshaler) newField() *field { + m := mm.m + idx := m.newFieldIndex() + f := &m.fs[idx] + if lastFieldIdx := mm.lastFieldIdx; lastFieldIdx >= 0 { + m.fs[lastFieldIdx].nextFieldIdx = idx + } else { + mm.firstFieldIdx = idx + } + mm.lastFieldIdx = idx + return f +} + +func (f *field) initMessageSize(m *Marshaler) uint64 { + n := uint64(0) + for { + if childMessageMarshalerIdx := f.childMessageMarshalerIdx; childMessageMarshalerIdx < 0 { + n += uint64(f.dataEnd - f.dataStart) + } else { + mmChild := m.mms[childMessageMarshalerIdx] + if tag := mmChild.tag; tag < 0x80 { + n++ + } else { + n += varuintLen(tag) + } + messageSize := uint64(0) + if firstFieldIdx := mmChild.firstFieldIdx; firstFieldIdx >= 0 { + messageSize = m.fs[firstFieldIdx].initMessageSize(m) + } + n += messageSize + if messageSize < 0x80 { + n++ + } else { + n += varuintLen(messageSize) + } + f.messageSize = messageSize + } + nextFieldIdx := f.nextFieldIdx + if nextFieldIdx < 0 { + return n + } + f = &m.fs[nextFieldIdx] + } +} + +func (f *field) marshal(dst []byte, m *Marshaler) []byte { + for { + if childMessageMarshalerIdx := f.childMessageMarshalerIdx; childMessageMarshalerIdx < 0 { + data := m.buf[f.dataStart:f.dataEnd] + dst = append(dst, data...) + } else { + mmChild := m.mms[childMessageMarshalerIdx] + tag := mmChild.tag + messageSize := f.messageSize + if tag < 0x80 && messageSize < 0x80 { + dst = append(dst, byte(tag), byte(messageSize)) + } else { + dst = marshalVarUint64(dst, mmChild.tag) + dst = marshalVarUint64(dst, f.messageSize) + } + if firstFieldIdx := mmChild.firstFieldIdx; firstFieldIdx >= 0 { + dst = m.fs[firstFieldIdx].marshal(dst, m) + } + } + nextFieldIdx := f.nextFieldIdx + if nextFieldIdx < 0 { + return dst + } + f = &m.fs[nextFieldIdx] + } +} + +func marshalUint64(dst []byte, u64 uint64) []byte { + return binary.LittleEndian.AppendUint64(dst, u64) +} + +func marshalUint32(dst []byte, u32 uint32) []byte { + return binary.LittleEndian.AppendUint32(dst, u32) +} + +func marshalVarUint64(dst []byte, u64 uint64) []byte { + if u64 < 0x80 { + // Fast path + dst = append(dst, byte(u64)) + return dst + } + for u64 > 0x7f { + dst = append(dst, 0x80|byte(u64)) + u64 >>= 7 + } + dst = append(dst, byte(u64)) + return dst +} + +func encodeZigZagInt64(i64 int64) uint64 { + return uint64((i64 << 1) ^ (i64 >> 63)) +} + +func encodeZigZagInt32(i32 int32) uint32 { + return uint32((i32 << 1) ^ (i32 >> 31)) +} + +func makeTag(fieldNum uint32, wt wireType) uint64 { + return (uint64(fieldNum) << 3) | uint64(wt) +} + +// varuintLen returns the number of bytes needed for varuint-encoding of u64. +// +// Note that it returns 0 for u64=0, so this case must be handled separately. +func varuintLen(u64 uint64) uint64 { + return uint64(((byte(bits.Len64(u64))) + 6) / 7) +} diff --git a/vendor/github.com/cespare/xxhash/v2/LICENSE.txt b/vendor/github.com/cespare/xxhash/v2/LICENSE.txt new file mode 100644 index 0000000..24b5306 --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2016 Caleb Spare + +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. diff --git a/vendor/github.com/cespare/xxhash/v2/README.md b/vendor/github.com/cespare/xxhash/v2/README.md new file mode 100644 index 0000000..33c8830 --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/README.md @@ -0,0 +1,74 @@ +# xxhash + +[![Go Reference](https://pkg.go.dev/badge/github.com/cespare/xxhash/v2.svg)](https://pkg.go.dev/github.com/cespare/xxhash/v2) +[![Test](https://github.com/cespare/xxhash/actions/workflows/test.yml/badge.svg)](https://github.com/cespare/xxhash/actions/workflows/test.yml) + +xxhash is a Go implementation of the 64-bit [xxHash] algorithm, XXH64. This is a +high-quality hashing algorithm that is much faster than anything in the Go +standard library. + +This package provides a straightforward API: + +``` +func Sum64(b []byte) uint64 +func Sum64String(s string) uint64 +type Digest struct{ ... } + func New() *Digest +``` + +The `Digest` type implements hash.Hash64. Its key methods are: + +``` +func (*Digest) Write([]byte) (int, error) +func (*Digest) WriteString(string) (int, error) +func (*Digest) Sum64() uint64 +``` + +The package is written with optimized pure Go and also contains even faster +assembly implementations for amd64 and arm64. If desired, the `purego` build tag +opts into using the Go code even on those architectures. + +[xxHash]: http://cyan4973.github.io/xxHash/ + +## Compatibility + +This package is in a module and the latest code is in version 2 of the module. +You need a version of Go with at least "minimal module compatibility" to use +github.com/cespare/xxhash/v2: + +* 1.9.7+ for Go 1.9 +* 1.10.3+ for Go 1.10 +* Go 1.11 or later + +I recommend using the latest release of Go. + +## Benchmarks + +Here are some quick benchmarks comparing the pure-Go and assembly +implementations of Sum64. + +| input size | purego | asm | +| ---------- | --------- | --------- | +| 4 B | 1.3 GB/s | 1.2 GB/s | +| 16 B | 2.9 GB/s | 3.5 GB/s | +| 100 B | 6.9 GB/s | 8.1 GB/s | +| 4 KB | 11.7 GB/s | 16.7 GB/s | +| 10 MB | 12.0 GB/s | 17.3 GB/s | + +These numbers were generated on Ubuntu 20.04 with an Intel Xeon Platinum 8252C +CPU using the following commands under Go 1.19.2: + +``` +benchstat <(go test -tags purego -benchtime 500ms -count 15 -bench 'Sum64$') +benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$') +``` + +## Projects using this package + +- [InfluxDB](https://github.com/influxdata/influxdb) +- [Prometheus](https://github.com/prometheus/prometheus) +- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics) +- [FreeCache](https://github.com/coocood/freecache) +- [FastCache](https://github.com/VictoriaMetrics/fastcache) +- [Ristretto](https://github.com/dgraph-io/ristretto) +- [Badger](https://github.com/dgraph-io/badger) diff --git a/vendor/github.com/cespare/xxhash/v2/testall.sh b/vendor/github.com/cespare/xxhash/v2/testall.sh new file mode 100644 index 0000000..94b9c44 --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/testall.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -eu -o pipefail + +# Small convenience script for running the tests with various combinations of +# arch/tags. This assumes we're running on amd64 and have qemu available. + +go test ./... +go test -tags purego ./... +GOARCH=arm64 go test +GOARCH=arm64 go test -tags purego diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash.go b/vendor/github.com/cespare/xxhash/v2/xxhash.go new file mode 100644 index 0000000..78bddf1 --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/xxhash.go @@ -0,0 +1,243 @@ +// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described +// at http://cyan4973.github.io/xxHash/. +package xxhash + +import ( + "encoding/binary" + "errors" + "math/bits" +) + +const ( + prime1 uint64 = 11400714785074694791 + prime2 uint64 = 14029467366897019727 + prime3 uint64 = 1609587929392839161 + prime4 uint64 = 9650029242287828579 + prime5 uint64 = 2870177450012600261 +) + +// Store the primes in an array as well. +// +// The consts are used when possible in Go code to avoid MOVs but we need a +// contiguous array for the assembly code. +var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5} + +// Digest implements hash.Hash64. +// +// Note that a zero-valued Digest is not ready to receive writes. +// Call Reset or create a Digest using New before calling other methods. +type Digest struct { + v1 uint64 + v2 uint64 + v3 uint64 + v4 uint64 + total uint64 + mem [32]byte + n int // how much of mem is used +} + +// New creates a new Digest with a zero seed. +func New() *Digest { + return NewWithSeed(0) +} + +// NewWithSeed creates a new Digest with the given seed. +func NewWithSeed(seed uint64) *Digest { + var d Digest + d.ResetWithSeed(seed) + return &d +} + +// Reset clears the Digest's state so that it can be reused. +// It uses a seed value of zero. +func (d *Digest) Reset() { + d.ResetWithSeed(0) +} + +// ResetWithSeed clears the Digest's state so that it can be reused. +// It uses the given seed to initialize the state. +func (d *Digest) ResetWithSeed(seed uint64) { + d.v1 = seed + prime1 + prime2 + d.v2 = seed + prime2 + d.v3 = seed + d.v4 = seed - prime1 + d.total = 0 + d.n = 0 +} + +// Size always returns 8 bytes. +func (d *Digest) Size() int { return 8 } + +// BlockSize always returns 32 bytes. +func (d *Digest) BlockSize() int { return 32 } + +// Write adds more data to d. It always returns len(b), nil. +func (d *Digest) Write(b []byte) (n int, err error) { + n = len(b) + d.total += uint64(n) + + memleft := d.mem[d.n&(len(d.mem)-1):] + + if d.n+n < 32 { + // This new data doesn't even fill the current block. + copy(memleft, b) + d.n += n + return + } + + if d.n > 0 { + // Finish off the partial block. + c := copy(memleft, b) + d.v1 = round(d.v1, u64(d.mem[0:8])) + d.v2 = round(d.v2, u64(d.mem[8:16])) + d.v3 = round(d.v3, u64(d.mem[16:24])) + d.v4 = round(d.v4, u64(d.mem[24:32])) + b = b[c:] + d.n = 0 + } + + if len(b) >= 32 { + // One or more full blocks left. + nw := writeBlocks(d, b) + b = b[nw:] + } + + // Store any remaining partial block. + copy(d.mem[:], b) + d.n = len(b) + + return +} + +// Sum appends the current hash to b and returns the resulting slice. +func (d *Digest) Sum(b []byte) []byte { + s := d.Sum64() + return append( + b, + byte(s>>56), + byte(s>>48), + byte(s>>40), + byte(s>>32), + byte(s>>24), + byte(s>>16), + byte(s>>8), + byte(s), + ) +} + +// Sum64 returns the current hash. +func (d *Digest) Sum64() uint64 { + var h uint64 + + if d.total >= 32 { + v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 + h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) + h = mergeRound(h, v1) + h = mergeRound(h, v2) + h = mergeRound(h, v3) + h = mergeRound(h, v4) + } else { + h = d.v3 + prime5 + } + + h += d.total + + b := d.mem[:d.n&(len(d.mem)-1)] + for ; len(b) >= 8; b = b[8:] { + k1 := round(0, u64(b[:8])) + h ^= k1 + h = rol27(h)*prime1 + prime4 + } + if len(b) >= 4 { + h ^= uint64(u32(b[:4])) * prime1 + h = rol23(h)*prime2 + prime3 + b = b[4:] + } + for ; len(b) > 0; b = b[1:] { + h ^= uint64(b[0]) * prime5 + h = rol11(h) * prime1 + } + + h ^= h >> 33 + h *= prime2 + h ^= h >> 29 + h *= prime3 + h ^= h >> 32 + + return h +} + +const ( + magic = "xxh\x06" + marshaledSize = len(magic) + 8*5 + 32 +) + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (d *Digest) MarshalBinary() ([]byte, error) { + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + b = appendUint64(b, d.v1) + b = appendUint64(b, d.v2) + b = appendUint64(b, d.v3) + b = appendUint64(b, d.v4) + b = appendUint64(b, d.total) + b = append(b, d.mem[:d.n]...) + b = b[:len(b)+len(d.mem)-d.n] + return b, nil +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +func (d *Digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("xxhash: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("xxhash: invalid hash state size") + } + b = b[len(magic):] + b, d.v1 = consumeUint64(b) + b, d.v2 = consumeUint64(b) + b, d.v3 = consumeUint64(b) + b, d.v4 = consumeUint64(b) + b, d.total = consumeUint64(b) + copy(d.mem[:], b) + d.n = int(d.total % uint64(len(d.mem))) + return nil +} + +func appendUint64(b []byte, x uint64) []byte { + var a [8]byte + binary.LittleEndian.PutUint64(a[:], x) + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + x := u64(b) + return b[8:], x +} + +func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) } +func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } + +func round(acc, input uint64) uint64 { + acc += input * prime2 + acc = rol31(acc) + acc *= prime1 + return acc +} + +func mergeRound(acc, val uint64) uint64 { + val = round(0, val) + acc ^= val + acc = acc*prime1 + prime4 + return acc +} + +func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) } +func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) } +func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) } +func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) } +func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) } +func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) } +func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) } +func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) } diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s new file mode 100644 index 0000000..3e8b132 --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s @@ -0,0 +1,209 @@ +//go:build !appengine && gc && !purego +// +build !appengine +// +build gc +// +build !purego + +#include "textflag.h" + +// Registers: +#define h AX +#define d AX +#define p SI // pointer to advance through b +#define n DX +#define end BX // loop end +#define v1 R8 +#define v2 R9 +#define v3 R10 +#define v4 R11 +#define x R12 +#define prime1 R13 +#define prime2 R14 +#define prime4 DI + +#define round(acc, x) \ + IMULQ prime2, x \ + ADDQ x, acc \ + ROLQ $31, acc \ + IMULQ prime1, acc + +// round0 performs the operation x = round(0, x). +#define round0(x) \ + IMULQ prime2, x \ + ROLQ $31, x \ + IMULQ prime1, x + +// mergeRound applies a merge round on the two registers acc and x. +// It assumes that prime1, prime2, and prime4 have been loaded. +#define mergeRound(acc, x) \ + round0(x) \ + XORQ x, acc \ + IMULQ prime1, acc \ + ADDQ prime4, acc + +// blockLoop processes as many 32-byte blocks as possible, +// updating v1, v2, v3, and v4. It assumes that there is at least one block +// to process. +#define blockLoop() \ +loop: \ + MOVQ +0(p), x \ + round(v1, x) \ + MOVQ +8(p), x \ + round(v2, x) \ + MOVQ +16(p), x \ + round(v3, x) \ + MOVQ +24(p), x \ + round(v4, x) \ + ADDQ $32, p \ + CMPQ p, end \ + JLE loop + +// func Sum64(b []byte) uint64 +TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32 + // Load fixed primes. + MOVQ ·primes+0(SB), prime1 + MOVQ ·primes+8(SB), prime2 + MOVQ ·primes+24(SB), prime4 + + // Load slice. + MOVQ b_base+0(FP), p + MOVQ b_len+8(FP), n + LEAQ (p)(n*1), end + + // The first loop limit will be len(b)-32. + SUBQ $32, end + + // Check whether we have at least one block. + CMPQ n, $32 + JLT noBlocks + + // Set up initial state (v1, v2, v3, v4). + MOVQ prime1, v1 + ADDQ prime2, v1 + MOVQ prime2, v2 + XORQ v3, v3 + XORQ v4, v4 + SUBQ prime1, v4 + + blockLoop() + + MOVQ v1, h + ROLQ $1, h + MOVQ v2, x + ROLQ $7, x + ADDQ x, h + MOVQ v3, x + ROLQ $12, x + ADDQ x, h + MOVQ v4, x + ROLQ $18, x + ADDQ x, h + + mergeRound(h, v1) + mergeRound(h, v2) + mergeRound(h, v3) + mergeRound(h, v4) + + JMP afterBlocks + +noBlocks: + MOVQ ·primes+32(SB), h + +afterBlocks: + ADDQ n, h + + ADDQ $24, end + CMPQ p, end + JG try4 + +loop8: + MOVQ (p), x + ADDQ $8, p + round0(x) + XORQ x, h + ROLQ $27, h + IMULQ prime1, h + ADDQ prime4, h + + CMPQ p, end + JLE loop8 + +try4: + ADDQ $4, end + CMPQ p, end + JG try1 + + MOVL (p), x + ADDQ $4, p + IMULQ prime1, x + XORQ x, h + + ROLQ $23, h + IMULQ prime2, h + ADDQ ·primes+16(SB), h + +try1: + ADDQ $4, end + CMPQ p, end + JGE finalize + +loop1: + MOVBQZX (p), x + ADDQ $1, p + IMULQ ·primes+32(SB), x + XORQ x, h + ROLQ $11, h + IMULQ prime1, h + + CMPQ p, end + JL loop1 + +finalize: + MOVQ h, x + SHRQ $33, x + XORQ x, h + IMULQ prime2, h + MOVQ h, x + SHRQ $29, x + XORQ x, h + IMULQ ·primes+16(SB), h + MOVQ h, x + SHRQ $32, x + XORQ x, h + + MOVQ h, ret+24(FP) + RET + +// func writeBlocks(d *Digest, b []byte) int +TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 + // Load fixed primes needed for round. + MOVQ ·primes+0(SB), prime1 + MOVQ ·primes+8(SB), prime2 + + // Load slice. + MOVQ b_base+8(FP), p + MOVQ b_len+16(FP), n + LEAQ (p)(n*1), end + SUBQ $32, end + + // Load vN from d. + MOVQ s+0(FP), d + MOVQ 0(d), v1 + MOVQ 8(d), v2 + MOVQ 16(d), v3 + MOVQ 24(d), v4 + + // We don't need to check the loop condition here; this function is + // always called with at least one block of data to process. + blockLoop() + + // Copy vN back to d. + MOVQ v1, 0(d) + MOVQ v2, 8(d) + MOVQ v3, 16(d) + MOVQ v4, 24(d) + + // The number of bytes written is p minus the old base pointer. + SUBQ b_base+8(FP), p + MOVQ p, ret+32(FP) + + RET diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s b/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s new file mode 100644 index 0000000..7e3145a --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s @@ -0,0 +1,183 @@ +//go:build !appengine && gc && !purego +// +build !appengine +// +build gc +// +build !purego + +#include "textflag.h" + +// Registers: +#define digest R1 +#define h R2 // return value +#define p R3 // input pointer +#define n R4 // input length +#define nblocks R5 // n / 32 +#define prime1 R7 +#define prime2 R8 +#define prime3 R9 +#define prime4 R10 +#define prime5 R11 +#define v1 R12 +#define v2 R13 +#define v3 R14 +#define v4 R15 +#define x1 R20 +#define x2 R21 +#define x3 R22 +#define x4 R23 + +#define round(acc, x) \ + MADD prime2, acc, x, acc \ + ROR $64-31, acc \ + MUL prime1, acc + +// round0 performs the operation x = round(0, x). +#define round0(x) \ + MUL prime2, x \ + ROR $64-31, x \ + MUL prime1, x + +#define mergeRound(acc, x) \ + round0(x) \ + EOR x, acc \ + MADD acc, prime4, prime1, acc + +// blockLoop processes as many 32-byte blocks as possible, +// updating v1, v2, v3, and v4. It assumes that n >= 32. +#define blockLoop() \ + LSR $5, n, nblocks \ + PCALIGN $16 \ + loop: \ + LDP.P 16(p), (x1, x2) \ + LDP.P 16(p), (x3, x4) \ + round(v1, x1) \ + round(v2, x2) \ + round(v3, x3) \ + round(v4, x4) \ + SUB $1, nblocks \ + CBNZ nblocks, loop + +// func Sum64(b []byte) uint64 +TEXT ·Sum64(SB), NOSPLIT|NOFRAME, $0-32 + LDP b_base+0(FP), (p, n) + + LDP ·primes+0(SB), (prime1, prime2) + LDP ·primes+16(SB), (prime3, prime4) + MOVD ·primes+32(SB), prime5 + + CMP $32, n + CSEL LT, prime5, ZR, h // if n < 32 { h = prime5 } else { h = 0 } + BLT afterLoop + + ADD prime1, prime2, v1 + MOVD prime2, v2 + MOVD $0, v3 + NEG prime1, v4 + + blockLoop() + + ROR $64-1, v1, x1 + ROR $64-7, v2, x2 + ADD x1, x2 + ROR $64-12, v3, x3 + ROR $64-18, v4, x4 + ADD x3, x4 + ADD x2, x4, h + + mergeRound(h, v1) + mergeRound(h, v2) + mergeRound(h, v3) + mergeRound(h, v4) + +afterLoop: + ADD n, h + + TBZ $4, n, try8 + LDP.P 16(p), (x1, x2) + + round0(x1) + + // NOTE: here and below, sequencing the EOR after the ROR (using a + // rotated register) is worth a small but measurable speedup for small + // inputs. + ROR $64-27, h + EOR x1 @> 64-27, h, h + MADD h, prime4, prime1, h + + round0(x2) + ROR $64-27, h + EOR x2 @> 64-27, h, h + MADD h, prime4, prime1, h + +try8: + TBZ $3, n, try4 + MOVD.P 8(p), x1 + + round0(x1) + ROR $64-27, h + EOR x1 @> 64-27, h, h + MADD h, prime4, prime1, h + +try4: + TBZ $2, n, try2 + MOVWU.P 4(p), x2 + + MUL prime1, x2 + ROR $64-23, h + EOR x2 @> 64-23, h, h + MADD h, prime3, prime2, h + +try2: + TBZ $1, n, try1 + MOVHU.P 2(p), x3 + AND $255, x3, x1 + LSR $8, x3, x2 + + MUL prime5, x1 + ROR $64-11, h + EOR x1 @> 64-11, h, h + MUL prime1, h + + MUL prime5, x2 + ROR $64-11, h + EOR x2 @> 64-11, h, h + MUL prime1, h + +try1: + TBZ $0, n, finalize + MOVBU (p), x4 + + MUL prime5, x4 + ROR $64-11, h + EOR x4 @> 64-11, h, h + MUL prime1, h + +finalize: + EOR h >> 33, h + MUL prime2, h + EOR h >> 29, h + MUL prime3, h + EOR h >> 32, h + + MOVD h, ret+24(FP) + RET + +// func writeBlocks(d *Digest, b []byte) int +TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40 + LDP ·primes+0(SB), (prime1, prime2) + + // Load state. Assume v[1-4] are stored contiguously. + MOVD d+0(FP), digest + LDP 0(digest), (v1, v2) + LDP 16(digest), (v3, v4) + + LDP b_base+8(FP), (p, n) + + blockLoop() + + // Store updated state. + STP (v1, v2), 0(digest) + STP (v3, v4), 16(digest) + + BIC $31, n + MOVD n, ret+32(FP) + RET diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go new file mode 100644 index 0000000..78f95f2 --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_asm.go @@ -0,0 +1,15 @@ +//go:build (amd64 || arm64) && !appengine && gc && !purego +// +build amd64 arm64 +// +build !appengine +// +build gc +// +build !purego + +package xxhash + +// Sum64 computes the 64-bit xxHash digest of b with a zero seed. +// +//go:noescape +func Sum64(b []byte) uint64 + +//go:noescape +func writeBlocks(d *Digest, b []byte) int diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_other.go b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go new file mode 100644 index 0000000..118e49e --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_other.go @@ -0,0 +1,76 @@ +//go:build (!amd64 && !arm64) || appengine || !gc || purego +// +build !amd64,!arm64 appengine !gc purego + +package xxhash + +// Sum64 computes the 64-bit xxHash digest of b with a zero seed. +func Sum64(b []byte) uint64 { + // A simpler version would be + // d := New() + // d.Write(b) + // return d.Sum64() + // but this is faster, particularly for small inputs. + + n := len(b) + var h uint64 + + if n >= 32 { + v1 := primes[0] + prime2 + v2 := prime2 + v3 := uint64(0) + v4 := -primes[0] + for len(b) >= 32 { + v1 = round(v1, u64(b[0:8:len(b)])) + v2 = round(v2, u64(b[8:16:len(b)])) + v3 = round(v3, u64(b[16:24:len(b)])) + v4 = round(v4, u64(b[24:32:len(b)])) + b = b[32:len(b):len(b)] + } + h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) + h = mergeRound(h, v1) + h = mergeRound(h, v2) + h = mergeRound(h, v3) + h = mergeRound(h, v4) + } else { + h = prime5 + } + + h += uint64(n) + + for ; len(b) >= 8; b = b[8:] { + k1 := round(0, u64(b[:8])) + h ^= k1 + h = rol27(h)*prime1 + prime4 + } + if len(b) >= 4 { + h ^= uint64(u32(b[:4])) * prime1 + h = rol23(h)*prime2 + prime3 + b = b[4:] + } + for ; len(b) > 0; b = b[1:] { + h ^= uint64(b[0]) * prime5 + h = rol11(h) * prime1 + } + + h ^= h >> 33 + h *= prime2 + h ^= h >> 29 + h *= prime3 + h ^= h >> 32 + + return h +} + +func writeBlocks(d *Digest, b []byte) int { + v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4 + n := len(b) + for len(b) >= 32 { + v1 = round(v1, u64(b[0:8:len(b)])) + v2 = round(v2, u64(b[8:16:len(b)])) + v3 = round(v3, u64(b[16:24:len(b)])) + v4 = round(v4, u64(b[24:32:len(b)])) + b = b[32:len(b):len(b)] + } + d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4 + return n - len(b) +} diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go new file mode 100644 index 0000000..05f5e7d --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_safe.go @@ -0,0 +1,16 @@ +//go:build appengine +// +build appengine + +// This file contains the safe implementations of otherwise unsafe-using code. + +package xxhash + +// Sum64String computes the 64-bit xxHash digest of s with a zero seed. +func Sum64String(s string) uint64 { + return Sum64([]byte(s)) +} + +// WriteString adds more data to d. It always returns len(s), nil. +func (d *Digest) WriteString(s string) (n int, err error) { + return d.Write([]byte(s)) +} diff --git a/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go new file mode 100644 index 0000000..cf9d42a --- /dev/null +++ b/vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go @@ -0,0 +1,58 @@ +//go:build !appengine +// +build !appengine + +// This file encapsulates usage of unsafe. +// xxhash_safe.go contains the safe implementations. + +package xxhash + +import ( + "unsafe" +) + +// In the future it's possible that compiler optimizations will make these +// XxxString functions unnecessary by realizing that calls such as +// Sum64([]byte(s)) don't need to copy s. See https://go.dev/issue/2205. +// If that happens, even if we keep these functions they can be replaced with +// the trivial safe code. + +// NOTE: The usual way of doing an unsafe string-to-[]byte conversion is: +// +// var b []byte +// bh := (*reflect.SliceHeader)(unsafe.Pointer(&b)) +// bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data +// bh.Len = len(s) +// bh.Cap = len(s) +// +// Unfortunately, as of Go 1.15.3 the inliner's cost model assigns a high enough +// weight to this sequence of expressions that any function that uses it will +// not be inlined. Instead, the functions below use a different unsafe +// conversion designed to minimize the inliner weight and allow both to be +// inlined. There is also a test (TestInlining) which verifies that these are +// inlined. +// +// See https://github.com/golang/go/issues/42739 for discussion. + +// Sum64String computes the 64-bit xxHash digest of s with a zero seed. +// It may be faster than Sum64([]byte(s)) by avoiding a copy. +func Sum64String(s string) uint64 { + b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})) + return Sum64(b) +} + +// WriteString adds more data to d. It always returns len(s), nil. +// It may be faster than Write([]byte(s)) by avoiding a copy. +func (d *Digest) WriteString(s string) (n int, err error) { + d.Write(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))) + // d.Write always returns len(s), nil. + // Ignoring the return output and returning these fixed values buys a + // savings of 6 in the inliner's cost model. + return len(s), nil +} + +// sliceHeader is similar to reflect.SliceHeader, but it assumes that the layout +// of the first two words is the same as the layout of a string. +type sliceHeader struct { + s string + cap int +} diff --git a/vendor/github.com/clipperhouse/displaywidth/.gitignore b/vendor/github.com/clipperhouse/displaywidth/.gitignore new file mode 100644 index 0000000..b356d43 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +*.out +*.test diff --git a/vendor/github.com/clipperhouse/displaywidth/AGENTS.md b/vendor/github.com/clipperhouse/displaywidth/AGENTS.md new file mode 100644 index 0000000..9ae951b --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/AGENTS.md @@ -0,0 +1,51 @@ +The goals and overview of this package can be found in the README.md file, +start by reading that. + +The goal of this package is to determine the display (column) width of a +string, UTF-8 bytes, or runes, as would happen in a monospace font, especially +in a terminal. + +When troubleshooting, write Go unit tests instead of executing debug scripts. +The tests can return whatever logs or output you need. If those tests are +only for temporary troubleshooting, clean up the tests after the debugging is +done. + +(Separate executable debugging scripts are messy, tend to have conflicting +dependencies and are hard to cleanup.) + +If you make changes to the trie generation in internal/gen, it can be invoked +by running `go generate` from the top package directory. + +## Pull Requests and branches + +For PRs (pull requests), you can use the gh CLI tool. Compare the current branch with main. Reviewing a PR and reviewing a branch are about the same, but the PR may add context. + +Understand the goals of the PR. Note any API changes, especially breaking changes. + +Look for thoroughness of tests, as well as GoDoc comments. + +Retrieve and consider the comments on the PR, which may have come from GitHub Copilot or Cursor BugBot. Think like GitHub Copilot or Cursor BugBot. + +Offer to optionally post a brief summary of the review to the PR, via the gh CLI tool. + +## Tagged Go releases + +If I ask you whether we are ready to release, this means a tagged Go release on the main branch. Go releases are git tagged with a version number. + +Review the changes since the last release, i.e. the previous git tag. Ensure that the changes are complete and correct. Identify new features, bug fixes, and performance improvements. + +Identify breaking changes, especially API changes. + +Ensure good test coverage. Look for performance changes, especially performance regressions, by running benchmarks against the previous release. + +Ensure that the documentation in READMEs and GoDocs are complete, correct and consistent. + +## Comparisons to go-runewidth + +We originally attempted to make this package compatible with go-runewidth. +However, we found that there were too many differences in the handling of +certain characters and properties. + +We believe, preliminarily, that our choices are more correct and complete, +by using more complete categories such as Unicode Cf (format) for zero-width +and Mn (Nonspacing_Mark) for combining marks. diff --git a/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md b/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md new file mode 100644 index 0000000..8c6efc1 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/CHANGELOG.md @@ -0,0 +1,129 @@ +# Changelog + +## [0.11.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.10.0...v0.11.0) + +### Added +- New `ControlSequences8Bit` option to treat 8-bit ECMA-48 (C1) escape sequences as zero-width. (#22) + +### Changed +- Upgraded uax29 dependency to v2.7.0 for 8-bit escape sequence support in the grapheme iterator. +- Truncation now validates that preserved trailing escape sequences are zero-width, preventing edge cases where non-zero-width sequences could leak into output. + +### Note +- `ControlSequences8Bit` is deliberately ignored by `TruncateString` and `TruncateBytes`, because C1 byte values (0x80–0x9F) overlap with UTF-8 multi-byte encoding. + +## [0.10.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.9.0...v0.10.0) + +### Added +- New `ControlSequences` option to treat ECMA-48/ANSI escape sequences as zero-width. (#20) +- `TruncateString` and `TruncateBytes` now preserve trailing ANSI escape sequences (such as SGR resets) when `ControlSequences` is true, preventing color bleed in terminal output. + +### Changed +- Removed `stringish` dependency; generic type constraints are now inline `~string | []byte`. +- Upgraded uax29 dependency to v2.6.0 for ANSI escape sequence support in the grapheme iterator. + +## [0.9.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.8.0...v0.9.0) + +### Changed +- Unicode 17 support: East Asian Width and emoji data updated to Unicode 17.0.0. (#18) +- Upgraded uax29 dependency to v2.5.0 (Unicode 17 grapheme segmentation). + +## [0.8.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.7.0...v0.8.0) + +### Changed +- Performance: ASCII fast path that applies to any run of printable + ASCII. 2x-10x faster for ASCII text vs v0.7.0. (#16) +- Upgraded uax29 dependency to v2.4.0 for Unicode 16 support. Text that includes + Indic_Conjunct_Break may segment differently (and more correctly). (#15) + +## [0.7.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.2...v0.7.0) + +### Added +- New `TruncateString` and `TruncateBytes` methods to truncate strings to a + maximum display width, with optional tail (like an ellipsis). (#13) + +## [0.6.2] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.1...v0.6.2) + +### Changed +- Internal: reduced property categories for simpler trie. + +## [0.6.1] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.6.0...v0.6.1) + +### Changed +- Perf improvements: replaced the ASCII lookup table with a simple + function. A bit more cache-friendly. More inlining. +- Bug fix: single regional indicators are now treated as width 2, since that + is what actual terminals do. + +## [0.6.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.5.0...v0.6.0) + +### Added +- New `StringGraphemes` and `BytesGraphemes` methods, for iterating over the +widths of grapheme clusters. + +### Changed +- Fast ASCII lookups + +## [0.5.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.4.1...v0.5.0) + +### Added +- Unicode 16 support +- Improved emoji presentation handling per Unicode TR51 + +### Changed +- Corrected VS15 (U+FE0E) handling: now preserves base character width (no-op) per Unicode TR51 +- Performance optimizations: reduced property lookups + +### Fixed +- VS15 variation selector now correctly preserves base character width instead of forcing width 1 + +## [0.4.1] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.4.0...v0.4.1) + +### Changed +- Updated uax29 dependency +- Improved flag handling + +## [0.4.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.3.1...v0.4.0) + +### Added +- Support for variation selectors (VS15, VS16) and regional indicator pairs (flags) + +## [0.3.1] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.3.0...v0.3.1) + +### Added +- Fuzz testing support + +### Changed +- Updated stringish dependency + +## [0.3.0] + +[Compare](https://github.com/clipperhouse/displaywidth/compare/v0.2.0...v0.3.0) + +### Changed +- Dropped compatibility with go-runewidth +- Trie implementation cleanup diff --git a/vendor/github.com/rivo/uniseg/LICENSE.txt b/vendor/github.com/clipperhouse/displaywidth/LICENSE similarity index 96% rename from vendor/github.com/rivo/uniseg/LICENSE.txt rename to vendor/github.com/clipperhouse/displaywidth/LICENSE index 5040f1e..4b8064e 100644 --- a/vendor/github.com/rivo/uniseg/LICENSE.txt +++ b/vendor/github.com/clipperhouse/displaywidth/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Oliver Kuederle +Copyright (c) 2025 Matt Sherman Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/clipperhouse/displaywidth/README.md b/vendor/github.com/clipperhouse/displaywidth/README.md new file mode 100644 index 0000000..506822b --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/README.md @@ -0,0 +1,190 @@ +# displaywidth + +A high-performance Go package for measuring the monospace display width of strings, UTF-8 bytes, and runes. + +[![Documentation](https://pkg.go.dev/badge/github.com/clipperhouse/displaywidth.svg)](https://pkg.go.dev/github.com/clipperhouse/displaywidth) +[![Test](https://github.com/clipperhouse/displaywidth/actions/workflows/gotest.yml/badge.svg)](https://github.com/clipperhouse/displaywidth/actions/workflows/gotest.yml) +[![Fuzz](https://github.com/clipperhouse/displaywidth/actions/workflows/gofuzz.yml/badge.svg)](https://github.com/clipperhouse/displaywidth/actions/workflows/gofuzz.yml) + +## Install +```bash +go get github.com/clipperhouse/displaywidth +``` + +## Usage + +```go +package main + +import ( + "fmt" + "github.com/clipperhouse/displaywidth" +) + +func main() { + width := displaywidth.String("Hello, 世界!") + fmt.Println(width) + + width = displaywidth.Bytes([]byte("🌍")) + fmt.Println(width) + + width = displaywidth.Rune('🌍') + fmt.Println(width) +} +``` + +For most purposes, you should use the `String` or `Bytes` methods. They sum +the widths of grapheme clusters in the string or byte slice. + +> Note: in your application, iterating over runes to measure width is likely incorrect; +the smallest unit of display is a grapheme, not a rune. + +### Iterating over graphemes + +If you need the individual graphemes: + +```go +import ( + "fmt" + "github.com/clipperhouse/displaywidth" +) + +func main() { + g := displaywidth.StringGraphemes("Hello, 世界!") + for g.Next() { + width := g.Width() + value := g.Value() + // do something with the width or value + } +} +``` + +### Options + +Create the options you need, and then use methods on the options struct. + +```go +var myOptions = displaywidth.Options{ + EastAsianWidth: true, + ControlSequences: true, +} + +width := myOptions.String("Hello, 世界!") +``` + +#### ControlSequences + +`ControlSequences` specifies whether to ignore ECMA-48 escape sequences +when calculating the display width. When `false` (default), ANSI escape +sequences are treated as just a series of characters. When `true`, they are +treated as a single zero-width unit. + +#### ControlSequences8Bit + +`ControlSequences8Bit` specifies whether to ignore 8-bit ECMA-48 escape sequences +when calculating the display width. When `false` (default), these are treated +as just a series of characters. When `true`, they are treated as a single +zero-width unit. + +Note: this option is ignored by the `Truncate` methods, as the concatenation +can lead to unintended UTF-8 semantics. + +#### EastAsianWidth + +`EastAsianWidth` defines how +[East Asian Ambiguous characters](https://www.unicode.org/reports/tr11/#Ambiguous) +are treated. + +When `false` (default), East Asian Ambiguous characters are treated as width 1. +When `true`, they are treated as width 2. + +You may wish to configure this based on environment variables or locale. + `go-runewidth`, for example, does so + [during package initialization](https://github.com/mattn/go-runewidth/blob/master/runewidth.go#L26C1-L45C2). `displaywidth` does not do this automatically, we prefer to leave it to you. + + +## Technical standards and compatibility + +This package implements the Unicode East Asian Width standard +([UAX #11](https://www.unicode.org/reports/tr11/tr11-43.html)), and handles +[version selectors](https://en.wikipedia.org/wiki/Variation_Selectors_(Unicode_block)), +and [regional indicator pairs](https://en.wikipedia.org/wiki/Regional_indicator_symbol) +(flags). We implement [Unicode TR51](https://www.unicode.org/reports/tr51/tr51-27.html) +for emojis. We are keeping an eye on +[emerging standards](https://www.jeffquast.com/post/state-of-terminal-emulation-2025/). + +For control sequences, we implement the [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/) standard for 7-bit and 8-bit control sequences. + +`clipperhouse/displaywidth`, `mattn/go-runewidth`, and `rivo/uniseg` will +give the same outputs for most real-world text. Extensive details are in the +[compatibility analysis](comparison/COMPATIBILITY_ANALYSIS.md). + +## Invalid UTF-8 + +This package does not validate UTF-8. If you pass invalid UTF-8, the results +are undefined. We fuzz against invalid UTF-8 to ensure we don't panic or +loop indefinitely. + +The `ControlSequences8Bit` option means that we will segment valid 8-bit +control sequences, which are typically _not_ valid UTF-8. 8-bit control bytes +happen to also be UTF-8 continuation bytes. Use with caution. + +## Prior Art + +[mattn/go-runewidth](https://github.com/mattn/go-runewidth) + +[rivo/uniseg](https://github.com/rivo/uniseg) + +[x/text/width](https://pkg.go.dev/golang.org/x/text/width) + +[x/text/internal/triegen](https://pkg.go.dev/golang.org/x/text/internal/triegen) + +## Benchmarks + +```bash +cd comparison +go test -bench=. -benchmem +``` + +``` +goos: darwin +goarch: arm64 +pkg: github.com/clipperhouse/displaywidth/comparison +cpu: Apple M2 + +BenchmarkString_Mixed/clipperhouse/displaywidth-8 5784 ns/op 291.69 MB/s 0 B/op 0 allocs/op +BenchmarkString_Mixed/mattn/go-runewidth-8 14751 ns/op 114.36 MB/s 0 B/op 0 allocs/op +BenchmarkString_Mixed/rivo/uniseg-8 19360 ns/op 87.14 MB/s 0 B/op 0 allocs/op + +BenchmarkString_ASCII/clipperhouse/displaywidth-8 54.60 ns/op 2344.32 MB/s 0 B/op 0 allocs/op +BenchmarkString_ASCII/mattn/go-runewidth-8 1195 ns/op 107.08 MB/s 0 B/op 0 allocs/op +BenchmarkString_ASCII/rivo/uniseg-8 1578 ns/op 81.13 MB/s 0 B/op 0 allocs/op + +BenchmarkString_EastAsian/clipperhouse/displaywidth-8 5837 ns/op 289.01 MB/s 0 B/op 0 allocs/op +BenchmarkString_EastAsian/mattn/go-runewidth-8 24418 ns/op 69.09 MB/s 0 B/op 0 allocs/op +BenchmarkString_EastAsian/rivo/uniseg-8 19339 ns/op 87.23 MB/s 0 B/op 0 allocs/op + +BenchmarkString_Emoji/clipperhouse/displaywidth-8 3225 ns/op 224.51 MB/s 0 B/op 0 allocs/op +BenchmarkString_Emoji/mattn/go-runewidth-8 4851 ns/op 149.25 MB/s 0 B/op 0 allocs/op +BenchmarkString_Emoji/rivo/uniseg-8 6591 ns/op 109.85 MB/s 0 B/op 0 allocs/op + +BenchmarkRune_Mixed/clipperhouse/displaywidth-8 3385 ns/op 498.34 MB/s 0 B/op 0 allocs/op +BenchmarkRune_Mixed/mattn/go-runewidth-8 5354 ns/op 315.07 MB/s 0 B/op 0 allocs/op + +BenchmarkRune_EastAsian/clipperhouse/displaywidth-8 3397 ns/op 496.56 MB/s 0 B/op 0 allocs/op +BenchmarkRune_EastAsian/mattn/go-runewidth-8 15673 ns/op 107.64 MB/s 0 B/op 0 allocs/op + +BenchmarkRune_ASCII/clipperhouse/displaywidth-8 255.7 ns/op 500.53 MB/s 0 B/op 0 allocs/op +BenchmarkRune_ASCII/mattn/go-runewidth-8 261.5 ns/op 489.55 MB/s 0 B/op 0 allocs/op + +BenchmarkRune_Emoji/clipperhouse/displaywidth-8 1371 ns/op 528.22 MB/s 0 B/op 0 allocs/op +BenchmarkRune_Emoji/mattn/go-runewidth-8 2267 ns/op 319.43 MB/s 0 B/op 0 allocs/op + +BenchmarkTruncateWithTail/clipperhouse/displaywidth-8 3229 ns/op 54.82 MB/s 192 B/op 14 allocs/op +BenchmarkTruncateWithTail/mattn/go-runewidth-8 8408 ns/op 21.05 MB/s 192 B/op 14 allocs/op + +BenchmarkTruncateWithoutTail/clipperhouse/displaywidth-8 3554 ns/op 64.43 MB/s 0 B/op 0 allocs/op +BenchmarkTruncateWithoutTail/mattn/go-runewidth-8 11189 ns/op 20.47 MB/s 0 B/op 0 allocs/op +``` + +Here are some notes on [how to make Unicode things fast](https://clipperhouse.com/go-unicode/). diff --git a/vendor/github.com/clipperhouse/displaywidth/gen.go b/vendor/github.com/clipperhouse/displaywidth/gen.go new file mode 100644 index 0000000..52e1085 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/gen.go @@ -0,0 +1,3 @@ +package displaywidth + +//go:generate go run -C internal/gen . diff --git a/vendor/github.com/clipperhouse/displaywidth/graphemes.go b/vendor/github.com/clipperhouse/displaywidth/graphemes.go new file mode 100644 index 0000000..14a5278 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/graphemes.go @@ -0,0 +1,73 @@ +package displaywidth + +import ( + "github.com/clipperhouse/uax29/v2/graphemes" +) + +// Graphemes is an iterator over grapheme clusters. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +type Graphemes[T ~string | []byte] struct { + iter *graphemes.Iterator[T] + options Options +} + +// Next advances the iterator to the next grapheme cluster. +func (g *Graphemes[T]) Next() bool { + return g.iter.Next() +} + +// Value returns the current grapheme cluster. +func (g *Graphemes[T]) Value() T { + return g.iter.Value() +} + +// Width returns the display width of the current grapheme cluster. +func (g *Graphemes[T]) Width() int { + return graphemeWidth(g.Value(), g.options) +} + +// StringGraphemes returns an iterator over grapheme clusters for the given +// string. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +func StringGraphemes(s string) Graphemes[string] { + return DefaultOptions.StringGraphemes(s) +} + +// StringGraphemes returns an iterator over grapheme clusters for the given +// string, with the given options. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +func (options Options) StringGraphemes(s string) Graphemes[string] { + g := graphemes.FromString(s) + g.AnsiEscapeSequences = options.ControlSequences + g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit + + return Graphemes[string]{iter: g, options: options} +} + +// BytesGraphemes returns an iterator over grapheme clusters for the given +// []byte. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +func BytesGraphemes(s []byte) Graphemes[[]byte] { + return DefaultOptions.BytesGraphemes(s) +} + +// BytesGraphemes returns an iterator over grapheme clusters for the given +// []byte, with the given options. +// +// Iterate using the Next method, and get the width of the current grapheme +// using the Width method. +func (options Options) BytesGraphemes(s []byte) Graphemes[[]byte] { + g := graphemes.FromBytes(s) + g.AnsiEscapeSequences = options.ControlSequences + g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit + + return Graphemes[[]byte]{iter: g, options: options} +} diff --git a/vendor/github.com/clipperhouse/displaywidth/options.go b/vendor/github.com/clipperhouse/displaywidth/options.go new file mode 100644 index 0000000..b63b585 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/options.go @@ -0,0 +1,30 @@ +package displaywidth + +// Options allows you to specify the treatment of ambiguous East Asian +// characters and ANSI escape sequences. +type Options struct { + // EastAsianWidth specifies whether to treat ambiguous East Asian characters + // as width 1 or 2. When false (default), ambiguous East Asian characters + // are treated as width 1. When true, they are width 2. + EastAsianWidth bool + + // ControlSequences specifies whether to ignore 7-bit ECMA-48 escape sequences + // when calculating the display width. When false (default), ANSI escape + // sequences are treated as just a series of characters. When true, they are + // treated as a single zero-width unit. + ControlSequences bool + // ControlSequences8Bit specifies whether to ignore 8-bit ECMA-48 escape sequences + // when calculating the display width. When false (default), these are treated + // as just a series of characters. When true, they are treated as a single + // zero-width unit. + ControlSequences8Bit bool +} + +// DefaultOptions is the default options for the display width +// calculation, which is EastAsianWidth false, ControlSequences false, and +// ControlSequences8Bit false. +var DefaultOptions = Options{ + EastAsianWidth: false, + ControlSequences: false, + ControlSequences8Bit: false, +} diff --git a/vendor/github.com/clipperhouse/displaywidth/trie.go b/vendor/github.com/clipperhouse/displaywidth/trie.go new file mode 100644 index 0000000..1d3a983 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/trie.go @@ -0,0 +1,1699 @@ +// Code generated by internal/gen/main.go. DO NOT EDIT. + +package displaywidth + +// property is an enum representing the properties of a character +type property uint8 + +const ( + // Always 0 width, includes combining marks, control characters, non-printable, etc + _Zero_Width property = iota + 1 + // Always 2 wide (East Asian Wide F/W, Emoji, Regional Indicator) + _Wide + // Width depends on EastAsianWidth option + _East_Asian_Ambiguous +) + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func lookup[T ~string | []byte](s T) (v uint8, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return stringWidthValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := stringWidthIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := stringWidthIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = stringWidthIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := stringWidthIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = stringWidthIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = stringWidthIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// stringWidthTrie. Total size: 17664 bytes (17.25 KiB). Checksum: 220983462f26d765. +// type stringWidthTrie struct { } + +// func newStringWidthTrie(i int) *stringWidthTrie { +// return &stringWidthTrie{} +// } + +// lookupValue determines the type of block n and looks up the value for b. +func lookupValue(n uint32, b byte) uint8 { + switch { + default: + return uint8(stringWidthValues[n<<6+uint32(b)]) + } +} + +// stringWidthValues: 246 blocks, 15744 entries, 15744 bytes +// The third block is the zero block. +var stringWidthValues = [15744]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x0001, 0xc1: 0x0001, 0xc2: 0x0001, 0xc3: 0x0001, 0xc4: 0x0001, 0xc5: 0x0001, + 0xc6: 0x0001, 0xc7: 0x0001, 0xc8: 0x0001, 0xc9: 0x0001, 0xca: 0x0001, 0xcb: 0x0001, + 0xcc: 0x0001, 0xcd: 0x0001, 0xce: 0x0001, 0xcf: 0x0001, 0xd0: 0x0001, 0xd1: 0x0001, + 0xd2: 0x0001, 0xd3: 0x0001, 0xd4: 0x0001, 0xd5: 0x0001, 0xd6: 0x0001, 0xd7: 0x0001, + 0xd8: 0x0001, 0xd9: 0x0001, 0xda: 0x0001, 0xdb: 0x0001, 0xdc: 0x0001, 0xdd: 0x0001, + 0xde: 0x0001, 0xdf: 0x0001, 0xe1: 0x0003, + 0xe4: 0x0003, 0xe7: 0x0003, 0xe8: 0x0003, + 0xea: 0x0003, 0xed: 0x0001, 0xee: 0x0003, + 0xf0: 0x0003, 0xf1: 0x0003, 0xf2: 0x0003, 0xf3: 0x0003, 0xf4: 0x0003, + 0xf6: 0x0003, 0xf7: 0x0003, 0xf8: 0x0003, 0xf9: 0x0003, 0xfa: 0x0003, + 0xfc: 0x0003, 0xfd: 0x0003, 0xfe: 0x0003, 0xff: 0x0003, + // Block 0x4, offset 0x100 + 0x106: 0x0003, + 0x110: 0x0003, + 0x117: 0x0003, + 0x118: 0x0003, + 0x11e: 0x0003, 0x11f: 0x0003, 0x120: 0x0003, 0x121: 0x0003, + 0x126: 0x0003, 0x128: 0x0003, 0x129: 0x0003, + 0x12a: 0x0003, 0x12c: 0x0003, 0x12d: 0x0003, + 0x130: 0x0003, 0x132: 0x0003, 0x133: 0x0003, + 0x137: 0x0003, 0x138: 0x0003, 0x139: 0x0003, 0x13a: 0x0003, + 0x13c: 0x0003, 0x13e: 0x0003, + // Block 0x5, offset 0x140 + 0x141: 0x0003, + 0x151: 0x0003, + 0x153: 0x0003, + 0x15b: 0x0003, + 0x166: 0x0003, 0x167: 0x0003, + 0x16b: 0x0003, + 0x171: 0x0003, 0x172: 0x0003, 0x173: 0x0003, + 0x178: 0x0003, + 0x17f: 0x0003, + // Block 0x6, offset 0x180 + 0x180: 0x0003, 0x181: 0x0003, 0x182: 0x0003, 0x184: 0x0003, + 0x188: 0x0003, 0x189: 0x0003, 0x18a: 0x0003, 0x18b: 0x0003, + 0x18d: 0x0003, + 0x192: 0x0003, 0x193: 0x0003, + 0x1a6: 0x0003, 0x1a7: 0x0003, + 0x1ab: 0x0003, + // Block 0x7, offset 0x1c0 + 0x1ce: 0x0003, 0x1d0: 0x0003, + 0x1d2: 0x0003, 0x1d4: 0x0003, 0x1d6: 0x0003, + 0x1d8: 0x0003, 0x1da: 0x0003, 0x1dc: 0x0003, + // Block 0x8, offset 0x200 + 0x211: 0x0003, + 0x221: 0x0003, + // Block 0x9, offset 0x240 + 0x244: 0x0003, + 0x247: 0x0003, 0x249: 0x0003, 0x24a: 0x0003, 0x24b: 0x0003, + 0x24d: 0x0003, 0x250: 0x0003, + 0x258: 0x0003, 0x259: 0x0003, 0x25a: 0x0003, 0x25b: 0x0003, 0x25d: 0x0003, + 0x25f: 0x0003, + // Block 0xa, offset 0x280 + 0x280: 0x0001, 0x281: 0x0001, 0x282: 0x0001, 0x283: 0x0001, 0x284: 0x0001, 0x285: 0x0001, + 0x286: 0x0001, 0x287: 0x0001, 0x288: 0x0001, 0x289: 0x0001, 0x28a: 0x0001, 0x28b: 0x0001, + 0x28c: 0x0001, 0x28d: 0x0001, 0x28e: 0x0001, 0x28f: 0x0001, 0x290: 0x0001, 0x291: 0x0001, + 0x292: 0x0001, 0x293: 0x0001, 0x294: 0x0001, 0x295: 0x0001, 0x296: 0x0001, 0x297: 0x0001, + 0x298: 0x0001, 0x299: 0x0001, 0x29a: 0x0001, 0x29b: 0x0001, 0x29c: 0x0001, 0x29d: 0x0001, + 0x29e: 0x0001, 0x29f: 0x0001, 0x2a0: 0x0001, 0x2a1: 0x0001, 0x2a2: 0x0001, 0x2a3: 0x0001, + 0x2a4: 0x0001, 0x2a5: 0x0001, 0x2a6: 0x0001, 0x2a7: 0x0001, 0x2a8: 0x0001, 0x2a9: 0x0001, + 0x2aa: 0x0001, 0x2ab: 0x0001, 0x2ac: 0x0001, 0x2ad: 0x0001, 0x2ae: 0x0001, 0x2af: 0x0001, + 0x2b0: 0x0001, 0x2b1: 0x0001, 0x2b2: 0x0001, 0x2b3: 0x0001, 0x2b4: 0x0001, 0x2b5: 0x0001, + 0x2b6: 0x0001, 0x2b7: 0x0001, 0x2b8: 0x0001, 0x2b9: 0x0001, 0x2ba: 0x0001, 0x2bb: 0x0001, + 0x2bc: 0x0001, 0x2bd: 0x0001, 0x2be: 0x0001, 0x2bf: 0x0001, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x0001, 0x2c1: 0x0001, 0x2c2: 0x0001, 0x2c3: 0x0001, 0x2c4: 0x0001, 0x2c5: 0x0001, + 0x2c6: 0x0001, 0x2c7: 0x0001, 0x2c8: 0x0001, 0x2c9: 0x0001, 0x2ca: 0x0001, 0x2cb: 0x0001, + 0x2cc: 0x0001, 0x2cd: 0x0001, 0x2ce: 0x0001, 0x2cf: 0x0001, 0x2d0: 0x0001, 0x2d1: 0x0001, + 0x2d2: 0x0001, 0x2d3: 0x0001, 0x2d4: 0x0001, 0x2d5: 0x0001, 0x2d6: 0x0001, 0x2d7: 0x0001, + 0x2d8: 0x0001, 0x2d9: 0x0001, 0x2da: 0x0001, 0x2db: 0x0001, 0x2dc: 0x0001, 0x2dd: 0x0001, + 0x2de: 0x0001, 0x2df: 0x0001, 0x2e0: 0x0001, 0x2e1: 0x0001, 0x2e2: 0x0001, 0x2e3: 0x0001, + 0x2e4: 0x0001, 0x2e5: 0x0001, 0x2e6: 0x0001, 0x2e7: 0x0001, 0x2e8: 0x0001, 0x2e9: 0x0001, + 0x2ea: 0x0001, 0x2eb: 0x0001, 0x2ec: 0x0001, 0x2ed: 0x0001, 0x2ee: 0x0001, 0x2ef: 0x0001, + // Block 0xc, offset 0x300 + 0x311: 0x0003, + 0x312: 0x0003, 0x313: 0x0003, 0x314: 0x0003, 0x315: 0x0003, 0x316: 0x0003, 0x317: 0x0003, + 0x318: 0x0003, 0x319: 0x0003, 0x31a: 0x0003, 0x31b: 0x0003, 0x31c: 0x0003, 0x31d: 0x0003, + 0x31e: 0x0003, 0x31f: 0x0003, 0x320: 0x0003, 0x321: 0x0003, 0x323: 0x0003, + 0x324: 0x0003, 0x325: 0x0003, 0x326: 0x0003, 0x327: 0x0003, 0x328: 0x0003, 0x329: 0x0003, + 0x331: 0x0003, 0x332: 0x0003, 0x333: 0x0003, 0x334: 0x0003, 0x335: 0x0003, + 0x336: 0x0003, 0x337: 0x0003, 0x338: 0x0003, 0x339: 0x0003, 0x33a: 0x0003, 0x33b: 0x0003, + 0x33c: 0x0003, 0x33d: 0x0003, 0x33e: 0x0003, 0x33f: 0x0003, + // Block 0xd, offset 0x340 + 0x340: 0x0003, 0x341: 0x0003, 0x343: 0x0003, 0x344: 0x0003, 0x345: 0x0003, + 0x346: 0x0003, 0x347: 0x0003, 0x348: 0x0003, 0x349: 0x0003, + // Block 0xe, offset 0x380 + 0x381: 0x0003, + 0x390: 0x0003, 0x391: 0x0003, + 0x392: 0x0003, 0x393: 0x0003, 0x394: 0x0003, 0x395: 0x0003, 0x396: 0x0003, 0x397: 0x0003, + 0x398: 0x0003, 0x399: 0x0003, 0x39a: 0x0003, 0x39b: 0x0003, 0x39c: 0x0003, 0x39d: 0x0003, + 0x39e: 0x0003, 0x39f: 0x0003, 0x3a0: 0x0003, 0x3a1: 0x0003, 0x3a2: 0x0003, 0x3a3: 0x0003, + 0x3a4: 0x0003, 0x3a5: 0x0003, 0x3a6: 0x0003, 0x3a7: 0x0003, 0x3a8: 0x0003, 0x3a9: 0x0003, + 0x3aa: 0x0003, 0x3ab: 0x0003, 0x3ac: 0x0003, 0x3ad: 0x0003, 0x3ae: 0x0003, 0x3af: 0x0003, + 0x3b0: 0x0003, 0x3b1: 0x0003, 0x3b2: 0x0003, 0x3b3: 0x0003, 0x3b4: 0x0003, 0x3b5: 0x0003, + 0x3b6: 0x0003, 0x3b7: 0x0003, 0x3b8: 0x0003, 0x3b9: 0x0003, 0x3ba: 0x0003, 0x3bb: 0x0003, + 0x3bc: 0x0003, 0x3bd: 0x0003, 0x3be: 0x0003, 0x3bf: 0x0003, + // Block 0xf, offset 0x3c0 + 0x3c0: 0x0003, 0x3c1: 0x0003, 0x3c2: 0x0003, 0x3c3: 0x0003, 0x3c4: 0x0003, 0x3c5: 0x0003, + 0x3c6: 0x0003, 0x3c7: 0x0003, 0x3c8: 0x0003, 0x3c9: 0x0003, 0x3ca: 0x0003, 0x3cb: 0x0003, + 0x3cc: 0x0003, 0x3cd: 0x0003, 0x3ce: 0x0003, 0x3cf: 0x0003, 0x3d1: 0x0003, + // Block 0x10, offset 0x400 + 0x403: 0x0001, 0x404: 0x0001, 0x405: 0x0001, + 0x406: 0x0001, 0x407: 0x0001, 0x408: 0x0001, 0x409: 0x0001, + // Block 0x11, offset 0x440 + 0x451: 0x0001, + 0x452: 0x0001, 0x453: 0x0001, 0x454: 0x0001, 0x455: 0x0001, 0x456: 0x0001, 0x457: 0x0001, + 0x458: 0x0001, 0x459: 0x0001, 0x45a: 0x0001, 0x45b: 0x0001, 0x45c: 0x0001, 0x45d: 0x0001, + 0x45e: 0x0001, 0x45f: 0x0001, 0x460: 0x0001, 0x461: 0x0001, 0x462: 0x0001, 0x463: 0x0001, + 0x464: 0x0001, 0x465: 0x0001, 0x466: 0x0001, 0x467: 0x0001, 0x468: 0x0001, 0x469: 0x0001, + 0x46a: 0x0001, 0x46b: 0x0001, 0x46c: 0x0001, 0x46d: 0x0001, 0x46e: 0x0001, 0x46f: 0x0001, + 0x470: 0x0001, 0x471: 0x0001, 0x472: 0x0001, 0x473: 0x0001, 0x474: 0x0001, 0x475: 0x0001, + 0x476: 0x0001, 0x477: 0x0001, 0x478: 0x0001, 0x479: 0x0001, 0x47a: 0x0001, 0x47b: 0x0001, + 0x47c: 0x0001, 0x47d: 0x0001, 0x47f: 0x0001, + // Block 0x12, offset 0x480 + 0x481: 0x0001, 0x482: 0x0001, 0x484: 0x0001, 0x485: 0x0001, + 0x487: 0x0001, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x0001, 0x4c1: 0x0001, 0x4c2: 0x0001, 0x4c3: 0x0001, 0x4c4: 0x0001, 0x4c5: 0x0001, + 0x4d0: 0x0001, 0x4d1: 0x0001, + 0x4d2: 0x0001, 0x4d3: 0x0001, 0x4d4: 0x0001, 0x4d5: 0x0001, 0x4d6: 0x0001, 0x4d7: 0x0001, + 0x4d8: 0x0001, 0x4d9: 0x0001, 0x4da: 0x0001, 0x4dc: 0x0001, + // Block 0x14, offset 0x500 + 0x50b: 0x0001, + 0x50c: 0x0001, 0x50d: 0x0001, 0x50e: 0x0001, 0x50f: 0x0001, 0x510: 0x0001, 0x511: 0x0001, + 0x512: 0x0001, 0x513: 0x0001, 0x514: 0x0001, 0x515: 0x0001, 0x516: 0x0001, 0x517: 0x0001, + 0x518: 0x0001, 0x519: 0x0001, 0x51a: 0x0001, 0x51b: 0x0001, 0x51c: 0x0001, 0x51d: 0x0001, + 0x51e: 0x0001, 0x51f: 0x0001, + 0x530: 0x0001, + // Block 0x15, offset 0x540 + 0x556: 0x0001, 0x557: 0x0001, + 0x558: 0x0001, 0x559: 0x0001, 0x55a: 0x0001, 0x55b: 0x0001, 0x55c: 0x0001, 0x55d: 0x0001, + 0x55f: 0x0001, 0x560: 0x0001, 0x561: 0x0001, 0x562: 0x0001, 0x563: 0x0001, + 0x564: 0x0001, 0x567: 0x0001, 0x568: 0x0001, + 0x56a: 0x0001, 0x56b: 0x0001, 0x56c: 0x0001, 0x56d: 0x0001, + // Block 0x16, offset 0x580 + 0x58f: 0x0001, 0x591: 0x0001, + 0x5b0: 0x0001, 0x5b1: 0x0001, 0x5b2: 0x0001, 0x5b3: 0x0001, 0x5b4: 0x0001, 0x5b5: 0x0001, + 0x5b6: 0x0001, 0x5b7: 0x0001, 0x5b8: 0x0001, 0x5b9: 0x0001, 0x5ba: 0x0001, 0x5bb: 0x0001, + 0x5bc: 0x0001, 0x5bd: 0x0001, 0x5be: 0x0001, 0x5bf: 0x0001, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x0001, 0x5c1: 0x0001, 0x5c2: 0x0001, 0x5c3: 0x0001, 0x5c4: 0x0001, 0x5c5: 0x0001, + 0x5c6: 0x0001, 0x5c7: 0x0001, 0x5c8: 0x0001, 0x5c9: 0x0001, 0x5ca: 0x0001, + // Block 0x18, offset 0x600 + 0x626: 0x0001, 0x627: 0x0001, 0x628: 0x0001, 0x629: 0x0001, + 0x62a: 0x0001, 0x62b: 0x0001, 0x62c: 0x0001, 0x62d: 0x0001, 0x62e: 0x0001, 0x62f: 0x0001, + 0x630: 0x0001, + // Block 0x19, offset 0x640 + 0x66b: 0x0001, 0x66c: 0x0001, 0x66d: 0x0001, 0x66e: 0x0001, 0x66f: 0x0001, + 0x670: 0x0001, 0x671: 0x0001, 0x672: 0x0001, 0x673: 0x0001, + 0x67d: 0x0001, + // Block 0x1a, offset 0x680 + 0x696: 0x0001, 0x697: 0x0001, + 0x698: 0x0001, 0x699: 0x0001, 0x69b: 0x0001, 0x69c: 0x0001, 0x69d: 0x0001, + 0x69e: 0x0001, 0x69f: 0x0001, 0x6a0: 0x0001, 0x6a1: 0x0001, 0x6a2: 0x0001, 0x6a3: 0x0001, + 0x6a5: 0x0001, 0x6a6: 0x0001, 0x6a7: 0x0001, 0x6a9: 0x0001, + 0x6aa: 0x0001, 0x6ab: 0x0001, 0x6ac: 0x0001, 0x6ad: 0x0001, + // Block 0x1b, offset 0x6c0 + 0x6d9: 0x0001, 0x6da: 0x0001, 0x6db: 0x0001, + // Block 0x1c, offset 0x700 + 0x710: 0x0001, 0x711: 0x0001, + 0x718: 0x0001, 0x719: 0x0001, 0x71a: 0x0001, 0x71b: 0x0001, 0x71c: 0x0001, 0x71d: 0x0001, + 0x71e: 0x0001, 0x71f: 0x0001, + // Block 0x1d, offset 0x740 + 0x74a: 0x0001, 0x74b: 0x0001, + 0x74c: 0x0001, 0x74d: 0x0001, 0x74e: 0x0001, 0x74f: 0x0001, 0x750: 0x0001, 0x751: 0x0001, + 0x752: 0x0001, 0x753: 0x0001, 0x754: 0x0001, 0x755: 0x0001, 0x756: 0x0001, 0x757: 0x0001, + 0x758: 0x0001, 0x759: 0x0001, 0x75a: 0x0001, 0x75b: 0x0001, 0x75c: 0x0001, 0x75d: 0x0001, + 0x75e: 0x0001, 0x75f: 0x0001, 0x760: 0x0001, 0x761: 0x0001, 0x762: 0x0001, 0x763: 0x0001, + 0x764: 0x0001, 0x765: 0x0001, 0x766: 0x0001, 0x767: 0x0001, 0x768: 0x0001, 0x769: 0x0001, + 0x76a: 0x0001, 0x76b: 0x0001, 0x76c: 0x0001, 0x76d: 0x0001, 0x76e: 0x0001, 0x76f: 0x0001, + 0x770: 0x0001, 0x771: 0x0001, 0x772: 0x0001, 0x773: 0x0001, 0x774: 0x0001, 0x775: 0x0001, + 0x776: 0x0001, 0x777: 0x0001, 0x778: 0x0001, 0x779: 0x0001, 0x77a: 0x0001, 0x77b: 0x0001, + 0x77c: 0x0001, 0x77d: 0x0001, 0x77e: 0x0001, 0x77f: 0x0001, + // Block 0x1e, offset 0x780 + 0x780: 0x0001, 0x781: 0x0001, 0x782: 0x0001, + 0x7ba: 0x0001, + 0x7bc: 0x0001, + // Block 0x1f, offset 0x7c0 + 0x7c1: 0x0001, 0x7c2: 0x0001, 0x7c3: 0x0001, 0x7c4: 0x0001, 0x7c5: 0x0001, + 0x7c6: 0x0001, 0x7c7: 0x0001, 0x7c8: 0x0001, + 0x7cd: 0x0001, 0x7d1: 0x0001, + 0x7d2: 0x0001, 0x7d3: 0x0001, 0x7d4: 0x0001, 0x7d5: 0x0001, 0x7d6: 0x0001, 0x7d7: 0x0001, + 0x7e2: 0x0001, 0x7e3: 0x0001, + // Block 0x20, offset 0x800 + 0x801: 0x0001, + 0x83c: 0x0001, + // Block 0x21, offset 0x840 + 0x841: 0x0001, 0x842: 0x0001, 0x843: 0x0001, 0x844: 0x0001, + 0x84d: 0x0001, + 0x862: 0x0001, 0x863: 0x0001, + 0x87e: 0x0001, + // Block 0x22, offset 0x880 + 0x881: 0x0001, 0x882: 0x0001, + 0x8bc: 0x0001, + // Block 0x23, offset 0x8c0 + 0x8c1: 0x0001, 0x8c2: 0x0001, + 0x8c7: 0x0001, 0x8c8: 0x0001, 0x8cb: 0x0001, + 0x8cc: 0x0001, 0x8cd: 0x0001, 0x8d1: 0x0001, + 0x8f0: 0x0001, 0x8f1: 0x0001, 0x8f5: 0x0001, + // Block 0x24, offset 0x900 + 0x901: 0x0001, 0x902: 0x0001, 0x903: 0x0001, 0x904: 0x0001, 0x905: 0x0001, + 0x907: 0x0001, 0x908: 0x0001, + 0x90d: 0x0001, + 0x922: 0x0001, 0x923: 0x0001, + 0x93a: 0x0001, 0x93b: 0x0001, + 0x93c: 0x0001, 0x93d: 0x0001, 0x93e: 0x0001, 0x93f: 0x0001, + // Block 0x25, offset 0x940 + 0x941: 0x0001, + 0x97c: 0x0001, 0x97f: 0x0001, + // Block 0x26, offset 0x980 + 0x981: 0x0001, 0x982: 0x0001, 0x983: 0x0001, 0x984: 0x0001, + 0x98d: 0x0001, + 0x995: 0x0001, 0x996: 0x0001, + 0x9a2: 0x0001, 0x9a3: 0x0001, + // Block 0x27, offset 0x9c0 + 0x9c2: 0x0001, + // Block 0x28, offset 0xa00 + 0xa00: 0x0001, + 0xa0d: 0x0001, + // Block 0x29, offset 0xa40 + 0xa40: 0x0001, 0xa44: 0x0001, + 0xa7c: 0x0001, 0xa7e: 0x0001, 0xa7f: 0x0001, + // Block 0x2a, offset 0xa80 + 0xa80: 0x0001, + 0xa86: 0x0001, 0xa87: 0x0001, 0xa88: 0x0001, 0xa8a: 0x0001, 0xa8b: 0x0001, + 0xa8c: 0x0001, 0xa8d: 0x0001, + 0xa95: 0x0001, 0xa96: 0x0001, + 0xaa2: 0x0001, 0xaa3: 0x0001, + // Block 0x2b, offset 0xac0 + 0xac6: 0x0001, + 0xacc: 0x0001, 0xacd: 0x0001, + 0xae2: 0x0001, 0xae3: 0x0001, + // Block 0x2c, offset 0xb00 + 0xb00: 0x0001, 0xb01: 0x0001, + 0xb3b: 0x0001, + 0xb3c: 0x0001, + // Block 0x2d, offset 0xb40 + 0xb41: 0x0001, 0xb42: 0x0001, 0xb43: 0x0001, 0xb44: 0x0001, + 0xb4d: 0x0001, + 0xb62: 0x0001, 0xb63: 0x0001, + // Block 0x2e, offset 0xb80 + 0xb81: 0x0001, + // Block 0x2f, offset 0xbc0 + 0xbca: 0x0001, + 0xbd2: 0x0001, 0xbd3: 0x0001, 0xbd4: 0x0001, 0xbd6: 0x0001, + // Block 0x30, offset 0xc00 + 0xc31: 0x0001, 0xc34: 0x0001, 0xc35: 0x0001, + 0xc36: 0x0001, 0xc37: 0x0001, 0xc38: 0x0001, 0xc39: 0x0001, 0xc3a: 0x0001, + // Block 0x31, offset 0xc40 + 0xc47: 0x0001, 0xc48: 0x0001, 0xc49: 0x0001, 0xc4a: 0x0001, 0xc4b: 0x0001, + 0xc4c: 0x0001, 0xc4d: 0x0001, 0xc4e: 0x0001, + // Block 0x32, offset 0xc80 + 0xcb1: 0x0001, 0xcb4: 0x0001, 0xcb5: 0x0001, + 0xcb6: 0x0001, 0xcb7: 0x0001, 0xcb8: 0x0001, 0xcb9: 0x0001, 0xcba: 0x0001, 0xcbb: 0x0001, + 0xcbc: 0x0001, + // Block 0x33, offset 0xcc0 + 0xcc8: 0x0001, 0xcc9: 0x0001, 0xcca: 0x0001, 0xccb: 0x0001, + 0xccc: 0x0001, 0xccd: 0x0001, 0xcce: 0x0001, + // Block 0x34, offset 0xd00 + 0xd18: 0x0001, 0xd19: 0x0001, + 0xd35: 0x0001, + 0xd37: 0x0001, 0xd39: 0x0001, + // Block 0x35, offset 0xd40 + 0xd71: 0x0001, 0xd72: 0x0001, 0xd73: 0x0001, 0xd74: 0x0001, 0xd75: 0x0001, + 0xd76: 0x0001, 0xd77: 0x0001, 0xd78: 0x0001, 0xd79: 0x0001, 0xd7a: 0x0001, 0xd7b: 0x0001, + 0xd7c: 0x0001, 0xd7d: 0x0001, 0xd7e: 0x0001, + // Block 0x36, offset 0xd80 + 0xd80: 0x0001, 0xd81: 0x0001, 0xd82: 0x0001, 0xd83: 0x0001, 0xd84: 0x0001, + 0xd86: 0x0001, 0xd87: 0x0001, + 0xd8d: 0x0001, 0xd8e: 0x0001, 0xd8f: 0x0001, 0xd90: 0x0001, 0xd91: 0x0001, + 0xd92: 0x0001, 0xd93: 0x0001, 0xd94: 0x0001, 0xd95: 0x0001, 0xd96: 0x0001, 0xd97: 0x0001, + 0xd99: 0x0001, 0xd9a: 0x0001, 0xd9b: 0x0001, 0xd9c: 0x0001, 0xd9d: 0x0001, + 0xd9e: 0x0001, 0xd9f: 0x0001, 0xda0: 0x0001, 0xda1: 0x0001, 0xda2: 0x0001, 0xda3: 0x0001, + 0xda4: 0x0001, 0xda5: 0x0001, 0xda6: 0x0001, 0xda7: 0x0001, 0xda8: 0x0001, 0xda9: 0x0001, + 0xdaa: 0x0001, 0xdab: 0x0001, 0xdac: 0x0001, 0xdad: 0x0001, 0xdae: 0x0001, 0xdaf: 0x0001, + 0xdb0: 0x0001, 0xdb1: 0x0001, 0xdb2: 0x0001, 0xdb3: 0x0001, 0xdb4: 0x0001, 0xdb5: 0x0001, + 0xdb6: 0x0001, 0xdb7: 0x0001, 0xdb8: 0x0001, 0xdb9: 0x0001, 0xdba: 0x0001, 0xdbb: 0x0001, + 0xdbc: 0x0001, + // Block 0x37, offset 0xdc0 + 0xdc6: 0x0001, + // Block 0x38, offset 0xe00 + 0xe2d: 0x0001, 0xe2e: 0x0001, 0xe2f: 0x0001, + 0xe30: 0x0001, 0xe32: 0x0001, 0xe33: 0x0001, 0xe34: 0x0001, 0xe35: 0x0001, + 0xe36: 0x0001, 0xe37: 0x0001, 0xe39: 0x0001, 0xe3a: 0x0001, + 0xe3d: 0x0001, 0xe3e: 0x0001, + // Block 0x39, offset 0xe40 + 0xe58: 0x0001, 0xe59: 0x0001, + 0xe5e: 0x0001, 0xe5f: 0x0001, 0xe60: 0x0001, + 0xe71: 0x0001, 0xe72: 0x0001, 0xe73: 0x0001, 0xe74: 0x0001, + // Block 0x3a, offset 0xe80 + 0xe82: 0x0001, 0xe85: 0x0001, + 0xe86: 0x0001, + 0xe8d: 0x0001, + 0xe9d: 0x0001, + // Block 0x3b, offset 0xec0 + 0xec0: 0x0002, 0xec1: 0x0002, 0xec2: 0x0002, 0xec3: 0x0002, 0xec4: 0x0002, 0xec5: 0x0002, + 0xec6: 0x0002, 0xec7: 0x0002, 0xec8: 0x0002, 0xec9: 0x0002, 0xeca: 0x0002, 0xecb: 0x0002, + 0xecc: 0x0002, 0xecd: 0x0002, 0xece: 0x0002, 0xecf: 0x0002, 0xed0: 0x0002, 0xed1: 0x0002, + 0xed2: 0x0002, 0xed3: 0x0002, 0xed4: 0x0002, 0xed5: 0x0002, 0xed6: 0x0002, 0xed7: 0x0002, + 0xed8: 0x0002, 0xed9: 0x0002, 0xeda: 0x0002, 0xedb: 0x0002, 0xedc: 0x0002, 0xedd: 0x0002, + 0xede: 0x0002, 0xedf: 0x0002, 0xee0: 0x0002, 0xee1: 0x0002, 0xee2: 0x0002, 0xee3: 0x0002, + 0xee4: 0x0002, 0xee5: 0x0002, 0xee6: 0x0002, 0xee7: 0x0002, 0xee8: 0x0002, 0xee9: 0x0002, + 0xeea: 0x0002, 0xeeb: 0x0002, 0xeec: 0x0002, 0xeed: 0x0002, 0xeee: 0x0002, 0xeef: 0x0002, + 0xef0: 0x0002, 0xef1: 0x0002, 0xef2: 0x0002, 0xef3: 0x0002, 0xef4: 0x0002, 0xef5: 0x0002, + 0xef6: 0x0002, 0xef7: 0x0002, 0xef8: 0x0002, 0xef9: 0x0002, 0xefa: 0x0002, 0xefb: 0x0002, + 0xefc: 0x0002, 0xefd: 0x0002, 0xefe: 0x0002, 0xeff: 0x0002, + // Block 0x3c, offset 0xf00 + 0xf00: 0x0002, 0xf01: 0x0002, 0xf02: 0x0002, 0xf03: 0x0002, 0xf04: 0x0002, 0xf05: 0x0002, + 0xf06: 0x0002, 0xf07: 0x0002, 0xf08: 0x0002, 0xf09: 0x0002, 0xf0a: 0x0002, 0xf0b: 0x0002, + 0xf0c: 0x0002, 0xf0d: 0x0002, 0xf0e: 0x0002, 0xf0f: 0x0002, 0xf10: 0x0002, 0xf11: 0x0002, + 0xf12: 0x0002, 0xf13: 0x0002, 0xf14: 0x0002, 0xf15: 0x0002, 0xf16: 0x0002, 0xf17: 0x0002, + 0xf18: 0x0002, 0xf19: 0x0002, 0xf1a: 0x0002, 0xf1b: 0x0002, 0xf1c: 0x0002, 0xf1d: 0x0002, + 0xf1e: 0x0002, 0xf1f: 0x0002, + // Block 0x3d, offset 0xf40 + 0xf5d: 0x0001, + 0xf5e: 0x0001, 0xf5f: 0x0001, + // Block 0x3e, offset 0xf80 + 0xf92: 0x0001, 0xf93: 0x0001, 0xf94: 0x0001, + 0xfb2: 0x0001, 0xfb3: 0x0001, + // Block 0x3f, offset 0xfc0 + 0xfd2: 0x0001, 0xfd3: 0x0001, + 0xff2: 0x0001, 0xff3: 0x0001, + // Block 0x40, offset 0x1000 + 0x1034: 0x0001, 0x1035: 0x0001, + 0x1037: 0x0001, 0x1038: 0x0001, 0x1039: 0x0001, 0x103a: 0x0001, 0x103b: 0x0001, + 0x103c: 0x0001, 0x103d: 0x0001, + // Block 0x41, offset 0x1040 + 0x1046: 0x0001, 0x1049: 0x0001, 0x104a: 0x0001, 0x104b: 0x0001, + 0x104c: 0x0001, 0x104d: 0x0001, 0x104e: 0x0001, 0x104f: 0x0001, 0x1050: 0x0001, 0x1051: 0x0001, + 0x1052: 0x0001, 0x1053: 0x0001, + 0x105d: 0x0001, + // Block 0x42, offset 0x1080 + 0x108b: 0x0001, + 0x108c: 0x0001, 0x108d: 0x0001, 0x108e: 0x0001, 0x108f: 0x0001, + // Block 0x43, offset 0x10c0 + 0x10c5: 0x0001, + 0x10c6: 0x0001, + 0x10e9: 0x0001, + // Block 0x44, offset 0x1100 + 0x1120: 0x0001, 0x1121: 0x0001, 0x1122: 0x0001, + 0x1127: 0x0001, 0x1128: 0x0001, + 0x1132: 0x0001, + 0x1139: 0x0001, 0x113a: 0x0001, 0x113b: 0x0001, + // Block 0x45, offset 0x1140 + 0x1157: 0x0001, + 0x1158: 0x0001, 0x115b: 0x0001, + // Block 0x46, offset 0x1180 + 0x1196: 0x0001, + 0x1198: 0x0001, 0x1199: 0x0001, 0x119a: 0x0001, 0x119b: 0x0001, 0x119c: 0x0001, 0x119d: 0x0001, + 0x119e: 0x0001, 0x11a0: 0x0001, 0x11a2: 0x0001, + 0x11a5: 0x0001, 0x11a6: 0x0001, 0x11a7: 0x0001, 0x11a8: 0x0001, 0x11a9: 0x0001, + 0x11aa: 0x0001, 0x11ab: 0x0001, 0x11ac: 0x0001, + 0x11b3: 0x0001, 0x11b4: 0x0001, 0x11b5: 0x0001, + 0x11b6: 0x0001, 0x11b7: 0x0001, 0x11b8: 0x0001, 0x11b9: 0x0001, 0x11ba: 0x0001, 0x11bb: 0x0001, + 0x11bc: 0x0001, 0x11bf: 0x0001, + // Block 0x47, offset 0x11c0 + 0x11f0: 0x0001, 0x11f1: 0x0001, 0x11f2: 0x0001, 0x11f3: 0x0001, 0x11f4: 0x0001, 0x11f5: 0x0001, + 0x11f6: 0x0001, 0x11f7: 0x0001, 0x11f8: 0x0001, 0x11f9: 0x0001, 0x11fa: 0x0001, 0x11fb: 0x0001, + 0x11fc: 0x0001, 0x11fd: 0x0001, 0x11fe: 0x0001, 0x11ff: 0x0001, + // Block 0x48, offset 0x1200 + 0x1200: 0x0001, 0x1201: 0x0001, 0x1202: 0x0001, 0x1203: 0x0001, 0x1204: 0x0001, 0x1205: 0x0001, + 0x1206: 0x0001, 0x1207: 0x0001, 0x1208: 0x0001, 0x1209: 0x0001, 0x120a: 0x0001, 0x120b: 0x0001, + 0x120c: 0x0001, 0x120d: 0x0001, 0x120e: 0x0001, + // Block 0x49, offset 0x1240 + 0x1240: 0x0001, 0x1241: 0x0001, 0x1242: 0x0001, 0x1243: 0x0001, + 0x1274: 0x0001, + 0x1276: 0x0001, 0x1277: 0x0001, 0x1278: 0x0001, 0x1279: 0x0001, 0x127a: 0x0001, + 0x127c: 0x0001, + // Block 0x4a, offset 0x1280 + 0x1282: 0x0001, + 0x12ab: 0x0001, 0x12ac: 0x0001, 0x12ad: 0x0001, 0x12ae: 0x0001, 0x12af: 0x0001, + 0x12b0: 0x0001, 0x12b1: 0x0001, 0x12b2: 0x0001, 0x12b3: 0x0001, + // Block 0x4b, offset 0x12c0 + 0x12c0: 0x0001, 0x12c1: 0x0001, + 0x12e2: 0x0001, 0x12e3: 0x0001, + 0x12e4: 0x0001, 0x12e5: 0x0001, 0x12e8: 0x0001, 0x12e9: 0x0001, + 0x12eb: 0x0001, 0x12ec: 0x0001, 0x12ed: 0x0001, + // Block 0x4c, offset 0x1300 + 0x1326: 0x0001, 0x1328: 0x0001, 0x1329: 0x0001, + 0x132d: 0x0001, 0x132f: 0x0001, + 0x1330: 0x0001, 0x1331: 0x0001, + // Block 0x4d, offset 0x1340 + 0x136c: 0x0001, 0x136d: 0x0001, 0x136e: 0x0001, 0x136f: 0x0001, + 0x1370: 0x0001, 0x1371: 0x0001, 0x1372: 0x0001, 0x1373: 0x0001, + 0x1376: 0x0001, 0x1377: 0x0001, + // Block 0x4e, offset 0x1380 + 0x1390: 0x0001, 0x1391: 0x0001, + 0x1392: 0x0001, 0x1394: 0x0001, 0x1395: 0x0001, 0x1396: 0x0001, 0x1397: 0x0001, + 0x1398: 0x0001, 0x1399: 0x0001, 0x139a: 0x0001, 0x139b: 0x0001, 0x139c: 0x0001, 0x139d: 0x0001, + 0x139e: 0x0001, 0x139f: 0x0001, 0x13a0: 0x0001, 0x13a2: 0x0001, 0x13a3: 0x0001, + 0x13a4: 0x0001, 0x13a5: 0x0001, 0x13a6: 0x0001, 0x13a7: 0x0001, 0x13a8: 0x0001, + 0x13ad: 0x0001, + 0x13b4: 0x0001, + 0x13b8: 0x0001, 0x13b9: 0x0001, + // Block 0x4f, offset 0x13c0 + 0x13cb: 0x0001, + 0x13cc: 0x0001, 0x13cd: 0x0001, 0x13ce: 0x0001, 0x13cf: 0x0001, 0x13d0: 0x0003, + 0x13d3: 0x0003, 0x13d4: 0x0003, 0x13d5: 0x0003, 0x13d6: 0x0003, + 0x13d8: 0x0003, 0x13d9: 0x0003, 0x13dc: 0x0003, 0x13dd: 0x0003, + 0x13e0: 0x0003, 0x13e1: 0x0003, 0x13e2: 0x0003, + 0x13e4: 0x0003, 0x13e5: 0x0003, 0x13e6: 0x0003, 0x13e7: 0x0003, 0x13e8: 0x0001, 0x13e9: 0x0001, + 0x13ea: 0x0001, 0x13eb: 0x0001, 0x13ec: 0x0001, 0x13ed: 0x0001, 0x13ee: 0x0001, + 0x13f0: 0x0003, 0x13f2: 0x0003, 0x13f3: 0x0003, 0x13f5: 0x0003, + 0x13fb: 0x0003, + 0x13fe: 0x0003, + // Block 0x50, offset 0x1400 + 0x1420: 0x0001, 0x1421: 0x0001, 0x1422: 0x0001, 0x1423: 0x0001, + 0x1424: 0x0001, 0x1426: 0x0001, 0x1427: 0x0001, 0x1428: 0x0001, 0x1429: 0x0001, + 0x142a: 0x0001, 0x142b: 0x0001, 0x142c: 0x0001, 0x142d: 0x0001, 0x142e: 0x0001, 0x142f: 0x0001, + 0x1434: 0x0003, + 0x143f: 0x0003, + // Block 0x51, offset 0x1440 + 0x1441: 0x0003, 0x1442: 0x0003, 0x1443: 0x0003, 0x1444: 0x0003, + 0x146c: 0x0003, + // Block 0x52, offset 0x1480 + 0x1490: 0x0001, 0x1491: 0x0001, + 0x1492: 0x0001, 0x1493: 0x0001, 0x1494: 0x0001, 0x1495: 0x0001, 0x1496: 0x0001, 0x1497: 0x0001, + 0x1498: 0x0001, 0x1499: 0x0001, 0x149a: 0x0001, 0x149b: 0x0001, 0x149c: 0x0001, 0x149d: 0x0001, + 0x149e: 0x0001, 0x149f: 0x0001, 0x14a0: 0x0001, 0x14a1: 0x0001, 0x14a2: 0x0001, 0x14a3: 0x0001, + 0x14a4: 0x0001, 0x14a5: 0x0001, 0x14a6: 0x0001, 0x14a7: 0x0001, 0x14a8: 0x0001, 0x14a9: 0x0001, + 0x14aa: 0x0001, 0x14ab: 0x0001, 0x14ac: 0x0001, 0x14ad: 0x0001, 0x14ae: 0x0001, 0x14af: 0x0001, + 0x14b0: 0x0001, + // Block 0x53, offset 0x14c0 + 0x14c3: 0x0003, 0x14c5: 0x0003, + 0x14c9: 0x0003, + 0x14d3: 0x0003, 0x14d6: 0x0003, + 0x14e1: 0x0003, 0x14e2: 0x0003, + 0x14e6: 0x0003, + 0x14eb: 0x0003, + // Block 0x54, offset 0x1500 + 0x1513: 0x0003, 0x1514: 0x0003, + 0x151b: 0x0003, 0x151c: 0x0003, 0x151d: 0x0003, + 0x151e: 0x0003, 0x1520: 0x0003, 0x1521: 0x0003, 0x1522: 0x0003, 0x1523: 0x0003, + 0x1524: 0x0003, 0x1525: 0x0003, 0x1526: 0x0003, 0x1527: 0x0003, 0x1528: 0x0003, 0x1529: 0x0003, + 0x152a: 0x0003, 0x152b: 0x0003, + 0x1530: 0x0003, 0x1531: 0x0003, 0x1532: 0x0003, 0x1533: 0x0003, 0x1534: 0x0003, 0x1535: 0x0003, + 0x1536: 0x0003, 0x1537: 0x0003, 0x1538: 0x0003, 0x1539: 0x0003, + // Block 0x55, offset 0x1540 + 0x1549: 0x0003, + 0x1550: 0x0003, 0x1551: 0x0003, + 0x1552: 0x0003, 0x1553: 0x0003, 0x1554: 0x0003, 0x1555: 0x0003, 0x1556: 0x0003, 0x1557: 0x0003, + 0x1558: 0x0003, 0x1559: 0x0003, + 0x1578: 0x0003, 0x1579: 0x0003, + // Block 0x56, offset 0x1580 + 0x1592: 0x0003, 0x1594: 0x0003, + 0x15a7: 0x0003, + // Block 0x57, offset 0x15c0 + 0x15c0: 0x0003, 0x15c2: 0x0003, 0x15c3: 0x0003, + 0x15c7: 0x0003, 0x15c8: 0x0003, 0x15cb: 0x0003, + 0x15cf: 0x0003, 0x15d1: 0x0003, + 0x15d5: 0x0003, + 0x15da: 0x0003, 0x15dd: 0x0003, + 0x15de: 0x0003, 0x15df: 0x0003, 0x15e0: 0x0003, 0x15e3: 0x0003, + 0x15e5: 0x0003, 0x15e7: 0x0003, 0x15e8: 0x0003, 0x15e9: 0x0003, + 0x15ea: 0x0003, 0x15eb: 0x0003, 0x15ec: 0x0003, 0x15ee: 0x0003, + 0x15f4: 0x0003, 0x15f5: 0x0003, + 0x15f6: 0x0003, 0x15f7: 0x0003, + 0x15fc: 0x0003, 0x15fd: 0x0003, + // Block 0x58, offset 0x1600 + 0x1608: 0x0003, + 0x160c: 0x0003, + 0x1612: 0x0003, + 0x1620: 0x0003, 0x1621: 0x0003, + 0x1624: 0x0003, 0x1625: 0x0003, 0x1626: 0x0003, 0x1627: 0x0003, + 0x162a: 0x0003, 0x162b: 0x0003, 0x162e: 0x0003, 0x162f: 0x0003, + // Block 0x59, offset 0x1640 + 0x1642: 0x0003, 0x1643: 0x0003, + 0x1646: 0x0003, 0x1647: 0x0003, + 0x1655: 0x0003, + 0x1659: 0x0003, + 0x1665: 0x0003, + 0x167f: 0x0003, + // Block 0x5a, offset 0x1680 + 0x1692: 0x0003, + 0x169a: 0x0002, 0x169b: 0x0002, + 0x16a9: 0x0002, + 0x16aa: 0x0002, + // Block 0x5b, offset 0x16c0 + 0x16e9: 0x0002, + 0x16ea: 0x0002, 0x16eb: 0x0002, 0x16ec: 0x0002, + 0x16f0: 0x0002, 0x16f3: 0x0002, + // Block 0x5c, offset 0x1700 + 0x1720: 0x0003, 0x1721: 0x0003, 0x1722: 0x0003, 0x1723: 0x0003, + 0x1724: 0x0003, 0x1725: 0x0003, 0x1726: 0x0003, 0x1727: 0x0003, 0x1728: 0x0003, 0x1729: 0x0003, + 0x172a: 0x0003, 0x172b: 0x0003, 0x172c: 0x0003, 0x172d: 0x0003, 0x172e: 0x0003, 0x172f: 0x0003, + 0x1730: 0x0003, 0x1731: 0x0003, 0x1732: 0x0003, 0x1733: 0x0003, 0x1734: 0x0003, 0x1735: 0x0003, + 0x1736: 0x0003, 0x1737: 0x0003, 0x1738: 0x0003, 0x1739: 0x0003, 0x173a: 0x0003, 0x173b: 0x0003, + 0x173c: 0x0003, 0x173d: 0x0003, 0x173e: 0x0003, 0x173f: 0x0003, + // Block 0x5d, offset 0x1740 + 0x1740: 0x0003, 0x1741: 0x0003, 0x1742: 0x0003, 0x1743: 0x0003, 0x1744: 0x0003, 0x1745: 0x0003, + 0x1746: 0x0003, 0x1747: 0x0003, 0x1748: 0x0003, 0x1749: 0x0003, 0x174a: 0x0003, 0x174b: 0x0003, + 0x174c: 0x0003, 0x174d: 0x0003, 0x174e: 0x0003, 0x174f: 0x0003, 0x1750: 0x0003, 0x1751: 0x0003, + 0x1752: 0x0003, 0x1753: 0x0003, 0x1754: 0x0003, 0x1755: 0x0003, 0x1756: 0x0003, 0x1757: 0x0003, + 0x1758: 0x0003, 0x1759: 0x0003, 0x175a: 0x0003, 0x175b: 0x0003, 0x175c: 0x0003, 0x175d: 0x0003, + 0x175e: 0x0003, 0x175f: 0x0003, 0x1760: 0x0003, 0x1761: 0x0003, 0x1762: 0x0003, 0x1763: 0x0003, + 0x1764: 0x0003, 0x1765: 0x0003, 0x1766: 0x0003, 0x1767: 0x0003, 0x1768: 0x0003, 0x1769: 0x0003, + 0x176a: 0x0003, 0x176b: 0x0003, 0x176c: 0x0003, 0x176d: 0x0003, 0x176e: 0x0003, 0x176f: 0x0003, + 0x1770: 0x0003, 0x1771: 0x0003, 0x1772: 0x0003, 0x1773: 0x0003, 0x1774: 0x0003, 0x1775: 0x0003, + 0x1776: 0x0003, 0x1777: 0x0003, 0x1778: 0x0003, 0x1779: 0x0003, 0x177a: 0x0003, 0x177b: 0x0003, + 0x177c: 0x0003, 0x177d: 0x0003, 0x177e: 0x0003, 0x177f: 0x0003, + // Block 0x5e, offset 0x1780 + 0x1780: 0x0003, 0x1781: 0x0003, 0x1782: 0x0003, 0x1783: 0x0003, 0x1784: 0x0003, 0x1785: 0x0003, + 0x1786: 0x0003, 0x1787: 0x0003, 0x1788: 0x0003, 0x1789: 0x0003, 0x178a: 0x0003, 0x178b: 0x0003, + 0x178c: 0x0003, 0x178d: 0x0003, 0x178e: 0x0003, 0x178f: 0x0003, 0x1790: 0x0003, 0x1791: 0x0003, + 0x1792: 0x0003, 0x1793: 0x0003, 0x1794: 0x0003, 0x1795: 0x0003, 0x1796: 0x0003, 0x1797: 0x0003, + 0x1798: 0x0003, 0x1799: 0x0003, 0x179a: 0x0003, 0x179b: 0x0003, 0x179c: 0x0003, 0x179d: 0x0003, + 0x179e: 0x0003, 0x179f: 0x0003, 0x17a0: 0x0003, 0x17a1: 0x0003, 0x17a2: 0x0003, 0x17a3: 0x0003, + 0x17a4: 0x0003, 0x17a5: 0x0003, 0x17a6: 0x0003, 0x17a7: 0x0003, 0x17a8: 0x0003, 0x17a9: 0x0003, + 0x17ab: 0x0003, 0x17ac: 0x0003, 0x17ad: 0x0003, 0x17ae: 0x0003, 0x17af: 0x0003, + 0x17b0: 0x0003, 0x17b1: 0x0003, 0x17b2: 0x0003, 0x17b3: 0x0003, 0x17b4: 0x0003, 0x17b5: 0x0003, + 0x17b6: 0x0003, 0x17b7: 0x0003, 0x17b8: 0x0003, 0x17b9: 0x0003, 0x17ba: 0x0003, 0x17bb: 0x0003, + 0x17bc: 0x0003, 0x17bd: 0x0003, 0x17be: 0x0003, 0x17bf: 0x0003, + // Block 0x5f, offset 0x17c0 + 0x17c0: 0x0003, 0x17c1: 0x0003, 0x17c2: 0x0003, 0x17c3: 0x0003, 0x17c4: 0x0003, 0x17c5: 0x0003, + 0x17c6: 0x0003, 0x17c7: 0x0003, 0x17c8: 0x0003, 0x17c9: 0x0003, 0x17ca: 0x0003, 0x17cb: 0x0003, + 0x17d0: 0x0003, 0x17d1: 0x0003, + 0x17d2: 0x0003, 0x17d3: 0x0003, 0x17d4: 0x0003, 0x17d5: 0x0003, 0x17d6: 0x0003, 0x17d7: 0x0003, + 0x17d8: 0x0003, 0x17d9: 0x0003, 0x17da: 0x0003, 0x17db: 0x0003, 0x17dc: 0x0003, 0x17dd: 0x0003, + 0x17de: 0x0003, 0x17df: 0x0003, 0x17e0: 0x0003, 0x17e1: 0x0003, 0x17e2: 0x0003, 0x17e3: 0x0003, + 0x17e4: 0x0003, 0x17e5: 0x0003, 0x17e6: 0x0003, 0x17e7: 0x0003, 0x17e8: 0x0003, 0x17e9: 0x0003, + 0x17ea: 0x0003, 0x17eb: 0x0003, 0x17ec: 0x0003, 0x17ed: 0x0003, 0x17ee: 0x0003, 0x17ef: 0x0003, + 0x17f0: 0x0003, 0x17f1: 0x0003, 0x17f2: 0x0003, 0x17f3: 0x0003, + // Block 0x60, offset 0x1800 + 0x1800: 0x0003, 0x1801: 0x0003, 0x1802: 0x0003, 0x1803: 0x0003, 0x1804: 0x0003, 0x1805: 0x0003, + 0x1806: 0x0003, 0x1807: 0x0003, 0x1808: 0x0003, 0x1809: 0x0003, 0x180a: 0x0003, 0x180b: 0x0003, + 0x180c: 0x0003, 0x180d: 0x0003, 0x180e: 0x0003, 0x180f: 0x0003, + 0x1812: 0x0003, 0x1813: 0x0003, 0x1814: 0x0003, 0x1815: 0x0003, + 0x1820: 0x0003, 0x1821: 0x0003, 0x1823: 0x0003, + 0x1824: 0x0003, 0x1825: 0x0003, 0x1826: 0x0003, 0x1827: 0x0003, 0x1828: 0x0003, 0x1829: 0x0003, + 0x1832: 0x0003, 0x1833: 0x0003, + 0x1836: 0x0003, 0x1837: 0x0003, + 0x183c: 0x0003, 0x183d: 0x0003, + // Block 0x61, offset 0x1840 + 0x1840: 0x0003, 0x1841: 0x0003, + 0x1846: 0x0003, 0x1847: 0x0003, 0x1848: 0x0003, 0x184b: 0x0003, + 0x184e: 0x0003, 0x184f: 0x0003, 0x1850: 0x0003, 0x1851: 0x0003, + 0x1862: 0x0003, 0x1863: 0x0003, + 0x1864: 0x0003, 0x1865: 0x0003, + 0x186f: 0x0003, + 0x187d: 0x0002, 0x187e: 0x0002, + // Block 0x62, offset 0x1880 + 0x1885: 0x0003, + 0x1886: 0x0003, 0x1889: 0x0003, + 0x188e: 0x0003, 0x188f: 0x0003, + 0x1894: 0x0002, 0x1895: 0x0002, + 0x189c: 0x0003, + 0x189e: 0x0003, + 0x18b0: 0x0002, 0x18b1: 0x0002, 0x18b2: 0x0002, 0x18b3: 0x0002, 0x18b4: 0x0002, 0x18b5: 0x0002, + 0x18b6: 0x0002, 0x18b7: 0x0002, + // Block 0x63, offset 0x18c0 + 0x18c0: 0x0003, 0x18c2: 0x0003, + 0x18c8: 0x0002, 0x18c9: 0x0002, 0x18ca: 0x0002, 0x18cb: 0x0002, + 0x18cc: 0x0002, 0x18cd: 0x0002, 0x18ce: 0x0002, 0x18cf: 0x0002, 0x18d0: 0x0002, 0x18d1: 0x0002, + 0x18d2: 0x0002, 0x18d3: 0x0002, + 0x18e0: 0x0003, 0x18e1: 0x0003, 0x18e3: 0x0003, + 0x18e4: 0x0003, 0x18e5: 0x0003, 0x18e7: 0x0003, 0x18e8: 0x0003, 0x18e9: 0x0003, + 0x18ea: 0x0003, 0x18ec: 0x0003, 0x18ed: 0x0003, 0x18ef: 0x0003, + 0x18ff: 0x0002, + // Block 0x64, offset 0x1900 + 0x190a: 0x0002, 0x190b: 0x0002, + 0x190c: 0x0002, 0x190d: 0x0002, 0x190e: 0x0002, 0x190f: 0x0002, + 0x1913: 0x0002, + 0x191e: 0x0003, 0x191f: 0x0003, 0x1921: 0x0002, + 0x192a: 0x0002, 0x192b: 0x0002, + 0x193d: 0x0002, 0x193e: 0x0002, 0x193f: 0x0003, + // Block 0x65, offset 0x1940 + 0x1944: 0x0002, 0x1945: 0x0002, + 0x1946: 0x0003, 0x1947: 0x0003, 0x1948: 0x0003, 0x1949: 0x0003, 0x194a: 0x0003, 0x194b: 0x0003, + 0x194c: 0x0003, 0x194d: 0x0003, 0x194e: 0x0002, 0x194f: 0x0003, 0x1950: 0x0003, 0x1951: 0x0003, + 0x1952: 0x0003, 0x1953: 0x0003, 0x1954: 0x0002, 0x1955: 0x0003, 0x1956: 0x0003, 0x1957: 0x0003, + 0x1958: 0x0003, 0x1959: 0x0003, 0x195a: 0x0003, 0x195b: 0x0003, 0x195c: 0x0003, 0x195d: 0x0003, + 0x195e: 0x0003, 0x195f: 0x0003, 0x1960: 0x0003, 0x1961: 0x0003, 0x1963: 0x0003, + 0x1968: 0x0003, 0x1969: 0x0003, + 0x196a: 0x0002, 0x196b: 0x0003, 0x196c: 0x0003, 0x196d: 0x0003, 0x196e: 0x0003, 0x196f: 0x0003, + 0x1970: 0x0003, 0x1971: 0x0003, 0x1972: 0x0002, 0x1973: 0x0002, 0x1974: 0x0003, 0x1975: 0x0002, + 0x1976: 0x0003, 0x1977: 0x0003, 0x1978: 0x0003, 0x1979: 0x0003, 0x197a: 0x0002, 0x197b: 0x0003, + 0x197c: 0x0003, 0x197d: 0x0002, 0x197e: 0x0003, 0x197f: 0x0003, + // Block 0x66, offset 0x1980 + 0x1985: 0x0002, + 0x198a: 0x0002, 0x198b: 0x0002, + 0x19a8: 0x0002, + 0x19bd: 0x0003, + // Block 0x67, offset 0x19c0 + 0x19cc: 0x0002, 0x19ce: 0x0002, + 0x19d3: 0x0002, 0x19d4: 0x0002, 0x19d5: 0x0002, 0x19d7: 0x0002, + 0x19f6: 0x0003, 0x19f7: 0x0003, 0x19f8: 0x0003, 0x19f9: 0x0003, 0x19fa: 0x0003, 0x19fb: 0x0003, + 0x19fc: 0x0003, 0x19fd: 0x0003, 0x19fe: 0x0003, 0x19ff: 0x0003, + // Block 0x68, offset 0x1a00 + 0x1a15: 0x0002, 0x1a16: 0x0002, 0x1a17: 0x0002, + 0x1a30: 0x0002, + 0x1a3f: 0x0002, + // Block 0x69, offset 0x1a40 + 0x1a5b: 0x0002, 0x1a5c: 0x0002, + // Block 0x6a, offset 0x1a80 + 0x1a90: 0x0002, + 0x1a95: 0x0002, 0x1a96: 0x0003, 0x1a97: 0x0003, + 0x1a98: 0x0003, 0x1a99: 0x0003, + // Block 0x6b, offset 0x1ac0 + 0x1aef: 0x0001, + 0x1af0: 0x0001, 0x1af1: 0x0001, + // Block 0x6c, offset 0x1b00 + 0x1b3f: 0x0001, + // Block 0x6d, offset 0x1b40 + 0x1b60: 0x0001, 0x1b61: 0x0001, 0x1b62: 0x0001, 0x1b63: 0x0001, + 0x1b64: 0x0001, 0x1b65: 0x0001, 0x1b66: 0x0001, 0x1b67: 0x0001, 0x1b68: 0x0001, 0x1b69: 0x0001, + 0x1b6a: 0x0001, 0x1b6b: 0x0001, 0x1b6c: 0x0001, 0x1b6d: 0x0001, 0x1b6e: 0x0001, 0x1b6f: 0x0001, + 0x1b70: 0x0001, 0x1b71: 0x0001, 0x1b72: 0x0001, 0x1b73: 0x0001, 0x1b74: 0x0001, 0x1b75: 0x0001, + 0x1b76: 0x0001, 0x1b77: 0x0001, 0x1b78: 0x0001, 0x1b79: 0x0001, 0x1b7a: 0x0001, 0x1b7b: 0x0001, + 0x1b7c: 0x0001, 0x1b7d: 0x0001, 0x1b7e: 0x0001, 0x1b7f: 0x0001, + // Block 0x6e, offset 0x1b80 + 0x1b80: 0x0002, 0x1b81: 0x0002, 0x1b82: 0x0002, 0x1b83: 0x0002, 0x1b84: 0x0002, 0x1b85: 0x0002, + 0x1b86: 0x0002, 0x1b87: 0x0002, 0x1b88: 0x0002, 0x1b89: 0x0002, 0x1b8a: 0x0002, 0x1b8b: 0x0002, + 0x1b8c: 0x0002, 0x1b8d: 0x0002, 0x1b8e: 0x0002, 0x1b8f: 0x0002, 0x1b90: 0x0002, 0x1b91: 0x0002, + 0x1b92: 0x0002, 0x1b93: 0x0002, 0x1b94: 0x0002, 0x1b95: 0x0002, 0x1b96: 0x0002, 0x1b97: 0x0002, + 0x1b98: 0x0002, 0x1b99: 0x0002, 0x1b9b: 0x0002, 0x1b9c: 0x0002, 0x1b9d: 0x0002, + 0x1b9e: 0x0002, 0x1b9f: 0x0002, 0x1ba0: 0x0002, 0x1ba1: 0x0002, 0x1ba2: 0x0002, 0x1ba3: 0x0002, + 0x1ba4: 0x0002, 0x1ba5: 0x0002, 0x1ba6: 0x0002, 0x1ba7: 0x0002, 0x1ba8: 0x0002, 0x1ba9: 0x0002, + 0x1baa: 0x0002, 0x1bab: 0x0002, 0x1bac: 0x0002, 0x1bad: 0x0002, 0x1bae: 0x0002, 0x1baf: 0x0002, + 0x1bb0: 0x0002, 0x1bb1: 0x0002, 0x1bb2: 0x0002, 0x1bb3: 0x0002, 0x1bb4: 0x0002, 0x1bb5: 0x0002, + 0x1bb6: 0x0002, 0x1bb7: 0x0002, 0x1bb8: 0x0002, 0x1bb9: 0x0002, 0x1bba: 0x0002, 0x1bbb: 0x0002, + 0x1bbc: 0x0002, 0x1bbd: 0x0002, 0x1bbe: 0x0002, 0x1bbf: 0x0002, + // Block 0x6f, offset 0x1bc0 + 0x1bc0: 0x0002, 0x1bc1: 0x0002, 0x1bc2: 0x0002, 0x1bc3: 0x0002, 0x1bc4: 0x0002, 0x1bc5: 0x0002, + 0x1bc6: 0x0002, 0x1bc7: 0x0002, 0x1bc8: 0x0002, 0x1bc9: 0x0002, 0x1bca: 0x0002, 0x1bcb: 0x0002, + 0x1bcc: 0x0002, 0x1bcd: 0x0002, 0x1bce: 0x0002, 0x1bcf: 0x0002, 0x1bd0: 0x0002, 0x1bd1: 0x0002, + 0x1bd2: 0x0002, 0x1bd3: 0x0002, 0x1bd4: 0x0002, 0x1bd5: 0x0002, 0x1bd6: 0x0002, 0x1bd7: 0x0002, + 0x1bd8: 0x0002, 0x1bd9: 0x0002, 0x1bda: 0x0002, 0x1bdb: 0x0002, 0x1bdc: 0x0002, 0x1bdd: 0x0002, + 0x1bde: 0x0002, 0x1bdf: 0x0002, 0x1be0: 0x0002, 0x1be1: 0x0002, 0x1be2: 0x0002, 0x1be3: 0x0002, + 0x1be4: 0x0002, 0x1be5: 0x0002, 0x1be6: 0x0002, 0x1be7: 0x0002, 0x1be8: 0x0002, 0x1be9: 0x0002, + 0x1bea: 0x0002, 0x1beb: 0x0002, 0x1bec: 0x0002, 0x1bed: 0x0002, 0x1bee: 0x0002, 0x1bef: 0x0002, + 0x1bf0: 0x0002, 0x1bf1: 0x0002, 0x1bf2: 0x0002, 0x1bf3: 0x0002, + // Block 0x70, offset 0x1c00 + 0x1c00: 0x0002, 0x1c01: 0x0002, 0x1c02: 0x0002, 0x1c03: 0x0002, 0x1c04: 0x0002, 0x1c05: 0x0002, + 0x1c06: 0x0002, 0x1c07: 0x0002, 0x1c08: 0x0002, 0x1c09: 0x0002, 0x1c0a: 0x0002, 0x1c0b: 0x0002, + 0x1c0c: 0x0002, 0x1c0d: 0x0002, 0x1c0e: 0x0002, 0x1c0f: 0x0002, 0x1c10: 0x0002, 0x1c11: 0x0002, + 0x1c12: 0x0002, 0x1c13: 0x0002, 0x1c14: 0x0002, 0x1c15: 0x0002, + 0x1c30: 0x0002, 0x1c31: 0x0002, 0x1c32: 0x0002, 0x1c33: 0x0002, 0x1c34: 0x0002, 0x1c35: 0x0002, + 0x1c36: 0x0002, 0x1c37: 0x0002, 0x1c38: 0x0002, 0x1c39: 0x0002, 0x1c3a: 0x0002, 0x1c3b: 0x0002, + 0x1c3c: 0x0002, 0x1c3d: 0x0002, 0x1c3e: 0x0002, 0x1c3f: 0x0002, + // Block 0x71, offset 0x1c40 + 0x1c40: 0x0002, 0x1c41: 0x0002, 0x1c42: 0x0002, 0x1c43: 0x0002, 0x1c44: 0x0002, 0x1c45: 0x0002, + 0x1c46: 0x0002, 0x1c47: 0x0002, 0x1c48: 0x0002, 0x1c49: 0x0002, 0x1c4a: 0x0002, 0x1c4b: 0x0002, + 0x1c4c: 0x0002, 0x1c4d: 0x0002, 0x1c4e: 0x0002, 0x1c4f: 0x0002, 0x1c50: 0x0002, 0x1c51: 0x0002, + 0x1c52: 0x0002, 0x1c53: 0x0002, 0x1c54: 0x0002, 0x1c55: 0x0002, 0x1c56: 0x0002, 0x1c57: 0x0002, + 0x1c58: 0x0002, 0x1c59: 0x0002, 0x1c5a: 0x0002, 0x1c5b: 0x0002, 0x1c5c: 0x0002, 0x1c5d: 0x0002, + 0x1c5e: 0x0002, 0x1c5f: 0x0002, 0x1c60: 0x0002, 0x1c61: 0x0002, 0x1c62: 0x0002, 0x1c63: 0x0002, + 0x1c64: 0x0002, 0x1c65: 0x0002, 0x1c66: 0x0002, 0x1c67: 0x0002, 0x1c68: 0x0002, 0x1c69: 0x0002, + 0x1c6a: 0x0001, 0x1c6b: 0x0001, 0x1c6c: 0x0001, 0x1c6d: 0x0001, 0x1c6e: 0x0002, 0x1c6f: 0x0002, + 0x1c70: 0x0002, 0x1c71: 0x0002, 0x1c72: 0x0002, 0x1c73: 0x0002, 0x1c74: 0x0002, 0x1c75: 0x0002, + 0x1c76: 0x0002, 0x1c77: 0x0002, 0x1c78: 0x0002, 0x1c79: 0x0002, 0x1c7a: 0x0002, 0x1c7b: 0x0002, + 0x1c7c: 0x0002, 0x1c7d: 0x0002, 0x1c7e: 0x0002, + // Block 0x72, offset 0x1c80 + 0x1c81: 0x0002, 0x1c82: 0x0002, 0x1c83: 0x0002, 0x1c84: 0x0002, 0x1c85: 0x0002, + 0x1c86: 0x0002, 0x1c87: 0x0002, 0x1c88: 0x0002, 0x1c89: 0x0002, 0x1c8a: 0x0002, 0x1c8b: 0x0002, + 0x1c8c: 0x0002, 0x1c8d: 0x0002, 0x1c8e: 0x0002, 0x1c8f: 0x0002, 0x1c90: 0x0002, 0x1c91: 0x0002, + 0x1c92: 0x0002, 0x1c93: 0x0002, 0x1c94: 0x0002, 0x1c95: 0x0002, 0x1c96: 0x0002, 0x1c97: 0x0002, + 0x1c98: 0x0002, 0x1c99: 0x0002, 0x1c9a: 0x0002, 0x1c9b: 0x0002, 0x1c9c: 0x0002, 0x1c9d: 0x0002, + 0x1c9e: 0x0002, 0x1c9f: 0x0002, 0x1ca0: 0x0002, 0x1ca1: 0x0002, 0x1ca2: 0x0002, 0x1ca3: 0x0002, + 0x1ca4: 0x0002, 0x1ca5: 0x0002, 0x1ca6: 0x0002, 0x1ca7: 0x0002, 0x1ca8: 0x0002, 0x1ca9: 0x0002, + 0x1caa: 0x0002, 0x1cab: 0x0002, 0x1cac: 0x0002, 0x1cad: 0x0002, 0x1cae: 0x0002, 0x1caf: 0x0002, + 0x1cb0: 0x0002, 0x1cb1: 0x0002, 0x1cb2: 0x0002, 0x1cb3: 0x0002, 0x1cb4: 0x0002, 0x1cb5: 0x0002, + 0x1cb6: 0x0002, 0x1cb7: 0x0002, 0x1cb8: 0x0002, 0x1cb9: 0x0002, 0x1cba: 0x0002, 0x1cbb: 0x0002, + 0x1cbc: 0x0002, 0x1cbd: 0x0002, 0x1cbe: 0x0002, 0x1cbf: 0x0002, + // Block 0x73, offset 0x1cc0 + 0x1cc0: 0x0002, 0x1cc1: 0x0002, 0x1cc2: 0x0002, 0x1cc3: 0x0002, 0x1cc4: 0x0002, 0x1cc5: 0x0002, + 0x1cc6: 0x0002, 0x1cc7: 0x0002, 0x1cc8: 0x0002, 0x1cc9: 0x0002, 0x1cca: 0x0002, 0x1ccb: 0x0002, + 0x1ccc: 0x0002, 0x1ccd: 0x0002, 0x1cce: 0x0002, 0x1ccf: 0x0002, 0x1cd0: 0x0002, 0x1cd1: 0x0002, + 0x1cd2: 0x0002, 0x1cd3: 0x0002, 0x1cd4: 0x0002, 0x1cd5: 0x0002, 0x1cd6: 0x0002, + 0x1cd9: 0x0001, 0x1cda: 0x0001, 0x1cdb: 0x0002, 0x1cdc: 0x0002, 0x1cdd: 0x0002, + 0x1cde: 0x0002, 0x1cdf: 0x0002, 0x1ce0: 0x0002, 0x1ce1: 0x0002, 0x1ce2: 0x0002, 0x1ce3: 0x0002, + 0x1ce4: 0x0002, 0x1ce5: 0x0002, 0x1ce6: 0x0002, 0x1ce7: 0x0002, 0x1ce8: 0x0002, 0x1ce9: 0x0002, + 0x1cea: 0x0002, 0x1ceb: 0x0002, 0x1cec: 0x0002, 0x1ced: 0x0002, 0x1cee: 0x0002, 0x1cef: 0x0002, + 0x1cf0: 0x0002, 0x1cf1: 0x0002, 0x1cf2: 0x0002, 0x1cf3: 0x0002, 0x1cf4: 0x0002, 0x1cf5: 0x0002, + 0x1cf6: 0x0002, 0x1cf7: 0x0002, 0x1cf8: 0x0002, 0x1cf9: 0x0002, 0x1cfa: 0x0002, 0x1cfb: 0x0002, + 0x1cfc: 0x0002, 0x1cfd: 0x0002, 0x1cfe: 0x0002, 0x1cff: 0x0002, + // Block 0x74, offset 0x1d00 + 0x1d05: 0x0002, + 0x1d06: 0x0002, 0x1d07: 0x0002, 0x1d08: 0x0002, 0x1d09: 0x0002, 0x1d0a: 0x0002, 0x1d0b: 0x0002, + 0x1d0c: 0x0002, 0x1d0d: 0x0002, 0x1d0e: 0x0002, 0x1d0f: 0x0002, 0x1d10: 0x0002, 0x1d11: 0x0002, + 0x1d12: 0x0002, 0x1d13: 0x0002, 0x1d14: 0x0002, 0x1d15: 0x0002, 0x1d16: 0x0002, 0x1d17: 0x0002, + 0x1d18: 0x0002, 0x1d19: 0x0002, 0x1d1a: 0x0002, 0x1d1b: 0x0002, 0x1d1c: 0x0002, 0x1d1d: 0x0002, + 0x1d1e: 0x0002, 0x1d1f: 0x0002, 0x1d20: 0x0002, 0x1d21: 0x0002, 0x1d22: 0x0002, 0x1d23: 0x0002, + 0x1d24: 0x0002, 0x1d25: 0x0002, 0x1d26: 0x0002, 0x1d27: 0x0002, 0x1d28: 0x0002, 0x1d29: 0x0002, + 0x1d2a: 0x0002, 0x1d2b: 0x0002, 0x1d2c: 0x0002, 0x1d2d: 0x0002, 0x1d2e: 0x0002, 0x1d2f: 0x0002, + 0x1d31: 0x0002, 0x1d32: 0x0002, 0x1d33: 0x0002, 0x1d34: 0x0002, 0x1d35: 0x0002, + 0x1d36: 0x0002, 0x1d37: 0x0002, 0x1d38: 0x0002, 0x1d39: 0x0002, 0x1d3a: 0x0002, 0x1d3b: 0x0002, + 0x1d3c: 0x0002, 0x1d3d: 0x0002, 0x1d3e: 0x0002, 0x1d3f: 0x0002, + // Block 0x75, offset 0x1d40 + 0x1d40: 0x0002, 0x1d41: 0x0002, 0x1d42: 0x0002, 0x1d43: 0x0002, 0x1d44: 0x0002, 0x1d45: 0x0002, + 0x1d46: 0x0002, 0x1d47: 0x0002, 0x1d48: 0x0002, 0x1d49: 0x0002, 0x1d4a: 0x0002, 0x1d4b: 0x0002, + 0x1d4c: 0x0002, 0x1d4d: 0x0002, 0x1d4e: 0x0002, 0x1d50: 0x0002, 0x1d51: 0x0002, + 0x1d52: 0x0002, 0x1d53: 0x0002, 0x1d54: 0x0002, 0x1d55: 0x0002, 0x1d56: 0x0002, 0x1d57: 0x0002, + 0x1d58: 0x0002, 0x1d59: 0x0002, 0x1d5a: 0x0002, 0x1d5b: 0x0002, 0x1d5c: 0x0002, 0x1d5d: 0x0002, + 0x1d5e: 0x0002, 0x1d5f: 0x0002, 0x1d60: 0x0002, 0x1d61: 0x0002, 0x1d62: 0x0002, 0x1d63: 0x0002, + 0x1d64: 0x0002, 0x1d65: 0x0002, 0x1d66: 0x0002, 0x1d67: 0x0002, 0x1d68: 0x0002, 0x1d69: 0x0002, + 0x1d6a: 0x0002, 0x1d6b: 0x0002, 0x1d6c: 0x0002, 0x1d6d: 0x0002, 0x1d6e: 0x0002, 0x1d6f: 0x0002, + 0x1d70: 0x0002, 0x1d71: 0x0002, 0x1d72: 0x0002, 0x1d73: 0x0002, 0x1d74: 0x0002, 0x1d75: 0x0002, + 0x1d76: 0x0002, 0x1d77: 0x0002, 0x1d78: 0x0002, 0x1d79: 0x0002, 0x1d7a: 0x0002, 0x1d7b: 0x0002, + 0x1d7c: 0x0002, 0x1d7d: 0x0002, 0x1d7e: 0x0002, 0x1d7f: 0x0002, + // Block 0x76, offset 0x1d80 + 0x1d80: 0x0002, 0x1d81: 0x0002, 0x1d82: 0x0002, 0x1d83: 0x0002, 0x1d84: 0x0002, 0x1d85: 0x0002, + 0x1d86: 0x0002, 0x1d87: 0x0002, 0x1d88: 0x0002, 0x1d89: 0x0002, 0x1d8a: 0x0002, 0x1d8b: 0x0002, + 0x1d8c: 0x0002, 0x1d8d: 0x0002, 0x1d8e: 0x0002, 0x1d8f: 0x0002, 0x1d90: 0x0002, 0x1d91: 0x0002, + 0x1d92: 0x0002, 0x1d93: 0x0002, 0x1d94: 0x0002, 0x1d95: 0x0002, 0x1d96: 0x0002, 0x1d97: 0x0002, + 0x1d98: 0x0002, 0x1d99: 0x0002, 0x1d9a: 0x0002, 0x1d9b: 0x0002, 0x1d9c: 0x0002, 0x1d9d: 0x0002, + 0x1d9e: 0x0002, 0x1d9f: 0x0002, 0x1da0: 0x0002, 0x1da1: 0x0002, 0x1da2: 0x0002, 0x1da3: 0x0002, + 0x1da4: 0x0002, 0x1da5: 0x0002, + 0x1daf: 0x0002, + 0x1db0: 0x0002, 0x1db1: 0x0002, 0x1db2: 0x0002, 0x1db3: 0x0002, 0x1db4: 0x0002, 0x1db5: 0x0002, + 0x1db6: 0x0002, 0x1db7: 0x0002, 0x1db8: 0x0002, 0x1db9: 0x0002, 0x1dba: 0x0002, 0x1dbb: 0x0002, + 0x1dbc: 0x0002, 0x1dbd: 0x0002, 0x1dbe: 0x0002, 0x1dbf: 0x0002, + // Block 0x77, offset 0x1dc0 + 0x1dc0: 0x0002, 0x1dc1: 0x0002, 0x1dc2: 0x0002, 0x1dc3: 0x0002, 0x1dc4: 0x0002, 0x1dc5: 0x0002, + 0x1dc6: 0x0002, 0x1dc7: 0x0002, 0x1dc8: 0x0002, 0x1dc9: 0x0002, 0x1dca: 0x0002, 0x1dcb: 0x0002, + 0x1dcc: 0x0002, 0x1dcd: 0x0002, 0x1dce: 0x0002, 0x1dcf: 0x0002, 0x1dd0: 0x0002, 0x1dd1: 0x0002, + 0x1dd2: 0x0002, 0x1dd3: 0x0002, 0x1dd4: 0x0002, 0x1dd5: 0x0002, 0x1dd6: 0x0002, 0x1dd7: 0x0002, + 0x1dd8: 0x0002, 0x1dd9: 0x0002, 0x1dda: 0x0002, 0x1ddb: 0x0002, 0x1ddc: 0x0002, 0x1ddd: 0x0002, + 0x1dde: 0x0002, 0x1de0: 0x0002, 0x1de1: 0x0002, 0x1de2: 0x0002, 0x1de3: 0x0002, + 0x1de4: 0x0002, 0x1de5: 0x0002, 0x1de6: 0x0002, 0x1de7: 0x0002, 0x1de8: 0x0002, 0x1de9: 0x0002, + 0x1dea: 0x0002, 0x1deb: 0x0002, 0x1dec: 0x0002, 0x1ded: 0x0002, 0x1dee: 0x0002, 0x1def: 0x0002, + 0x1df0: 0x0002, 0x1df1: 0x0002, 0x1df2: 0x0002, 0x1df3: 0x0002, 0x1df4: 0x0002, 0x1df5: 0x0002, + 0x1df6: 0x0002, 0x1df7: 0x0002, 0x1df8: 0x0002, 0x1df9: 0x0002, 0x1dfa: 0x0002, 0x1dfb: 0x0002, + 0x1dfc: 0x0002, 0x1dfd: 0x0002, 0x1dfe: 0x0002, 0x1dff: 0x0002, + // Block 0x78, offset 0x1e00 + 0x1e00: 0x0002, 0x1e01: 0x0002, 0x1e02: 0x0002, 0x1e03: 0x0002, 0x1e04: 0x0002, 0x1e05: 0x0002, + 0x1e06: 0x0002, 0x1e07: 0x0002, 0x1e08: 0x0003, 0x1e09: 0x0003, 0x1e0a: 0x0003, 0x1e0b: 0x0003, + 0x1e0c: 0x0003, 0x1e0d: 0x0003, 0x1e0e: 0x0003, 0x1e0f: 0x0003, 0x1e10: 0x0002, 0x1e11: 0x0002, + 0x1e12: 0x0002, 0x1e13: 0x0002, 0x1e14: 0x0002, 0x1e15: 0x0002, 0x1e16: 0x0002, 0x1e17: 0x0002, + 0x1e18: 0x0002, 0x1e19: 0x0002, 0x1e1a: 0x0002, 0x1e1b: 0x0002, 0x1e1c: 0x0002, 0x1e1d: 0x0002, + 0x1e1e: 0x0002, 0x1e1f: 0x0002, 0x1e20: 0x0002, 0x1e21: 0x0002, 0x1e22: 0x0002, 0x1e23: 0x0002, + 0x1e24: 0x0002, 0x1e25: 0x0002, 0x1e26: 0x0002, 0x1e27: 0x0002, 0x1e28: 0x0002, 0x1e29: 0x0002, + 0x1e2a: 0x0002, 0x1e2b: 0x0002, 0x1e2c: 0x0002, 0x1e2d: 0x0002, 0x1e2e: 0x0002, 0x1e2f: 0x0002, + 0x1e30: 0x0002, 0x1e31: 0x0002, 0x1e32: 0x0002, 0x1e33: 0x0002, 0x1e34: 0x0002, 0x1e35: 0x0002, + 0x1e36: 0x0002, 0x1e37: 0x0002, 0x1e38: 0x0002, 0x1e39: 0x0002, 0x1e3a: 0x0002, 0x1e3b: 0x0002, + 0x1e3c: 0x0002, 0x1e3d: 0x0002, 0x1e3e: 0x0002, 0x1e3f: 0x0002, + // Block 0x79, offset 0x1e40 + 0x1e40: 0x0002, 0x1e41: 0x0002, 0x1e42: 0x0002, 0x1e43: 0x0002, 0x1e44: 0x0002, 0x1e45: 0x0002, + 0x1e46: 0x0002, 0x1e47: 0x0002, 0x1e48: 0x0002, 0x1e49: 0x0002, 0x1e4a: 0x0002, 0x1e4b: 0x0002, + 0x1e4c: 0x0002, 0x1e50: 0x0002, 0x1e51: 0x0002, + 0x1e52: 0x0002, 0x1e53: 0x0002, 0x1e54: 0x0002, 0x1e55: 0x0002, 0x1e56: 0x0002, 0x1e57: 0x0002, + 0x1e58: 0x0002, 0x1e59: 0x0002, 0x1e5a: 0x0002, 0x1e5b: 0x0002, 0x1e5c: 0x0002, 0x1e5d: 0x0002, + 0x1e5e: 0x0002, 0x1e5f: 0x0002, 0x1e60: 0x0002, 0x1e61: 0x0002, 0x1e62: 0x0002, 0x1e63: 0x0002, + 0x1e64: 0x0002, 0x1e65: 0x0002, 0x1e66: 0x0002, 0x1e67: 0x0002, 0x1e68: 0x0002, 0x1e69: 0x0002, + 0x1e6a: 0x0002, 0x1e6b: 0x0002, 0x1e6c: 0x0002, 0x1e6d: 0x0002, 0x1e6e: 0x0002, 0x1e6f: 0x0002, + 0x1e70: 0x0002, 0x1e71: 0x0002, 0x1e72: 0x0002, 0x1e73: 0x0002, 0x1e74: 0x0002, 0x1e75: 0x0002, + 0x1e76: 0x0002, 0x1e77: 0x0002, 0x1e78: 0x0002, 0x1e79: 0x0002, 0x1e7a: 0x0002, 0x1e7b: 0x0002, + 0x1e7c: 0x0002, 0x1e7d: 0x0002, 0x1e7e: 0x0002, 0x1e7f: 0x0002, + // Block 0x7a, offset 0x1e80 + 0x1e80: 0x0002, 0x1e81: 0x0002, 0x1e82: 0x0002, 0x1e83: 0x0002, 0x1e84: 0x0002, 0x1e85: 0x0002, + 0x1e86: 0x0002, + // Block 0x7b, offset 0x1ec0 + 0x1eef: 0x0001, + 0x1ef0: 0x0001, 0x1ef1: 0x0001, 0x1ef2: 0x0001, 0x1ef4: 0x0001, 0x1ef5: 0x0001, + 0x1ef6: 0x0001, 0x1ef7: 0x0001, 0x1ef8: 0x0001, 0x1ef9: 0x0001, 0x1efa: 0x0001, 0x1efb: 0x0001, + 0x1efc: 0x0001, 0x1efd: 0x0001, + // Block 0x7c, offset 0x1f00 + 0x1f1e: 0x0001, 0x1f1f: 0x0001, + // Block 0x7d, offset 0x1f40 + 0x1f70: 0x0001, 0x1f71: 0x0001, + // Block 0x7e, offset 0x1f80 + 0x1f82: 0x0001, + 0x1f86: 0x0001, 0x1f8b: 0x0001, + 0x1fa5: 0x0001, 0x1fa6: 0x0001, + 0x1fac: 0x0001, + // Block 0x7f, offset 0x1fc0 + 0x1fc4: 0x0001, 0x1fc5: 0x0001, + 0x1fe0: 0x0001, 0x1fe1: 0x0001, 0x1fe2: 0x0001, 0x1fe3: 0x0001, + 0x1fe4: 0x0001, 0x1fe5: 0x0001, 0x1fe6: 0x0001, 0x1fe7: 0x0001, 0x1fe8: 0x0001, 0x1fe9: 0x0001, + 0x1fea: 0x0001, 0x1feb: 0x0001, 0x1fec: 0x0001, 0x1fed: 0x0001, 0x1fee: 0x0001, 0x1fef: 0x0001, + 0x1ff0: 0x0001, 0x1ff1: 0x0001, + 0x1fff: 0x0001, + // Block 0x80, offset 0x2000 + 0x2026: 0x0001, 0x2027: 0x0001, 0x2028: 0x0001, 0x2029: 0x0001, + 0x202a: 0x0001, 0x202b: 0x0001, 0x202c: 0x0001, 0x202d: 0x0001, + // Block 0x81, offset 0x2040 + 0x2047: 0x0001, 0x2048: 0x0001, 0x2049: 0x0001, 0x204a: 0x0001, 0x204b: 0x0001, + 0x204c: 0x0001, 0x204d: 0x0001, 0x204e: 0x0001, 0x204f: 0x0001, 0x2050: 0x0001, 0x2051: 0x0001, + 0x2060: 0x0002, 0x2061: 0x0002, 0x2062: 0x0002, 0x2063: 0x0002, + 0x2064: 0x0002, 0x2065: 0x0002, 0x2066: 0x0002, 0x2067: 0x0002, 0x2068: 0x0002, 0x2069: 0x0002, + 0x206a: 0x0002, 0x206b: 0x0002, 0x206c: 0x0002, 0x206d: 0x0002, 0x206e: 0x0002, 0x206f: 0x0002, + 0x2070: 0x0002, 0x2071: 0x0002, 0x2072: 0x0002, 0x2073: 0x0002, 0x2074: 0x0002, 0x2075: 0x0002, + 0x2076: 0x0002, 0x2077: 0x0002, 0x2078: 0x0002, 0x2079: 0x0002, 0x207a: 0x0002, 0x207b: 0x0002, + 0x207c: 0x0002, + // Block 0x82, offset 0x2080 + 0x2080: 0x0001, 0x2081: 0x0001, 0x2082: 0x0001, + 0x20b3: 0x0001, + 0x20b6: 0x0001, 0x20b7: 0x0001, 0x20b8: 0x0001, 0x20b9: 0x0001, + 0x20bc: 0x0001, 0x20bd: 0x0001, + // Block 0x83, offset 0x20c0 + 0x20e5: 0x0001, + // Block 0x84, offset 0x2100 + 0x2129: 0x0001, + 0x212a: 0x0001, 0x212b: 0x0001, 0x212c: 0x0001, 0x212d: 0x0001, 0x212e: 0x0001, + 0x2131: 0x0001, 0x2132: 0x0001, 0x2135: 0x0001, + 0x2136: 0x0001, + // Block 0x85, offset 0x2140 + 0x2143: 0x0001, + 0x214c: 0x0001, + 0x217c: 0x0001, + // Block 0x86, offset 0x2180 + 0x21b0: 0x0001, 0x21b2: 0x0001, 0x21b3: 0x0001, 0x21b4: 0x0001, + 0x21b7: 0x0001, 0x21b8: 0x0001, + 0x21be: 0x0001, 0x21bf: 0x0001, + // Block 0x87, offset 0x21c0 + 0x21c1: 0x0001, + 0x21ec: 0x0001, 0x21ed: 0x0001, + 0x21f6: 0x0001, + // Block 0x88, offset 0x2200 + 0x2225: 0x0001, 0x2228: 0x0001, + 0x222d: 0x0001, + // Block 0x89, offset 0x2240 + 0x2240: 0x0002, 0x2241: 0x0002, 0x2242: 0x0002, 0x2243: 0x0002, 0x2244: 0x0002, 0x2245: 0x0002, + 0x2246: 0x0002, 0x2247: 0x0002, 0x2248: 0x0002, 0x2249: 0x0002, 0x224a: 0x0002, 0x224b: 0x0002, + 0x224c: 0x0002, 0x224d: 0x0002, 0x224e: 0x0002, 0x224f: 0x0002, 0x2250: 0x0002, 0x2251: 0x0002, + 0x2252: 0x0002, 0x2253: 0x0002, 0x2254: 0x0002, 0x2255: 0x0002, 0x2256: 0x0002, 0x2257: 0x0002, + 0x2258: 0x0002, 0x2259: 0x0002, 0x225a: 0x0002, 0x225b: 0x0002, 0x225c: 0x0002, 0x225d: 0x0002, + 0x225e: 0x0002, 0x225f: 0x0002, 0x2260: 0x0002, 0x2261: 0x0002, 0x2262: 0x0002, 0x2263: 0x0002, + // Block 0x8a, offset 0x2280 + 0x229e: 0x0001, + // Block 0x8b, offset 0x22c0 + 0x22c0: 0x0001, 0x22c1: 0x0001, 0x22c2: 0x0001, 0x22c3: 0x0001, 0x22c4: 0x0001, 0x22c5: 0x0001, + 0x22c6: 0x0001, 0x22c7: 0x0001, 0x22c8: 0x0001, 0x22c9: 0x0001, 0x22ca: 0x0001, 0x22cb: 0x0001, + 0x22cc: 0x0001, 0x22cd: 0x0001, 0x22ce: 0x0001, 0x22cf: 0x0001, 0x22d0: 0x0002, 0x22d1: 0x0002, + 0x22d2: 0x0002, 0x22d3: 0x0002, 0x22d4: 0x0002, 0x22d5: 0x0002, 0x22d6: 0x0002, 0x22d7: 0x0002, + 0x22d8: 0x0002, 0x22d9: 0x0002, + 0x22e0: 0x0001, 0x22e1: 0x0001, 0x22e2: 0x0001, 0x22e3: 0x0001, + 0x22e4: 0x0001, 0x22e5: 0x0001, 0x22e6: 0x0001, 0x22e7: 0x0001, 0x22e8: 0x0001, 0x22e9: 0x0001, + 0x22ea: 0x0001, 0x22eb: 0x0001, 0x22ec: 0x0001, 0x22ed: 0x0001, 0x22ee: 0x0001, 0x22ef: 0x0001, + 0x22f0: 0x0002, 0x22f1: 0x0002, 0x22f2: 0x0002, 0x22f3: 0x0002, 0x22f4: 0x0002, 0x22f5: 0x0002, + 0x22f6: 0x0002, 0x22f7: 0x0002, 0x22f8: 0x0002, 0x22f9: 0x0002, 0x22fa: 0x0002, 0x22fb: 0x0002, + 0x22fc: 0x0002, 0x22fd: 0x0002, 0x22fe: 0x0002, 0x22ff: 0x0002, + // Block 0x8c, offset 0x2300 + 0x2300: 0x0002, 0x2301: 0x0002, 0x2302: 0x0002, 0x2303: 0x0002, 0x2304: 0x0002, 0x2305: 0x0002, + 0x2306: 0x0002, 0x2307: 0x0002, 0x2308: 0x0002, 0x2309: 0x0002, 0x230a: 0x0002, 0x230b: 0x0002, + 0x230c: 0x0002, 0x230d: 0x0002, 0x230e: 0x0002, 0x230f: 0x0002, 0x2310: 0x0002, 0x2311: 0x0002, + 0x2312: 0x0002, 0x2314: 0x0002, 0x2315: 0x0002, 0x2316: 0x0002, 0x2317: 0x0002, + 0x2318: 0x0002, 0x2319: 0x0002, 0x231a: 0x0002, 0x231b: 0x0002, 0x231c: 0x0002, 0x231d: 0x0002, + 0x231e: 0x0002, 0x231f: 0x0002, 0x2320: 0x0002, 0x2321: 0x0002, 0x2322: 0x0002, 0x2323: 0x0002, + 0x2324: 0x0002, 0x2325: 0x0002, 0x2326: 0x0002, 0x2328: 0x0002, 0x2329: 0x0002, + 0x232a: 0x0002, 0x232b: 0x0002, + // Block 0x8d, offset 0x2340 + 0x2340: 0x0002, 0x2341: 0x0002, 0x2342: 0x0002, 0x2343: 0x0002, 0x2344: 0x0002, 0x2345: 0x0002, + 0x2346: 0x0002, 0x2347: 0x0002, 0x2348: 0x0002, 0x2349: 0x0002, 0x234a: 0x0002, 0x234b: 0x0002, + 0x234c: 0x0002, 0x234d: 0x0002, 0x234e: 0x0002, 0x234f: 0x0002, 0x2350: 0x0002, 0x2351: 0x0002, + 0x2352: 0x0002, 0x2353: 0x0002, 0x2354: 0x0002, 0x2355: 0x0002, 0x2356: 0x0002, 0x2357: 0x0002, + 0x2358: 0x0002, 0x2359: 0x0002, 0x235a: 0x0002, 0x235b: 0x0002, 0x235c: 0x0002, 0x235d: 0x0002, + 0x235e: 0x0002, 0x235f: 0x0002, 0x2360: 0x0002, + // Block 0x8e, offset 0x2380 + 0x23a0: 0x0002, 0x23a1: 0x0002, 0x23a2: 0x0002, 0x23a3: 0x0002, + 0x23a4: 0x0002, 0x23a5: 0x0002, 0x23a6: 0x0002, + 0x23b9: 0x0001, 0x23ba: 0x0001, 0x23bb: 0x0001, + 0x23be: 0x0001, 0x23bf: 0x0001, + // Block 0x8f, offset 0x23c0 + 0x23fd: 0x0001, + // Block 0x90, offset 0x2400 + 0x2420: 0x0001, + // Block 0x91, offset 0x2440 + 0x2476: 0x0001, 0x2477: 0x0001, 0x2478: 0x0001, 0x2479: 0x0001, 0x247a: 0x0001, + // Block 0x92, offset 0x2480 + 0x2481: 0x0001, 0x2482: 0x0001, 0x2483: 0x0001, 0x2485: 0x0001, + 0x2486: 0x0001, + 0x248c: 0x0001, 0x248d: 0x0001, 0x248e: 0x0001, 0x248f: 0x0001, + 0x24b8: 0x0001, 0x24b9: 0x0001, 0x24ba: 0x0001, + 0x24bf: 0x0001, + // Block 0x93, offset 0x24c0 + 0x24e5: 0x0001, 0x24e6: 0x0001, + // Block 0x94, offset 0x2500 + 0x2524: 0x0001, 0x2525: 0x0001, 0x2526: 0x0001, 0x2527: 0x0001, + // Block 0x95, offset 0x2540 + 0x256b: 0x0001, 0x256c: 0x0001, + // Block 0x96, offset 0x2580 + 0x25bd: 0x0001, 0x25be: 0x0001, 0x25bf: 0x0001, + // Block 0x97, offset 0x25c0 + 0x25c6: 0x0001, 0x25c7: 0x0001, 0x25c8: 0x0001, 0x25c9: 0x0001, 0x25ca: 0x0001, 0x25cb: 0x0001, + 0x25cc: 0x0001, 0x25cd: 0x0001, 0x25ce: 0x0001, 0x25cf: 0x0001, 0x25d0: 0x0001, + // Block 0x98, offset 0x2600 + 0x2602: 0x0001, 0x2603: 0x0001, 0x2604: 0x0001, 0x2605: 0x0001, + // Block 0x99, offset 0x2640 + 0x2641: 0x0001, + 0x2678: 0x0001, 0x2679: 0x0001, 0x267a: 0x0001, 0x267b: 0x0001, + 0x267c: 0x0001, 0x267d: 0x0001, 0x267e: 0x0001, 0x267f: 0x0001, + // Block 0x9a, offset 0x2680 + 0x2680: 0x0001, 0x2681: 0x0001, 0x2682: 0x0001, 0x2683: 0x0001, 0x2684: 0x0001, 0x2685: 0x0001, + 0x2686: 0x0001, + 0x26b0: 0x0001, 0x26b3: 0x0001, 0x26b4: 0x0001, + 0x26bf: 0x0001, + // Block 0x9b, offset 0x26c0 + 0x26c0: 0x0001, 0x26c1: 0x0001, + 0x26f3: 0x0001, 0x26f4: 0x0001, 0x26f5: 0x0001, + 0x26f6: 0x0001, 0x26f9: 0x0001, 0x26fa: 0x0001, + 0x26fd: 0x0001, + // Block 0x9c, offset 0x2700 + 0x2702: 0x0001, + 0x270d: 0x0001, + // Block 0x9d, offset 0x2740 + 0x2740: 0x0001, 0x2741: 0x0001, 0x2742: 0x0001, + 0x2767: 0x0001, 0x2768: 0x0001, 0x2769: 0x0001, + 0x276a: 0x0001, 0x276b: 0x0001, 0x276d: 0x0001, 0x276e: 0x0001, 0x276f: 0x0001, + 0x2770: 0x0001, 0x2771: 0x0001, 0x2772: 0x0001, 0x2773: 0x0001, 0x2774: 0x0001, + // Block 0x9e, offset 0x2780 + 0x27b3: 0x0001, + // Block 0x9f, offset 0x27c0 + 0x27c0: 0x0001, 0x27c1: 0x0001, + 0x27f6: 0x0001, 0x27f7: 0x0001, 0x27f8: 0x0001, 0x27f9: 0x0001, 0x27fa: 0x0001, 0x27fb: 0x0001, + 0x27fc: 0x0001, 0x27fd: 0x0001, 0x27fe: 0x0001, + // Block 0xa0, offset 0x2800 + 0x2809: 0x0001, 0x280a: 0x0001, 0x280b: 0x0001, + 0x280c: 0x0001, 0x280f: 0x0001, + // Block 0xa1, offset 0x2840 + 0x286f: 0x0001, + 0x2870: 0x0001, 0x2871: 0x0001, 0x2874: 0x0001, + 0x2876: 0x0001, 0x2877: 0x0001, + 0x287e: 0x0001, + // Block 0xa2, offset 0x2880 + 0x289f: 0x0001, 0x28a3: 0x0001, + 0x28a4: 0x0001, 0x28a5: 0x0001, 0x28a6: 0x0001, 0x28a7: 0x0001, 0x28a8: 0x0001, 0x28a9: 0x0001, + 0x28aa: 0x0001, + // Block 0xa3, offset 0x28c0 + 0x28c0: 0x0001, + 0x28e6: 0x0001, 0x28e7: 0x0001, 0x28e8: 0x0001, 0x28e9: 0x0001, + 0x28ea: 0x0001, 0x28eb: 0x0001, 0x28ec: 0x0001, + 0x28f0: 0x0001, 0x28f1: 0x0001, 0x28f2: 0x0001, 0x28f3: 0x0001, 0x28f4: 0x0001, + // Block 0xa4, offset 0x2900 + 0x2938: 0x0001, 0x2939: 0x0001, 0x293a: 0x0001, 0x293b: 0x0001, + 0x293c: 0x0001, 0x293d: 0x0001, 0x293e: 0x0001, 0x293f: 0x0001, + // Block 0xa5, offset 0x2940 + 0x2942: 0x0001, 0x2943: 0x0001, 0x2944: 0x0001, + 0x2946: 0x0001, + 0x295e: 0x0001, + // Block 0xa6, offset 0x2980 + 0x29b3: 0x0001, 0x29b4: 0x0001, 0x29b5: 0x0001, + 0x29b6: 0x0001, 0x29b7: 0x0001, 0x29b8: 0x0001, 0x29ba: 0x0001, + 0x29bf: 0x0001, + // Block 0xa7, offset 0x29c0 + 0x29c0: 0x0001, 0x29c2: 0x0001, 0x29c3: 0x0001, + // Block 0xa8, offset 0x2a00 + 0x2a32: 0x0001, 0x2a33: 0x0001, 0x2a34: 0x0001, 0x2a35: 0x0001, + 0x2a3c: 0x0001, 0x2a3d: 0x0001, 0x2a3f: 0x0001, + // Block 0xa9, offset 0x2a40 + 0x2a40: 0x0001, + 0x2a5c: 0x0001, 0x2a5d: 0x0001, + // Block 0xaa, offset 0x2a80 + 0x2ab3: 0x0001, 0x2ab4: 0x0001, 0x2ab5: 0x0001, + 0x2ab6: 0x0001, 0x2ab7: 0x0001, 0x2ab8: 0x0001, 0x2ab9: 0x0001, 0x2aba: 0x0001, + 0x2abd: 0x0001, 0x2abf: 0x0001, + // Block 0xab, offset 0x2ac0 + 0x2ac0: 0x0001, + // Block 0xac, offset 0x2b00 + 0x2b2b: 0x0001, 0x2b2d: 0x0001, + 0x2b30: 0x0001, 0x2b31: 0x0001, 0x2b32: 0x0001, 0x2b33: 0x0001, 0x2b34: 0x0001, 0x2b35: 0x0001, + 0x2b37: 0x0001, + // Block 0xad, offset 0x2b40 + 0x2b5d: 0x0001, + 0x2b5e: 0x0001, 0x2b5f: 0x0001, 0x2b62: 0x0001, 0x2b63: 0x0001, + 0x2b64: 0x0001, 0x2b65: 0x0001, 0x2b67: 0x0001, 0x2b68: 0x0001, 0x2b69: 0x0001, + 0x2b6a: 0x0001, 0x2b6b: 0x0001, + // Block 0xae, offset 0x2b80 + 0x2baf: 0x0001, + 0x2bb0: 0x0001, 0x2bb1: 0x0001, 0x2bb2: 0x0001, 0x2bb3: 0x0001, 0x2bb4: 0x0001, 0x2bb5: 0x0001, + 0x2bb6: 0x0001, 0x2bb7: 0x0001, 0x2bb9: 0x0001, 0x2bba: 0x0001, + // Block 0xaf, offset 0x2bc0 + 0x2bfb: 0x0001, + 0x2bfc: 0x0001, 0x2bfe: 0x0001, + // Block 0xb0, offset 0x2c00 + 0x2c03: 0x0001, + // Block 0xb1, offset 0x2c40 + 0x2c54: 0x0001, 0x2c55: 0x0001, 0x2c56: 0x0001, 0x2c57: 0x0001, + 0x2c5a: 0x0001, 0x2c5b: 0x0001, + 0x2c60: 0x0001, + // Block 0xb2, offset 0x2c80 + 0x2c81: 0x0001, 0x2c82: 0x0001, 0x2c83: 0x0001, 0x2c84: 0x0001, 0x2c85: 0x0001, + 0x2c86: 0x0001, 0x2c87: 0x0001, 0x2c88: 0x0001, 0x2c89: 0x0001, 0x2c8a: 0x0001, + 0x2cb3: 0x0001, 0x2cb4: 0x0001, 0x2cb5: 0x0001, + 0x2cb6: 0x0001, 0x2cb7: 0x0001, 0x2cb8: 0x0001, 0x2cbb: 0x0001, + 0x2cbc: 0x0001, 0x2cbd: 0x0001, 0x2cbe: 0x0001, + // Block 0xb3, offset 0x2cc0 + 0x2cc7: 0x0001, + 0x2cd1: 0x0001, + 0x2cd2: 0x0001, 0x2cd3: 0x0001, 0x2cd4: 0x0001, 0x2cd5: 0x0001, 0x2cd6: 0x0001, + 0x2cd9: 0x0001, 0x2cda: 0x0001, 0x2cdb: 0x0001, + // Block 0xb4, offset 0x2d00 + 0x2d0a: 0x0001, 0x2d0b: 0x0001, + 0x2d0c: 0x0001, 0x2d0d: 0x0001, 0x2d0e: 0x0001, 0x2d0f: 0x0001, 0x2d10: 0x0001, 0x2d11: 0x0001, + 0x2d12: 0x0001, 0x2d13: 0x0001, 0x2d14: 0x0001, 0x2d15: 0x0001, 0x2d16: 0x0001, + 0x2d18: 0x0001, 0x2d19: 0x0001, + // Block 0xb5, offset 0x2d40 + 0x2d70: 0x0001, 0x2d71: 0x0001, 0x2d72: 0x0001, 0x2d73: 0x0001, 0x2d74: 0x0001, 0x2d75: 0x0001, + 0x2d76: 0x0001, 0x2d78: 0x0001, 0x2d79: 0x0001, 0x2d7a: 0x0001, 0x2d7b: 0x0001, + 0x2d7c: 0x0001, 0x2d7d: 0x0001, 0x2d7f: 0x0001, + // Block 0xb6, offset 0x2d80 + 0x2d92: 0x0001, 0x2d93: 0x0001, 0x2d94: 0x0001, 0x2d95: 0x0001, 0x2d96: 0x0001, 0x2d97: 0x0001, + 0x2d98: 0x0001, 0x2d99: 0x0001, 0x2d9a: 0x0001, 0x2d9b: 0x0001, 0x2d9c: 0x0001, 0x2d9d: 0x0001, + 0x2d9e: 0x0001, 0x2d9f: 0x0001, 0x2da0: 0x0001, 0x2da1: 0x0001, 0x2da2: 0x0001, 0x2da3: 0x0001, + 0x2da4: 0x0001, 0x2da5: 0x0001, 0x2da6: 0x0001, 0x2da7: 0x0001, + 0x2daa: 0x0001, 0x2dab: 0x0001, 0x2dac: 0x0001, 0x2dad: 0x0001, 0x2dae: 0x0001, 0x2daf: 0x0001, + 0x2db0: 0x0001, 0x2db2: 0x0001, 0x2db3: 0x0001, 0x2db5: 0x0001, + 0x2db6: 0x0001, + // Block 0xb7, offset 0x2dc0 + 0x2df1: 0x0001, 0x2df2: 0x0001, 0x2df3: 0x0001, 0x2df4: 0x0001, 0x2df5: 0x0001, + 0x2df6: 0x0001, 0x2dfa: 0x0001, + 0x2dfc: 0x0001, 0x2dfd: 0x0001, 0x2dff: 0x0001, + // Block 0xb8, offset 0x2e00 + 0x2e00: 0x0001, 0x2e01: 0x0001, 0x2e02: 0x0001, 0x2e03: 0x0001, 0x2e04: 0x0001, 0x2e05: 0x0001, + 0x2e07: 0x0001, + // Block 0xb9, offset 0x2e40 + 0x2e50: 0x0001, 0x2e51: 0x0001, + 0x2e55: 0x0001, 0x2e57: 0x0001, + // Block 0xba, offset 0x2e80 + 0x2eb3: 0x0001, 0x2eb4: 0x0001, + // Block 0xbb, offset 0x2ec0 + 0x2ec0: 0x0001, 0x2ec1: 0x0001, + 0x2ef6: 0x0001, 0x2ef7: 0x0001, 0x2ef8: 0x0001, 0x2ef9: 0x0001, 0x2efa: 0x0001, + // Block 0xbc, offset 0x2f00 + 0x2f00: 0x0001, 0x2f02: 0x0001, + // Block 0xbd, offset 0x2f40 + 0x2f40: 0x0001, + 0x2f47: 0x0001, 0x2f48: 0x0001, 0x2f49: 0x0001, 0x2f4a: 0x0001, 0x2f4b: 0x0001, + 0x2f4c: 0x0001, 0x2f4d: 0x0001, 0x2f4e: 0x0001, 0x2f4f: 0x0001, 0x2f50: 0x0001, 0x2f51: 0x0001, + 0x2f52: 0x0001, 0x2f53: 0x0001, 0x2f54: 0x0001, 0x2f55: 0x0001, + // Block 0xbe, offset 0x2f80 + 0x2fb0: 0x0001, 0x2fb1: 0x0001, 0x2fb2: 0x0001, 0x2fb3: 0x0001, 0x2fb4: 0x0001, + // Block 0xbf, offset 0x2fc0 + 0x2ff0: 0x0001, 0x2ff1: 0x0001, 0x2ff2: 0x0001, 0x2ff3: 0x0001, 0x2ff4: 0x0001, 0x2ff5: 0x0001, + 0x2ff6: 0x0001, + // Block 0xc0, offset 0x3000 + 0x300f: 0x0001, + // Block 0xc1, offset 0x3040 + 0x304f: 0x0001, 0x3050: 0x0001, 0x3051: 0x0001, + 0x3052: 0x0001, + // Block 0xc2, offset 0x3080 + 0x30a0: 0x0002, 0x30a1: 0x0002, 0x30a2: 0x0002, 0x30a3: 0x0002, + 0x30a4: 0x0001, + 0x30b0: 0x0002, 0x30b1: 0x0002, 0x30b2: 0x0002, 0x30b3: 0x0002, 0x30b4: 0x0002, 0x30b5: 0x0002, + 0x30b6: 0x0002, + // Block 0xc3, offset 0x30c0 + 0x30c0: 0x0002, 0x30c1: 0x0002, 0x30c2: 0x0002, 0x30c3: 0x0002, 0x30c4: 0x0002, 0x30c5: 0x0002, + 0x30c6: 0x0002, 0x30c7: 0x0002, 0x30c8: 0x0002, 0x30c9: 0x0002, 0x30ca: 0x0002, 0x30cb: 0x0002, + 0x30cc: 0x0002, 0x30cd: 0x0002, 0x30ce: 0x0002, 0x30cf: 0x0002, 0x30d0: 0x0002, 0x30d1: 0x0002, + 0x30d2: 0x0002, 0x30d3: 0x0002, 0x30d4: 0x0002, 0x30d5: 0x0002, + 0x30ff: 0x0002, + // Block 0xc4, offset 0x3100 + 0x3100: 0x0002, 0x3101: 0x0002, 0x3102: 0x0002, 0x3103: 0x0002, 0x3104: 0x0002, 0x3105: 0x0002, + 0x3106: 0x0002, 0x3107: 0x0002, 0x3108: 0x0002, 0x3109: 0x0002, 0x310a: 0x0002, 0x310b: 0x0002, + 0x310c: 0x0002, 0x310d: 0x0002, 0x310e: 0x0002, 0x310f: 0x0002, 0x3110: 0x0002, 0x3111: 0x0002, + 0x3112: 0x0002, 0x3113: 0x0002, 0x3114: 0x0002, 0x3115: 0x0002, 0x3116: 0x0002, 0x3117: 0x0002, + 0x3118: 0x0002, 0x3119: 0x0002, 0x311a: 0x0002, 0x311b: 0x0002, 0x311c: 0x0002, 0x311d: 0x0002, + 0x311e: 0x0002, + // Block 0xc5, offset 0x3140 + 0x3140: 0x0002, 0x3141: 0x0002, 0x3142: 0x0002, 0x3143: 0x0002, 0x3144: 0x0002, 0x3145: 0x0002, + 0x3146: 0x0002, 0x3147: 0x0002, 0x3148: 0x0002, 0x3149: 0x0002, 0x314a: 0x0002, 0x314b: 0x0002, + 0x314c: 0x0002, 0x314d: 0x0002, 0x314e: 0x0002, 0x314f: 0x0002, 0x3150: 0x0002, 0x3151: 0x0002, + 0x3152: 0x0002, 0x3153: 0x0002, 0x3154: 0x0002, 0x3155: 0x0002, 0x3156: 0x0002, 0x3157: 0x0002, + 0x3158: 0x0002, 0x3159: 0x0002, 0x315a: 0x0002, 0x315b: 0x0002, 0x315c: 0x0002, 0x315d: 0x0002, + 0x315e: 0x0002, 0x315f: 0x0002, 0x3160: 0x0002, 0x3161: 0x0002, 0x3162: 0x0002, 0x3163: 0x0002, + 0x3164: 0x0002, 0x3165: 0x0002, 0x3166: 0x0002, 0x3167: 0x0002, 0x3168: 0x0002, 0x3169: 0x0002, + 0x316a: 0x0002, 0x316b: 0x0002, 0x316c: 0x0002, 0x316d: 0x0002, 0x316e: 0x0002, 0x316f: 0x0002, + 0x3170: 0x0002, 0x3171: 0x0002, 0x3172: 0x0002, + // Block 0xc6, offset 0x3180 + 0x31b0: 0x0002, 0x31b1: 0x0002, 0x31b2: 0x0002, 0x31b3: 0x0002, 0x31b5: 0x0002, + 0x31b6: 0x0002, 0x31b7: 0x0002, 0x31b8: 0x0002, 0x31b9: 0x0002, 0x31ba: 0x0002, 0x31bb: 0x0002, + 0x31bd: 0x0002, 0x31be: 0x0002, + // Block 0xc7, offset 0x31c0 + 0x31c0: 0x0002, 0x31c1: 0x0002, 0x31c2: 0x0002, 0x31c3: 0x0002, 0x31c4: 0x0002, 0x31c5: 0x0002, + 0x31c6: 0x0002, 0x31c7: 0x0002, 0x31c8: 0x0002, 0x31c9: 0x0002, 0x31ca: 0x0002, 0x31cb: 0x0002, + 0x31cc: 0x0002, 0x31cd: 0x0002, 0x31ce: 0x0002, 0x31cf: 0x0002, 0x31d0: 0x0002, 0x31d1: 0x0002, + 0x31d2: 0x0002, 0x31d3: 0x0002, 0x31d4: 0x0002, 0x31d5: 0x0002, 0x31d6: 0x0002, 0x31d7: 0x0002, + 0x31d8: 0x0002, 0x31d9: 0x0002, 0x31da: 0x0002, 0x31db: 0x0002, 0x31dc: 0x0002, 0x31dd: 0x0002, + 0x31de: 0x0002, 0x31df: 0x0002, 0x31e0: 0x0002, 0x31e1: 0x0002, 0x31e2: 0x0002, + 0x31f2: 0x0002, + // Block 0xc8, offset 0x3200 + 0x3210: 0x0002, 0x3211: 0x0002, + 0x3212: 0x0002, 0x3215: 0x0002, + 0x3224: 0x0002, 0x3225: 0x0002, 0x3226: 0x0002, 0x3227: 0x0002, + 0x3230: 0x0002, 0x3231: 0x0002, 0x3232: 0x0002, 0x3233: 0x0002, 0x3234: 0x0002, 0x3235: 0x0002, + 0x3236: 0x0002, 0x3237: 0x0002, 0x3238: 0x0002, 0x3239: 0x0002, 0x323a: 0x0002, 0x323b: 0x0002, + 0x323c: 0x0002, 0x323d: 0x0002, 0x323e: 0x0002, 0x323f: 0x0002, + // Block 0xc9, offset 0x3240 + 0x3240: 0x0002, 0x3241: 0x0002, 0x3242: 0x0002, 0x3243: 0x0002, 0x3244: 0x0002, 0x3245: 0x0002, + 0x3246: 0x0002, 0x3247: 0x0002, 0x3248: 0x0002, 0x3249: 0x0002, 0x324a: 0x0002, 0x324b: 0x0002, + 0x324c: 0x0002, 0x324d: 0x0002, 0x324e: 0x0002, 0x324f: 0x0002, 0x3250: 0x0002, 0x3251: 0x0002, + 0x3252: 0x0002, 0x3253: 0x0002, 0x3254: 0x0002, 0x3255: 0x0002, 0x3256: 0x0002, 0x3257: 0x0002, + 0x3258: 0x0002, 0x3259: 0x0002, 0x325a: 0x0002, 0x325b: 0x0002, 0x325c: 0x0002, 0x325d: 0x0002, + 0x325e: 0x0002, 0x325f: 0x0002, 0x3260: 0x0002, 0x3261: 0x0002, 0x3262: 0x0002, 0x3263: 0x0002, + 0x3264: 0x0002, 0x3265: 0x0002, 0x3266: 0x0002, 0x3267: 0x0002, 0x3268: 0x0002, 0x3269: 0x0002, + 0x326a: 0x0002, 0x326b: 0x0002, 0x326c: 0x0002, 0x326d: 0x0002, 0x326e: 0x0002, 0x326f: 0x0002, + 0x3270: 0x0002, 0x3271: 0x0002, 0x3272: 0x0002, 0x3273: 0x0002, 0x3274: 0x0002, 0x3275: 0x0002, + 0x3276: 0x0002, 0x3277: 0x0002, 0x3278: 0x0002, 0x3279: 0x0002, 0x327a: 0x0002, 0x327b: 0x0002, + // Block 0xca, offset 0x3280 + 0x329d: 0x0001, + 0x329e: 0x0001, 0x32a0: 0x0001, 0x32a1: 0x0001, 0x32a2: 0x0001, 0x32a3: 0x0001, + // Block 0xcb, offset 0x32c0 + 0x32c0: 0x0001, 0x32c1: 0x0001, 0x32c2: 0x0001, 0x32c3: 0x0001, 0x32c4: 0x0001, 0x32c5: 0x0001, + 0x32c6: 0x0001, 0x32c7: 0x0001, 0x32c8: 0x0001, 0x32c9: 0x0001, 0x32ca: 0x0001, 0x32cb: 0x0001, + 0x32cc: 0x0001, 0x32cd: 0x0001, 0x32ce: 0x0001, 0x32cf: 0x0001, 0x32d0: 0x0001, 0x32d1: 0x0001, + 0x32d2: 0x0001, 0x32d3: 0x0001, 0x32d4: 0x0001, 0x32d5: 0x0001, 0x32d6: 0x0001, 0x32d7: 0x0001, + 0x32d8: 0x0001, 0x32d9: 0x0001, 0x32da: 0x0001, 0x32db: 0x0001, 0x32dc: 0x0001, 0x32dd: 0x0001, + 0x32de: 0x0001, 0x32df: 0x0001, 0x32e0: 0x0001, 0x32e1: 0x0001, 0x32e2: 0x0001, 0x32e3: 0x0001, + 0x32e4: 0x0001, 0x32e5: 0x0001, 0x32e6: 0x0001, 0x32e7: 0x0001, 0x32e8: 0x0001, 0x32e9: 0x0001, + 0x32ea: 0x0001, 0x32eb: 0x0001, 0x32ec: 0x0001, 0x32ed: 0x0001, + 0x32f0: 0x0001, 0x32f1: 0x0001, 0x32f2: 0x0001, 0x32f3: 0x0001, 0x32f4: 0x0001, 0x32f5: 0x0001, + 0x32f6: 0x0001, 0x32f7: 0x0001, 0x32f8: 0x0001, 0x32f9: 0x0001, 0x32fa: 0x0001, 0x32fb: 0x0001, + 0x32fc: 0x0001, 0x32fd: 0x0001, 0x32fe: 0x0001, 0x32ff: 0x0001, + // Block 0xcc, offset 0x3300 + 0x3300: 0x0001, 0x3301: 0x0001, 0x3302: 0x0001, 0x3303: 0x0001, 0x3304: 0x0001, 0x3305: 0x0001, + 0x3306: 0x0001, + // Block 0xcd, offset 0x3340 + 0x3367: 0x0001, 0x3368: 0x0001, 0x3369: 0x0001, + 0x3373: 0x0001, 0x3374: 0x0001, 0x3375: 0x0001, + 0x3376: 0x0001, 0x3377: 0x0001, 0x3378: 0x0001, 0x3379: 0x0001, 0x337a: 0x0001, 0x337b: 0x0001, + 0x337c: 0x0001, 0x337d: 0x0001, 0x337e: 0x0001, 0x337f: 0x0001, + // Block 0xce, offset 0x3380 + 0x3380: 0x0001, 0x3381: 0x0001, 0x3382: 0x0001, 0x3385: 0x0001, + 0x3386: 0x0001, 0x3387: 0x0001, 0x3388: 0x0001, 0x3389: 0x0001, 0x338a: 0x0001, 0x338b: 0x0001, + 0x33aa: 0x0001, 0x33ab: 0x0001, 0x33ac: 0x0001, 0x33ad: 0x0001, + // Block 0xcf, offset 0x33c0 + 0x33c2: 0x0001, 0x33c3: 0x0001, 0x33c4: 0x0001, + // Block 0xd0, offset 0x3400 + 0x3400: 0x0002, 0x3401: 0x0002, 0x3402: 0x0002, 0x3403: 0x0002, 0x3404: 0x0002, 0x3405: 0x0002, + 0x3406: 0x0002, 0x3407: 0x0002, 0x3408: 0x0002, 0x3409: 0x0002, 0x340a: 0x0002, 0x340b: 0x0002, + 0x340c: 0x0002, 0x340d: 0x0002, 0x340e: 0x0002, 0x340f: 0x0002, 0x3410: 0x0002, 0x3411: 0x0002, + 0x3412: 0x0002, 0x3413: 0x0002, 0x3414: 0x0002, 0x3415: 0x0002, 0x3416: 0x0002, + 0x3420: 0x0002, 0x3421: 0x0002, 0x3422: 0x0002, 0x3423: 0x0002, + 0x3424: 0x0002, 0x3425: 0x0002, 0x3426: 0x0002, 0x3427: 0x0002, 0x3428: 0x0002, 0x3429: 0x0002, + 0x342a: 0x0002, 0x342b: 0x0002, 0x342c: 0x0002, 0x342d: 0x0002, 0x342e: 0x0002, 0x342f: 0x0002, + 0x3430: 0x0002, 0x3431: 0x0002, 0x3432: 0x0002, 0x3433: 0x0002, 0x3434: 0x0002, 0x3435: 0x0002, + 0x3436: 0x0002, + // Block 0xd1, offset 0x3440 + 0x3440: 0x0001, 0x3441: 0x0001, 0x3442: 0x0001, 0x3443: 0x0001, 0x3444: 0x0001, 0x3445: 0x0001, + 0x3446: 0x0001, 0x3447: 0x0001, 0x3448: 0x0001, 0x3449: 0x0001, 0x344a: 0x0001, 0x344b: 0x0001, + 0x344c: 0x0001, 0x344d: 0x0001, 0x344e: 0x0001, 0x344f: 0x0001, 0x3450: 0x0001, 0x3451: 0x0001, + 0x3452: 0x0001, 0x3453: 0x0001, 0x3454: 0x0001, 0x3455: 0x0001, 0x3456: 0x0001, 0x3457: 0x0001, + 0x3458: 0x0001, 0x3459: 0x0001, 0x345a: 0x0001, 0x345b: 0x0001, 0x345c: 0x0001, 0x345d: 0x0001, + 0x345e: 0x0001, 0x345f: 0x0001, 0x3460: 0x0001, 0x3461: 0x0001, 0x3462: 0x0001, 0x3463: 0x0001, + 0x3464: 0x0001, 0x3465: 0x0001, 0x3466: 0x0001, 0x3467: 0x0001, 0x3468: 0x0001, 0x3469: 0x0001, + 0x346a: 0x0001, 0x346b: 0x0001, 0x346c: 0x0001, 0x346d: 0x0001, 0x346e: 0x0001, 0x346f: 0x0001, + 0x3470: 0x0001, 0x3471: 0x0001, 0x3472: 0x0001, 0x3473: 0x0001, 0x3474: 0x0001, 0x3475: 0x0001, + 0x3476: 0x0001, 0x347b: 0x0001, + 0x347c: 0x0001, 0x347d: 0x0001, 0x347e: 0x0001, 0x347f: 0x0001, + // Block 0xd2, offset 0x3480 + 0x3480: 0x0001, 0x3481: 0x0001, 0x3482: 0x0001, 0x3483: 0x0001, 0x3484: 0x0001, 0x3485: 0x0001, + 0x3486: 0x0001, 0x3487: 0x0001, 0x3488: 0x0001, 0x3489: 0x0001, 0x348a: 0x0001, 0x348b: 0x0001, + 0x348c: 0x0001, 0x348d: 0x0001, 0x348e: 0x0001, 0x348f: 0x0001, 0x3490: 0x0001, 0x3491: 0x0001, + 0x3492: 0x0001, 0x3493: 0x0001, 0x3494: 0x0001, 0x3495: 0x0001, 0x3496: 0x0001, 0x3497: 0x0001, + 0x3498: 0x0001, 0x3499: 0x0001, 0x349a: 0x0001, 0x349b: 0x0001, 0x349c: 0x0001, 0x349d: 0x0001, + 0x349e: 0x0001, 0x349f: 0x0001, 0x34a0: 0x0001, 0x34a1: 0x0001, 0x34a2: 0x0001, 0x34a3: 0x0001, + 0x34a4: 0x0001, 0x34a5: 0x0001, 0x34a6: 0x0001, 0x34a7: 0x0001, 0x34a8: 0x0001, 0x34a9: 0x0001, + 0x34aa: 0x0001, 0x34ab: 0x0001, 0x34ac: 0x0001, + 0x34b5: 0x0001, + // Block 0xd3, offset 0x34c0 + 0x34c4: 0x0001, + 0x34db: 0x0001, 0x34dc: 0x0001, 0x34dd: 0x0001, + 0x34de: 0x0001, 0x34df: 0x0001, 0x34e1: 0x0001, 0x34e2: 0x0001, 0x34e3: 0x0001, + 0x34e4: 0x0001, 0x34e5: 0x0001, 0x34e6: 0x0001, 0x34e7: 0x0001, 0x34e8: 0x0001, 0x34e9: 0x0001, + 0x34ea: 0x0001, 0x34eb: 0x0001, 0x34ec: 0x0001, 0x34ed: 0x0001, 0x34ee: 0x0001, 0x34ef: 0x0001, + // Block 0xd4, offset 0x3500 + 0x3500: 0x0001, 0x3501: 0x0001, 0x3502: 0x0001, 0x3503: 0x0001, 0x3504: 0x0001, 0x3505: 0x0001, + 0x3506: 0x0001, 0x3508: 0x0001, 0x3509: 0x0001, 0x350a: 0x0001, 0x350b: 0x0001, + 0x350c: 0x0001, 0x350d: 0x0001, 0x350e: 0x0001, 0x350f: 0x0001, 0x3510: 0x0001, 0x3511: 0x0001, + 0x3512: 0x0001, 0x3513: 0x0001, 0x3514: 0x0001, 0x3515: 0x0001, 0x3516: 0x0001, 0x3517: 0x0001, + 0x3518: 0x0001, 0x351b: 0x0001, 0x351c: 0x0001, 0x351d: 0x0001, + 0x351e: 0x0001, 0x351f: 0x0001, 0x3520: 0x0001, 0x3521: 0x0001, 0x3523: 0x0001, + 0x3524: 0x0001, 0x3526: 0x0001, 0x3527: 0x0001, 0x3528: 0x0001, 0x3529: 0x0001, + 0x352a: 0x0001, + // Block 0xd5, offset 0x3540 + 0x356e: 0x0001, + // Block 0xd6, offset 0x3580 + 0x35ac: 0x0001, 0x35ad: 0x0001, 0x35ae: 0x0001, 0x35af: 0x0001, + // Block 0xd7, offset 0x35c0 + 0x35d0: 0x0001, 0x35d1: 0x0001, + 0x35d2: 0x0001, 0x35d3: 0x0001, 0x35d4: 0x0001, 0x35d5: 0x0001, 0x35d6: 0x0001, + // Block 0xd8, offset 0x3600 + 0x3604: 0x0001, 0x3605: 0x0001, + 0x3606: 0x0001, 0x3607: 0x0001, 0x3608: 0x0001, 0x3609: 0x0001, 0x360a: 0x0001, + // Block 0xd9, offset 0x3640 + 0x3644: 0x0002, + // Block 0xda, offset 0x3680 + 0x368f: 0x0002, + // Block 0xdb, offset 0x36c0 + 0x36c0: 0x0003, 0x36c1: 0x0003, 0x36c2: 0x0003, 0x36c3: 0x0003, 0x36c4: 0x0003, 0x36c5: 0x0003, + 0x36c6: 0x0003, 0x36c7: 0x0003, 0x36c8: 0x0003, 0x36c9: 0x0003, 0x36ca: 0x0003, + 0x36d0: 0x0003, 0x36d1: 0x0003, + 0x36d2: 0x0003, 0x36d3: 0x0003, 0x36d4: 0x0003, 0x36d5: 0x0003, 0x36d6: 0x0003, 0x36d7: 0x0003, + 0x36d8: 0x0003, 0x36d9: 0x0003, 0x36da: 0x0003, 0x36db: 0x0003, 0x36dc: 0x0003, 0x36dd: 0x0003, + 0x36de: 0x0003, 0x36df: 0x0003, 0x36e0: 0x0003, 0x36e1: 0x0003, 0x36e2: 0x0003, 0x36e3: 0x0003, + 0x36e4: 0x0003, 0x36e5: 0x0003, 0x36e6: 0x0003, 0x36e7: 0x0003, 0x36e8: 0x0003, 0x36e9: 0x0003, + 0x36ea: 0x0003, 0x36eb: 0x0003, 0x36ec: 0x0003, 0x36ed: 0x0003, + 0x36f0: 0x0003, 0x36f1: 0x0003, 0x36f2: 0x0003, 0x36f3: 0x0003, 0x36f4: 0x0003, 0x36f5: 0x0003, + 0x36f6: 0x0003, 0x36f7: 0x0003, 0x36f8: 0x0003, 0x36f9: 0x0003, 0x36fa: 0x0003, 0x36fb: 0x0003, + 0x36fc: 0x0003, 0x36fd: 0x0003, 0x36fe: 0x0003, 0x36ff: 0x0003, + // Block 0xdc, offset 0x3700 + 0x3700: 0x0003, 0x3701: 0x0003, 0x3702: 0x0003, 0x3703: 0x0003, 0x3704: 0x0003, 0x3705: 0x0003, + 0x3706: 0x0003, 0x3707: 0x0003, 0x3708: 0x0003, 0x3709: 0x0003, 0x370a: 0x0003, 0x370b: 0x0003, + 0x370c: 0x0003, 0x370d: 0x0003, 0x370e: 0x0003, 0x370f: 0x0003, 0x3710: 0x0003, 0x3711: 0x0003, + 0x3712: 0x0003, 0x3713: 0x0003, 0x3714: 0x0003, 0x3715: 0x0003, 0x3716: 0x0003, 0x3717: 0x0003, + 0x3718: 0x0003, 0x3719: 0x0003, 0x371a: 0x0003, 0x371b: 0x0003, 0x371c: 0x0003, 0x371d: 0x0003, + 0x371e: 0x0003, 0x371f: 0x0003, 0x3720: 0x0003, 0x3721: 0x0003, 0x3722: 0x0003, 0x3723: 0x0003, + 0x3724: 0x0003, 0x3725: 0x0003, 0x3726: 0x0003, 0x3727: 0x0003, 0x3728: 0x0003, 0x3729: 0x0003, + 0x3730: 0x0003, 0x3731: 0x0003, 0x3732: 0x0003, 0x3733: 0x0003, 0x3734: 0x0003, 0x3735: 0x0003, + 0x3736: 0x0003, 0x3737: 0x0003, 0x3738: 0x0003, 0x3739: 0x0003, 0x373a: 0x0003, 0x373b: 0x0003, + 0x373c: 0x0003, 0x373d: 0x0003, 0x373e: 0x0003, 0x373f: 0x0003, + // Block 0xdd, offset 0x3740 + 0x3740: 0x0003, 0x3741: 0x0003, 0x3742: 0x0003, 0x3743: 0x0003, 0x3744: 0x0003, 0x3745: 0x0003, + 0x3746: 0x0003, 0x3747: 0x0003, 0x3748: 0x0003, 0x3749: 0x0003, 0x374a: 0x0003, 0x374b: 0x0003, + 0x374c: 0x0003, 0x374d: 0x0003, 0x374e: 0x0002, 0x374f: 0x0003, 0x3750: 0x0003, 0x3751: 0x0002, + 0x3752: 0x0002, 0x3753: 0x0002, 0x3754: 0x0002, 0x3755: 0x0002, 0x3756: 0x0002, 0x3757: 0x0002, + 0x3758: 0x0002, 0x3759: 0x0002, 0x375a: 0x0002, 0x375b: 0x0003, 0x375c: 0x0003, 0x375d: 0x0003, + 0x375e: 0x0003, 0x375f: 0x0003, 0x3760: 0x0003, 0x3761: 0x0003, 0x3762: 0x0003, 0x3763: 0x0003, + 0x3764: 0x0003, 0x3765: 0x0003, 0x3766: 0x0003, 0x3767: 0x0003, 0x3768: 0x0003, 0x3769: 0x0003, + 0x376a: 0x0003, 0x376b: 0x0003, 0x376c: 0x0003, + // Block 0xde, offset 0x3780 + 0x37a6: 0x0002, 0x37a7: 0x0002, 0x37a8: 0x0002, 0x37a9: 0x0002, + 0x37aa: 0x0002, 0x37ab: 0x0002, 0x37ac: 0x0002, 0x37ad: 0x0002, 0x37ae: 0x0002, 0x37af: 0x0002, + 0x37b0: 0x0002, 0x37b1: 0x0002, 0x37b2: 0x0002, 0x37b3: 0x0002, 0x37b4: 0x0002, 0x37b5: 0x0002, + 0x37b6: 0x0002, 0x37b7: 0x0002, 0x37b8: 0x0002, 0x37b9: 0x0002, 0x37ba: 0x0002, 0x37bb: 0x0002, + 0x37bc: 0x0002, 0x37bd: 0x0002, 0x37be: 0x0002, 0x37bf: 0x0002, + // Block 0xdf, offset 0x37c0 + 0x37c0: 0x0002, 0x37c1: 0x0002, 0x37c2: 0x0002, + 0x37d0: 0x0002, 0x37d1: 0x0002, + 0x37d2: 0x0002, 0x37d3: 0x0002, 0x37d4: 0x0002, 0x37d5: 0x0002, 0x37d6: 0x0002, 0x37d7: 0x0002, + 0x37d8: 0x0002, 0x37d9: 0x0002, 0x37da: 0x0002, 0x37db: 0x0002, 0x37dc: 0x0002, 0x37dd: 0x0002, + 0x37de: 0x0002, 0x37df: 0x0002, 0x37e0: 0x0002, 0x37e1: 0x0002, 0x37e2: 0x0002, 0x37e3: 0x0002, + 0x37e4: 0x0002, 0x37e5: 0x0002, 0x37e6: 0x0002, 0x37e7: 0x0002, 0x37e8: 0x0002, 0x37e9: 0x0002, + 0x37ea: 0x0002, 0x37eb: 0x0002, 0x37ec: 0x0002, 0x37ed: 0x0002, 0x37ee: 0x0002, 0x37ef: 0x0002, + 0x37f0: 0x0002, 0x37f1: 0x0002, 0x37f2: 0x0002, 0x37f3: 0x0002, 0x37f4: 0x0002, 0x37f5: 0x0002, + 0x37f6: 0x0002, 0x37f7: 0x0002, 0x37f8: 0x0002, 0x37f9: 0x0002, 0x37fa: 0x0002, 0x37fb: 0x0002, + // Block 0xe0, offset 0x3800 + 0x3800: 0x0002, 0x3801: 0x0002, 0x3802: 0x0002, 0x3803: 0x0002, 0x3804: 0x0002, 0x3805: 0x0002, + 0x3806: 0x0002, 0x3807: 0x0002, 0x3808: 0x0002, + 0x3810: 0x0002, 0x3811: 0x0002, + 0x3820: 0x0002, 0x3821: 0x0002, 0x3822: 0x0002, 0x3823: 0x0002, + 0x3824: 0x0002, 0x3825: 0x0002, + // Block 0xe1, offset 0x3840 + 0x3840: 0x0002, 0x3841: 0x0002, 0x3842: 0x0002, 0x3843: 0x0002, 0x3844: 0x0002, 0x3845: 0x0002, + 0x3846: 0x0002, 0x3847: 0x0002, 0x3848: 0x0002, 0x3849: 0x0002, 0x384a: 0x0002, 0x384b: 0x0002, + 0x384c: 0x0002, 0x384d: 0x0002, 0x384e: 0x0002, 0x384f: 0x0002, 0x3850: 0x0002, 0x3851: 0x0002, + 0x3852: 0x0002, 0x3853: 0x0002, 0x3854: 0x0002, 0x3855: 0x0002, 0x3856: 0x0002, 0x3857: 0x0002, + 0x3858: 0x0002, 0x3859: 0x0002, 0x385a: 0x0002, 0x385b: 0x0002, 0x385c: 0x0002, 0x385d: 0x0002, + 0x385e: 0x0002, 0x385f: 0x0002, 0x3860: 0x0002, + 0x386d: 0x0002, 0x386e: 0x0002, 0x386f: 0x0002, + 0x3870: 0x0002, 0x3871: 0x0002, 0x3872: 0x0002, 0x3873: 0x0002, 0x3874: 0x0002, 0x3875: 0x0002, + 0x3877: 0x0002, 0x3878: 0x0002, 0x3879: 0x0002, 0x387a: 0x0002, 0x387b: 0x0002, + 0x387c: 0x0002, 0x387d: 0x0002, 0x387e: 0x0002, 0x387f: 0x0002, + // Block 0xe2, offset 0x3880 + 0x3880: 0x0002, 0x3881: 0x0002, 0x3882: 0x0002, 0x3883: 0x0002, 0x3884: 0x0002, 0x3885: 0x0002, + 0x3886: 0x0002, 0x3887: 0x0002, 0x3888: 0x0002, 0x3889: 0x0002, 0x388a: 0x0002, 0x388b: 0x0002, + 0x388c: 0x0002, 0x388d: 0x0002, 0x388e: 0x0002, 0x388f: 0x0002, 0x3890: 0x0002, 0x3891: 0x0002, + 0x3892: 0x0002, 0x3893: 0x0002, 0x3894: 0x0002, 0x3895: 0x0002, 0x3896: 0x0002, 0x3897: 0x0002, + 0x3898: 0x0002, 0x3899: 0x0002, 0x389a: 0x0002, 0x389b: 0x0002, 0x389c: 0x0002, 0x389d: 0x0002, + 0x389e: 0x0002, 0x389f: 0x0002, 0x38a0: 0x0002, 0x38a1: 0x0002, 0x38a2: 0x0002, 0x38a3: 0x0002, + 0x38a4: 0x0002, 0x38a5: 0x0002, 0x38a6: 0x0002, 0x38a7: 0x0002, 0x38a8: 0x0002, 0x38a9: 0x0002, + 0x38aa: 0x0002, 0x38ab: 0x0002, 0x38ac: 0x0002, 0x38ad: 0x0002, 0x38ae: 0x0002, 0x38af: 0x0002, + 0x38b0: 0x0002, 0x38b1: 0x0002, 0x38b2: 0x0002, 0x38b3: 0x0002, 0x38b4: 0x0002, 0x38b5: 0x0002, + 0x38b6: 0x0002, 0x38b7: 0x0002, 0x38b8: 0x0002, 0x38b9: 0x0002, 0x38ba: 0x0002, 0x38bb: 0x0002, + 0x38bc: 0x0002, 0x38be: 0x0002, 0x38bf: 0x0002, + // Block 0xe3, offset 0x38c0 + 0x38c0: 0x0002, 0x38c1: 0x0002, 0x38c2: 0x0002, 0x38c3: 0x0002, 0x38c4: 0x0002, 0x38c5: 0x0002, + 0x38c6: 0x0002, 0x38c7: 0x0002, 0x38c8: 0x0002, 0x38c9: 0x0002, 0x38ca: 0x0002, 0x38cb: 0x0002, + 0x38cc: 0x0002, 0x38cd: 0x0002, 0x38ce: 0x0002, 0x38cf: 0x0002, 0x38d0: 0x0002, 0x38d1: 0x0002, + 0x38d2: 0x0002, 0x38d3: 0x0002, + 0x38e0: 0x0002, 0x38e1: 0x0002, 0x38e2: 0x0002, 0x38e3: 0x0002, + 0x38e4: 0x0002, 0x38e5: 0x0002, 0x38e6: 0x0002, 0x38e7: 0x0002, 0x38e8: 0x0002, 0x38e9: 0x0002, + 0x38ea: 0x0002, 0x38eb: 0x0002, 0x38ec: 0x0002, 0x38ed: 0x0002, 0x38ee: 0x0002, 0x38ef: 0x0002, + 0x38f0: 0x0002, 0x38f1: 0x0002, 0x38f2: 0x0002, 0x38f3: 0x0002, 0x38f4: 0x0002, 0x38f5: 0x0002, + 0x38f6: 0x0002, 0x38f7: 0x0002, 0x38f8: 0x0002, 0x38f9: 0x0002, 0x38fa: 0x0002, 0x38fb: 0x0002, + 0x38fc: 0x0002, 0x38fd: 0x0002, 0x38fe: 0x0002, 0x38ff: 0x0002, + // Block 0xe4, offset 0x3900 + 0x3900: 0x0002, 0x3901: 0x0002, 0x3902: 0x0002, 0x3903: 0x0002, 0x3904: 0x0002, 0x3905: 0x0002, + 0x3906: 0x0002, 0x3907: 0x0002, 0x3908: 0x0002, 0x3909: 0x0002, 0x390a: 0x0002, + 0x390f: 0x0002, 0x3910: 0x0002, 0x3911: 0x0002, + 0x3912: 0x0002, 0x3913: 0x0002, + 0x3920: 0x0002, 0x3921: 0x0002, 0x3922: 0x0002, 0x3923: 0x0002, + 0x3924: 0x0002, 0x3925: 0x0002, 0x3926: 0x0002, 0x3927: 0x0002, 0x3928: 0x0002, 0x3929: 0x0002, + 0x392a: 0x0002, 0x392b: 0x0002, 0x392c: 0x0002, 0x392d: 0x0002, 0x392e: 0x0002, 0x392f: 0x0002, + 0x3930: 0x0002, 0x3934: 0x0002, + 0x3938: 0x0002, 0x3939: 0x0002, 0x393a: 0x0002, 0x393b: 0x0002, + 0x393c: 0x0002, 0x393d: 0x0002, 0x393e: 0x0002, 0x393f: 0x0002, + // Block 0xe5, offset 0x3940 + 0x3940: 0x0002, 0x3941: 0x0002, 0x3942: 0x0002, 0x3943: 0x0002, 0x3944: 0x0002, 0x3945: 0x0002, + 0x3946: 0x0002, 0x3947: 0x0002, 0x3948: 0x0002, 0x3949: 0x0002, 0x394a: 0x0002, 0x394b: 0x0002, + 0x394c: 0x0002, 0x394d: 0x0002, 0x394e: 0x0002, 0x394f: 0x0002, 0x3950: 0x0002, 0x3951: 0x0002, + 0x3952: 0x0002, 0x3953: 0x0002, 0x3954: 0x0002, 0x3955: 0x0002, 0x3956: 0x0002, 0x3957: 0x0002, + 0x3958: 0x0002, 0x3959: 0x0002, 0x395a: 0x0002, 0x395b: 0x0002, 0x395c: 0x0002, 0x395d: 0x0002, + 0x395e: 0x0002, 0x395f: 0x0002, 0x3960: 0x0002, 0x3961: 0x0002, 0x3962: 0x0002, 0x3963: 0x0002, + 0x3964: 0x0002, 0x3965: 0x0002, 0x3966: 0x0002, 0x3967: 0x0002, 0x3968: 0x0002, 0x3969: 0x0002, + 0x396a: 0x0002, 0x396b: 0x0002, 0x396c: 0x0002, 0x396d: 0x0002, 0x396e: 0x0002, 0x396f: 0x0002, + 0x3970: 0x0002, 0x3971: 0x0002, 0x3972: 0x0002, 0x3973: 0x0002, 0x3974: 0x0002, 0x3975: 0x0002, + 0x3976: 0x0002, 0x3977: 0x0002, 0x3978: 0x0002, 0x3979: 0x0002, 0x397a: 0x0002, 0x397b: 0x0002, + 0x397c: 0x0002, 0x397d: 0x0002, 0x397e: 0x0002, + // Block 0xe6, offset 0x3980 + 0x3980: 0x0002, 0x3982: 0x0002, 0x3983: 0x0002, 0x3984: 0x0002, 0x3985: 0x0002, + 0x3986: 0x0002, 0x3987: 0x0002, 0x3988: 0x0002, 0x3989: 0x0002, 0x398a: 0x0002, 0x398b: 0x0002, + 0x398c: 0x0002, 0x398d: 0x0002, 0x398e: 0x0002, 0x398f: 0x0002, 0x3990: 0x0002, 0x3991: 0x0002, + 0x3992: 0x0002, 0x3993: 0x0002, 0x3994: 0x0002, 0x3995: 0x0002, 0x3996: 0x0002, 0x3997: 0x0002, + 0x3998: 0x0002, 0x3999: 0x0002, 0x399a: 0x0002, 0x399b: 0x0002, 0x399c: 0x0002, 0x399d: 0x0002, + 0x399e: 0x0002, 0x399f: 0x0002, 0x39a0: 0x0002, 0x39a1: 0x0002, 0x39a2: 0x0002, 0x39a3: 0x0002, + 0x39a4: 0x0002, 0x39a5: 0x0002, 0x39a6: 0x0002, 0x39a7: 0x0002, 0x39a8: 0x0002, 0x39a9: 0x0002, + 0x39aa: 0x0002, 0x39ab: 0x0002, 0x39ac: 0x0002, 0x39ad: 0x0002, 0x39ae: 0x0002, 0x39af: 0x0002, + 0x39b0: 0x0002, 0x39b1: 0x0002, 0x39b2: 0x0002, 0x39b3: 0x0002, 0x39b4: 0x0002, 0x39b5: 0x0002, + 0x39b6: 0x0002, 0x39b7: 0x0002, 0x39b8: 0x0002, 0x39b9: 0x0002, 0x39ba: 0x0002, 0x39bb: 0x0002, + 0x39bc: 0x0002, 0x39bd: 0x0002, 0x39be: 0x0002, 0x39bf: 0x0002, + // Block 0xe7, offset 0x39c0 + 0x39c0: 0x0002, 0x39c1: 0x0002, 0x39c2: 0x0002, 0x39c3: 0x0002, 0x39c4: 0x0002, 0x39c5: 0x0002, + 0x39c6: 0x0002, 0x39c7: 0x0002, 0x39c8: 0x0002, 0x39c9: 0x0002, 0x39ca: 0x0002, 0x39cb: 0x0002, + 0x39cc: 0x0002, 0x39cd: 0x0002, 0x39ce: 0x0002, 0x39cf: 0x0002, 0x39d0: 0x0002, 0x39d1: 0x0002, + 0x39d2: 0x0002, 0x39d3: 0x0002, 0x39d4: 0x0002, 0x39d5: 0x0002, 0x39d6: 0x0002, 0x39d7: 0x0002, + 0x39d8: 0x0002, 0x39d9: 0x0002, 0x39da: 0x0002, 0x39db: 0x0002, 0x39dc: 0x0002, 0x39dd: 0x0002, + 0x39de: 0x0002, 0x39df: 0x0002, 0x39e0: 0x0002, 0x39e1: 0x0002, 0x39e2: 0x0002, 0x39e3: 0x0002, + 0x39e4: 0x0002, 0x39e5: 0x0002, 0x39e6: 0x0002, 0x39e7: 0x0002, 0x39e8: 0x0002, 0x39e9: 0x0002, + 0x39ea: 0x0002, 0x39eb: 0x0002, 0x39ec: 0x0002, 0x39ed: 0x0002, 0x39ee: 0x0002, 0x39ef: 0x0002, + 0x39f0: 0x0002, 0x39f1: 0x0002, 0x39f2: 0x0002, 0x39f3: 0x0002, 0x39f4: 0x0002, 0x39f5: 0x0002, + 0x39f6: 0x0002, 0x39f7: 0x0002, 0x39f8: 0x0002, 0x39f9: 0x0002, 0x39fa: 0x0002, 0x39fb: 0x0002, + 0x39fc: 0x0002, 0x39ff: 0x0002, + // Block 0xe8, offset 0x3a00 + 0x3a00: 0x0002, 0x3a01: 0x0002, 0x3a02: 0x0002, 0x3a03: 0x0002, 0x3a04: 0x0002, 0x3a05: 0x0002, + 0x3a06: 0x0002, 0x3a07: 0x0002, 0x3a08: 0x0002, 0x3a09: 0x0002, 0x3a0a: 0x0002, 0x3a0b: 0x0002, + 0x3a0c: 0x0002, 0x3a0d: 0x0002, 0x3a0e: 0x0002, 0x3a0f: 0x0002, 0x3a10: 0x0002, 0x3a11: 0x0002, + 0x3a12: 0x0002, 0x3a13: 0x0002, 0x3a14: 0x0002, 0x3a15: 0x0002, 0x3a16: 0x0002, 0x3a17: 0x0002, + 0x3a18: 0x0002, 0x3a19: 0x0002, 0x3a1a: 0x0002, 0x3a1b: 0x0002, 0x3a1c: 0x0002, 0x3a1d: 0x0002, + 0x3a1e: 0x0002, 0x3a1f: 0x0002, 0x3a20: 0x0002, 0x3a21: 0x0002, 0x3a22: 0x0002, 0x3a23: 0x0002, + 0x3a24: 0x0002, 0x3a25: 0x0002, 0x3a26: 0x0002, 0x3a27: 0x0002, 0x3a28: 0x0002, 0x3a29: 0x0002, + 0x3a2a: 0x0002, 0x3a2b: 0x0002, 0x3a2c: 0x0002, 0x3a2d: 0x0002, 0x3a2e: 0x0002, 0x3a2f: 0x0002, + 0x3a30: 0x0002, 0x3a31: 0x0002, 0x3a32: 0x0002, 0x3a33: 0x0002, 0x3a34: 0x0002, 0x3a35: 0x0002, + 0x3a36: 0x0002, 0x3a37: 0x0002, 0x3a38: 0x0002, 0x3a39: 0x0002, 0x3a3a: 0x0002, 0x3a3b: 0x0002, + 0x3a3c: 0x0002, 0x3a3d: 0x0002, + // Block 0xe9, offset 0x3a40 + 0x3a4b: 0x0002, + 0x3a4c: 0x0002, 0x3a4d: 0x0002, 0x3a4e: 0x0002, 0x3a50: 0x0002, 0x3a51: 0x0002, + 0x3a52: 0x0002, 0x3a53: 0x0002, 0x3a54: 0x0002, 0x3a55: 0x0002, 0x3a56: 0x0002, 0x3a57: 0x0002, + 0x3a58: 0x0002, 0x3a59: 0x0002, 0x3a5a: 0x0002, 0x3a5b: 0x0002, 0x3a5c: 0x0002, 0x3a5d: 0x0002, + 0x3a5e: 0x0002, 0x3a5f: 0x0002, 0x3a60: 0x0002, 0x3a61: 0x0002, 0x3a62: 0x0002, 0x3a63: 0x0002, + 0x3a64: 0x0002, 0x3a65: 0x0002, 0x3a66: 0x0002, 0x3a67: 0x0002, + 0x3a7a: 0x0002, + // Block 0xea, offset 0x3a80 + 0x3a95: 0x0002, 0x3a96: 0x0002, + 0x3aa4: 0x0002, + // Block 0xeb, offset 0x3ac0 + 0x3afb: 0x0002, + 0x3afc: 0x0002, 0x3afd: 0x0002, 0x3afe: 0x0002, 0x3aff: 0x0002, + // Block 0xec, offset 0x3b00 + 0x3b00: 0x0002, 0x3b01: 0x0002, 0x3b02: 0x0002, 0x3b03: 0x0002, 0x3b04: 0x0002, 0x3b05: 0x0002, + 0x3b06: 0x0002, 0x3b07: 0x0002, 0x3b08: 0x0002, 0x3b09: 0x0002, 0x3b0a: 0x0002, 0x3b0b: 0x0002, + 0x3b0c: 0x0002, 0x3b0d: 0x0002, 0x3b0e: 0x0002, 0x3b0f: 0x0002, + // Block 0xed, offset 0x3b40 + 0x3b40: 0x0002, 0x3b41: 0x0002, 0x3b42: 0x0002, 0x3b43: 0x0002, 0x3b44: 0x0002, 0x3b45: 0x0002, + 0x3b4c: 0x0002, 0x3b50: 0x0002, 0x3b51: 0x0002, + 0x3b52: 0x0002, 0x3b55: 0x0002, 0x3b56: 0x0002, 0x3b57: 0x0002, + 0x3b58: 0x0002, 0x3b5c: 0x0002, 0x3b5d: 0x0002, + 0x3b5e: 0x0002, 0x3b5f: 0x0002, + 0x3b6b: 0x0002, 0x3b6c: 0x0002, + 0x3b74: 0x0002, 0x3b75: 0x0002, + 0x3b76: 0x0002, 0x3b77: 0x0002, 0x3b78: 0x0002, 0x3b79: 0x0002, 0x3b7a: 0x0002, 0x3b7b: 0x0002, + 0x3b7c: 0x0002, + // Block 0xee, offset 0x3b80 + 0x3ba0: 0x0002, 0x3ba1: 0x0002, 0x3ba2: 0x0002, 0x3ba3: 0x0002, + 0x3ba4: 0x0002, 0x3ba5: 0x0002, 0x3ba6: 0x0002, 0x3ba7: 0x0002, 0x3ba8: 0x0002, 0x3ba9: 0x0002, + 0x3baa: 0x0002, 0x3bab: 0x0002, + 0x3bb0: 0x0002, + // Block 0xef, offset 0x3bc0 + 0x3bcc: 0x0002, 0x3bcd: 0x0002, 0x3bce: 0x0002, 0x3bcf: 0x0002, 0x3bd0: 0x0002, 0x3bd1: 0x0002, + 0x3bd2: 0x0002, 0x3bd3: 0x0002, 0x3bd4: 0x0002, 0x3bd5: 0x0002, 0x3bd6: 0x0002, 0x3bd7: 0x0002, + 0x3bd8: 0x0002, 0x3bd9: 0x0002, 0x3bda: 0x0002, 0x3bdb: 0x0002, 0x3bdc: 0x0002, 0x3bdd: 0x0002, + 0x3bde: 0x0002, 0x3bdf: 0x0002, 0x3be0: 0x0002, 0x3be1: 0x0002, 0x3be2: 0x0002, 0x3be3: 0x0002, + 0x3be4: 0x0002, 0x3be5: 0x0002, 0x3be6: 0x0002, 0x3be7: 0x0002, 0x3be8: 0x0002, 0x3be9: 0x0002, + 0x3bea: 0x0002, 0x3beb: 0x0002, 0x3bec: 0x0002, 0x3bed: 0x0002, 0x3bee: 0x0002, 0x3bef: 0x0002, + 0x3bf0: 0x0002, 0x3bf1: 0x0002, 0x3bf2: 0x0002, 0x3bf3: 0x0002, 0x3bf4: 0x0002, 0x3bf5: 0x0002, + 0x3bf6: 0x0002, 0x3bf7: 0x0002, 0x3bf8: 0x0002, 0x3bf9: 0x0002, 0x3bfa: 0x0002, + 0x3bfc: 0x0002, 0x3bfd: 0x0002, 0x3bfe: 0x0002, 0x3bff: 0x0002, + // Block 0xf0, offset 0x3c00 + 0x3c00: 0x0002, 0x3c01: 0x0002, 0x3c02: 0x0002, 0x3c03: 0x0002, 0x3c04: 0x0002, 0x3c05: 0x0002, + 0x3c07: 0x0002, 0x3c08: 0x0002, 0x3c09: 0x0002, 0x3c0a: 0x0002, 0x3c0b: 0x0002, + 0x3c0c: 0x0002, 0x3c0d: 0x0002, 0x3c0e: 0x0002, 0x3c0f: 0x0002, 0x3c10: 0x0002, 0x3c11: 0x0002, + 0x3c12: 0x0002, 0x3c13: 0x0002, 0x3c14: 0x0002, 0x3c15: 0x0002, 0x3c16: 0x0002, 0x3c17: 0x0002, + 0x3c18: 0x0002, 0x3c19: 0x0002, 0x3c1a: 0x0002, 0x3c1b: 0x0002, 0x3c1c: 0x0002, 0x3c1d: 0x0002, + 0x3c1e: 0x0002, 0x3c1f: 0x0002, 0x3c20: 0x0002, 0x3c21: 0x0002, 0x3c22: 0x0002, 0x3c23: 0x0002, + 0x3c24: 0x0002, 0x3c25: 0x0002, 0x3c26: 0x0002, 0x3c27: 0x0002, 0x3c28: 0x0002, 0x3c29: 0x0002, + 0x3c2a: 0x0002, 0x3c2b: 0x0002, 0x3c2c: 0x0002, 0x3c2d: 0x0002, 0x3c2e: 0x0002, 0x3c2f: 0x0002, + 0x3c30: 0x0002, 0x3c31: 0x0002, 0x3c32: 0x0002, 0x3c33: 0x0002, 0x3c34: 0x0002, 0x3c35: 0x0002, + 0x3c36: 0x0002, 0x3c37: 0x0002, 0x3c38: 0x0002, 0x3c39: 0x0002, 0x3c3a: 0x0002, 0x3c3b: 0x0002, + 0x3c3c: 0x0002, 0x3c3d: 0x0002, 0x3c3e: 0x0002, 0x3c3f: 0x0002, + // Block 0xf1, offset 0x3c40 + 0x3c70: 0x0002, 0x3c71: 0x0002, 0x3c72: 0x0002, 0x3c73: 0x0002, 0x3c74: 0x0002, 0x3c75: 0x0002, + 0x3c76: 0x0002, 0x3c77: 0x0002, 0x3c78: 0x0002, 0x3c79: 0x0002, 0x3c7a: 0x0002, 0x3c7b: 0x0002, + 0x3c7c: 0x0002, + // Block 0xf2, offset 0x3c80 + 0x3c80: 0x0002, 0x3c81: 0x0002, 0x3c82: 0x0002, 0x3c83: 0x0002, 0x3c84: 0x0002, 0x3c85: 0x0002, + 0x3c86: 0x0002, 0x3c87: 0x0002, 0x3c88: 0x0002, 0x3c89: 0x0002, 0x3c8a: 0x0002, + 0x3c8e: 0x0002, 0x3c8f: 0x0002, 0x3c90: 0x0002, 0x3c91: 0x0002, + 0x3c92: 0x0002, 0x3c93: 0x0002, 0x3c94: 0x0002, 0x3c95: 0x0002, 0x3c96: 0x0002, 0x3c97: 0x0002, + 0x3c98: 0x0002, 0x3c99: 0x0002, 0x3c9a: 0x0002, 0x3c9b: 0x0002, 0x3c9c: 0x0002, 0x3c9d: 0x0002, + 0x3c9e: 0x0002, 0x3c9f: 0x0002, 0x3ca0: 0x0002, 0x3ca1: 0x0002, 0x3ca2: 0x0002, 0x3ca3: 0x0002, + 0x3ca4: 0x0002, 0x3ca5: 0x0002, 0x3ca6: 0x0002, 0x3ca7: 0x0002, 0x3ca8: 0x0002, 0x3ca9: 0x0002, + 0x3caa: 0x0002, 0x3cab: 0x0002, 0x3cac: 0x0002, 0x3cad: 0x0002, 0x3cae: 0x0002, 0x3caf: 0x0002, + 0x3cb0: 0x0002, 0x3cb1: 0x0002, 0x3cb2: 0x0002, 0x3cb3: 0x0002, 0x3cb4: 0x0002, 0x3cb5: 0x0002, + 0x3cb6: 0x0002, 0x3cb7: 0x0002, 0x3cb8: 0x0002, 0x3cb9: 0x0002, 0x3cba: 0x0002, 0x3cbb: 0x0002, + 0x3cbc: 0x0002, 0x3cbd: 0x0002, 0x3cbe: 0x0002, 0x3cbf: 0x0002, + // Block 0xf3, offset 0x3cc0 + 0x3cc0: 0x0002, 0x3cc1: 0x0002, 0x3cc2: 0x0002, 0x3cc3: 0x0002, 0x3cc4: 0x0002, 0x3cc5: 0x0002, + 0x3cc6: 0x0002, 0x3cc8: 0x0002, + 0x3ccd: 0x0002, 0x3cce: 0x0002, 0x3ccf: 0x0002, 0x3cd0: 0x0002, 0x3cd1: 0x0002, + 0x3cd2: 0x0002, 0x3cd3: 0x0002, 0x3cd4: 0x0002, 0x3cd5: 0x0002, 0x3cd6: 0x0002, 0x3cd7: 0x0002, + 0x3cd8: 0x0002, 0x3cd9: 0x0002, 0x3cda: 0x0002, 0x3cdb: 0x0002, 0x3cdc: 0x0002, + 0x3cdf: 0x0002, 0x3ce0: 0x0002, 0x3ce1: 0x0002, 0x3ce2: 0x0002, 0x3ce3: 0x0002, + 0x3ce4: 0x0002, 0x3ce5: 0x0002, 0x3ce6: 0x0002, 0x3ce7: 0x0002, 0x3ce8: 0x0002, 0x3ce9: 0x0002, + 0x3cea: 0x0002, 0x3cef: 0x0002, + 0x3cf0: 0x0002, 0x3cf1: 0x0002, 0x3cf2: 0x0002, 0x3cf3: 0x0002, 0x3cf4: 0x0002, 0x3cf5: 0x0002, + 0x3cf6: 0x0002, 0x3cf7: 0x0002, 0x3cf8: 0x0002, + // Block 0xf4, offset 0x3d00 + 0x3d01: 0x0001, + 0x3d20: 0x0001, 0x3d21: 0x0001, 0x3d22: 0x0001, 0x3d23: 0x0001, + 0x3d24: 0x0001, 0x3d25: 0x0001, 0x3d26: 0x0001, 0x3d27: 0x0001, 0x3d28: 0x0001, 0x3d29: 0x0001, + 0x3d2a: 0x0001, 0x3d2b: 0x0001, 0x3d2c: 0x0001, 0x3d2d: 0x0001, 0x3d2e: 0x0001, 0x3d2f: 0x0001, + 0x3d30: 0x0001, 0x3d31: 0x0001, 0x3d32: 0x0001, 0x3d33: 0x0001, 0x3d34: 0x0001, 0x3d35: 0x0001, + 0x3d36: 0x0001, 0x3d37: 0x0001, 0x3d38: 0x0001, 0x3d39: 0x0001, 0x3d3a: 0x0001, 0x3d3b: 0x0001, + 0x3d3c: 0x0001, 0x3d3d: 0x0001, 0x3d3e: 0x0001, 0x3d3f: 0x0001, + // Block 0xf5, offset 0x3d40 + 0x3d40: 0x0003, 0x3d41: 0x0003, 0x3d42: 0x0003, 0x3d43: 0x0003, 0x3d44: 0x0003, 0x3d45: 0x0003, + 0x3d46: 0x0003, 0x3d47: 0x0003, 0x3d48: 0x0003, 0x3d49: 0x0003, 0x3d4a: 0x0003, 0x3d4b: 0x0003, + 0x3d4c: 0x0003, 0x3d4d: 0x0003, 0x3d4e: 0x0003, 0x3d4f: 0x0003, 0x3d50: 0x0003, 0x3d51: 0x0003, + 0x3d52: 0x0003, 0x3d53: 0x0003, 0x3d54: 0x0003, 0x3d55: 0x0003, 0x3d56: 0x0003, 0x3d57: 0x0003, + 0x3d58: 0x0003, 0x3d59: 0x0003, 0x3d5a: 0x0003, 0x3d5b: 0x0003, 0x3d5c: 0x0003, 0x3d5d: 0x0003, + 0x3d5e: 0x0003, 0x3d5f: 0x0003, 0x3d60: 0x0003, 0x3d61: 0x0003, 0x3d62: 0x0003, 0x3d63: 0x0003, + 0x3d64: 0x0003, 0x3d65: 0x0003, 0x3d66: 0x0003, 0x3d67: 0x0003, 0x3d68: 0x0003, 0x3d69: 0x0003, + 0x3d6a: 0x0003, 0x3d6b: 0x0003, 0x3d6c: 0x0003, 0x3d6d: 0x0003, 0x3d6e: 0x0003, 0x3d6f: 0x0003, + 0x3d70: 0x0003, 0x3d71: 0x0003, 0x3d72: 0x0003, 0x3d73: 0x0003, 0x3d74: 0x0003, 0x3d75: 0x0003, + 0x3d76: 0x0003, 0x3d77: 0x0003, 0x3d78: 0x0003, 0x3d79: 0x0003, 0x3d7a: 0x0003, 0x3d7b: 0x0003, + 0x3d7c: 0x0003, 0x3d7d: 0x0003, +} + +// stringWidthIndex: 30 blocks, 1920 entries, 1920 bytes +// Block 0 is the zero block. +var stringWidthIndex = [1920]uint8{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x01, 0xc3: 0x02, 0xc4: 0x03, 0xc5: 0x04, 0xc7: 0x05, + 0xc9: 0x06, 0xcb: 0x07, 0xcc: 0x08, 0xcd: 0x09, 0xce: 0x0a, 0xcf: 0x0b, + 0xd0: 0x0c, 0xd1: 0x0d, 0xd2: 0x0e, 0xd6: 0x0f, 0xd7: 0x10, + 0xd8: 0x11, 0xd9: 0x12, 0xdb: 0x13, 0xdc: 0x14, 0xdd: 0x15, 0xde: 0x16, 0xdf: 0x17, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, 0xe4: 0x06, 0xe5: 0x06, 0xe6: 0x06, 0xe7: 0x06, + 0xe8: 0x06, 0xe9: 0x06, 0xea: 0x07, 0xeb: 0x06, 0xec: 0x06, 0xed: 0x08, 0xee: 0x09, 0xef: 0x0a, + 0xf0: 0x17, 0xf3: 0x1a, 0xf4: 0x1b, + // Block 0x4, offset 0x100 + 0x120: 0x18, 0x121: 0x19, 0x122: 0x1a, 0x123: 0x1b, 0x124: 0x1c, 0x125: 0x1d, 0x126: 0x1e, 0x127: 0x1f, + 0x128: 0x20, 0x129: 0x21, 0x12a: 0x20, 0x12b: 0x22, 0x12c: 0x23, 0x12d: 0x24, 0x12e: 0x25, 0x12f: 0x26, + 0x130: 0x27, 0x131: 0x28, 0x132: 0x23, 0x133: 0x29, 0x134: 0x2a, 0x135: 0x2b, 0x136: 0x2c, 0x137: 0x2d, + 0x138: 0x2e, 0x139: 0x2f, 0x13a: 0x30, 0x13b: 0x31, 0x13c: 0x32, 0x13d: 0x33, 0x13e: 0x34, 0x13f: 0x35, + // Block 0x5, offset 0x140 + 0x140: 0x36, 0x141: 0x37, 0x142: 0x38, 0x144: 0x39, 0x145: 0x3a, + 0x14d: 0x3b, + 0x15c: 0x3c, 0x15d: 0x3d, 0x15e: 0x3e, 0x15f: 0x3f, + 0x160: 0x40, 0x162: 0x41, 0x164: 0x42, + 0x168: 0x43, 0x169: 0x44, 0x16a: 0x45, 0x16b: 0x46, 0x16c: 0x47, 0x16d: 0x48, 0x16e: 0x49, 0x16f: 0x4a, + 0x170: 0x4b, 0x173: 0x4c, 0x177: 0x08, + // Block 0x6, offset 0x180 + 0x180: 0x4d, 0x181: 0x4e, 0x182: 0x4f, 0x183: 0x50, 0x184: 0x51, 0x185: 0x52, 0x186: 0x53, 0x187: 0x54, + 0x188: 0x55, 0x189: 0x56, 0x18a: 0x57, 0x18c: 0x58, 0x18f: 0x59, + 0x191: 0x5a, 0x192: 0x5b, 0x193: 0x5c, 0x194: 0x5b, 0x195: 0x5d, 0x196: 0x5e, 0x197: 0x5f, + 0x198: 0x60, 0x199: 0x61, 0x19a: 0x62, 0x19b: 0x63, 0x19c: 0x64, 0x19d: 0x65, 0x19e: 0x66, + 0x1ac: 0x67, 0x1ad: 0x68, + 0x1b3: 0x69, 0x1b5: 0x6a, 0x1b7: 0x6b, + 0x1ba: 0x6c, 0x1bb: 0x6d, 0x1bc: 0x39, 0x1bd: 0x39, 0x1be: 0x39, 0x1bf: 0x6e, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x6f, 0x1c1: 0x70, 0x1c2: 0x71, 0x1c3: 0x39, 0x1c4: 0x72, 0x1c5: 0x39, 0x1c6: 0x73, 0x1c7: 0x74, + 0x1c8: 0x75, 0x1c9: 0x76, 0x1ca: 0x39, 0x1cb: 0x39, 0x1cc: 0x39, 0x1cd: 0x39, 0x1ce: 0x39, 0x1cf: 0x39, + 0x1d0: 0x39, 0x1d1: 0x39, 0x1d2: 0x39, 0x1d3: 0x39, 0x1d4: 0x39, 0x1d5: 0x39, 0x1d6: 0x39, 0x1d7: 0x39, + 0x1d8: 0x39, 0x1d9: 0x39, 0x1da: 0x39, 0x1db: 0x39, 0x1dc: 0x39, 0x1dd: 0x39, 0x1de: 0x39, 0x1df: 0x39, + 0x1e0: 0x39, 0x1e1: 0x39, 0x1e2: 0x39, 0x1e3: 0x39, 0x1e4: 0x39, 0x1e5: 0x39, 0x1e6: 0x39, 0x1e7: 0x39, + 0x1e8: 0x39, 0x1e9: 0x39, 0x1ea: 0x39, 0x1eb: 0x39, 0x1ec: 0x39, 0x1ed: 0x39, 0x1ee: 0x39, 0x1ef: 0x39, + 0x1f0: 0x39, 0x1f1: 0x39, 0x1f2: 0x39, 0x1f3: 0x39, 0x1f4: 0x39, 0x1f5: 0x39, 0x1f6: 0x39, 0x1f7: 0x39, + 0x1f8: 0x39, 0x1f9: 0x39, 0x1fa: 0x39, 0x1fb: 0x39, 0x1fc: 0x39, 0x1fd: 0x39, 0x1fe: 0x39, 0x1ff: 0x39, + // Block 0x8, offset 0x200 + 0x200: 0x39, 0x201: 0x39, 0x202: 0x39, 0x203: 0x39, 0x204: 0x39, 0x205: 0x39, 0x206: 0x39, 0x207: 0x39, + 0x208: 0x39, 0x209: 0x39, 0x20a: 0x39, 0x20b: 0x39, 0x20c: 0x39, 0x20d: 0x39, 0x20e: 0x39, 0x20f: 0x39, + 0x210: 0x39, 0x211: 0x39, 0x212: 0x39, 0x213: 0x39, 0x214: 0x39, 0x215: 0x39, 0x216: 0x39, 0x217: 0x39, + 0x218: 0x39, 0x219: 0x39, 0x21a: 0x39, 0x21b: 0x39, 0x21c: 0x39, 0x21d: 0x39, 0x21e: 0x39, 0x21f: 0x39, + 0x220: 0x39, 0x221: 0x39, 0x222: 0x39, 0x223: 0x39, 0x224: 0x39, 0x225: 0x39, 0x226: 0x39, 0x227: 0x39, + 0x228: 0x39, 0x229: 0x39, 0x22a: 0x39, 0x22b: 0x39, 0x22c: 0x39, 0x22d: 0x39, 0x22e: 0x39, 0x22f: 0x39, + 0x230: 0x39, 0x231: 0x39, 0x232: 0x39, 0x233: 0x39, 0x234: 0x39, 0x235: 0x39, 0x236: 0x39, 0x237: 0x39, + 0x238: 0x39, 0x239: 0x39, 0x23a: 0x39, 0x23b: 0x39, 0x23c: 0x39, 0x23d: 0x39, 0x23e: 0x39, 0x23f: 0x39, + // Block 0x9, offset 0x240 + 0x240: 0x39, 0x241: 0x39, 0x242: 0x39, 0x243: 0x39, 0x244: 0x39, 0x245: 0x39, 0x246: 0x39, 0x247: 0x39, + 0x248: 0x39, 0x249: 0x39, 0x24a: 0x39, 0x24b: 0x39, 0x24c: 0x39, 0x24d: 0x39, 0x24e: 0x39, 0x24f: 0x39, + 0x250: 0x39, 0x251: 0x39, 0x252: 0x77, 0x253: 0x78, + 0x259: 0x79, 0x25a: 0x7a, 0x25b: 0x7b, + 0x260: 0x7c, 0x263: 0x7d, 0x264: 0x7e, 0x265: 0x7f, 0x266: 0x80, 0x267: 0x81, + 0x268: 0x82, 0x269: 0x83, 0x26a: 0x84, 0x26b: 0x85, 0x26f: 0x86, + 0x270: 0x39, 0x271: 0x39, 0x272: 0x39, 0x273: 0x39, 0x274: 0x39, 0x275: 0x39, 0x276: 0x39, 0x277: 0x39, + 0x278: 0x39, 0x279: 0x39, 0x27a: 0x39, 0x27b: 0x39, 0x27c: 0x39, 0x27d: 0x39, 0x27e: 0x39, 0x27f: 0x39, + // Block 0xa, offset 0x280 + 0x280: 0x39, 0x281: 0x39, 0x282: 0x39, 0x283: 0x39, 0x284: 0x39, 0x285: 0x39, 0x286: 0x39, 0x287: 0x39, + 0x288: 0x39, 0x289: 0x39, 0x28a: 0x39, 0x28b: 0x39, 0x28c: 0x39, 0x28d: 0x39, 0x28e: 0x39, 0x28f: 0x39, + 0x290: 0x39, 0x291: 0x39, 0x292: 0x39, 0x293: 0x39, 0x294: 0x39, 0x295: 0x39, 0x296: 0x39, 0x297: 0x39, + 0x298: 0x39, 0x299: 0x39, 0x29a: 0x39, 0x29b: 0x39, 0x29c: 0x39, 0x29d: 0x39, 0x29e: 0x87, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x5b, 0x2c1: 0x5b, 0x2c2: 0x5b, 0x2c3: 0x5b, 0x2c4: 0x5b, 0x2c5: 0x5b, 0x2c6: 0x5b, 0x2c7: 0x5b, + 0x2c8: 0x5b, 0x2c9: 0x5b, 0x2ca: 0x5b, 0x2cb: 0x5b, 0x2cc: 0x5b, 0x2cd: 0x5b, 0x2ce: 0x5b, 0x2cf: 0x5b, + 0x2d0: 0x5b, 0x2d1: 0x5b, 0x2d2: 0x5b, 0x2d3: 0x5b, 0x2d4: 0x5b, 0x2d5: 0x5b, 0x2d6: 0x5b, 0x2d7: 0x5b, + 0x2d8: 0x5b, 0x2d9: 0x5b, 0x2da: 0x5b, 0x2db: 0x5b, 0x2dc: 0x5b, 0x2dd: 0x5b, 0x2de: 0x5b, 0x2df: 0x5b, + 0x2e0: 0x5b, 0x2e1: 0x5b, 0x2e2: 0x5b, 0x2e3: 0x5b, 0x2e4: 0x5b, 0x2e5: 0x5b, 0x2e6: 0x5b, 0x2e7: 0x5b, + 0x2e8: 0x5b, 0x2e9: 0x5b, 0x2ea: 0x5b, 0x2eb: 0x5b, 0x2ec: 0x5b, 0x2ed: 0x5b, 0x2ee: 0x5b, 0x2ef: 0x5b, + 0x2f0: 0x5b, 0x2f1: 0x5b, 0x2f2: 0x5b, 0x2f3: 0x5b, 0x2f4: 0x5b, 0x2f5: 0x5b, 0x2f6: 0x5b, 0x2f7: 0x5b, + 0x2f8: 0x5b, 0x2f9: 0x5b, 0x2fa: 0x5b, 0x2fb: 0x5b, 0x2fc: 0x5b, 0x2fd: 0x5b, 0x2fe: 0x5b, 0x2ff: 0x5b, + // Block 0xc, offset 0x300 + 0x300: 0x5b, 0x301: 0x5b, 0x302: 0x5b, 0x303: 0x5b, 0x304: 0x5b, 0x305: 0x5b, 0x306: 0x5b, 0x307: 0x5b, + 0x308: 0x5b, 0x309: 0x5b, 0x30a: 0x5b, 0x30b: 0x5b, 0x30c: 0x5b, 0x30d: 0x5b, 0x30e: 0x5b, 0x30f: 0x5b, + 0x310: 0x5b, 0x311: 0x5b, 0x312: 0x5b, 0x313: 0x5b, 0x314: 0x5b, 0x315: 0x5b, 0x316: 0x5b, 0x317: 0x5b, + 0x318: 0x5b, 0x319: 0x5b, 0x31a: 0x5b, 0x31b: 0x5b, 0x31c: 0x5b, 0x31d: 0x5b, 0x31e: 0x5b, 0x31f: 0x5b, + 0x320: 0x5b, 0x321: 0x5b, 0x322: 0x5b, 0x323: 0x5b, 0x324: 0x39, 0x325: 0x39, 0x326: 0x39, 0x327: 0x39, + 0x328: 0x39, 0x329: 0x39, 0x32a: 0x39, 0x32b: 0x39, 0x32c: 0x88, + 0x338: 0x89, 0x339: 0x8a, 0x33b: 0x6a, 0x33c: 0x70, 0x33d: 0x8b, 0x33f: 0x8c, + // Block 0xd, offset 0x340 + 0x347: 0x8d, + 0x34b: 0x8e, 0x34d: 0x8f, + 0x368: 0x90, 0x36b: 0x91, + 0x374: 0x92, + 0x37a: 0x93, 0x37b: 0x94, 0x37d: 0x95, 0x37e: 0x96, + // Block 0xe, offset 0x380 + 0x380: 0x97, 0x381: 0x98, 0x382: 0x99, 0x383: 0x9a, 0x384: 0x9b, 0x385: 0x9c, 0x386: 0x9d, 0x387: 0x9e, + 0x388: 0x9f, 0x389: 0x2c, 0x38b: 0xa0, 0x38c: 0x2a, 0x38d: 0xa1, + 0x390: 0xa2, 0x391: 0xa3, 0x392: 0xa4, 0x393: 0xa5, 0x396: 0xa6, 0x397: 0xa7, + 0x398: 0xa8, 0x399: 0xa9, 0x39a: 0xaa, 0x39c: 0xab, + 0x3a0: 0xac, 0x3a4: 0xad, 0x3a5: 0xae, 0x3a7: 0xaf, + 0x3a8: 0xb0, 0x3a9: 0xb1, 0x3aa: 0xb2, + 0x3b0: 0xb3, 0x3b2: 0xb4, 0x3b4: 0xb5, 0x3b5: 0xb6, 0x3b6: 0xb7, + 0x3bb: 0xb8, 0x3bc: 0xb9, 0x3bd: 0xba, + // Block 0xf, offset 0x3c0 + 0x3d0: 0x45, 0x3d1: 0xbb, + // Block 0x10, offset 0x400 + 0x42b: 0xbc, 0x42c: 0xbd, + 0x43d: 0xbe, 0x43e: 0xbf, 0x43f: 0xc0, + // Block 0x11, offset 0x440 + 0x440: 0x39, 0x441: 0x39, 0x442: 0x39, 0x443: 0x39, 0x444: 0x39, 0x445: 0x39, 0x446: 0x39, 0x447: 0x39, + 0x448: 0x39, 0x449: 0x39, 0x44a: 0x39, 0x44b: 0x39, 0x44c: 0x39, 0x44d: 0x39, 0x44e: 0x39, 0x44f: 0x39, + 0x450: 0x39, 0x451: 0x39, 0x452: 0x39, 0x453: 0x39, 0x454: 0x39, 0x455: 0x39, 0x456: 0x39, 0x457: 0x39, + 0x458: 0x39, 0x459: 0x39, 0x45a: 0x39, 0x45b: 0x39, 0x45c: 0x39, 0x45d: 0x39, 0x45e: 0x39, 0x45f: 0x39, + 0x460: 0x39, 0x461: 0x39, 0x462: 0x39, 0x463: 0x39, 0x464: 0x39, 0x465: 0x39, 0x466: 0x39, 0x467: 0x39, + 0x468: 0x39, 0x469: 0x39, 0x46a: 0x39, 0x46b: 0x39, 0x46c: 0x39, 0x46d: 0x39, 0x46e: 0x39, 0x46f: 0x39, + 0x470: 0x39, 0x471: 0x39, 0x472: 0x39, 0x473: 0xc1, 0x474: 0xc2, 0x476: 0x39, 0x477: 0xc3, + // Block 0x12, offset 0x480 + 0x4bf: 0xc4, + // Block 0x13, offset 0x4c0 + 0x4c0: 0x39, 0x4c1: 0x39, 0x4c2: 0x39, 0x4c3: 0x39, 0x4c4: 0xc5, 0x4c5: 0xc6, 0x4c6: 0x39, 0x4c7: 0x39, + 0x4c8: 0x39, 0x4c9: 0x39, 0x4ca: 0x39, 0x4cb: 0xc7, + 0x4f2: 0xc8, + // Block 0x14, offset 0x500 + 0x53c: 0xc9, 0x53d: 0xca, + // Block 0x15, offset 0x540 + 0x545: 0xcb, 0x546: 0xcc, + 0x549: 0xcd, 0x54c: 0x39, 0x54d: 0xce, + 0x568: 0xcf, 0x569: 0xd0, 0x56a: 0xd1, + // Block 0x16, offset 0x580 + 0x580: 0xd2, 0x582: 0xbe, 0x584: 0xbd, + 0x58a: 0xd3, 0x58b: 0xd4, + 0x593: 0xd4, + 0x5a3: 0xd5, 0x5a5: 0xd6, + // Block 0x17, offset 0x5c0 + 0x5c0: 0xd7, 0x5c3: 0xd8, 0x5c4: 0xd9, 0x5c5: 0xda, 0x5c6: 0xdb, 0x5c7: 0xdc, + 0x5c8: 0xdd, 0x5c9: 0xde, 0x5cc: 0xdf, 0x5cd: 0xe0, 0x5ce: 0xe1, 0x5cf: 0xe2, + 0x5d0: 0xe3, 0x5d1: 0xe4, 0x5d2: 0x39, 0x5d3: 0xe5, 0x5d4: 0xe6, 0x5d5: 0xe7, 0x5d6: 0xe8, 0x5d7: 0xe9, + 0x5d8: 0x39, 0x5d9: 0xea, 0x5da: 0x39, 0x5db: 0xeb, 0x5df: 0xec, + 0x5e4: 0xed, 0x5e5: 0xee, 0x5e6: 0x39, 0x5e7: 0x39, + 0x5e9: 0xef, 0x5ea: 0xf0, 0x5eb: 0xf1, + // Block 0x18, offset 0x600 + 0x600: 0x39, 0x601: 0x39, 0x602: 0x39, 0x603: 0x39, 0x604: 0x39, 0x605: 0x39, 0x606: 0x39, 0x607: 0x39, + 0x608: 0x39, 0x609: 0x39, 0x60a: 0x39, 0x60b: 0x39, 0x60c: 0x39, 0x60d: 0x39, 0x60e: 0x39, 0x60f: 0x39, + 0x610: 0x39, 0x611: 0x39, 0x612: 0x39, 0x613: 0x39, 0x614: 0x39, 0x615: 0x39, 0x616: 0x39, 0x617: 0x39, + 0x618: 0x39, 0x619: 0x39, 0x61a: 0x39, 0x61b: 0x39, 0x61c: 0x39, 0x61d: 0x39, 0x61e: 0x39, 0x61f: 0x39, + 0x620: 0x39, 0x621: 0x39, 0x622: 0x39, 0x623: 0x39, 0x624: 0x39, 0x625: 0x39, 0x626: 0x39, 0x627: 0x39, + 0x628: 0x39, 0x629: 0x39, 0x62a: 0x39, 0x62b: 0x39, 0x62c: 0x39, 0x62d: 0x39, 0x62e: 0x39, 0x62f: 0x39, + 0x630: 0x39, 0x631: 0x39, 0x632: 0x39, 0x633: 0x39, 0x634: 0x39, 0x635: 0x39, 0x636: 0x39, 0x637: 0x39, + 0x638: 0x39, 0x639: 0x39, 0x63a: 0x39, 0x63b: 0x39, 0x63c: 0x39, 0x63d: 0x39, 0x63e: 0x39, 0x63f: 0xe6, + // Block 0x19, offset 0x640 + 0x650: 0x0b, 0x651: 0x0c, 0x653: 0x0d, 0x656: 0x0e, 0x657: 0x06, + 0x658: 0x0f, 0x65a: 0x10, 0x65b: 0x11, 0x65c: 0x12, 0x65d: 0x13, 0x65e: 0x14, 0x65f: 0x15, + 0x660: 0x06, 0x661: 0x06, 0x662: 0x06, 0x663: 0x06, 0x664: 0x06, 0x665: 0x06, 0x666: 0x06, 0x667: 0x06, + 0x668: 0x06, 0x669: 0x06, 0x66a: 0x06, 0x66b: 0x06, 0x66c: 0x06, 0x66d: 0x06, 0x66e: 0x06, 0x66f: 0x16, + 0x670: 0x06, 0x671: 0x06, 0x672: 0x06, 0x673: 0x06, 0x674: 0x06, 0x675: 0x06, 0x676: 0x06, 0x677: 0x06, + 0x678: 0x06, 0x679: 0x06, 0x67a: 0x06, 0x67b: 0x06, 0x67c: 0x06, 0x67d: 0x06, 0x67e: 0x06, 0x67f: 0x16, + // Block 0x1a, offset 0x680 + 0x680: 0xf2, 0x681: 0x08, 0x684: 0x08, 0x685: 0x08, 0x686: 0x08, 0x687: 0x09, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x5b, 0x6c1: 0x5b, 0x6c2: 0x5b, 0x6c3: 0x5b, 0x6c4: 0x5b, 0x6c5: 0x5b, 0x6c6: 0x5b, 0x6c7: 0x5b, + 0x6c8: 0x5b, 0x6c9: 0x5b, 0x6ca: 0x5b, 0x6cb: 0x5b, 0x6cc: 0x5b, 0x6cd: 0x5b, 0x6ce: 0x5b, 0x6cf: 0x5b, + 0x6d0: 0x5b, 0x6d1: 0x5b, 0x6d2: 0x5b, 0x6d3: 0x5b, 0x6d4: 0x5b, 0x6d5: 0x5b, 0x6d6: 0x5b, 0x6d7: 0x5b, + 0x6d8: 0x5b, 0x6d9: 0x5b, 0x6da: 0x5b, 0x6db: 0x5b, 0x6dc: 0x5b, 0x6dd: 0x5b, 0x6de: 0x5b, 0x6df: 0x5b, + 0x6e0: 0x5b, 0x6e1: 0x5b, 0x6e2: 0x5b, 0x6e3: 0x5b, 0x6e4: 0x5b, 0x6e5: 0x5b, 0x6e6: 0x5b, 0x6e7: 0x5b, + 0x6e8: 0x5b, 0x6e9: 0x5b, 0x6ea: 0x5b, 0x6eb: 0x5b, 0x6ec: 0x5b, 0x6ed: 0x5b, 0x6ee: 0x5b, 0x6ef: 0x5b, + 0x6f0: 0x5b, 0x6f1: 0x5b, 0x6f2: 0x5b, 0x6f3: 0x5b, 0x6f4: 0x5b, 0x6f5: 0x5b, 0x6f6: 0x5b, 0x6f7: 0x5b, + 0x6f8: 0x5b, 0x6f9: 0x5b, 0x6fa: 0x5b, 0x6fb: 0x5b, 0x6fc: 0x5b, 0x6fd: 0x5b, 0x6fe: 0x5b, 0x6ff: 0xf3, + // Block 0x1c, offset 0x700 + 0x720: 0x18, + 0x730: 0x09, 0x731: 0x09, 0x732: 0x09, 0x733: 0x09, 0x734: 0x09, 0x735: 0x09, 0x736: 0x09, 0x737: 0x09, + 0x738: 0x09, 0x739: 0x09, 0x73a: 0x09, 0x73b: 0x09, 0x73c: 0x09, 0x73d: 0x09, 0x73e: 0x09, 0x73f: 0x19, + // Block 0x1d, offset 0x740 + 0x740: 0x09, 0x741: 0x09, 0x742: 0x09, 0x743: 0x09, 0x744: 0x09, 0x745: 0x09, 0x746: 0x09, 0x747: 0x09, + 0x748: 0x09, 0x749: 0x09, 0x74a: 0x09, 0x74b: 0x09, 0x74c: 0x09, 0x74d: 0x09, 0x74e: 0x09, 0x74f: 0x19, +} diff --git a/vendor/github.com/clipperhouse/displaywidth/truncate.go b/vendor/github.com/clipperhouse/displaywidth/truncate.go new file mode 100644 index 0000000..b3e696f --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/truncate.go @@ -0,0 +1,149 @@ +package displaywidth + +import ( + "strings" + + "github.com/clipperhouse/uax29/v2/graphemes" +) + +// TruncateString truncates a string to the given maxWidth, and appends the +// given tail if the string is truncated. +// +// It ensures the visible width, including the width of the tail, is less than or +// equal to maxWidth. +// +// When [Options.ControlSequences] is true, 7-bit ANSI escape sequences that +// appear after the truncation point are preserved in the output. This ensures +// that escape sequences such as SGR resets are not lost, preventing color +// bleed in terminal output. +// +// [Options.ControlSequences8Bit] is ignored by truncation. 8-bit C1 byte values +// (0x80-0x9F) overlap with UTF-8 multi-byte encoding, so manipulating them +// during truncation can shift byte boundaries and form unintended visible +// characters. Use [Options.String] or [Options.Bytes] for 8-bit-aware width +// measurement. +func (options Options) TruncateString(s string, maxWidth int, tail string) string { + // We deliberately ignore ControlSequences8Bit for truncation, see above. + options.ControlSequences8Bit = false + + maxWidthWithoutTail := maxWidth - options.String(tail) + + var pos, total int + g := graphemes.FromString(s) + g.AnsiEscapeSequences = options.ControlSequences + + for g.Next() { + gw := graphemeWidth(g.Value(), options) + if total+gw <= maxWidthWithoutTail { + pos = g.End() + } + total += gw + if total > maxWidth { + if options.ControlSequences { + // Build result with trailing 7-bit ANSI escape sequences preserved + var b strings.Builder + b.Grow(len(s) + len(tail)) // at most original + tail + b.WriteString(s[:pos]) + b.WriteString(tail) + + rem := graphemes.FromString(s[pos:]) + rem.AnsiEscapeSequences = options.ControlSequences + + for rem.Next() { + v := rem.Value() + // Only preserve 7-bit escapes (ESC = 0x1B) that measure + // as zero-width on their own; some sequences (e.g. SOS) + // are only valid in their original context. + if len(v) > 0 && v[0] == 0x1B && options.String(v) == 0 { + b.WriteString(v) + } + } + return b.String() + } + return s[:pos] + tail + } + } + // No truncation + return s +} + +// TruncateString truncates a string to the given maxWidth, and appends the +// given tail if the string is truncated. +// +// It ensures the total width, including the width of the tail, is less than or +// equal to maxWidth. +func TruncateString(s string, maxWidth int, tail string) string { + return DefaultOptions.TruncateString(s, maxWidth, tail) +} + +// TruncateBytes truncates a []byte to the given maxWidth, and appends the +// given tail if the []byte is truncated. +// +// It ensures the visible width, including the width of the tail, is less than or +// equal to maxWidth. +// +// When [Options.ControlSequences] is true, 7-bit ANSI escape sequences that +// appear after the truncation point are preserved in the output. This ensures +// that escape sequences such as SGR resets are not lost, preventing color +// bleed in terminal output. +// +// [Options.ControlSequences8Bit] is ignored by truncation. 8-bit C1 byte values +// (0x80-0x9F) overlap with UTF-8 multi-byte encoding, so manipulating them +// during truncation can shift byte boundaries and form unintended visible +// characters. Use [Options.String] or [Options.Bytes] for 8-bit-aware width +// measurement. +func (options Options) TruncateBytes(s []byte, maxWidth int, tail []byte) []byte { + // We deliberately ignore ControlSequences8Bit for truncation, see above. + options.ControlSequences8Bit = false + + maxWidthWithoutTail := maxWidth - options.Bytes(tail) + + var pos, total int + g := graphemes.FromBytes(s) + g.AnsiEscapeSequences = options.ControlSequences + + for g.Next() { + gw := graphemeWidth(g.Value(), options) + if total+gw <= maxWidthWithoutTail { + pos = g.End() + } + total += gw + if total > maxWidth { + if options.ControlSequences { + // Build result with trailing 7-bit ANSI escape sequences preserved + result := make([]byte, 0, len(s)+len(tail)) // at most original + tail + result = append(result, s[:pos]...) + result = append(result, tail...) + + rem := graphemes.FromBytes(s[pos:]) + rem.AnsiEscapeSequences = options.ControlSequences + + for rem.Next() { + v := rem.Value() + // Only preserve 7-bit escapes (ESC = 0x1B) that measure + // as zero-width on their own; some sequences (e.g. SOS) + // are only valid in their original context. + if len(v) > 0 && v[0] == 0x1B && options.Bytes(v) == 0 { + result = append(result, v...) + } + } + return result + } + result := make([]byte, 0, pos+len(tail)) + result = append(result, s[:pos]...) + result = append(result, tail...) + return result + } + } + // No truncation + return s +} + +// TruncateBytes truncates a []byte to the given maxWidth, and appends the +// given tail if the []byte is truncated. +// +// It ensures the total width, including the width of the tail, is less than or +// equal to maxWidth. +func TruncateBytes(s []byte, maxWidth int, tail []byte) []byte { + return DefaultOptions.TruncateBytes(s, maxWidth, tail) +} diff --git a/vendor/github.com/clipperhouse/displaywidth/width.go b/vendor/github.com/clipperhouse/displaywidth/width.go new file mode 100644 index 0000000..f6e0ab7 --- /dev/null +++ b/vendor/github.com/clipperhouse/displaywidth/width.go @@ -0,0 +1,239 @@ +package displaywidth + +import ( + "unicode/utf8" + + "github.com/clipperhouse/uax29/v2/graphemes" +) + +// String calculates the display width of a string, +// by iterating over grapheme clusters in the string +// and summing their widths. +func String(s string) int { + return DefaultOptions.String(s) +} + +// String calculates the display width of a string, for the given options, by +// iterating over grapheme clusters in the string and summing their widths. +func (options Options) String(s string) int { + width := 0 + pos := 0 + + for pos < len(s) { + // Try ASCII optimization + asciiLen := printableASCIILength(s[pos:]) + if asciiLen > 0 { + width += asciiLen + pos += asciiLen + continue + } + + // Not ASCII, use grapheme parsing + g := graphemes.FromString(s[pos:]) + g.AnsiEscapeSequences = options.ControlSequences + g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit + + start := pos + + for g.Next() { + v := g.Value() + width += graphemeWidth(v, options) + pos += len(v) + + // Quick check: if remaining might have printable ASCII, break to outer loop + if pos < len(s) && s[pos] >= 0x20 && s[pos] <= 0x7E { + break + } + } + + // Defensive, should not happen: if no progress was made, + // skip a byte to prevent infinite loop. Only applies if + // the grapheme parser misbehaves. + if pos == start { + pos++ + } + } + + return width +} + +// Bytes calculates the display width of a []byte, +// by iterating over grapheme clusters in the byte slice +// and summing their widths. +func Bytes(s []byte) int { + return DefaultOptions.Bytes(s) +} + +// Bytes calculates the display width of a []byte, for the given options, by +// iterating over grapheme clusters in the slice and summing their widths. +func (options Options) Bytes(s []byte) int { + width := 0 + pos := 0 + + for pos < len(s) { + // Try ASCII optimization + asciiLen := printableASCIILength(s[pos:]) + if asciiLen > 0 { + width += asciiLen + pos += asciiLen + continue + } + + // Not ASCII, use grapheme parsing + g := graphemes.FromBytes(s[pos:]) + g.AnsiEscapeSequences = options.ControlSequences + g.AnsiEscapeSequences8Bit = options.ControlSequences8Bit + + start := pos + + for g.Next() { + v := g.Value() + width += graphemeWidth(v, options) + pos += len(v) + + // Quick check: if remaining might have printable ASCII, break to outer loop + if pos < len(s) && s[pos] >= 0x20 && s[pos] <= 0x7E { + break + } + } + + // Defensive, should not happen: if no progress was made, + // skip a byte to prevent infinite loop. Only applies if + // the grapheme parser misbehaves. + if pos == start { + pos++ + } + } + + return width +} + +// Rune calculates the display width of a rune. You +// should almost certainly use [String] or [Bytes] for +// most purposes. +// +// The smallest unit of display width is a grapheme +// cluster, not a rune. Iterating over runes to measure +// width is incorrect in many cases. +func Rune(r rune) int { + return DefaultOptions.Rune(r) +} + +// Rune calculates the display width of a rune, for the given options. +// +// You should almost certainly use [String] or [Bytes] for most purposes. +// +// The smallest unit of display width is a grapheme cluster, not a rune. +// Iterating over runes to measure width is incorrect in many cases. +func (options Options) Rune(r rune) int { + if r < utf8.RuneSelf { + return asciiWidth(byte(r)) + } + + // Surrogates (U+D800-U+DFFF) are invalid UTF-8. + if r >= 0xD800 && r <= 0xDFFF { + return 0 + } + + var buf [4]byte + n := utf8.EncodeRune(buf[:], r) + + // Skip the grapheme iterator + return graphemeWidth(buf[:n], options) +} + +const _Default property = 0 + +// graphemeWidth returns the display width of a grapheme cluster. +// The passed string must be a single grapheme cluster. +func graphemeWidth[T ~string | []byte](s T, options Options) int { + if len(s) == 0 { + return 0 + } + + // C1 controls (0x80-0x9F) are zero-width when 8-bit control sequences + // are enabled. This must be checked before the single-byte optimization + // below, which would otherwise return width 1 for these bytes. + if options.ControlSequences8Bit && s[0] >= 0x80 && s[0] <= 0x9F { + return 0 + } + + // Optimization: single-byte graphemes need no property lookup + if len(s) == 1 { + return asciiWidth(s[0]) + } + + // Multi-byte grapheme clusters led by a C0 control (0x00-0x1F) + if s[0] <= 0x1F { + return 0 + } + + p, sz := lookup(s) + prop := property(p) + + // Variation Selector 16 (VS16) requests emoji presentation + if prop != _Wide && sz > 0 && len(s) >= sz+3 { + vs := s[sz : sz+3] + if isVS16(vs) { + prop = _Wide + } + // VS15 (0x8E) requests text presentation but does not affect width, + // in my reading of Unicode TR51. Falls through to return the base + // character's property. + } + + if options.EastAsianWidth && prop == _East_Asian_Ambiguous { + prop = _Wide + } + + if prop > upperBound { + prop = _Default + } + + return propertyWidths[prop] +} + +func asciiWidth(b byte) int { + if b <= 0x1F || b == 0x7F { + return 0 + } + return 1 +} + +// printableASCIILength returns the length of consecutive printable ASCII bytes +// starting at the beginning of s. +func printableASCIILength[T string | []byte](s T) int { + i := 0 + for ; i < len(s); i++ { + b := s[i] + // Printable ASCII is 0x20-0x7E (space through tilde) + if b < 0x20 || b > 0x7E { + break + } + } + + // If the next byte is non-ASCII (>= 0x80), back off by 1. The grapheme + // parser may group the last ASCII byte with subsequent non-ASCII bytes, + // such as combining marks. + if i > 0 && i < len(s) && s[i] >= 0x80 { + i-- + } + + return i +} + +// isVS16 checks if the slice matches VS16 (U+FE0F) UTF-8 encoding +// (EF B8 8F). It assumes len(s) >= 3. +func isVS16[T ~string | []byte](s T) bool { + return s[0] == 0xEF && s[1] == 0xB8 && s[2] == 0x8F +} + +// propertyWidths is a jump table of sorts, instead of a switch +var propertyWidths = [4]int{ + _Default: 1, + _Zero_Width: 0, + _Wide: 2, + _East_Asian_Ambiguous: 1, +} + +const upperBound = property(len(propertyWidths) - 1) diff --git a/vendor/github.com/clipperhouse/uax29/v2/LICENSE b/vendor/github.com/clipperhouse/uax29/v2/LICENSE new file mode 100644 index 0000000..6ae86a9 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Matt Sherman + +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/clipperhouse/uax29/v2/graphemes/README.md b/vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md new file mode 100644 index 0000000..3f8a5e3 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/README.md @@ -0,0 +1,120 @@ +An implementation of grapheme cluster boundaries from [Unicode text segmentation](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) (UAX 29), for Unicode 17. + +[![Documentation](https://pkg.go.dev/badge/github.com/clipperhouse/uax29/v2/graphemes.svg)](https://pkg.go.dev/github.com/clipperhouse/uax29/v2/graphemes) +![Tests](https://github.com/clipperhouse/uax29/actions/workflows/gotest.yml/badge.svg) +![Fuzz](https://github.com/clipperhouse/uax29/actions/workflows/gofuzz.yml/badge.svg) + +## Quick start + +``` +go get github.com/clipperhouse/uax29/v2/graphemes +``` + +```go +import "github.com/clipperhouse/uax29/v2/graphemes" + +text := "Hello, 世界. Nice dog! 👍🐶" +g := graphemes.FromString(text) + +for g.Next() { // Next() returns true until end of data + fmt.Println(g.Value()) // Do something with the current grapheme +} +``` + +_A grapheme is a “single visible character”, which might be a simple as a single letter, or a complex emoji that consists of several Unicode code points._ + +## Conformance + +We use the Unicode [test suite](https://unicode.org/reports/tr41/tr41-36.html#Tests29). + +![Tests](https://github.com/clipperhouse/uax29/actions/workflows/gotest.yml/badge.svg) +![Fuzz](https://github.com/clipperhouse/uax29/actions/workflows/gofuzz.yml/badge.svg) + +## APIs + +### If you have a `string` + +```go +text := "Hello, 世界. Nice dog! 👍🐶" +g := graphemes.FromString(text) + +for g.Next() { // Next() returns true until end of data + fmt.Println(g.Value()) // Do something with the current grapheme +} +``` + +### If you have an `io.Reader` + +`FromReader` embeds a [`bufio.Scanner`](https://pkg.go.dev/bufio#Scanner), so just use those methods. + +```go +r := getYourReader() // from a file or network maybe +g := graphemes.FromReader(r) + +for g.Scan() { // Scan() returns true until error or EOF + fmt.Println(g.Text()) // Do something with the current grapheme +} + +if g.Err() != nil { // Check the error + log.Fatal(g.Err()) +} +``` + +### If you have a `[]byte` + +```go +b := []byte("Hello, 世界. Nice dog! 👍🐶") + +g := graphemes.FromBytes(b) + +for g.Next() { // Next() returns true until end of data + fmt.Println(g.Value()) // Do something with the current grapheme +} +``` + +### ANSI escape sequences + +By the UAX 29 specification, ANSI escape sequences are not grapheme clusters. To treat 7-bit ANSI escape sequences as a single cluster, set `AnsiEscapeSequences` to true. + +```go +text := "Hello, \x1b[31mworld\x1b[0m!" +g := graphemes.FromString(text) +g.AnsiEscapeSequences = true + +for g.Next() { + fmt.Println(g.Value()) +} +``` + +To also parse 8-bit C1 controls (non-UTF-8 bytes), set `AnsiEscapeSequences8Bit` to true. + +```go +g.AnsiEscapeSequences = true // 7-bit forms (ESC ...) +g.AnsiEscapeSequences8Bit = true // 8-bit C1 forms (0x80-0x9F), not valid UTF-8 +``` + +For ESC-initiated (7-bit) control strings, only 7-bit terminators are recognized. +For C1-initiated (8-bit) control strings, only C1 ST (`0x9C`) is recognized as ST. + +We implement [ECMA-48](https://ecma-international.org/publications-and-standards/standards/ecma-48/) control codes in both 7-bit and 8-bit representations. 8-bit control codes are not UTF-8 encoded and are not valid UTF-8, caveat emptor. + +### Benchmarks + +``` +goos: darwin +goarch: arm64 +pkg: github.com/clipperhouse/uax29/graphemes/comparative +cpu: Apple M2 + +BenchmarkGraphemesMixed/clipperhouse/uax29-8 142635 ns/op 245.12 MB/s 0 B/op 0 allocs/op +BenchmarkGraphemesMixed/rivo/uniseg-8 2018284 ns/op 17.32 MB/s 0 B/op 0 allocs/op + +BenchmarkGraphemesASCII/clipperhouse/uax29-8 8846 ns/op 508.73 MB/s 0 B/op 0 allocs/op +BenchmarkGraphemesASCII/rivo/uniseg-8 366760 ns/op 12.27 MB/s 0 B/op 0 allocs/op +``` + +### Invalid inputs + +Invalid UTF-8 input is considered undefined behavior. We test to ensure that bad inputs will not cause pathological outcomes, such as a panic or infinite loop. Callers should expect “garbage-in, garbage-out”. + +Your pipeline should probably include a call to [`utf8.Valid()`](https://pkg.go.dev/unicode/utf8#Valid). diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go new file mode 100644 index 0000000..9cd09b4 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi.go @@ -0,0 +1,138 @@ +package graphemes + +// ansiEscapeLength returns the byte length of a valid 7-bit ANSI escape +// sequence at the start of data, or 0 if none. +// +// Recognized forms (ECMA-48 / ISO 6429): +// - CSI: ESC [ then parameter bytes (0x30-0x3F), intermediate (0x20-0x2F), final (0x40-0x7E) +// - OSC: ESC ] then payload until BEL (0x07), 7-bit ST (ESC \), CAN (0x18), or SUB (0x1A) +// - DCS, SOS, PM, APC: ESC P/X/^/_ then payload until 7-bit ST (ESC \), CAN, or SUB +// - Two-byte: ESC + Fe/Fs (0x40-0x7E excluding above), or Fp (0x30-0x3F), or nF (0x20-0x2F then final) +func ansiEscapeLength[T ~string | ~[]byte](data T) int { + n := len(data) + if n < 2 || data[0] != esc { + return 0 + } + + b1 := data[1] + switch b1 { + case '[': // CSI + body := csiBodyLength(data[2:]) + if body == 0 { + return 0 + } + return 2 + body + case ']': // OSC - allows BEL or 7-bit ST terminator + body := oscLength(data[2:]) + if body < 0 { + return 0 + } + return 2 + body + case 'P', 'X', '^', '_': // DCS, SOS, PM, APC + body := stSequenceLength(data[2:]) + if body < 0 { + return 0 + } + return 2 + body + } + + if b1 >= 0x40 && b1 <= 0x7E { + // Fe/Fs two-byte; [ ] P X ^ _ handled above + return 2 + } + if b1 >= 0x30 && b1 <= 0x3F { + // Fp (private) two-byte + return 2 + } + if b1 >= 0x20 && b1 <= 0x2F { + // nF: intermediates then one final (0x30-0x7E) + i := 2 + for i < n && data[i] >= 0x20 && data[i] <= 0x2F { + i++ + } + if i < n && data[i] >= 0x30 && data[i] <= 0x7E { + return i + 1 + } + return 0 + } + + return 0 +} + +// csiBodyLength returns the length of the CSI body (param/intermediate/final bytes). +// data is the slice after "ESC [". +// Per ECMA-48, the CSI body has the form: +// +// parameters (0x30–0x3F)*, intermediates (0x20–0x2F)*, final (0x40–0x7E) +// +// Once an intermediate byte is seen, subsequent parameter bytes are invalid. +func csiBodyLength[T ~string | ~[]byte](data T) int { + seenIntermediate := false + for i := 0; i < len(data); i++ { + b := data[i] + if b >= 0x30 && b <= 0x3F { + if seenIntermediate { + return 0 + } + continue + } + if b >= 0x20 && b <= 0x2F { + seenIntermediate = true + continue + } + if b >= 0x40 && b <= 0x7E { + return i + 1 + } + return 0 + } + return 0 +} + +// oscLength returns the length of the OSC body. +// data is the slice after "ESC ]". +// +// Returns: +// - n >= 0: consumed body length (includes BEL/ST terminator when present) +// - -1: not terminated in the provided data +// +// OSC accepts BEL (0x07) or 7-bit ST (ESC \) as terminators by widespread convention. +// Per ECMA-48, CAN (0x18) and SUB (0x1A) cancel the control string; in that +// case they are not part of the OSC sequence length. +func oscLength[T ~string | ~[]byte](data T) int { + for i := 0; i < len(data); i++ { + b := data[i] + if b == bel { + return i + 1 + } + if b == can || b == sub { + return i + } + if b == esc && i+1 < len(data) && data[i+1] == '\\' { + return i + 2 + } + } + return -1 +} + +// stSequenceLength returns the length of a control-string body. +// data is the slice after "ESC x". +// +// Returns: +// - n >= 0: consumed body length (includes ST terminator when present) +// - -1: not terminated in the provided data +// +// Used for DCS, SOS, PM, and APC, which per ECMA-48 terminate with ST. +// ST here is the 7-bit form (ESC \). +// CAN (0x18) and SUB (0x1A) cancel the control string; in that case they are +// not part of the sequence length. +func stSequenceLength[T ~string | ~[]byte](data T) int { + for i := 0; i < len(data); i++ { + if data[i] == can || data[i] == sub { + return i + } + if data[i] == esc && i+1 < len(data) && data[i+1] == '\\' { + return i + 2 + } + } + return -1 +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go new file mode 100644 index 0000000..d9b0c48 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/ansi8.go @@ -0,0 +1,79 @@ +package graphemes + +// ansiEscapeLength8Bit returns the byte length of a valid 8-bit C1 ANSI +// sequence at the start of data, or 0 if none. +// +// Recognized forms (ECMA-48 / ISO 6429): +// - C1 CSI (0x9B) body as parameter/intermediate/final bytes +// - C1 OSC (0x9D) body terminated by BEL, C1 ST, CAN, or SUB +// - C1 DCS/SOS/PM/APC (0x90/0x98/0x9E/0x9F) body terminated by C1 ST, CAN, or SUB +// - Standalone C1 controls (0x80..0x9F not listed above): single byte +func ansiEscapeLength8Bit[T ~string | ~[]byte](data T) int { + if len(data) == 0 { + return 0 + } + + switch data[0] { + case 0x9B: // C1 CSI + body := csiBodyLength(data[1:]) + if body == 0 { + return 0 + } + return 1 + body + case 0x9D: // C1 OSC + body := oscLengthC1(data[1:]) + if body < 0 { + return 0 + } + return 1 + body + case 0x90, 0x98, 0x9E, 0x9F: // C1 DCS, SOS, PM, APC + body := stSequenceLengthC1(data[1:]) + if body < 0 { + return 0 + } + return 1 + body + default: + if data[0] >= 0x80 && data[0] <= 0x9F { + return 1 + } + } + + return 0 +} + +// oscLengthC1 returns the length of a C1 OSC body. +// data is the slice after the C1 OSC initiator (0x9D). +// +// Returns: +// - n >= 0: consumed body length (includes BEL/ST terminator when present) +// - -1: not terminated in the provided data +// +// Terminators: BEL (0x07) or C1 ST (0x9C). +// CAN (0x18) and SUB (0x1A) cancel the control string. +func oscLengthC1[T ~string | ~[]byte](data T) int { + for i := 0; i < len(data); i++ { + b := data[i] + if b == bel || b == st { + return i + 1 + } + if b == can || b == sub { + return i + } + } + return -1 +} + +// stSequenceLengthC1 parses DCS/SOS/PM/APC bodies that terminate with C1 ST +// (0x9C), or are canceled by CAN/SUB. +func stSequenceLengthC1[T ~string | ~[]byte](data T) int { + for i := 0; i < len(data); i++ { + b := data[i] + if b == can || b == sub { + return i + } + if b == st { + return i + 1 + } + } + return -1 +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go new file mode 100644 index 0000000..d37d43d --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/iterator.go @@ -0,0 +1,144 @@ +package graphemes + +import "unicode/utf8" + +// FromString returns an iterator for the grapheme clusters in the input string. +// Iterate while Next() is true, and access the grapheme via Value(). +func FromString(s string) *Iterator[string] { + return &Iterator[string]{ + split: splitFuncString, + data: s, + } +} + +// FromBytes returns an iterator for the grapheme clusters in the input bytes. +// Iterate while Next() is true, and access the grapheme via Value(). +func FromBytes(b []byte) *Iterator[[]byte] { + return &Iterator[[]byte]{ + split: splitFuncBytes, + data: b, + } +} + +// Iterator is a generic iterator for grapheme clusters in strings or byte slices, +// with an ASCII hot path optimization. +type Iterator[T ~string | ~[]byte] struct { + split func(T, bool) (int, T, error) + data T + pos int + start int + // AnsiEscapeSequences treats 7-bit ANSI escape sequences (ECMA-48) as + // single grapheme clusters when true. The default is false. + // + // 8-bit controls are not enabled by this option. See [AnsiEscapeSequences8Bit]. + AnsiEscapeSequences bool + // AnsiEscapeSequences8Bit treats 8-bit C1 ANSI escape sequences (ECMA-48) as single + // grapheme clusters when true. The default is false. + // + // 8-bit control bytes are not UTF-8 encoded, i.e. not valid UTF-8. If you + // choose this option, you are choosing to interpret non-UTF-8 data, caveat + // emptor. + AnsiEscapeSequences8Bit bool +} + +var ( + splitFuncString = splitFunc[string] + splitFuncBytes = splitFunc[[]byte] +) + +const ( + esc = 0x1B + cr = 0x0D + bel = 0x07 + can = 0x18 + sub = 0x1A + st = 0x9C +) + +// Next advances the iterator to the next grapheme cluster. +// Returns false when there are no more grapheme clusters. +func (iter *Iterator[T]) Next() bool { + if iter.pos >= len(iter.data) { + return false + } + iter.start = iter.pos + + b := iter.data[iter.pos] + if iter.AnsiEscapeSequences && b == esc { + if a := ansiEscapeLength(iter.data[iter.pos:]); a > 0 { + iter.pos += a + return true + } + } + if iter.AnsiEscapeSequences8Bit && b >= 0x80 && b <= 0x9F { + if a := ansiEscapeLength8Bit(iter.data[iter.pos:]); a > 0 { + iter.pos += a + return true + } + } + + // ASCII hot path: any ASCII is one grapheme when next byte is ASCII or end. + if b < utf8.RuneSelf && b != cr { + if iter.pos+1 >= len(iter.data) || iter.data[iter.pos+1] < utf8.RuneSelf { + iter.pos++ + return true + } + } + + // Fall back to UAX29 grapheme parsing + remaining := iter.data[iter.pos:] + advance, _, err := iter.split(remaining, true) + if err != nil { + panic(err) + } + if advance <= 0 { + panic("splitFunc returned a zero or negative advance") + } + iter.pos += advance + if iter.pos > len(iter.data) { + panic("splitFunc advanced beyond end of data") + } + return true +} + +// Value returns the current grapheme cluster. +func (iter *Iterator[T]) Value() T { + return iter.data[iter.start:iter.pos] +} + +// Start returns the byte position of the current grapheme in the original data. +func (iter *Iterator[T]) Start() int { + return iter.start +} + +// End returns the byte position after the current grapheme in the original data. +func (iter *Iterator[T]) End() int { + return iter.pos +} + +// Reset resets the iterator to the beginning of the data. +func (iter *Iterator[T]) Reset() { + iter.start = 0 + iter.pos = 0 +} + +// SetText sets the data for the iterator to operate on, and resets all state. +func (iter *Iterator[T]) SetText(data T) { + iter.data = data + iter.start = 0 + iter.pos = 0 +} + +// First returns the first grapheme cluster without advancing the iterator. +func (iter *Iterator[T]) First() T { + if len(iter.data) == 0 { + return iter.data + } + + // Use a copy to leverage Next()'s ASCII optimization + cp := *iter + cp.pos = 0 + cp.start = 0 + cp.Next() + return cp.Value() +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/reader.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/reader.go new file mode 100644 index 0000000..9aa0066 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/reader.go @@ -0,0 +1,25 @@ +// Package graphemes implements Unicode grapheme cluster boundaries: https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries +package graphemes + +import ( + "bufio" + "io" +) + +type Scanner struct { + *bufio.Scanner +} + +// FromReader returns a Scanner, to split graphemes per +// https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries. +// +// It embeds a [bufio.Scanner], so you can use its methods. +// +// Iterate through graphemes by calling Scan() until false, then check Err(). +func FromReader(r io.Reader) *Scanner { + sc := bufio.NewScanner(r) + sc.Split(SplitFunc) + return &Scanner{ + Scanner: sc, + } +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go new file mode 100644 index 0000000..0ac7c6f --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/splitfunc.go @@ -0,0 +1,205 @@ +package graphemes + +import ( + "bufio" +) + +// is determines if lookup intersects propert(ies) +func (lookup property) is(properties property) bool { + return (lookup & properties) != 0 +} + +const _Ignore = _Extend + +// incbState tracks state for GB9c rule (Indic conjunct clusters) +// Pattern: Consonant (Extend|Linker)* Linker (Extend|Linker)* × Consonant +type incbState int + +const ( + incbNone incbState = iota // initial/reset + incbConsonant // seen Consonant, awaiting Linker + incbLinker // seen Consonant and Linker (conjunct ready) +) + +// SplitFunc is a bufio.SplitFunc implementation of Unicode grapheme cluster segmentation, for use with bufio.Scanner. +// +// See https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries. +var SplitFunc bufio.SplitFunc = splitFunc[[]byte] + +func splitFunc[T ~string | ~[]byte](data T, atEOF bool) (advance int, token T, err error) { + var empty T + if len(data) == 0 { + return 0, empty, nil + } + + // These vars are stateful across loop iterations + var pos int + var lastExIgnore property = 0 // "last excluding ignored categories" + var lastLastExIgnore property = 0 // "last one before that" + var regionalIndicatorCount int + + // GB9c state: tracking Indic conjunct clusters + var incb incbState + + // Rules are usually of the form Cat1 × Cat2; "current" refers to the first property + // to the right of the ×, from which we look back or forward + + current, w := lookup(data[pos:]) + if w == 0 { + if !atEOF { + // Rune extends past current data, request more + return 0, empty, nil + } + pos = len(data) + return pos, data[:pos], nil + } + + // https://unicode.org/reports/tr29/#GB1 + // Start of text always advances + pos += w + + for { + eot := pos == len(data) // "end of text" + + if eot { + if !atEOF { + // Token extends past current data, request more + return 0, empty, nil + } + + // https://unicode.org/reports/tr29/#GB2 + break + } + + /* + We've switched the evaluation order of GB1↓ and GB2↑. It's ok: + because we've checked for len(data) at the top of this function, + sot and eot are mutually exclusive, order doesn't matter. + */ + + // Rules are usually of the form Cat1 × Cat2; "current" refers to the first property + // to the right of the ×, from which we look back or forward + + // Remember previous properties to avoid lookups/lookbacks + last := current + if !last.is(_Ignore) { + lastLastExIgnore = lastExIgnore + lastExIgnore = last + } + + // Update GB9c state based on what we just advanced past + if last.is(_InCBConsonant | _InCBLinker | _InCBExtend) { + switch { + case last.is(_InCBConsonant): + if incb != incbLinker { + incb = incbConsonant + } + case last.is(_InCBLinker): + if incb >= incbConsonant { + incb = incbLinker + } + // case last.is(_InCBExtend): stay in current state + } + } else { + incb = incbNone + } + + current, w = lookup(data[pos:]) + if w == 0 { + if atEOF { + // Just return the bytes, we can't do anything with them + pos = len(data) + break + } + // Rune extends past current data, request more + return 0, empty, nil + } + + // Optimization: no rule can possibly apply + if current|last == 0 { // i.e. both are zero + break + } + + // https://unicode.org/reports/tr29/#GB3 + if current.is(_LF) && last.is(_CR) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB4 + // https://unicode.org/reports/tr29/#GB5 + if (current | last).is(_Control | _CR | _LF) { + break + } + + // https://unicode.org/reports/tr29/#GB6 + if current.is(_L|_V|_LV|_LVT) && last.is(_L) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB7 + if current.is(_V|_T) && last.is(_LV|_V) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB8 + if current.is(_T) && last.is(_LVT|_T) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB9 + if current.is(_Extend | _ZWJ) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB9a + if current.is(_SpacingMark) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB9b + if last.is(_Prepend) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB9c + // Do not break within certain combinations with Indic_Conjunct_Break (InCB)=Linker. + if incb == incbLinker && current.is(_InCBConsonant) { + // After matching the pattern, reset state to start tracking a new pattern + // The current Consonant becomes the start of the new pattern + incb = incbConsonant + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB11 + if current.is(_ExtendedPictographic) && last.is(_ZWJ) && lastLastExIgnore.is(_ExtendedPictographic) { + pos += w + continue + } + + // https://unicode.org/reports/tr29/#GB12 + // https://unicode.org/reports/tr29/#GB13 + if (current & last).is(_RegionalIndicator) { + regionalIndicatorCount++ + + odd := regionalIndicatorCount%2 == 1 + if odd { + pos += w + continue + } + } + + // If we fall through all the above rules, it's a grapheme cluster break + break + } + + // Return token + return pos, data[:pos], nil +} diff --git a/vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go b/vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go new file mode 100644 index 0000000..56192b7 --- /dev/null +++ b/vendor/github.com/clipperhouse/uax29/v2/graphemes/trie.go @@ -0,0 +1,1717 @@ +package graphemes + +// generated by github.com/clipperhouse/uax29/v2 +// from https://www.unicode.org/Public/17.0.0/ucd/auxiliary/GraphemeBreakProperty.txt + +type property uint32 + +const ( + _CR property = 1 << iota + _Control + _Extend + _ExtendedPictographic + _InCBConsonant + _InCBExtend + _InCBLinker + _L + _LF + _LV + _LVT + _Prepend + _RegionalIndicator + _SpacingMark + _T + _V + _ZWJ +) + +// lookup returns the trie value for the first UTF-8 encoding in s and +// the width in bytes of this encoding. The size will be 0 if s does not +// hold enough bytes to complete the encoding. len(s) must be greater than 0. +func lookup[T ~string | ~[]byte](s T) (v property, sz int) { + c0 := s[0] + switch { + case c0 < 0x80: // is ASCII + return graphemesValues[c0], 1 + case c0 < 0xC2: + return 0, 1 // Illegal UTF-8: not a starter, not ASCII. + case c0 < 0xE0: // 2-byte UTF-8 + if len(s) < 2 { + return 0, 0 + } + i := graphemesIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c1), 2 + case c0 < 0xF0: // 3-byte UTF-8 + if len(s) < 3 { + return 0, 0 + } + i := graphemesIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = graphemesIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c2), 3 + case c0 < 0xF8: // 4-byte UTF-8 + if len(s) < 4 { + return 0, 0 + } + i := graphemesIndex[c0] + c1 := s[1] + if c1 < 0x80 || 0xC0 <= c1 { + return 0, 1 // Illegal UTF-8: not a continuation byte. + } + o := uint32(i)<<6 + uint32(c1) + i = graphemesIndex[o] + c2 := s[2] + if c2 < 0x80 || 0xC0 <= c2 { + return 0, 2 // Illegal UTF-8: not a continuation byte. + } + o = uint32(i)<<6 + uint32(c2) + i = graphemesIndex[o] + c3 := s[3] + if c3 < 0x80 || 0xC0 <= c3 { + return 0, 3 // Illegal UTF-8: not a continuation byte. + } + return lookupValue(uint32(i), c3), 4 + } + // Illegal rune + return 0, 1 +} + +// graphemesTrie. Total size: 61760 bytes (60.31 KiB). Checksum: af733ba94cd94ba6. +// type graphemesTrie struct { } + +// func newGraphemesTrie(i int) *graphemesTrie { +// return &graphemesTrie{} +// } + +// lookupValue determines the type of block n and looks up the value for b. +func lookupValue(n uint32, b byte) property { + switch { + default: + return property(graphemesValues[n<<6+uint32(b)]) + } +} + +// graphemesValues: 235 blocks, 15040 entries, 60160 bytes +// The third block is the zero block. +var graphemesValues = [15040]property{ + // Block 0x0, offset 0x0 + 0x00: 0x0002, 0x01: 0x0002, 0x02: 0x0002, 0x03: 0x0002, 0x04: 0x0002, 0x05: 0x0002, + 0x06: 0x0002, 0x07: 0x0002, 0x08: 0x0002, 0x09: 0x0002, 0x0a: 0x0100, 0x0b: 0x0002, + 0x0c: 0x0002, 0x0d: 0x0001, 0x0e: 0x0002, 0x0f: 0x0002, 0x10: 0x0002, 0x11: 0x0002, + 0x12: 0x0002, 0x13: 0x0002, 0x14: 0x0002, 0x15: 0x0002, 0x16: 0x0002, 0x17: 0x0002, + 0x18: 0x0002, 0x19: 0x0002, 0x1a: 0x0002, 0x1b: 0x0002, 0x1c: 0x0002, 0x1d: 0x0002, + 0x1e: 0x0002, 0x1f: 0x0002, + // Block 0x1, offset 0x40 + 0x7f: 0x0002, + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc0: 0x0002, 0xc1: 0x0002, 0xc2: 0x0002, 0xc3: 0x0002, 0xc4: 0x0002, 0xc5: 0x0002, + 0xc6: 0x0002, 0xc7: 0x0002, 0xc8: 0x0002, 0xc9: 0x0002, 0xca: 0x0002, 0xcb: 0x0002, + 0xcc: 0x0002, 0xcd: 0x0002, 0xce: 0x0002, 0xcf: 0x0002, 0xd0: 0x0002, 0xd1: 0x0002, + 0xd2: 0x0002, 0xd3: 0x0002, 0xd4: 0x0002, 0xd5: 0x0002, 0xd6: 0x0002, 0xd7: 0x0002, + 0xd8: 0x0002, 0xd9: 0x0002, 0xda: 0x0002, 0xdb: 0x0002, 0xdc: 0x0002, 0xdd: 0x0002, + 0xde: 0x0002, 0xdf: 0x0002, + 0xe9: 0x0008, + 0xed: 0x0002, 0xee: 0x0008, + // Block 0x4, offset 0x100 + 0x100: 0x0024, 0x101: 0x0024, 0x102: 0x0024, 0x103: 0x0024, 0x104: 0x0024, 0x105: 0x0024, + 0x106: 0x0024, 0x107: 0x0024, 0x108: 0x0024, 0x109: 0x0024, 0x10a: 0x0024, 0x10b: 0x0024, + 0x10c: 0x0024, 0x10d: 0x0024, 0x10e: 0x0024, 0x10f: 0x0024, 0x110: 0x0024, 0x111: 0x0024, + 0x112: 0x0024, 0x113: 0x0024, 0x114: 0x0024, 0x115: 0x0024, 0x116: 0x0024, 0x117: 0x0024, + 0x118: 0x0024, 0x119: 0x0024, 0x11a: 0x0024, 0x11b: 0x0024, 0x11c: 0x0024, 0x11d: 0x0024, + 0x11e: 0x0024, 0x11f: 0x0024, 0x120: 0x0024, 0x121: 0x0024, 0x122: 0x0024, 0x123: 0x0024, + 0x124: 0x0024, 0x125: 0x0024, 0x126: 0x0024, 0x127: 0x0024, 0x128: 0x0024, 0x129: 0x0024, + 0x12a: 0x0024, 0x12b: 0x0024, 0x12c: 0x0024, 0x12d: 0x0024, 0x12e: 0x0024, 0x12f: 0x0024, + 0x130: 0x0024, 0x131: 0x0024, 0x132: 0x0024, 0x133: 0x0024, 0x134: 0x0024, 0x135: 0x0024, + 0x136: 0x0024, 0x137: 0x0024, 0x138: 0x0024, 0x139: 0x0024, 0x13a: 0x0024, 0x13b: 0x0024, + 0x13c: 0x0024, 0x13d: 0x0024, 0x13e: 0x0024, 0x13f: 0x0024, + // Block 0x5, offset 0x140 + 0x140: 0x0024, 0x141: 0x0024, 0x142: 0x0024, 0x143: 0x0024, 0x144: 0x0024, 0x145: 0x0024, + 0x146: 0x0024, 0x147: 0x0024, 0x148: 0x0024, 0x149: 0x0024, 0x14a: 0x0024, 0x14b: 0x0024, + 0x14c: 0x0024, 0x14d: 0x0024, 0x14e: 0x0024, 0x14f: 0x0024, 0x150: 0x0024, 0x151: 0x0024, + 0x152: 0x0024, 0x153: 0x0024, 0x154: 0x0024, 0x155: 0x0024, 0x156: 0x0024, 0x157: 0x0024, + 0x158: 0x0024, 0x159: 0x0024, 0x15a: 0x0024, 0x15b: 0x0024, 0x15c: 0x0024, 0x15d: 0x0024, + 0x15e: 0x0024, 0x15f: 0x0024, 0x160: 0x0024, 0x161: 0x0024, 0x162: 0x0024, 0x163: 0x0024, + 0x164: 0x0024, 0x165: 0x0024, 0x166: 0x0024, 0x167: 0x0024, 0x168: 0x0024, 0x169: 0x0024, + 0x16a: 0x0024, 0x16b: 0x0024, 0x16c: 0x0024, 0x16d: 0x0024, 0x16e: 0x0024, 0x16f: 0x0024, + // Block 0x6, offset 0x180 + 0x183: 0x0024, 0x184: 0x0024, 0x185: 0x0024, + 0x186: 0x0024, 0x187: 0x0024, 0x188: 0x0024, 0x189: 0x0024, + // Block 0x7, offset 0x1c0 + 0x1d1: 0x0024, + 0x1d2: 0x0024, 0x1d3: 0x0024, 0x1d4: 0x0024, 0x1d5: 0x0024, 0x1d6: 0x0024, 0x1d7: 0x0024, + 0x1d8: 0x0024, 0x1d9: 0x0024, 0x1da: 0x0024, 0x1db: 0x0024, 0x1dc: 0x0024, 0x1dd: 0x0024, + 0x1de: 0x0024, 0x1df: 0x0024, 0x1e0: 0x0024, 0x1e1: 0x0024, 0x1e2: 0x0024, 0x1e3: 0x0024, + 0x1e4: 0x0024, 0x1e5: 0x0024, 0x1e6: 0x0024, 0x1e7: 0x0024, 0x1e8: 0x0024, 0x1e9: 0x0024, + 0x1ea: 0x0024, 0x1eb: 0x0024, 0x1ec: 0x0024, 0x1ed: 0x0024, 0x1ee: 0x0024, 0x1ef: 0x0024, + 0x1f0: 0x0024, 0x1f1: 0x0024, 0x1f2: 0x0024, 0x1f3: 0x0024, 0x1f4: 0x0024, 0x1f5: 0x0024, + 0x1f6: 0x0024, 0x1f7: 0x0024, 0x1f8: 0x0024, 0x1f9: 0x0024, 0x1fa: 0x0024, 0x1fb: 0x0024, + 0x1fc: 0x0024, 0x1fd: 0x0024, 0x1ff: 0x0024, + // Block 0x8, offset 0x200 + 0x201: 0x0024, 0x202: 0x0024, 0x204: 0x0024, 0x205: 0x0024, + 0x207: 0x0024, + // Block 0x9, offset 0x240 + 0x240: 0x0800, 0x241: 0x0800, 0x242: 0x0800, 0x243: 0x0800, 0x244: 0x0800, 0x245: 0x0800, + 0x250: 0x0024, 0x251: 0x0024, + 0x252: 0x0024, 0x253: 0x0024, 0x254: 0x0024, 0x255: 0x0024, 0x256: 0x0024, 0x257: 0x0024, + 0x258: 0x0024, 0x259: 0x0024, 0x25a: 0x0024, 0x25c: 0x0002, + // Block 0xa, offset 0x280 + 0x28b: 0x0024, + 0x28c: 0x0024, 0x28d: 0x0024, 0x28e: 0x0024, 0x28f: 0x0024, 0x290: 0x0024, 0x291: 0x0024, + 0x292: 0x0024, 0x293: 0x0024, 0x294: 0x0024, 0x295: 0x0024, 0x296: 0x0024, 0x297: 0x0024, + 0x298: 0x0024, 0x299: 0x0024, 0x29a: 0x0024, 0x29b: 0x0024, 0x29c: 0x0024, 0x29d: 0x0024, + 0x29e: 0x0024, 0x29f: 0x0024, + 0x2b0: 0x0024, + // Block 0xb, offset 0x2c0 + 0x2d6: 0x0024, 0x2d7: 0x0024, + 0x2d8: 0x0024, 0x2d9: 0x0024, 0x2da: 0x0024, 0x2db: 0x0024, 0x2dc: 0x0024, 0x2dd: 0x0800, + 0x2df: 0x0024, 0x2e0: 0x0024, 0x2e1: 0x0024, 0x2e2: 0x0024, 0x2e3: 0x0024, + 0x2e4: 0x0024, 0x2e7: 0x0024, 0x2e8: 0x0024, + 0x2ea: 0x0024, 0x2eb: 0x0024, 0x2ec: 0x0024, 0x2ed: 0x0024, + // Block 0xc, offset 0x300 + 0x30f: 0x0800, 0x311: 0x0024, + 0x330: 0x0024, 0x331: 0x0024, 0x332: 0x0024, 0x333: 0x0024, 0x334: 0x0024, 0x335: 0x0024, + 0x336: 0x0024, 0x337: 0x0024, 0x338: 0x0024, 0x339: 0x0024, 0x33a: 0x0024, 0x33b: 0x0024, + 0x33c: 0x0024, 0x33d: 0x0024, 0x33e: 0x0024, 0x33f: 0x0024, + // Block 0xd, offset 0x340 + 0x340: 0x0024, 0x341: 0x0024, 0x342: 0x0024, 0x343: 0x0024, 0x344: 0x0024, 0x345: 0x0024, + 0x346: 0x0024, 0x347: 0x0024, 0x348: 0x0024, 0x349: 0x0024, 0x34a: 0x0024, + // Block 0xe, offset 0x380 + 0x3a6: 0x0024, 0x3a7: 0x0024, 0x3a8: 0x0024, 0x3a9: 0x0024, + 0x3aa: 0x0024, 0x3ab: 0x0024, 0x3ac: 0x0024, 0x3ad: 0x0024, 0x3ae: 0x0024, 0x3af: 0x0024, + 0x3b0: 0x0024, + // Block 0xf, offset 0x3c0 + 0x3eb: 0x0024, 0x3ec: 0x0024, 0x3ed: 0x0024, 0x3ee: 0x0024, 0x3ef: 0x0024, + 0x3f0: 0x0024, 0x3f1: 0x0024, 0x3f2: 0x0024, 0x3f3: 0x0024, + 0x3fd: 0x0024, + // Block 0x10, offset 0x400 + 0x416: 0x0024, 0x417: 0x0024, + 0x418: 0x0024, 0x419: 0x0024, 0x41b: 0x0024, 0x41c: 0x0024, 0x41d: 0x0024, + 0x41e: 0x0024, 0x41f: 0x0024, 0x420: 0x0024, 0x421: 0x0024, 0x422: 0x0024, 0x423: 0x0024, + 0x425: 0x0024, 0x426: 0x0024, 0x427: 0x0024, 0x429: 0x0024, + 0x42a: 0x0024, 0x42b: 0x0024, 0x42c: 0x0024, 0x42d: 0x0024, + // Block 0x11, offset 0x440 + 0x459: 0x0024, 0x45a: 0x0024, 0x45b: 0x0024, + // Block 0x12, offset 0x480 + 0x490: 0x0800, 0x491: 0x0800, + 0x497: 0x0024, + 0x498: 0x0024, 0x499: 0x0024, 0x49a: 0x0024, 0x49b: 0x0024, 0x49c: 0x0024, 0x49d: 0x0024, + 0x49e: 0x0024, 0x49f: 0x0024, + // Block 0x13, offset 0x4c0 + 0x4ca: 0x0024, 0x4cb: 0x0024, + 0x4cc: 0x0024, 0x4cd: 0x0024, 0x4ce: 0x0024, 0x4cf: 0x0024, 0x4d0: 0x0024, 0x4d1: 0x0024, + 0x4d2: 0x0024, 0x4d3: 0x0024, 0x4d4: 0x0024, 0x4d5: 0x0024, 0x4d6: 0x0024, 0x4d7: 0x0024, + 0x4d8: 0x0024, 0x4d9: 0x0024, 0x4da: 0x0024, 0x4db: 0x0024, 0x4dc: 0x0024, 0x4dd: 0x0024, + 0x4de: 0x0024, 0x4df: 0x0024, 0x4e0: 0x0024, 0x4e1: 0x0024, 0x4e2: 0x0800, 0x4e3: 0x0024, + 0x4e4: 0x0024, 0x4e5: 0x0024, 0x4e6: 0x0024, 0x4e7: 0x0024, 0x4e8: 0x0024, 0x4e9: 0x0024, + 0x4ea: 0x0024, 0x4eb: 0x0024, 0x4ec: 0x0024, 0x4ed: 0x0024, 0x4ee: 0x0024, 0x4ef: 0x0024, + 0x4f0: 0x0024, 0x4f1: 0x0024, 0x4f2: 0x0024, 0x4f3: 0x0024, 0x4f4: 0x0024, 0x4f5: 0x0024, + 0x4f6: 0x0024, 0x4f7: 0x0024, 0x4f8: 0x0024, 0x4f9: 0x0024, 0x4fa: 0x0024, 0x4fb: 0x0024, + 0x4fc: 0x0024, 0x4fd: 0x0024, 0x4fe: 0x0024, 0x4ff: 0x0024, + // Block 0x14, offset 0x500 + 0x500: 0x0024, 0x501: 0x0024, 0x502: 0x0024, 0x503: 0x2000, + 0x515: 0x0010, 0x516: 0x0010, 0x517: 0x0010, + 0x518: 0x0010, 0x519: 0x0010, 0x51a: 0x0010, 0x51b: 0x0010, 0x51c: 0x0010, 0x51d: 0x0010, + 0x51e: 0x0010, 0x51f: 0x0010, 0x520: 0x0010, 0x521: 0x0010, 0x522: 0x0010, 0x523: 0x0010, + 0x524: 0x0010, 0x525: 0x0010, 0x526: 0x0010, 0x527: 0x0010, 0x528: 0x0010, 0x529: 0x0010, + 0x52a: 0x0010, 0x52b: 0x0010, 0x52c: 0x0010, 0x52d: 0x0010, 0x52e: 0x0010, 0x52f: 0x0010, + 0x530: 0x0010, 0x531: 0x0010, 0x532: 0x0010, 0x533: 0x0010, 0x534: 0x0010, 0x535: 0x0010, + 0x536: 0x0010, 0x537: 0x0010, 0x538: 0x0010, 0x539: 0x0010, 0x53a: 0x0024, 0x53b: 0x2000, + 0x53c: 0x0024, 0x53e: 0x2000, 0x53f: 0x2000, + // Block 0x15, offset 0x540 + 0x540: 0x2000, 0x541: 0x0024, 0x542: 0x0024, 0x543: 0x0024, 0x544: 0x0024, 0x545: 0x0024, + 0x546: 0x0024, 0x547: 0x0024, 0x548: 0x0024, 0x549: 0x2000, 0x54a: 0x2000, 0x54b: 0x2000, + 0x54c: 0x2000, 0x54d: 0x0044, 0x54e: 0x2000, 0x54f: 0x2000, 0x551: 0x0024, + 0x552: 0x0024, 0x553: 0x0024, 0x554: 0x0024, 0x555: 0x0024, 0x556: 0x0024, 0x557: 0x0024, + 0x558: 0x0010, 0x559: 0x0010, 0x55a: 0x0010, 0x55b: 0x0010, 0x55c: 0x0010, 0x55d: 0x0010, + 0x55e: 0x0010, 0x55f: 0x0010, 0x562: 0x0024, 0x563: 0x0024, + 0x578: 0x0010, 0x579: 0x0010, 0x57a: 0x0010, 0x57b: 0x0010, + 0x57c: 0x0010, 0x57d: 0x0010, 0x57e: 0x0010, 0x57f: 0x0010, + // Block 0x16, offset 0x580 + 0x581: 0x0024, 0x582: 0x2000, 0x583: 0x2000, + 0x595: 0x0010, 0x596: 0x0010, 0x597: 0x0010, + 0x598: 0x0010, 0x599: 0x0010, 0x59a: 0x0010, 0x59b: 0x0010, 0x59c: 0x0010, 0x59d: 0x0010, + 0x59e: 0x0010, 0x59f: 0x0010, 0x5a0: 0x0010, 0x5a1: 0x0010, 0x5a2: 0x0010, 0x5a3: 0x0010, + 0x5a4: 0x0010, 0x5a5: 0x0010, 0x5a6: 0x0010, 0x5a7: 0x0010, 0x5a8: 0x0010, + 0x5aa: 0x0010, 0x5ab: 0x0010, 0x5ac: 0x0010, 0x5ad: 0x0010, 0x5ae: 0x0010, 0x5af: 0x0010, + 0x5b0: 0x0010, 0x5b2: 0x0010, + 0x5b6: 0x0010, 0x5b7: 0x0010, 0x5b8: 0x0010, 0x5b9: 0x0010, + 0x5bc: 0x0024, 0x5be: 0x0024, 0x5bf: 0x2000, + // Block 0x17, offset 0x5c0 + 0x5c0: 0x2000, 0x5c1: 0x0024, 0x5c2: 0x0024, 0x5c3: 0x0024, 0x5c4: 0x0024, + 0x5c7: 0x2000, 0x5c8: 0x2000, 0x5cb: 0x2000, + 0x5cc: 0x2000, 0x5cd: 0x0044, + 0x5d7: 0x0024, + 0x5dc: 0x0010, 0x5dd: 0x0010, + 0x5df: 0x0010, 0x5e2: 0x0024, 0x5e3: 0x0024, + 0x5f0: 0x0010, 0x5f1: 0x0010, + 0x5fe: 0x0024, + // Block 0x18, offset 0x600 + 0x601: 0x0024, 0x602: 0x0024, 0x603: 0x2000, + 0x63c: 0x0024, 0x63e: 0x2000, 0x63f: 0x2000, + // Block 0x19, offset 0x640 + 0x640: 0x2000, 0x641: 0x0024, 0x642: 0x0024, + 0x647: 0x0024, 0x648: 0x0024, 0x64b: 0x0024, + 0x64c: 0x0024, 0x64d: 0x0024, 0x651: 0x0024, + 0x670: 0x0024, 0x671: 0x0024, 0x675: 0x0024, + // Block 0x1a, offset 0x680 + 0x681: 0x0024, 0x682: 0x0024, 0x683: 0x2000, + 0x695: 0x0010, 0x696: 0x0010, 0x697: 0x0010, + 0x698: 0x0010, 0x699: 0x0010, 0x69a: 0x0010, 0x69b: 0x0010, 0x69c: 0x0010, 0x69d: 0x0010, + 0x69e: 0x0010, 0x69f: 0x0010, 0x6a0: 0x0010, 0x6a1: 0x0010, 0x6a2: 0x0010, 0x6a3: 0x0010, + 0x6a4: 0x0010, 0x6a5: 0x0010, 0x6a6: 0x0010, 0x6a7: 0x0010, 0x6a8: 0x0010, + 0x6aa: 0x0010, 0x6ab: 0x0010, 0x6ac: 0x0010, 0x6ad: 0x0010, 0x6ae: 0x0010, 0x6af: 0x0010, + 0x6b0: 0x0010, 0x6b2: 0x0010, 0x6b3: 0x0010, 0x6b5: 0x0010, + 0x6b6: 0x0010, 0x6b7: 0x0010, 0x6b8: 0x0010, 0x6b9: 0x0010, + 0x6bc: 0x0024, 0x6be: 0x2000, 0x6bf: 0x2000, + // Block 0x1b, offset 0x6c0 + 0x6c0: 0x2000, 0x6c1: 0x0024, 0x6c2: 0x0024, 0x6c3: 0x0024, 0x6c4: 0x0024, 0x6c5: 0x0024, + 0x6c7: 0x0024, 0x6c8: 0x0024, 0x6c9: 0x2000, 0x6cb: 0x2000, + 0x6cc: 0x2000, 0x6cd: 0x0044, + 0x6e2: 0x0024, 0x6e3: 0x0024, + 0x6f9: 0x0010, 0x6fa: 0x0024, 0x6fb: 0x0024, + 0x6fc: 0x0024, 0x6fd: 0x0024, 0x6fe: 0x0024, 0x6ff: 0x0024, + // Block 0x1c, offset 0x700 + 0x701: 0x0024, 0x702: 0x2000, 0x703: 0x2000, + 0x715: 0x0010, 0x716: 0x0010, 0x717: 0x0010, + 0x718: 0x0010, 0x719: 0x0010, 0x71a: 0x0010, 0x71b: 0x0010, 0x71c: 0x0010, 0x71d: 0x0010, + 0x71e: 0x0010, 0x71f: 0x0010, 0x720: 0x0010, 0x721: 0x0010, 0x722: 0x0010, 0x723: 0x0010, + 0x724: 0x0010, 0x725: 0x0010, 0x726: 0x0010, 0x727: 0x0010, 0x728: 0x0010, + 0x72a: 0x0010, 0x72b: 0x0010, 0x72c: 0x0010, 0x72d: 0x0010, 0x72e: 0x0010, 0x72f: 0x0010, + 0x730: 0x0010, 0x732: 0x0010, 0x733: 0x0010, 0x735: 0x0010, + 0x736: 0x0010, 0x737: 0x0010, 0x738: 0x0010, 0x739: 0x0010, + 0x73c: 0x0024, 0x73e: 0x0024, 0x73f: 0x0024, + // Block 0x1d, offset 0x740 + 0x740: 0x2000, 0x741: 0x0024, 0x742: 0x0024, 0x743: 0x0024, 0x744: 0x0024, + 0x747: 0x2000, 0x748: 0x2000, 0x74b: 0x2000, + 0x74c: 0x2000, 0x74d: 0x0044, + 0x755: 0x0024, 0x756: 0x0024, 0x757: 0x0024, + 0x75c: 0x0010, 0x75d: 0x0010, + 0x75f: 0x0010, 0x762: 0x0024, 0x763: 0x0024, + 0x771: 0x0010, + // Block 0x1e, offset 0x780 + 0x782: 0x0024, + 0x7be: 0x0024, 0x7bf: 0x2000, + // Block 0x1f, offset 0x7c0 + 0x7c0: 0x0024, 0x7c1: 0x2000, 0x7c2: 0x2000, + 0x7c6: 0x2000, 0x7c7: 0x2000, 0x7c8: 0x2000, 0x7ca: 0x2000, 0x7cb: 0x2000, + 0x7cc: 0x2000, 0x7cd: 0x0024, + 0x7d7: 0x0024, + // Block 0x20, offset 0x800 + 0x800: 0x0024, 0x801: 0x2000, 0x802: 0x2000, 0x803: 0x2000, 0x804: 0x0024, + 0x815: 0x0010, 0x816: 0x0010, 0x817: 0x0010, + 0x818: 0x0010, 0x819: 0x0010, 0x81a: 0x0010, 0x81b: 0x0010, 0x81c: 0x0010, 0x81d: 0x0010, + 0x81e: 0x0010, 0x81f: 0x0010, 0x820: 0x0010, 0x821: 0x0010, 0x822: 0x0010, 0x823: 0x0010, + 0x824: 0x0010, 0x825: 0x0010, 0x826: 0x0010, 0x827: 0x0010, 0x828: 0x0010, + 0x82a: 0x0010, 0x82b: 0x0010, 0x82c: 0x0010, 0x82d: 0x0010, 0x82e: 0x0010, 0x82f: 0x0010, + 0x830: 0x0010, 0x831: 0x0010, 0x832: 0x0010, 0x833: 0x0010, 0x834: 0x0010, 0x835: 0x0010, + 0x836: 0x0010, 0x837: 0x0010, 0x838: 0x0010, 0x839: 0x0010, + 0x83c: 0x0024, 0x83e: 0x0024, 0x83f: 0x0024, + // Block 0x21, offset 0x840 + 0x840: 0x0024, 0x841: 0x2000, 0x842: 0x2000, 0x843: 0x2000, 0x844: 0x2000, + 0x846: 0x0024, 0x847: 0x0024, 0x848: 0x0024, 0x84a: 0x0024, 0x84b: 0x0024, + 0x84c: 0x0024, 0x84d: 0x0044, + 0x855: 0x0024, 0x856: 0x0024, + 0x858: 0x0010, 0x859: 0x0010, 0x85a: 0x0010, + 0x862: 0x0024, 0x863: 0x0024, + // Block 0x22, offset 0x880 + 0x881: 0x0024, 0x882: 0x2000, 0x883: 0x2000, + 0x8bc: 0x0024, 0x8be: 0x2000, 0x8bf: 0x0024, + // Block 0x23, offset 0x8c0 + 0x8c0: 0x0024, 0x8c1: 0x2000, 0x8c2: 0x0024, 0x8c3: 0x2000, 0x8c4: 0x2000, + 0x8c6: 0x0024, 0x8c7: 0x0024, 0x8c8: 0x0024, 0x8ca: 0x0024, 0x8cb: 0x0024, + 0x8cc: 0x0024, 0x8cd: 0x0024, + 0x8d5: 0x0024, 0x8d6: 0x0024, + 0x8e2: 0x0024, 0x8e3: 0x0024, + 0x8f3: 0x2000, + // Block 0x24, offset 0x900 + 0x900: 0x0024, 0x901: 0x0024, 0x902: 0x2000, 0x903: 0x2000, + 0x915: 0x0010, 0x916: 0x0010, 0x917: 0x0010, + 0x918: 0x0010, 0x919: 0x0010, 0x91a: 0x0010, 0x91b: 0x0010, 0x91c: 0x0010, 0x91d: 0x0010, + 0x91e: 0x0010, 0x91f: 0x0010, 0x920: 0x0010, 0x921: 0x0010, 0x922: 0x0010, 0x923: 0x0010, + 0x924: 0x0010, 0x925: 0x0010, 0x926: 0x0010, 0x927: 0x0010, 0x928: 0x0010, 0x929: 0x0010, + 0x92a: 0x0010, 0x92b: 0x0010, 0x92c: 0x0010, 0x92d: 0x0010, 0x92e: 0x0010, 0x92f: 0x0010, + 0x930: 0x0010, 0x931: 0x0010, 0x932: 0x0010, 0x933: 0x0010, 0x934: 0x0010, 0x935: 0x0010, + 0x936: 0x0010, 0x937: 0x0010, 0x938: 0x0010, 0x939: 0x0010, 0x93a: 0x0010, 0x93b: 0x0024, + 0x93c: 0x0024, 0x93e: 0x0024, 0x93f: 0x2000, + // Block 0x25, offset 0x940 + 0x940: 0x2000, 0x941: 0x0024, 0x942: 0x0024, 0x943: 0x0024, 0x944: 0x0024, + 0x946: 0x2000, 0x947: 0x2000, 0x948: 0x2000, 0x94a: 0x2000, 0x94b: 0x2000, + 0x94c: 0x2000, 0x94d: 0x0044, 0x94e: 0x0800, + 0x957: 0x0024, + 0x962: 0x0024, 0x963: 0x0024, + // Block 0x26, offset 0x980 + 0x981: 0x0024, 0x982: 0x2000, 0x983: 0x2000, + // Block 0x27, offset 0x9c0 + 0x9ca: 0x0024, + 0x9cf: 0x0024, 0x9d0: 0x2000, 0x9d1: 0x2000, + 0x9d2: 0x0024, 0x9d3: 0x0024, 0x9d4: 0x0024, 0x9d6: 0x0024, + 0x9d8: 0x2000, 0x9d9: 0x2000, 0x9da: 0x2000, 0x9db: 0x2000, 0x9dc: 0x2000, 0x9dd: 0x2000, + 0x9de: 0x2000, 0x9df: 0x0024, + 0x9f2: 0x2000, 0x9f3: 0x2000, + // Block 0x28, offset 0xa00 + 0xa31: 0x0024, 0xa33: 0x2000, 0xa34: 0x0024, 0xa35: 0x0024, + 0xa36: 0x0024, 0xa37: 0x0024, 0xa38: 0x0024, 0xa39: 0x0024, 0xa3a: 0x0024, + // Block 0x29, offset 0xa40 + 0xa47: 0x0024, 0xa48: 0x0024, 0xa49: 0x0024, 0xa4a: 0x0024, 0xa4b: 0x0024, + 0xa4c: 0x0024, 0xa4d: 0x0024, 0xa4e: 0x0024, + // Block 0x2a, offset 0xa80 + 0xab1: 0x0024, 0xab3: 0x2000, 0xab4: 0x0024, 0xab5: 0x0024, + 0xab6: 0x0024, 0xab7: 0x0024, 0xab8: 0x0024, 0xab9: 0x0024, 0xaba: 0x0024, 0xabb: 0x0024, + 0xabc: 0x0024, + // Block 0x2b, offset 0xac0 + 0xac8: 0x0024, 0xac9: 0x0024, 0xaca: 0x0024, 0xacb: 0x0024, + 0xacc: 0x0024, 0xacd: 0x0024, 0xace: 0x0024, + // Block 0x2c, offset 0xb00 + 0xb18: 0x0024, 0xb19: 0x0024, + 0xb35: 0x0024, + 0xb37: 0x0024, 0xb39: 0x0024, + 0xb3e: 0x2000, 0xb3f: 0x2000, + // Block 0x2d, offset 0xb40 + 0xb71: 0x0024, 0xb72: 0x0024, 0xb73: 0x0024, 0xb74: 0x0024, 0xb75: 0x0024, + 0xb76: 0x0024, 0xb77: 0x0024, 0xb78: 0x0024, 0xb79: 0x0024, 0xb7a: 0x0024, 0xb7b: 0x0024, + 0xb7c: 0x0024, 0xb7d: 0x0024, 0xb7e: 0x0024, 0xb7f: 0x2000, + // Block 0x2e, offset 0xb80 + 0xb80: 0x0024, 0xb81: 0x0024, 0xb82: 0x0024, 0xb83: 0x0024, 0xb84: 0x0024, + 0xb86: 0x0024, 0xb87: 0x0024, + 0xb8d: 0x0024, 0xb8e: 0x0024, 0xb8f: 0x0024, 0xb90: 0x0024, 0xb91: 0x0024, + 0xb92: 0x0024, 0xb93: 0x0024, 0xb94: 0x0024, 0xb95: 0x0024, 0xb96: 0x0024, 0xb97: 0x0024, + 0xb99: 0x0024, 0xb9a: 0x0024, 0xb9b: 0x0024, 0xb9c: 0x0024, 0xb9d: 0x0024, + 0xb9e: 0x0024, 0xb9f: 0x0024, 0xba0: 0x0024, 0xba1: 0x0024, 0xba2: 0x0024, 0xba3: 0x0024, + 0xba4: 0x0024, 0xba5: 0x0024, 0xba6: 0x0024, 0xba7: 0x0024, 0xba8: 0x0024, 0xba9: 0x0024, + 0xbaa: 0x0024, 0xbab: 0x0024, 0xbac: 0x0024, 0xbad: 0x0024, 0xbae: 0x0024, 0xbaf: 0x0024, + 0xbb0: 0x0024, 0xbb1: 0x0024, 0xbb2: 0x0024, 0xbb3: 0x0024, 0xbb4: 0x0024, 0xbb5: 0x0024, + 0xbb6: 0x0024, 0xbb7: 0x0024, 0xbb8: 0x0024, 0xbb9: 0x0024, 0xbba: 0x0024, 0xbbb: 0x0024, + 0xbbc: 0x0024, + // Block 0x2f, offset 0xbc0 + 0xbc6: 0x0024, + // Block 0x30, offset 0xc00 + 0xc00: 0x0010, 0xc01: 0x0010, 0xc02: 0x0010, 0xc03: 0x0010, 0xc04: 0x0010, 0xc05: 0x0010, + 0xc06: 0x0010, 0xc07: 0x0010, 0xc08: 0x0010, 0xc09: 0x0010, 0xc0a: 0x0010, 0xc0b: 0x0010, + 0xc0c: 0x0010, 0xc0d: 0x0010, 0xc0e: 0x0010, 0xc0f: 0x0010, 0xc10: 0x0010, 0xc11: 0x0010, + 0xc12: 0x0010, 0xc13: 0x0010, 0xc14: 0x0010, 0xc15: 0x0010, 0xc16: 0x0010, 0xc17: 0x0010, + 0xc18: 0x0010, 0xc19: 0x0010, 0xc1a: 0x0010, 0xc1b: 0x0010, 0xc1c: 0x0010, 0xc1d: 0x0010, + 0xc1e: 0x0010, 0xc1f: 0x0010, 0xc20: 0x0010, 0xc21: 0x0010, 0xc22: 0x0010, 0xc23: 0x0010, + 0xc24: 0x0010, 0xc25: 0x0010, 0xc26: 0x0010, 0xc27: 0x0010, 0xc28: 0x0010, 0xc29: 0x0010, + 0xc2a: 0x0010, 0xc2d: 0x0024, 0xc2e: 0x0024, 0xc2f: 0x0024, + 0xc30: 0x0024, 0xc31: 0x2000, 0xc32: 0x0024, 0xc33: 0x0024, 0xc34: 0x0024, 0xc35: 0x0024, + 0xc36: 0x0024, 0xc37: 0x0024, 0xc39: 0x0044, 0xc3a: 0x0024, 0xc3b: 0x2000, + 0xc3c: 0x2000, 0xc3d: 0x0024, 0xc3e: 0x0024, 0xc3f: 0x0010, + // Block 0x31, offset 0xc40 + 0xc50: 0x0010, 0xc51: 0x0010, + 0xc52: 0x0010, 0xc53: 0x0010, 0xc54: 0x0010, 0xc55: 0x0010, 0xc56: 0x2000, 0xc57: 0x2000, + 0xc58: 0x0024, 0xc59: 0x0024, 0xc5a: 0x0010, 0xc5b: 0x0010, 0xc5c: 0x0010, 0xc5d: 0x0010, + 0xc5e: 0x0024, 0xc5f: 0x0024, 0xc60: 0x0024, 0xc61: 0x0010, + 0xc65: 0x0010, 0xc66: 0x0010, + 0xc6e: 0x0010, 0xc6f: 0x0010, + 0xc70: 0x0010, 0xc71: 0x0024, 0xc72: 0x0024, 0xc73: 0x0024, 0xc74: 0x0024, 0xc75: 0x0010, + 0xc76: 0x0010, 0xc77: 0x0010, 0xc78: 0x0010, 0xc79: 0x0010, 0xc7a: 0x0010, 0xc7b: 0x0010, + 0xc7c: 0x0010, 0xc7d: 0x0010, 0xc7e: 0x0010, 0xc7f: 0x0010, + // Block 0x32, offset 0xc80 + 0xc80: 0x0010, 0xc81: 0x0010, 0xc82: 0x0024, 0xc84: 0x2000, 0xc85: 0x0024, + 0xc86: 0x0024, + 0xc8d: 0x0024, 0xc8e: 0x0010, + 0xc9d: 0x0024, + // Block 0x33, offset 0xcc0 + 0xcc0: 0x0080, 0xcc1: 0x0080, 0xcc2: 0x0080, 0xcc3: 0x0080, 0xcc4: 0x0080, 0xcc5: 0x0080, + 0xcc6: 0x0080, 0xcc7: 0x0080, 0xcc8: 0x0080, 0xcc9: 0x0080, 0xcca: 0x0080, 0xccb: 0x0080, + 0xccc: 0x0080, 0xccd: 0x0080, 0xcce: 0x0080, 0xccf: 0x0080, 0xcd0: 0x0080, 0xcd1: 0x0080, + 0xcd2: 0x0080, 0xcd3: 0x0080, 0xcd4: 0x0080, 0xcd5: 0x0080, 0xcd6: 0x0080, 0xcd7: 0x0080, + 0xcd8: 0x0080, 0xcd9: 0x0080, 0xcda: 0x0080, 0xcdb: 0x0080, 0xcdc: 0x0080, 0xcdd: 0x0080, + 0xcde: 0x0080, 0xcdf: 0x0080, 0xce0: 0x0080, 0xce1: 0x0080, 0xce2: 0x0080, 0xce3: 0x0080, + 0xce4: 0x0080, 0xce5: 0x0080, 0xce6: 0x0080, 0xce7: 0x0080, 0xce8: 0x0080, 0xce9: 0x0080, + 0xcea: 0x0080, 0xceb: 0x0080, 0xcec: 0x0080, 0xced: 0x0080, 0xcee: 0x0080, 0xcef: 0x0080, + 0xcf0: 0x0080, 0xcf1: 0x0080, 0xcf2: 0x0080, 0xcf3: 0x0080, 0xcf4: 0x0080, 0xcf5: 0x0080, + 0xcf6: 0x0080, 0xcf7: 0x0080, 0xcf8: 0x0080, 0xcf9: 0x0080, 0xcfa: 0x0080, 0xcfb: 0x0080, + 0xcfc: 0x0080, 0xcfd: 0x0080, 0xcfe: 0x0080, 0xcff: 0x0080, + // Block 0x34, offset 0xd00 + 0xd00: 0x0080, 0xd01: 0x0080, 0xd02: 0x0080, 0xd03: 0x0080, 0xd04: 0x0080, 0xd05: 0x0080, + 0xd06: 0x0080, 0xd07: 0x0080, 0xd08: 0x0080, 0xd09: 0x0080, 0xd0a: 0x0080, 0xd0b: 0x0080, + 0xd0c: 0x0080, 0xd0d: 0x0080, 0xd0e: 0x0080, 0xd0f: 0x0080, 0xd10: 0x0080, 0xd11: 0x0080, + 0xd12: 0x0080, 0xd13: 0x0080, 0xd14: 0x0080, 0xd15: 0x0080, 0xd16: 0x0080, 0xd17: 0x0080, + 0xd18: 0x0080, 0xd19: 0x0080, 0xd1a: 0x0080, 0xd1b: 0x0080, 0xd1c: 0x0080, 0xd1d: 0x0080, + 0xd1e: 0x0080, 0xd1f: 0x0080, 0xd20: 0x8000, 0xd21: 0x8000, 0xd22: 0x8000, 0xd23: 0x8000, + 0xd24: 0x8000, 0xd25: 0x8000, 0xd26: 0x8000, 0xd27: 0x8000, 0xd28: 0x8000, 0xd29: 0x8000, + 0xd2a: 0x8000, 0xd2b: 0x8000, 0xd2c: 0x8000, 0xd2d: 0x8000, 0xd2e: 0x8000, 0xd2f: 0x8000, + 0xd30: 0x8000, 0xd31: 0x8000, 0xd32: 0x8000, 0xd33: 0x8000, 0xd34: 0x8000, 0xd35: 0x8000, + 0xd36: 0x8000, 0xd37: 0x8000, 0xd38: 0x8000, 0xd39: 0x8000, 0xd3a: 0x8000, 0xd3b: 0x8000, + 0xd3c: 0x8000, 0xd3d: 0x8000, 0xd3e: 0x8000, 0xd3f: 0x8000, + // Block 0x35, offset 0xd40 + 0xd40: 0x8000, 0xd41: 0x8000, 0xd42: 0x8000, 0xd43: 0x8000, 0xd44: 0x8000, 0xd45: 0x8000, + 0xd46: 0x8000, 0xd47: 0x8000, 0xd48: 0x8000, 0xd49: 0x8000, 0xd4a: 0x8000, 0xd4b: 0x8000, + 0xd4c: 0x8000, 0xd4d: 0x8000, 0xd4e: 0x8000, 0xd4f: 0x8000, 0xd50: 0x8000, 0xd51: 0x8000, + 0xd52: 0x8000, 0xd53: 0x8000, 0xd54: 0x8000, 0xd55: 0x8000, 0xd56: 0x8000, 0xd57: 0x8000, + 0xd58: 0x8000, 0xd59: 0x8000, 0xd5a: 0x8000, 0xd5b: 0x8000, 0xd5c: 0x8000, 0xd5d: 0x8000, + 0xd5e: 0x8000, 0xd5f: 0x8000, 0xd60: 0x8000, 0xd61: 0x8000, 0xd62: 0x8000, 0xd63: 0x8000, + 0xd64: 0x8000, 0xd65: 0x8000, 0xd66: 0x8000, 0xd67: 0x8000, 0xd68: 0x4000, 0xd69: 0x4000, + 0xd6a: 0x4000, 0xd6b: 0x4000, 0xd6c: 0x4000, 0xd6d: 0x4000, 0xd6e: 0x4000, 0xd6f: 0x4000, + 0xd70: 0x4000, 0xd71: 0x4000, 0xd72: 0x4000, 0xd73: 0x4000, 0xd74: 0x4000, 0xd75: 0x4000, + 0xd76: 0x4000, 0xd77: 0x4000, 0xd78: 0x4000, 0xd79: 0x4000, 0xd7a: 0x4000, 0xd7b: 0x4000, + 0xd7c: 0x4000, 0xd7d: 0x4000, 0xd7e: 0x4000, 0xd7f: 0x4000, + // Block 0x36, offset 0xd80 + 0xd80: 0x4000, 0xd81: 0x4000, 0xd82: 0x4000, 0xd83: 0x4000, 0xd84: 0x4000, 0xd85: 0x4000, + 0xd86: 0x4000, 0xd87: 0x4000, 0xd88: 0x4000, 0xd89: 0x4000, 0xd8a: 0x4000, 0xd8b: 0x4000, + 0xd8c: 0x4000, 0xd8d: 0x4000, 0xd8e: 0x4000, 0xd8f: 0x4000, 0xd90: 0x4000, 0xd91: 0x4000, + 0xd92: 0x4000, 0xd93: 0x4000, 0xd94: 0x4000, 0xd95: 0x4000, 0xd96: 0x4000, 0xd97: 0x4000, + 0xd98: 0x4000, 0xd99: 0x4000, 0xd9a: 0x4000, 0xd9b: 0x4000, 0xd9c: 0x4000, 0xd9d: 0x4000, + 0xd9e: 0x4000, 0xd9f: 0x4000, 0xda0: 0x4000, 0xda1: 0x4000, 0xda2: 0x4000, 0xda3: 0x4000, + 0xda4: 0x4000, 0xda5: 0x4000, 0xda6: 0x4000, 0xda7: 0x4000, 0xda8: 0x4000, 0xda9: 0x4000, + 0xdaa: 0x4000, 0xdab: 0x4000, 0xdac: 0x4000, 0xdad: 0x4000, 0xdae: 0x4000, 0xdaf: 0x4000, + 0xdb0: 0x4000, 0xdb1: 0x4000, 0xdb2: 0x4000, 0xdb3: 0x4000, 0xdb4: 0x4000, 0xdb5: 0x4000, + 0xdb6: 0x4000, 0xdb7: 0x4000, 0xdb8: 0x4000, 0xdb9: 0x4000, 0xdba: 0x4000, 0xdbb: 0x4000, + 0xdbc: 0x4000, 0xdbd: 0x4000, 0xdbe: 0x4000, 0xdbf: 0x4000, + // Block 0x37, offset 0xdc0 + 0xddd: 0x0024, + 0xdde: 0x0024, 0xddf: 0x0024, + // Block 0x38, offset 0xe00 + 0xe12: 0x0024, 0xe13: 0x0024, 0xe14: 0x0024, 0xe15: 0x0024, + 0xe32: 0x0024, 0xe33: 0x0024, 0xe34: 0x0024, + // Block 0x39, offset 0xe40 + 0xe52: 0x0024, 0xe53: 0x0024, + 0xe72: 0x0024, 0xe73: 0x0024, + // Block 0x3a, offset 0xe80 + 0xe80: 0x0010, 0xe81: 0x0010, 0xe82: 0x0010, 0xe83: 0x0010, 0xe84: 0x0010, 0xe85: 0x0010, + 0xe86: 0x0010, 0xe87: 0x0010, 0xe88: 0x0010, 0xe89: 0x0010, 0xe8a: 0x0010, 0xe8b: 0x0010, + 0xe8c: 0x0010, 0xe8d: 0x0010, 0xe8e: 0x0010, 0xe8f: 0x0010, 0xe90: 0x0010, 0xe91: 0x0010, + 0xe92: 0x0010, 0xe93: 0x0010, 0xe94: 0x0010, 0xe95: 0x0010, 0xe96: 0x0010, 0xe97: 0x0010, + 0xe98: 0x0010, 0xe99: 0x0010, 0xe9a: 0x0010, 0xe9b: 0x0010, 0xe9c: 0x0010, 0xe9d: 0x0010, + 0xe9e: 0x0010, 0xe9f: 0x0010, 0xea0: 0x0010, 0xea1: 0x0010, 0xea2: 0x0010, 0xea3: 0x0010, + 0xea4: 0x0010, 0xea5: 0x0010, 0xea6: 0x0010, 0xea7: 0x0010, 0xea8: 0x0010, 0xea9: 0x0010, + 0xeaa: 0x0010, 0xeab: 0x0010, 0xeac: 0x0010, 0xead: 0x0010, 0xeae: 0x0010, 0xeaf: 0x0010, + 0xeb0: 0x0010, 0xeb1: 0x0010, 0xeb2: 0x0010, 0xeb3: 0x0010, 0xeb4: 0x0024, 0xeb5: 0x0024, + 0xeb6: 0x2000, 0xeb7: 0x0024, 0xeb8: 0x0024, 0xeb9: 0x0024, 0xeba: 0x0024, 0xebb: 0x0024, + 0xebc: 0x0024, 0xebd: 0x0024, 0xebe: 0x2000, 0xebf: 0x2000, + // Block 0x3b, offset 0xec0 + 0xec0: 0x2000, 0xec1: 0x2000, 0xec2: 0x2000, 0xec3: 0x2000, 0xec4: 0x2000, 0xec5: 0x2000, + 0xec6: 0x0024, 0xec7: 0x2000, 0xec8: 0x2000, 0xec9: 0x0024, 0xeca: 0x0024, 0xecb: 0x0024, + 0xecc: 0x0024, 0xecd: 0x0024, 0xece: 0x0024, 0xecf: 0x0024, 0xed0: 0x0024, 0xed1: 0x0024, + 0xed2: 0x0044, 0xed3: 0x0024, + 0xedd: 0x0024, + // Block 0x3c, offset 0xf00 + 0xf0b: 0x0024, + 0xf0c: 0x0024, 0xf0d: 0x0024, 0xf0e: 0x0002, 0xf0f: 0x0024, + // Block 0x3d, offset 0xf40 + 0xf45: 0x0024, + 0xf46: 0x0024, + 0xf69: 0x0024, + // Block 0x3e, offset 0xf80 + 0xfa0: 0x0024, 0xfa1: 0x0024, 0xfa2: 0x0024, 0xfa3: 0x2000, + 0xfa4: 0x2000, 0xfa5: 0x2000, 0xfa6: 0x2000, 0xfa7: 0x0024, 0xfa8: 0x0024, 0xfa9: 0x2000, + 0xfaa: 0x2000, 0xfab: 0x2000, + 0xfb0: 0x2000, 0xfb1: 0x2000, 0xfb2: 0x0024, 0xfb3: 0x2000, 0xfb4: 0x2000, 0xfb5: 0x2000, + 0xfb6: 0x2000, 0xfb7: 0x2000, 0xfb8: 0x2000, 0xfb9: 0x0024, 0xfba: 0x0024, 0xfbb: 0x0024, + // Block 0x3f, offset 0xfc0 + 0xfd7: 0x0024, + 0xfd8: 0x0024, 0xfd9: 0x2000, 0xfda: 0x2000, 0xfdb: 0x0024, + 0xfe0: 0x0010, 0xfe1: 0x0010, 0xfe2: 0x0010, 0xfe3: 0x0010, + 0xfe4: 0x0010, 0xfe5: 0x0010, 0xfe6: 0x0010, 0xfe7: 0x0010, 0xfe8: 0x0010, 0xfe9: 0x0010, + 0xfea: 0x0010, 0xfeb: 0x0010, 0xfec: 0x0010, 0xfed: 0x0010, 0xfee: 0x0010, 0xfef: 0x0010, + 0xff0: 0x0010, 0xff1: 0x0010, 0xff2: 0x0010, 0xff3: 0x0010, 0xff4: 0x0010, 0xff5: 0x0010, + 0xff6: 0x0010, 0xff7: 0x0010, 0xff8: 0x0010, 0xff9: 0x0010, 0xffa: 0x0010, 0xffb: 0x0010, + 0xffc: 0x0010, 0xffd: 0x0010, 0xffe: 0x0010, 0xfff: 0x0010, + // Block 0x40, offset 0x1000 + 0x1000: 0x0010, 0x1001: 0x0010, 0x1002: 0x0010, 0x1003: 0x0010, 0x1004: 0x0010, 0x1005: 0x0010, + 0x1006: 0x0010, 0x1007: 0x0010, 0x1008: 0x0010, 0x1009: 0x0010, 0x100a: 0x0010, 0x100b: 0x0010, + 0x100c: 0x0010, 0x100d: 0x0010, 0x100e: 0x0010, 0x100f: 0x0010, 0x1010: 0x0010, 0x1011: 0x0010, + 0x1012: 0x0010, 0x1013: 0x0010, 0x1014: 0x0010, 0x1015: 0x2000, 0x1016: 0x0024, 0x1017: 0x2000, + 0x1018: 0x0024, 0x1019: 0x0024, 0x101a: 0x0024, 0x101b: 0x0024, 0x101c: 0x0024, 0x101d: 0x0024, + 0x101e: 0x0024, 0x1020: 0x0044, 0x1022: 0x0024, + 0x1025: 0x0024, 0x1026: 0x0024, 0x1027: 0x0024, 0x1028: 0x0024, 0x1029: 0x0024, + 0x102a: 0x0024, 0x102b: 0x0024, 0x102c: 0x0024, 0x102d: 0x2000, 0x102e: 0x2000, 0x102f: 0x2000, + 0x1030: 0x2000, 0x1031: 0x2000, 0x1032: 0x2000, 0x1033: 0x0024, 0x1034: 0x0024, 0x1035: 0x0024, + 0x1036: 0x0024, 0x1037: 0x0024, 0x1038: 0x0024, 0x1039: 0x0024, 0x103a: 0x0024, 0x103b: 0x0024, + 0x103c: 0x0024, 0x103f: 0x0024, + // Block 0x41, offset 0x1040 + 0x1070: 0x0024, 0x1071: 0x0024, 0x1072: 0x0024, 0x1073: 0x0024, 0x1074: 0x0024, 0x1075: 0x0024, + 0x1076: 0x0024, 0x1077: 0x0024, 0x1078: 0x0024, 0x1079: 0x0024, 0x107a: 0x0024, 0x107b: 0x0024, + 0x107c: 0x0024, 0x107d: 0x0024, 0x107e: 0x0024, 0x107f: 0x0024, + // Block 0x42, offset 0x1080 + 0x1080: 0x0024, 0x1081: 0x0024, 0x1082: 0x0024, 0x1083: 0x0024, 0x1084: 0x0024, 0x1085: 0x0024, + 0x1086: 0x0024, 0x1087: 0x0024, 0x1088: 0x0024, 0x1089: 0x0024, 0x108a: 0x0024, 0x108b: 0x0024, + 0x108c: 0x0024, 0x108d: 0x0024, 0x108e: 0x0024, 0x108f: 0x0024, 0x1090: 0x0024, 0x1091: 0x0024, + 0x1092: 0x0024, 0x1093: 0x0024, 0x1094: 0x0024, 0x1095: 0x0024, 0x1096: 0x0024, 0x1097: 0x0024, + 0x1098: 0x0024, 0x1099: 0x0024, 0x109a: 0x0024, 0x109b: 0x0024, 0x109c: 0x0024, 0x109d: 0x0024, + 0x10a0: 0x0024, 0x10a1: 0x0024, 0x10a2: 0x0024, 0x10a3: 0x0024, + 0x10a4: 0x0024, 0x10a5: 0x0024, 0x10a6: 0x0024, 0x10a7: 0x0024, 0x10a8: 0x0024, 0x10a9: 0x0024, + 0x10aa: 0x0024, 0x10ab: 0x0024, + // Block 0x43, offset 0x10c0 + 0x10c0: 0x0024, 0x10c1: 0x0024, 0x10c2: 0x0024, 0x10c3: 0x0024, 0x10c4: 0x2000, + 0x10cb: 0x0010, + 0x10cc: 0x0010, + 0x10d3: 0x0010, 0x10d4: 0x0010, 0x10d5: 0x0010, 0x10d6: 0x0010, 0x10d7: 0x0010, + 0x10d8: 0x0010, 0x10d9: 0x0010, 0x10da: 0x0010, 0x10db: 0x0010, 0x10dc: 0x0010, 0x10dd: 0x0010, + 0x10de: 0x0010, 0x10df: 0x0010, 0x10e0: 0x0010, 0x10e1: 0x0010, 0x10e2: 0x0010, 0x10e3: 0x0010, + 0x10e4: 0x0010, 0x10e5: 0x0010, 0x10e6: 0x0010, 0x10e7: 0x0010, 0x10e8: 0x0010, 0x10e9: 0x0010, + 0x10ea: 0x0010, 0x10eb: 0x0010, 0x10ec: 0x0010, 0x10ed: 0x0010, 0x10ee: 0x0010, 0x10ef: 0x0010, + 0x10f0: 0x0010, 0x10f1: 0x0010, 0x10f2: 0x0010, 0x10f3: 0x0010, 0x10f4: 0x0024, 0x10f5: 0x0024, + 0x10f6: 0x0024, 0x10f7: 0x0024, 0x10f8: 0x0024, 0x10f9: 0x0024, 0x10fa: 0x0024, 0x10fb: 0x0024, + 0x10fc: 0x0024, 0x10fd: 0x0024, 0x10fe: 0x2000, 0x10ff: 0x2000, + // Block 0x44, offset 0x1100 + 0x1100: 0x2000, 0x1101: 0x2000, 0x1102: 0x0024, 0x1103: 0x0024, 0x1104: 0x0044, 0x1105: 0x0010, + 0x1106: 0x0010, 0x1107: 0x0010, 0x1108: 0x0010, 0x1109: 0x0010, 0x110a: 0x0010, 0x110b: 0x0010, + 0x110c: 0x0010, + 0x112b: 0x0024, 0x112c: 0x0024, 0x112d: 0x0024, 0x112e: 0x0024, 0x112f: 0x0024, + 0x1130: 0x0024, 0x1131: 0x0024, 0x1132: 0x0024, 0x1133: 0x0024, + // Block 0x45, offset 0x1140 + 0x1140: 0x0024, 0x1141: 0x0024, 0x1142: 0x2000, 0x1143: 0x0010, 0x1144: 0x0010, 0x1145: 0x0010, + 0x1146: 0x0010, 0x1147: 0x0010, 0x1148: 0x0010, 0x1149: 0x0010, 0x114a: 0x0010, 0x114b: 0x0010, + 0x114c: 0x0010, 0x114d: 0x0010, 0x114e: 0x0010, 0x114f: 0x0010, 0x1150: 0x0010, 0x1151: 0x0010, + 0x1152: 0x0010, 0x1153: 0x0010, 0x1154: 0x0010, 0x1155: 0x0010, 0x1156: 0x0010, 0x1157: 0x0010, + 0x1158: 0x0010, 0x1159: 0x0010, 0x115a: 0x0010, 0x115b: 0x0010, 0x115c: 0x0010, 0x115d: 0x0010, + 0x115e: 0x0010, 0x115f: 0x0010, 0x1160: 0x0010, 0x1161: 0x2000, 0x1162: 0x0024, 0x1163: 0x0024, + 0x1164: 0x0024, 0x1165: 0x0024, 0x1166: 0x2000, 0x1167: 0x2000, 0x1168: 0x0024, 0x1169: 0x0024, + 0x116a: 0x0024, 0x116b: 0x0044, 0x116c: 0x0024, 0x116d: 0x0024, 0x116e: 0x0010, 0x116f: 0x0010, + 0x117b: 0x0010, + 0x117c: 0x0010, 0x117d: 0x0010, + // Block 0x46, offset 0x1180 + 0x11a6: 0x0024, 0x11a7: 0x2000, 0x11a8: 0x0024, 0x11a9: 0x0024, + 0x11aa: 0x2000, 0x11ab: 0x2000, 0x11ac: 0x2000, 0x11ad: 0x0024, 0x11ae: 0x2000, 0x11af: 0x0024, + 0x11b0: 0x0024, 0x11b1: 0x0024, 0x11b2: 0x0024, 0x11b3: 0x0024, + // Block 0x47, offset 0x11c0 + 0x11e4: 0x2000, 0x11e5: 0x2000, 0x11e6: 0x2000, 0x11e7: 0x2000, 0x11e8: 0x2000, 0x11e9: 0x2000, + 0x11ea: 0x2000, 0x11eb: 0x2000, 0x11ec: 0x0024, 0x11ed: 0x0024, 0x11ee: 0x0024, 0x11ef: 0x0024, + 0x11f0: 0x0024, 0x11f1: 0x0024, 0x11f2: 0x0024, 0x11f3: 0x0024, 0x11f4: 0x2000, 0x11f5: 0x2000, + 0x11f6: 0x0024, 0x11f7: 0x0024, + // Block 0x48, offset 0x1200 + 0x1210: 0x0024, 0x1211: 0x0024, + 0x1212: 0x0024, 0x1214: 0x0024, 0x1215: 0x0024, 0x1216: 0x0024, 0x1217: 0x0024, + 0x1218: 0x0024, 0x1219: 0x0024, 0x121a: 0x0024, 0x121b: 0x0024, 0x121c: 0x0024, 0x121d: 0x0024, + 0x121e: 0x0024, 0x121f: 0x0024, 0x1220: 0x0024, 0x1221: 0x2000, 0x1222: 0x0024, 0x1223: 0x0024, + 0x1224: 0x0024, 0x1225: 0x0024, 0x1226: 0x0024, 0x1227: 0x0024, 0x1228: 0x0024, + 0x122d: 0x0024, + 0x1234: 0x0024, + 0x1237: 0x2000, 0x1238: 0x0024, 0x1239: 0x0024, + // Block 0x49, offset 0x1240 + 0x124b: 0x0002, + 0x124c: 0x0004, 0x124d: 0x10020, 0x124e: 0x0002, 0x124f: 0x0002, + 0x1268: 0x0002, 0x1269: 0x0002, + 0x126a: 0x0002, 0x126b: 0x0002, 0x126c: 0x0002, 0x126d: 0x0002, 0x126e: 0x0002, + 0x127c: 0x0008, + // Block 0x4a, offset 0x1280 + 0x1289: 0x0008, + 0x12a0: 0x0002, 0x12a1: 0x0002, 0x12a2: 0x0002, 0x12a3: 0x0002, + 0x12a4: 0x0002, 0x12a5: 0x0002, 0x12a6: 0x0002, 0x12a7: 0x0002, 0x12a8: 0x0002, 0x12a9: 0x0002, + 0x12aa: 0x0002, 0x12ab: 0x0002, 0x12ac: 0x0002, 0x12ad: 0x0002, 0x12ae: 0x0002, 0x12af: 0x0002, + // Block 0x4b, offset 0x12c0 + 0x12d0: 0x0024, 0x12d1: 0x0024, + 0x12d2: 0x0024, 0x12d3: 0x0024, 0x12d4: 0x0024, 0x12d5: 0x0024, 0x12d6: 0x0024, 0x12d7: 0x0024, + 0x12d8: 0x0024, 0x12d9: 0x0024, 0x12da: 0x0024, 0x12db: 0x0024, 0x12dc: 0x0024, 0x12dd: 0x0024, + 0x12de: 0x0024, 0x12df: 0x0024, 0x12e0: 0x0024, 0x12e1: 0x0024, 0x12e2: 0x0024, 0x12e3: 0x0024, + 0x12e4: 0x0024, 0x12e5: 0x0024, 0x12e6: 0x0024, 0x12e7: 0x0024, 0x12e8: 0x0024, 0x12e9: 0x0024, + 0x12ea: 0x0024, 0x12eb: 0x0024, 0x12ec: 0x0024, 0x12ed: 0x0024, 0x12ee: 0x0024, 0x12ef: 0x0024, + 0x12f0: 0x0024, + // Block 0x4c, offset 0x1300 + 0x1322: 0x0008, + 0x1339: 0x0008, + // Block 0x4d, offset 0x1340 + 0x1354: 0x0008, 0x1355: 0x0008, 0x1356: 0x0008, 0x1357: 0x0008, + 0x1358: 0x0008, 0x1359: 0x0008, + 0x1369: 0x0008, + 0x136a: 0x0008, + // Block 0x4e, offset 0x1380 + 0x139a: 0x0008, 0x139b: 0x0008, + 0x13a8: 0x0008, + // Block 0x4f, offset 0x13c0 + 0x13cf: 0x0008, + 0x13e9: 0x0008, + 0x13ea: 0x0008, 0x13eb: 0x0008, 0x13ec: 0x0008, 0x13ed: 0x0008, 0x13ee: 0x0008, 0x13ef: 0x0008, + 0x13f0: 0x0008, 0x13f1: 0x0008, 0x13f2: 0x0008, 0x13f3: 0x0008, + 0x13f8: 0x0008, 0x13f9: 0x0008, 0x13fa: 0x0008, + // Block 0x50, offset 0x1400 + 0x1402: 0x0008, + // Block 0x51, offset 0x1440 + 0x146a: 0x0008, 0x146b: 0x0008, + 0x1476: 0x0008, + // Block 0x52, offset 0x1480 + 0x1480: 0x0008, + 0x14bb: 0x0008, + 0x14bc: 0x0008, 0x14bd: 0x0008, 0x14be: 0x0008, + // Block 0x53, offset 0x14c0 + 0x14c0: 0x0008, 0x14c1: 0x0008, 0x14c2: 0x0008, 0x14c3: 0x0008, 0x14c4: 0x0008, + 0x14ce: 0x0008, 0x14d1: 0x0008, + 0x14d4: 0x0008, 0x14d5: 0x0008, + 0x14d8: 0x0008, 0x14dd: 0x0008, + 0x14e0: 0x0008, 0x14e2: 0x0008, 0x14e3: 0x0008, + 0x14e6: 0x0008, + 0x14ea: 0x0008, 0x14ee: 0x0008, 0x14ef: 0x0008, + 0x14f8: 0x0008, 0x14f9: 0x0008, 0x14fa: 0x0008, + // Block 0x54, offset 0x1500 + 0x1500: 0x0008, 0x1502: 0x0008, + 0x1508: 0x0008, 0x1509: 0x0008, 0x150a: 0x0008, 0x150b: 0x0008, + 0x150c: 0x0008, 0x150d: 0x0008, 0x150e: 0x0008, 0x150f: 0x0008, 0x1510: 0x0008, 0x1511: 0x0008, + 0x1512: 0x0008, 0x1513: 0x0008, + 0x151f: 0x0008, 0x1520: 0x0008, 0x1523: 0x0008, + 0x1525: 0x0008, 0x1526: 0x0008, 0x1528: 0x0008, + 0x153b: 0x0008, + 0x153e: 0x0008, 0x153f: 0x0008, + // Block 0x55, offset 0x1540 + 0x1552: 0x0008, 0x1553: 0x0008, 0x1554: 0x0008, 0x1555: 0x0008, 0x1556: 0x0008, 0x1557: 0x0008, + 0x1559: 0x0008, 0x155b: 0x0008, 0x155c: 0x0008, + 0x1560: 0x0008, 0x1561: 0x0008, + 0x1567: 0x0008, + 0x156a: 0x0008, 0x156b: 0x0008, + 0x1570: 0x0008, 0x1571: 0x0008, + 0x157d: 0x0008, 0x157e: 0x0008, + // Block 0x56, offset 0x1580 + 0x1584: 0x0008, 0x1585: 0x0008, + 0x1588: 0x0008, + 0x158e: 0x0008, 0x158f: 0x0008, 0x1591: 0x0008, + 0x1593: 0x0008, 0x1594: 0x0008, + 0x15a9: 0x0008, + 0x15aa: 0x0008, + 0x15b0: 0x0008, 0x15b1: 0x0008, 0x15b2: 0x0008, 0x15b3: 0x0008, 0x15b4: 0x0008, 0x15b5: 0x0008, + 0x15b7: 0x0008, 0x15b8: 0x0008, 0x15b9: 0x0008, 0x15ba: 0x0008, + 0x15bd: 0x0008, + // Block 0x57, offset 0x15c0 + 0x15c2: 0x0008, 0x15c5: 0x0008, + 0x15c8: 0x0008, 0x15c9: 0x0008, 0x15ca: 0x0008, 0x15cb: 0x0008, + 0x15cc: 0x0008, 0x15cd: 0x0008, 0x15cf: 0x0008, + 0x15d2: 0x0008, 0x15d4: 0x0008, 0x15d6: 0x0008, + 0x15dd: 0x0008, + 0x15e1: 0x0008, + 0x15e8: 0x0008, + 0x15f3: 0x0008, 0x15f4: 0x0008, + // Block 0x58, offset 0x1600 + 0x1604: 0x0008, + 0x1607: 0x0008, + 0x160c: 0x0008, 0x160e: 0x0008, + 0x1613: 0x0008, 0x1614: 0x0008, 0x1615: 0x0008, 0x1617: 0x0008, + 0x1623: 0x0008, + 0x1624: 0x0008, + // Block 0x59, offset 0x1640 + 0x1655: 0x0008, 0x1656: 0x0008, 0x1657: 0x0008, + 0x1661: 0x0008, + 0x1670: 0x0008, + 0x167f: 0x0008, + // Block 0x5a, offset 0x1680 + 0x16b4: 0x0008, 0x16b5: 0x0008, + // Block 0x5b, offset 0x16c0 + 0x16c5: 0x0008, + 0x16c6: 0x0008, 0x16c7: 0x0008, + 0x16db: 0x0008, 0x16dc: 0x0008, + // Block 0x5c, offset 0x1700 + 0x1710: 0x0008, + 0x1715: 0x0008, + // Block 0x5d, offset 0x1740 + 0x176f: 0x0024, + 0x1770: 0x0024, 0x1771: 0x0024, + // Block 0x5e, offset 0x1780 + 0x17bf: 0x0024, + // Block 0x5f, offset 0x17c0 + 0x17e0: 0x0024, 0x17e1: 0x0024, 0x17e2: 0x0024, 0x17e3: 0x0024, + 0x17e4: 0x0024, 0x17e5: 0x0024, 0x17e6: 0x0024, 0x17e7: 0x0024, 0x17e8: 0x0024, 0x17e9: 0x0024, + 0x17ea: 0x0024, 0x17eb: 0x0024, 0x17ec: 0x0024, 0x17ed: 0x0024, 0x17ee: 0x0024, 0x17ef: 0x0024, + 0x17f0: 0x0024, 0x17f1: 0x0024, 0x17f2: 0x0024, 0x17f3: 0x0024, 0x17f4: 0x0024, 0x17f5: 0x0024, + 0x17f6: 0x0024, 0x17f7: 0x0024, 0x17f8: 0x0024, 0x17f9: 0x0024, 0x17fa: 0x0024, 0x17fb: 0x0024, + 0x17fc: 0x0024, 0x17fd: 0x0024, 0x17fe: 0x0024, 0x17ff: 0x0024, + // Block 0x60, offset 0x1800 + 0x182a: 0x0024, 0x182b: 0x0024, 0x182c: 0x0024, 0x182d: 0x0024, 0x182e: 0x0024, 0x182f: 0x0024, + 0x1830: 0x0008, + 0x183d: 0x0008, + // Block 0x61, offset 0x1840 + 0x1859: 0x0024, 0x185a: 0x0024, + // Block 0x62, offset 0x1880 + 0x1897: 0x0008, + 0x1899: 0x0008, + // Block 0x63, offset 0x18c0 + 0x18ef: 0x0024, + 0x18f0: 0x0024, 0x18f1: 0x0024, 0x18f2: 0x0024, 0x18f4: 0x0024, 0x18f5: 0x0024, + 0x18f6: 0x0024, 0x18f7: 0x0024, 0x18f8: 0x0024, 0x18f9: 0x0024, 0x18fa: 0x0024, 0x18fb: 0x0024, + 0x18fc: 0x0024, 0x18fd: 0x0024, + // Block 0x64, offset 0x1900 + 0x191e: 0x0024, 0x191f: 0x0024, + // Block 0x65, offset 0x1940 + 0x1970: 0x0024, 0x1971: 0x0024, + // Block 0x66, offset 0x1980 + 0x1982: 0x0024, + 0x1986: 0x0024, 0x198b: 0x0024, + 0x19a3: 0x2000, + 0x19a4: 0x2000, 0x19a5: 0x0024, 0x19a6: 0x0024, 0x19a7: 0x2000, + 0x19ac: 0x0024, + // Block 0x67, offset 0x19c0 + 0x19c0: 0x2000, 0x19c1: 0x2000, + 0x19f4: 0x2000, 0x19f5: 0x2000, + 0x19f6: 0x2000, 0x19f7: 0x2000, 0x19f8: 0x2000, 0x19f9: 0x2000, 0x19fa: 0x2000, 0x19fb: 0x2000, + 0x19fc: 0x2000, 0x19fd: 0x2000, 0x19fe: 0x2000, 0x19ff: 0x2000, + // Block 0x68, offset 0x1a00 + 0x1a00: 0x2000, 0x1a01: 0x2000, 0x1a02: 0x2000, 0x1a03: 0x2000, 0x1a04: 0x0024, 0x1a05: 0x0024, + 0x1a20: 0x0024, 0x1a21: 0x0024, 0x1a22: 0x0024, 0x1a23: 0x0024, + 0x1a24: 0x0024, 0x1a25: 0x0024, 0x1a26: 0x0024, 0x1a27: 0x0024, 0x1a28: 0x0024, 0x1a29: 0x0024, + 0x1a2a: 0x0024, 0x1a2b: 0x0024, 0x1a2c: 0x0024, 0x1a2d: 0x0024, 0x1a2e: 0x0024, 0x1a2f: 0x0024, + 0x1a30: 0x0024, 0x1a31: 0x0024, + 0x1a3f: 0x0024, + // Block 0x69, offset 0x1a40 + 0x1a66: 0x0024, 0x1a67: 0x0024, 0x1a68: 0x0024, 0x1a69: 0x0024, + 0x1a6a: 0x0024, 0x1a6b: 0x0024, 0x1a6c: 0x0024, 0x1a6d: 0x0024, + // Block 0x6a, offset 0x1a80 + 0x1a87: 0x0024, 0x1a88: 0x0024, 0x1a89: 0x0024, 0x1a8a: 0x0024, 0x1a8b: 0x0024, + 0x1a8c: 0x0024, 0x1a8d: 0x0024, 0x1a8e: 0x0024, 0x1a8f: 0x0024, 0x1a90: 0x0024, 0x1a91: 0x0024, + 0x1a92: 0x2000, 0x1a93: 0x0024, + 0x1aa0: 0x0080, 0x1aa1: 0x0080, 0x1aa2: 0x0080, 0x1aa3: 0x0080, + 0x1aa4: 0x0080, 0x1aa5: 0x0080, 0x1aa6: 0x0080, 0x1aa7: 0x0080, 0x1aa8: 0x0080, 0x1aa9: 0x0080, + 0x1aaa: 0x0080, 0x1aab: 0x0080, 0x1aac: 0x0080, 0x1aad: 0x0080, 0x1aae: 0x0080, 0x1aaf: 0x0080, + 0x1ab0: 0x0080, 0x1ab1: 0x0080, 0x1ab2: 0x0080, 0x1ab3: 0x0080, 0x1ab4: 0x0080, 0x1ab5: 0x0080, + 0x1ab6: 0x0080, 0x1ab7: 0x0080, 0x1ab8: 0x0080, 0x1ab9: 0x0080, 0x1aba: 0x0080, 0x1abb: 0x0080, + 0x1abc: 0x0080, + // Block 0x6b, offset 0x1ac0 + 0x1ac0: 0x0024, 0x1ac1: 0x0024, 0x1ac2: 0x0024, 0x1ac3: 0x2000, + 0x1ac9: 0x0010, 0x1aca: 0x0010, 0x1acb: 0x0010, + 0x1acf: 0x0010, 0x1ad0: 0x0010, 0x1ad1: 0x0010, + 0x1ad2: 0x0010, 0x1ad3: 0x0010, 0x1ad4: 0x0010, 0x1ad5: 0x0010, 0x1ad6: 0x0010, 0x1ad7: 0x0010, + 0x1ad8: 0x0010, 0x1ad9: 0x0010, 0x1ada: 0x0010, 0x1adb: 0x0010, 0x1adc: 0x0010, 0x1add: 0x0010, + 0x1ade: 0x0010, 0x1adf: 0x0010, 0x1ae0: 0x0010, 0x1ae1: 0x0010, 0x1ae2: 0x0010, 0x1ae3: 0x0010, + 0x1ae4: 0x0010, 0x1ae5: 0x0010, 0x1ae6: 0x0010, 0x1ae7: 0x0010, 0x1ae8: 0x0010, 0x1ae9: 0x0010, + 0x1aea: 0x0010, 0x1aeb: 0x0010, 0x1aec: 0x0010, 0x1aed: 0x0010, 0x1aee: 0x0010, 0x1aef: 0x0010, + 0x1af0: 0x0010, 0x1af1: 0x0010, 0x1af2: 0x0010, 0x1af3: 0x0024, 0x1af4: 0x2000, 0x1af5: 0x2000, + 0x1af6: 0x0024, 0x1af7: 0x0024, 0x1af8: 0x0024, 0x1af9: 0x0024, 0x1afa: 0x2000, 0x1afb: 0x2000, + 0x1afc: 0x0024, 0x1afd: 0x0024, 0x1afe: 0x2000, 0x1aff: 0x2000, + // Block 0x6c, offset 0x1b00 + 0x1b00: 0x0044, + 0x1b20: 0x0010, 0x1b21: 0x0010, 0x1b22: 0x0010, 0x1b23: 0x0010, + 0x1b24: 0x0010, 0x1b25: 0x0024, 0x1b27: 0x0010, 0x1b28: 0x0010, 0x1b29: 0x0010, + 0x1b2a: 0x0010, 0x1b2b: 0x0010, 0x1b2c: 0x0010, 0x1b2d: 0x0010, 0x1b2e: 0x0010, 0x1b2f: 0x0010, + 0x1b3a: 0x0010, 0x1b3b: 0x0010, + 0x1b3c: 0x0010, 0x1b3d: 0x0010, 0x1b3e: 0x0010, + // Block 0x6d, offset 0x1b40 + 0x1b69: 0x0024, + 0x1b6a: 0x0024, 0x1b6b: 0x0024, 0x1b6c: 0x0024, 0x1b6d: 0x0024, 0x1b6e: 0x0024, 0x1b6f: 0x2000, + 0x1b70: 0x2000, 0x1b71: 0x0024, 0x1b72: 0x0024, 0x1b73: 0x2000, 0x1b74: 0x2000, 0x1b75: 0x0024, + 0x1b76: 0x0024, + // Block 0x6e, offset 0x1b80 + 0x1b83: 0x0024, + 0x1b8c: 0x0024, 0x1b8d: 0x2000, + 0x1ba0: 0x0010, 0x1ba1: 0x0010, 0x1ba2: 0x0010, 0x1ba3: 0x0010, + 0x1ba4: 0x0010, 0x1ba5: 0x0010, 0x1ba6: 0x0010, 0x1ba7: 0x0010, 0x1ba8: 0x0010, 0x1ba9: 0x0010, + 0x1baa: 0x0010, 0x1bab: 0x0010, 0x1bac: 0x0010, 0x1bad: 0x0010, 0x1bae: 0x0010, 0x1baf: 0x0010, + 0x1bb1: 0x0010, 0x1bb2: 0x0010, 0x1bb3: 0x0010, + 0x1bba: 0x0010, + 0x1bbc: 0x0024, 0x1bbe: 0x0010, 0x1bbf: 0x0010, + // Block 0x6f, offset 0x1bc0 + 0x1bf0: 0x0024, 0x1bf2: 0x0024, 0x1bf3: 0x0024, 0x1bf4: 0x0024, + 0x1bf7: 0x0024, 0x1bf8: 0x0024, + 0x1bfe: 0x0024, 0x1bff: 0x0024, + // Block 0x70, offset 0x1c00 + 0x1c01: 0x0024, + 0x1c20: 0x0010, 0x1c21: 0x0010, 0x1c22: 0x0010, 0x1c23: 0x0010, + 0x1c24: 0x0010, 0x1c25: 0x0010, 0x1c26: 0x0010, 0x1c27: 0x0010, 0x1c28: 0x0010, 0x1c29: 0x0010, + 0x1c2a: 0x0010, 0x1c2b: 0x2000, 0x1c2c: 0x0024, 0x1c2d: 0x0024, 0x1c2e: 0x2000, 0x1c2f: 0x2000, + 0x1c35: 0x2000, + 0x1c36: 0x0044, + // Block 0x71, offset 0x1c40 + 0x1c40: 0x0010, 0x1c41: 0x0010, 0x1c42: 0x0010, 0x1c43: 0x0010, 0x1c44: 0x0010, 0x1c45: 0x0010, + 0x1c46: 0x0010, 0x1c47: 0x0010, 0x1c48: 0x0010, 0x1c49: 0x0010, 0x1c4a: 0x0010, 0x1c4b: 0x0010, + 0x1c4c: 0x0010, 0x1c4d: 0x0010, 0x1c4e: 0x0010, 0x1c4f: 0x0010, 0x1c50: 0x0010, 0x1c51: 0x0010, + 0x1c52: 0x0010, 0x1c53: 0x0010, 0x1c54: 0x0010, 0x1c55: 0x0010, 0x1c56: 0x0010, 0x1c57: 0x0010, + 0x1c58: 0x0010, 0x1c59: 0x0010, 0x1c5a: 0x0010, + 0x1c63: 0x2000, + 0x1c64: 0x2000, 0x1c65: 0x0024, 0x1c66: 0x2000, 0x1c67: 0x2000, 0x1c68: 0x0024, 0x1c69: 0x2000, + 0x1c6a: 0x2000, 0x1c6c: 0x2000, 0x1c6d: 0x0024, + // Block 0x72, offset 0x1c80 + 0x1c80: 0x0200, 0x1c81: 0x0400, 0x1c82: 0x0400, 0x1c83: 0x0400, 0x1c84: 0x0400, 0x1c85: 0x0400, + 0x1c86: 0x0400, 0x1c87: 0x0400, 0x1c88: 0x0400, 0x1c89: 0x0400, 0x1c8a: 0x0400, 0x1c8b: 0x0400, + 0x1c8c: 0x0400, 0x1c8d: 0x0400, 0x1c8e: 0x0400, 0x1c8f: 0x0400, 0x1c90: 0x0400, 0x1c91: 0x0400, + 0x1c92: 0x0400, 0x1c93: 0x0400, 0x1c94: 0x0400, 0x1c95: 0x0400, 0x1c96: 0x0400, 0x1c97: 0x0400, + 0x1c98: 0x0400, 0x1c99: 0x0400, 0x1c9a: 0x0400, 0x1c9b: 0x0400, 0x1c9c: 0x0200, 0x1c9d: 0x0400, + 0x1c9e: 0x0400, 0x1c9f: 0x0400, 0x1ca0: 0x0400, 0x1ca1: 0x0400, 0x1ca2: 0x0400, 0x1ca3: 0x0400, + 0x1ca4: 0x0400, 0x1ca5: 0x0400, 0x1ca6: 0x0400, 0x1ca7: 0x0400, 0x1ca8: 0x0400, 0x1ca9: 0x0400, + 0x1caa: 0x0400, 0x1cab: 0x0400, 0x1cac: 0x0400, 0x1cad: 0x0400, 0x1cae: 0x0400, 0x1caf: 0x0400, + 0x1cb0: 0x0400, 0x1cb1: 0x0400, 0x1cb2: 0x0400, 0x1cb3: 0x0400, 0x1cb4: 0x0400, 0x1cb5: 0x0400, + 0x1cb6: 0x0400, 0x1cb7: 0x0400, 0x1cb8: 0x0200, 0x1cb9: 0x0400, 0x1cba: 0x0400, 0x1cbb: 0x0400, + 0x1cbc: 0x0400, 0x1cbd: 0x0400, 0x1cbe: 0x0400, 0x1cbf: 0x0400, + // Block 0x73, offset 0x1cc0 + 0x1cc0: 0x0400, 0x1cc1: 0x0400, 0x1cc2: 0x0400, 0x1cc3: 0x0400, 0x1cc4: 0x0400, 0x1cc5: 0x0400, + 0x1cc6: 0x0400, 0x1cc7: 0x0400, 0x1cc8: 0x0400, 0x1cc9: 0x0400, 0x1cca: 0x0400, 0x1ccb: 0x0400, + 0x1ccc: 0x0400, 0x1ccd: 0x0400, 0x1cce: 0x0400, 0x1ccf: 0x0400, 0x1cd0: 0x0400, 0x1cd1: 0x0400, + 0x1cd2: 0x0400, 0x1cd3: 0x0400, 0x1cd4: 0x0200, 0x1cd5: 0x0400, 0x1cd6: 0x0400, 0x1cd7: 0x0400, + 0x1cd8: 0x0400, 0x1cd9: 0x0400, 0x1cda: 0x0400, 0x1cdb: 0x0400, 0x1cdc: 0x0400, 0x1cdd: 0x0400, + 0x1cde: 0x0400, 0x1cdf: 0x0400, 0x1ce0: 0x0400, 0x1ce1: 0x0400, 0x1ce2: 0x0400, 0x1ce3: 0x0400, + 0x1ce4: 0x0400, 0x1ce5: 0x0400, 0x1ce6: 0x0400, 0x1ce7: 0x0400, 0x1ce8: 0x0400, 0x1ce9: 0x0400, + 0x1cea: 0x0400, 0x1ceb: 0x0400, 0x1cec: 0x0400, 0x1ced: 0x0400, 0x1cee: 0x0400, 0x1cef: 0x0400, + 0x1cf0: 0x0200, 0x1cf1: 0x0400, 0x1cf2: 0x0400, 0x1cf3: 0x0400, 0x1cf4: 0x0400, 0x1cf5: 0x0400, + 0x1cf6: 0x0400, 0x1cf7: 0x0400, 0x1cf8: 0x0400, 0x1cf9: 0x0400, 0x1cfa: 0x0400, 0x1cfb: 0x0400, + 0x1cfc: 0x0400, 0x1cfd: 0x0400, 0x1cfe: 0x0400, 0x1cff: 0x0400, + // Block 0x74, offset 0x1d00 + 0x1d00: 0x0400, 0x1d01: 0x0400, 0x1d02: 0x0400, 0x1d03: 0x0400, 0x1d04: 0x0400, 0x1d05: 0x0400, + 0x1d06: 0x0400, 0x1d07: 0x0400, 0x1d08: 0x0400, 0x1d09: 0x0400, 0x1d0a: 0x0400, 0x1d0b: 0x0400, + 0x1d0c: 0x0200, 0x1d0d: 0x0400, 0x1d0e: 0x0400, 0x1d0f: 0x0400, 0x1d10: 0x0400, 0x1d11: 0x0400, + 0x1d12: 0x0400, 0x1d13: 0x0400, 0x1d14: 0x0400, 0x1d15: 0x0400, 0x1d16: 0x0400, 0x1d17: 0x0400, + 0x1d18: 0x0400, 0x1d19: 0x0400, 0x1d1a: 0x0400, 0x1d1b: 0x0400, 0x1d1c: 0x0400, 0x1d1d: 0x0400, + 0x1d1e: 0x0400, 0x1d1f: 0x0400, 0x1d20: 0x0400, 0x1d21: 0x0400, 0x1d22: 0x0400, 0x1d23: 0x0400, + 0x1d24: 0x0400, 0x1d25: 0x0400, 0x1d26: 0x0400, 0x1d27: 0x0400, 0x1d28: 0x0200, 0x1d29: 0x0400, + 0x1d2a: 0x0400, 0x1d2b: 0x0400, 0x1d2c: 0x0400, 0x1d2d: 0x0400, 0x1d2e: 0x0400, 0x1d2f: 0x0400, + 0x1d30: 0x0400, 0x1d31: 0x0400, 0x1d32: 0x0400, 0x1d33: 0x0400, 0x1d34: 0x0400, 0x1d35: 0x0400, + 0x1d36: 0x0400, 0x1d37: 0x0400, 0x1d38: 0x0400, 0x1d39: 0x0400, 0x1d3a: 0x0400, 0x1d3b: 0x0400, + 0x1d3c: 0x0400, 0x1d3d: 0x0400, 0x1d3e: 0x0400, 0x1d3f: 0x0400, + // Block 0x75, offset 0x1d40 + 0x1d40: 0x0400, 0x1d41: 0x0400, 0x1d42: 0x0400, 0x1d43: 0x0400, 0x1d44: 0x0200, 0x1d45: 0x0400, + 0x1d46: 0x0400, 0x1d47: 0x0400, 0x1d48: 0x0400, 0x1d49: 0x0400, 0x1d4a: 0x0400, 0x1d4b: 0x0400, + 0x1d4c: 0x0400, 0x1d4d: 0x0400, 0x1d4e: 0x0400, 0x1d4f: 0x0400, 0x1d50: 0x0400, 0x1d51: 0x0400, + 0x1d52: 0x0400, 0x1d53: 0x0400, 0x1d54: 0x0400, 0x1d55: 0x0400, 0x1d56: 0x0400, 0x1d57: 0x0400, + 0x1d58: 0x0400, 0x1d59: 0x0400, 0x1d5a: 0x0400, 0x1d5b: 0x0400, 0x1d5c: 0x0400, 0x1d5d: 0x0400, + 0x1d5e: 0x0400, 0x1d5f: 0x0400, 0x1d60: 0x0200, 0x1d61: 0x0400, 0x1d62: 0x0400, 0x1d63: 0x0400, + 0x1d64: 0x0400, 0x1d65: 0x0400, 0x1d66: 0x0400, 0x1d67: 0x0400, 0x1d68: 0x0400, 0x1d69: 0x0400, + 0x1d6a: 0x0400, 0x1d6b: 0x0400, 0x1d6c: 0x0400, 0x1d6d: 0x0400, 0x1d6e: 0x0400, 0x1d6f: 0x0400, + 0x1d70: 0x0400, 0x1d71: 0x0400, 0x1d72: 0x0400, 0x1d73: 0x0400, 0x1d74: 0x0400, 0x1d75: 0x0400, + 0x1d76: 0x0400, 0x1d77: 0x0400, 0x1d78: 0x0400, 0x1d79: 0x0400, 0x1d7a: 0x0400, 0x1d7b: 0x0400, + 0x1d7c: 0x0200, 0x1d7d: 0x0400, 0x1d7e: 0x0400, 0x1d7f: 0x0400, + // Block 0x76, offset 0x1d80 + 0x1d80: 0x0400, 0x1d81: 0x0400, 0x1d82: 0x0400, 0x1d83: 0x0400, 0x1d84: 0x0400, 0x1d85: 0x0400, + 0x1d86: 0x0400, 0x1d87: 0x0400, 0x1d88: 0x0400, 0x1d89: 0x0400, 0x1d8a: 0x0400, 0x1d8b: 0x0400, + 0x1d8c: 0x0400, 0x1d8d: 0x0400, 0x1d8e: 0x0400, 0x1d8f: 0x0400, 0x1d90: 0x0400, 0x1d91: 0x0400, + 0x1d92: 0x0400, 0x1d93: 0x0400, 0x1d94: 0x0400, 0x1d95: 0x0400, 0x1d96: 0x0400, 0x1d97: 0x0400, + 0x1d98: 0x0200, 0x1d99: 0x0400, 0x1d9a: 0x0400, 0x1d9b: 0x0400, 0x1d9c: 0x0400, 0x1d9d: 0x0400, + 0x1d9e: 0x0400, 0x1d9f: 0x0400, 0x1da0: 0x0400, 0x1da1: 0x0400, 0x1da2: 0x0400, 0x1da3: 0x0400, + 0x1da4: 0x0400, 0x1da5: 0x0400, 0x1da6: 0x0400, 0x1da7: 0x0400, 0x1da8: 0x0400, 0x1da9: 0x0400, + 0x1daa: 0x0400, 0x1dab: 0x0400, 0x1dac: 0x0400, 0x1dad: 0x0400, 0x1dae: 0x0400, 0x1daf: 0x0400, + 0x1db0: 0x0400, 0x1db1: 0x0400, 0x1db2: 0x0400, 0x1db3: 0x0400, 0x1db4: 0x0200, 0x1db5: 0x0400, + 0x1db6: 0x0400, 0x1db7: 0x0400, 0x1db8: 0x0400, 0x1db9: 0x0400, 0x1dba: 0x0400, 0x1dbb: 0x0400, + 0x1dbc: 0x0400, 0x1dbd: 0x0400, 0x1dbe: 0x0400, 0x1dbf: 0x0400, + // Block 0x77, offset 0x1dc0 + 0x1dc0: 0x0400, 0x1dc1: 0x0400, 0x1dc2: 0x0400, 0x1dc3: 0x0400, 0x1dc4: 0x0400, 0x1dc5: 0x0400, + 0x1dc6: 0x0400, 0x1dc7: 0x0400, 0x1dc8: 0x0400, 0x1dc9: 0x0400, 0x1dca: 0x0400, 0x1dcb: 0x0400, + 0x1dcc: 0x0400, 0x1dcd: 0x0400, 0x1dce: 0x0400, 0x1dcf: 0x0400, 0x1dd0: 0x0200, 0x1dd1: 0x0400, + 0x1dd2: 0x0400, 0x1dd3: 0x0400, 0x1dd4: 0x0400, 0x1dd5: 0x0400, 0x1dd6: 0x0400, 0x1dd7: 0x0400, + 0x1dd8: 0x0400, 0x1dd9: 0x0400, 0x1dda: 0x0400, 0x1ddb: 0x0400, 0x1ddc: 0x0400, 0x1ddd: 0x0400, + 0x1dde: 0x0400, 0x1ddf: 0x0400, 0x1de0: 0x0400, 0x1de1: 0x0400, 0x1de2: 0x0400, 0x1de3: 0x0400, + 0x1de4: 0x0400, 0x1de5: 0x0400, 0x1de6: 0x0400, 0x1de7: 0x0400, 0x1de8: 0x0400, 0x1de9: 0x0400, + 0x1dea: 0x0400, 0x1deb: 0x0400, 0x1dec: 0x0200, 0x1ded: 0x0400, 0x1dee: 0x0400, 0x1def: 0x0400, + 0x1df0: 0x0400, 0x1df1: 0x0400, 0x1df2: 0x0400, 0x1df3: 0x0400, 0x1df4: 0x0400, 0x1df5: 0x0400, + 0x1df6: 0x0400, 0x1df7: 0x0400, 0x1df8: 0x0400, 0x1df9: 0x0400, 0x1dfa: 0x0400, 0x1dfb: 0x0400, + 0x1dfc: 0x0400, 0x1dfd: 0x0400, 0x1dfe: 0x0400, 0x1dff: 0x0400, + // Block 0x78, offset 0x1e00 + 0x1e00: 0x0400, 0x1e01: 0x0400, 0x1e02: 0x0400, 0x1e03: 0x0400, 0x1e04: 0x0400, 0x1e05: 0x0400, + 0x1e06: 0x0400, 0x1e07: 0x0400, 0x1e08: 0x0200, 0x1e09: 0x0400, 0x1e0a: 0x0400, 0x1e0b: 0x0400, + 0x1e0c: 0x0400, 0x1e0d: 0x0400, 0x1e0e: 0x0400, 0x1e0f: 0x0400, 0x1e10: 0x0400, 0x1e11: 0x0400, + 0x1e12: 0x0400, 0x1e13: 0x0400, 0x1e14: 0x0400, 0x1e15: 0x0400, 0x1e16: 0x0400, 0x1e17: 0x0400, + 0x1e18: 0x0400, 0x1e19: 0x0400, 0x1e1a: 0x0400, 0x1e1b: 0x0400, 0x1e1c: 0x0400, 0x1e1d: 0x0400, + 0x1e1e: 0x0400, 0x1e1f: 0x0400, 0x1e20: 0x0400, 0x1e21: 0x0400, 0x1e22: 0x0400, 0x1e23: 0x0400, + 0x1e24: 0x0200, 0x1e25: 0x0400, 0x1e26: 0x0400, 0x1e27: 0x0400, 0x1e28: 0x0400, 0x1e29: 0x0400, + 0x1e2a: 0x0400, 0x1e2b: 0x0400, 0x1e2c: 0x0400, 0x1e2d: 0x0400, 0x1e2e: 0x0400, 0x1e2f: 0x0400, + 0x1e30: 0x0400, 0x1e31: 0x0400, 0x1e32: 0x0400, 0x1e33: 0x0400, 0x1e34: 0x0400, 0x1e35: 0x0400, + 0x1e36: 0x0400, 0x1e37: 0x0400, 0x1e38: 0x0400, 0x1e39: 0x0400, 0x1e3a: 0x0400, 0x1e3b: 0x0400, + 0x1e3c: 0x0400, 0x1e3d: 0x0400, 0x1e3e: 0x0400, 0x1e3f: 0x0400, + // Block 0x79, offset 0x1e40 + 0x1e40: 0x0400, 0x1e41: 0x0400, 0x1e42: 0x0400, 0x1e43: 0x0400, 0x1e44: 0x0400, 0x1e45: 0x0400, + 0x1e46: 0x0400, 0x1e47: 0x0400, 0x1e48: 0x0200, 0x1e49: 0x0400, 0x1e4a: 0x0400, 0x1e4b: 0x0400, + 0x1e4c: 0x0400, 0x1e4d: 0x0400, 0x1e4e: 0x0400, 0x1e4f: 0x0400, 0x1e50: 0x0400, 0x1e51: 0x0400, + 0x1e52: 0x0400, 0x1e53: 0x0400, 0x1e54: 0x0400, 0x1e55: 0x0400, 0x1e56: 0x0400, 0x1e57: 0x0400, + 0x1e58: 0x0400, 0x1e59: 0x0400, 0x1e5a: 0x0400, 0x1e5b: 0x0400, 0x1e5c: 0x0400, 0x1e5d: 0x0400, + 0x1e5e: 0x0400, 0x1e5f: 0x0400, 0x1e60: 0x0400, 0x1e61: 0x0400, 0x1e62: 0x0400, 0x1e63: 0x0400, + 0x1e70: 0x8000, 0x1e71: 0x8000, 0x1e72: 0x8000, 0x1e73: 0x8000, 0x1e74: 0x8000, 0x1e75: 0x8000, + 0x1e76: 0x8000, 0x1e77: 0x8000, 0x1e78: 0x8000, 0x1e79: 0x8000, 0x1e7a: 0x8000, 0x1e7b: 0x8000, + 0x1e7c: 0x8000, 0x1e7d: 0x8000, 0x1e7e: 0x8000, 0x1e7f: 0x8000, + // Block 0x7a, offset 0x1e80 + 0x1e80: 0x8000, 0x1e81: 0x8000, 0x1e82: 0x8000, 0x1e83: 0x8000, 0x1e84: 0x8000, 0x1e85: 0x8000, + 0x1e86: 0x8000, 0x1e8b: 0x4000, + 0x1e8c: 0x4000, 0x1e8d: 0x4000, 0x1e8e: 0x4000, 0x1e8f: 0x4000, 0x1e90: 0x4000, 0x1e91: 0x4000, + 0x1e92: 0x4000, 0x1e93: 0x4000, 0x1e94: 0x4000, 0x1e95: 0x4000, 0x1e96: 0x4000, 0x1e97: 0x4000, + 0x1e98: 0x4000, 0x1e99: 0x4000, 0x1e9a: 0x4000, 0x1e9b: 0x4000, 0x1e9c: 0x4000, 0x1e9d: 0x4000, + 0x1e9e: 0x4000, 0x1e9f: 0x4000, 0x1ea0: 0x4000, 0x1ea1: 0x4000, 0x1ea2: 0x4000, 0x1ea3: 0x4000, + 0x1ea4: 0x4000, 0x1ea5: 0x4000, 0x1ea6: 0x4000, 0x1ea7: 0x4000, 0x1ea8: 0x4000, 0x1ea9: 0x4000, + 0x1eaa: 0x4000, 0x1eab: 0x4000, 0x1eac: 0x4000, 0x1ead: 0x4000, 0x1eae: 0x4000, 0x1eaf: 0x4000, + 0x1eb0: 0x4000, 0x1eb1: 0x4000, 0x1eb2: 0x4000, 0x1eb3: 0x4000, 0x1eb4: 0x4000, 0x1eb5: 0x4000, + 0x1eb6: 0x4000, 0x1eb7: 0x4000, 0x1eb8: 0x4000, 0x1eb9: 0x4000, 0x1eba: 0x4000, 0x1ebb: 0x4000, + // Block 0x7b, offset 0x1ec0 + 0x1ede: 0x0024, + // Block 0x7c, offset 0x1f00 + 0x1f00: 0x0024, 0x1f01: 0x0024, 0x1f02: 0x0024, 0x1f03: 0x0024, 0x1f04: 0x0024, 0x1f05: 0x0024, + 0x1f06: 0x0024, 0x1f07: 0x0024, 0x1f08: 0x0024, 0x1f09: 0x0024, 0x1f0a: 0x0024, 0x1f0b: 0x0024, + 0x1f0c: 0x0024, 0x1f0d: 0x0024, 0x1f0e: 0x0024, 0x1f0f: 0x0024, + 0x1f20: 0x0024, 0x1f21: 0x0024, 0x1f22: 0x0024, 0x1f23: 0x0024, + 0x1f24: 0x0024, 0x1f25: 0x0024, 0x1f26: 0x0024, 0x1f27: 0x0024, 0x1f28: 0x0024, 0x1f29: 0x0024, + 0x1f2a: 0x0024, 0x1f2b: 0x0024, 0x1f2c: 0x0024, 0x1f2d: 0x0024, 0x1f2e: 0x0024, 0x1f2f: 0x0024, + // Block 0x7d, offset 0x1f40 + 0x1f7f: 0x0002, + // Block 0x7e, offset 0x1f80 + 0x1fb0: 0x0002, 0x1fb1: 0x0002, 0x1fb2: 0x0002, 0x1fb3: 0x0002, 0x1fb4: 0x0002, 0x1fb5: 0x0002, + 0x1fb6: 0x0002, 0x1fb7: 0x0002, 0x1fb8: 0x0002, 0x1fb9: 0x0002, 0x1fba: 0x0002, 0x1fbb: 0x0002, + // Block 0x7f, offset 0x1fc0 + 0x1ffd: 0x0024, + // Block 0x80, offset 0x2000 + 0x2020: 0x0024, + // Block 0x81, offset 0x2040 + 0x2076: 0x0024, 0x2077: 0x0024, 0x2078: 0x0024, 0x2079: 0x0024, 0x207a: 0x0024, + // Block 0x82, offset 0x2080 + 0x2080: 0x0010, 0x2081: 0x0024, 0x2082: 0x0024, 0x2083: 0x0024, 0x2085: 0x0024, + 0x2086: 0x0024, + 0x208c: 0x0024, 0x208d: 0x0024, 0x208e: 0x0024, 0x208f: 0x0024, 0x2090: 0x0010, 0x2091: 0x0010, + 0x2092: 0x0010, 0x2093: 0x0010, 0x2095: 0x0010, 0x2096: 0x0010, 0x2097: 0x0010, + 0x2099: 0x0010, 0x209a: 0x0010, 0x209b: 0x0010, 0x209c: 0x0010, 0x209d: 0x0010, + 0x209e: 0x0010, 0x209f: 0x0010, 0x20a0: 0x0010, 0x20a1: 0x0010, 0x20a2: 0x0010, 0x20a3: 0x0010, + 0x20a4: 0x0010, 0x20a5: 0x0010, 0x20a6: 0x0010, 0x20a7: 0x0010, 0x20a8: 0x0010, 0x20a9: 0x0010, + 0x20aa: 0x0010, 0x20ab: 0x0010, 0x20ac: 0x0010, 0x20ad: 0x0010, 0x20ae: 0x0010, 0x20af: 0x0010, + 0x20b0: 0x0010, 0x20b1: 0x0010, 0x20b2: 0x0010, 0x20b3: 0x0010, 0x20b4: 0x0010, 0x20b5: 0x0010, + 0x20b8: 0x0024, 0x20b9: 0x0024, 0x20ba: 0x0024, + 0x20bf: 0x0044, + // Block 0x83, offset 0x20c0 + 0x20e5: 0x0024, 0x20e6: 0x0024, + // Block 0x84, offset 0x2100 + 0x2124: 0x0024, 0x2125: 0x0024, 0x2126: 0x0024, 0x2127: 0x0024, + // Block 0x85, offset 0x2140 + 0x2169: 0x0024, + 0x216a: 0x0024, 0x216b: 0x0024, 0x216c: 0x0024, 0x216d: 0x0024, + // Block 0x86, offset 0x2180 + 0x21ab: 0x0024, 0x21ac: 0x0024, + // Block 0x87, offset 0x21c0 + 0x21fa: 0x0024, 0x21fb: 0x0024, + 0x21fc: 0x0024, 0x21fd: 0x0024, 0x21fe: 0x0024, 0x21ff: 0x0024, + // Block 0x88, offset 0x2200 + 0x2206: 0x0024, 0x2207: 0x0024, 0x2208: 0x0024, 0x2209: 0x0024, 0x220a: 0x0024, 0x220b: 0x0024, + 0x220c: 0x0024, 0x220d: 0x0024, 0x220e: 0x0024, 0x220f: 0x0024, 0x2210: 0x0024, + // Block 0x89, offset 0x2240 + 0x2242: 0x0024, 0x2243: 0x0024, 0x2244: 0x0024, 0x2245: 0x0024, + // Block 0x8a, offset 0x2280 + 0x2280: 0x2000, 0x2281: 0x0024, 0x2282: 0x2000, + 0x22b8: 0x0024, 0x22b9: 0x0024, 0x22ba: 0x0024, 0x22bb: 0x0024, + 0x22bc: 0x0024, 0x22bd: 0x0024, 0x22be: 0x0024, 0x22bf: 0x0024, + // Block 0x8b, offset 0x22c0 + 0x22c0: 0x0024, 0x22c1: 0x0024, 0x22c2: 0x0024, 0x22c3: 0x0024, 0x22c4: 0x0024, 0x22c5: 0x0024, + 0x22c6: 0x0024, + 0x22f0: 0x0024, 0x22f3: 0x0024, 0x22f4: 0x0024, + 0x22ff: 0x0024, + // Block 0x8c, offset 0x2300 + 0x2300: 0x0024, 0x2301: 0x0024, 0x2302: 0x2000, + 0x2330: 0x2000, 0x2331: 0x2000, 0x2332: 0x2000, 0x2333: 0x0024, 0x2334: 0x0024, 0x2335: 0x0024, + 0x2336: 0x0024, 0x2337: 0x2000, 0x2338: 0x2000, 0x2339: 0x0024, 0x233a: 0x0024, + 0x233d: 0x0800, + // Block 0x8d, offset 0x2340 + 0x2342: 0x0024, + 0x234d: 0x0800, + // Block 0x8e, offset 0x2380 + 0x2380: 0x0024, 0x2381: 0x0024, 0x2382: 0x0024, 0x2383: 0x0010, 0x2384: 0x0010, 0x2385: 0x0010, + 0x2386: 0x0010, 0x2387: 0x0010, 0x2388: 0x0010, 0x2389: 0x0010, 0x238a: 0x0010, 0x238b: 0x0010, + 0x238c: 0x0010, 0x238d: 0x0010, 0x238e: 0x0010, 0x238f: 0x0010, 0x2390: 0x0010, 0x2391: 0x0010, + 0x2392: 0x0010, 0x2393: 0x0010, 0x2394: 0x0010, 0x2395: 0x0010, 0x2396: 0x0010, 0x2397: 0x0010, + 0x2398: 0x0010, 0x2399: 0x0010, 0x239a: 0x0010, 0x239b: 0x0010, 0x239c: 0x0010, 0x239d: 0x0010, + 0x239e: 0x0010, 0x239f: 0x0010, 0x23a0: 0x0010, 0x23a1: 0x0010, 0x23a2: 0x0010, 0x23a3: 0x0010, + 0x23a4: 0x0010, 0x23a5: 0x0010, 0x23a6: 0x0010, 0x23a7: 0x0024, 0x23a8: 0x0024, 0x23a9: 0x0024, + 0x23aa: 0x0024, 0x23ab: 0x0024, 0x23ac: 0x2000, 0x23ad: 0x0024, 0x23ae: 0x0024, 0x23af: 0x0024, + 0x23b0: 0x0024, 0x23b1: 0x0024, 0x23b2: 0x0024, 0x23b3: 0x0044, 0x23b4: 0x0024, + // Block 0x8f, offset 0x23c0 + 0x23c4: 0x0010, 0x23c5: 0x2000, + 0x23c6: 0x2000, 0x23c7: 0x0010, + 0x23f3: 0x0024, + // Block 0x90, offset 0x2400 + 0x2400: 0x0024, 0x2401: 0x0024, 0x2402: 0x2000, + 0x2433: 0x2000, 0x2434: 0x2000, 0x2435: 0x2000, + 0x2436: 0x0024, 0x2437: 0x0024, 0x2438: 0x0024, 0x2439: 0x0024, 0x243a: 0x0024, 0x243b: 0x0024, + 0x243c: 0x0024, 0x243d: 0x0024, 0x243e: 0x0024, 0x243f: 0x2000, + // Block 0x91, offset 0x2440 + 0x2440: 0x0024, 0x2442: 0x0800, 0x2443: 0x0800, + 0x2449: 0x0024, 0x244a: 0x0024, 0x244b: 0x0024, + 0x244c: 0x0024, 0x244e: 0x2000, 0x244f: 0x0024, + // Block 0x92, offset 0x2480 + 0x24ac: 0x2000, 0x24ad: 0x2000, 0x24ae: 0x2000, 0x24af: 0x0024, + 0x24b0: 0x0024, 0x24b1: 0x0024, 0x24b2: 0x2000, 0x24b3: 0x2000, 0x24b4: 0x0024, 0x24b5: 0x0024, + 0x24b6: 0x0024, 0x24b7: 0x0024, + 0x24be: 0x0024, + // Block 0x93, offset 0x24c0 + 0x24c1: 0x0024, + // Block 0x94, offset 0x2500 + 0x251f: 0x0024, 0x2520: 0x2000, 0x2521: 0x2000, 0x2522: 0x2000, 0x2523: 0x0024, + 0x2524: 0x0024, 0x2525: 0x0024, 0x2526: 0x0024, 0x2527: 0x0024, 0x2528: 0x0024, 0x2529: 0x0024, + 0x252a: 0x0024, + // Block 0x95, offset 0x2540 + 0x2540: 0x0024, 0x2541: 0x0024, 0x2542: 0x2000, 0x2543: 0x2000, + 0x257b: 0x0024, + 0x257c: 0x0024, 0x257e: 0x0024, 0x257f: 0x2000, + // Block 0x96, offset 0x2580 + 0x2580: 0x0024, 0x2581: 0x2000, 0x2582: 0x2000, 0x2583: 0x2000, 0x2584: 0x2000, + 0x2587: 0x2000, 0x2588: 0x2000, 0x258b: 0x2000, + 0x258c: 0x2000, 0x258d: 0x0024, + 0x2597: 0x0024, + 0x25a2: 0x2000, 0x25a3: 0x2000, + 0x25a6: 0x0024, 0x25a7: 0x0024, 0x25a8: 0x0024, 0x25a9: 0x0024, + 0x25aa: 0x0024, 0x25ab: 0x0024, 0x25ac: 0x0024, + 0x25b0: 0x0024, 0x25b1: 0x0024, 0x25b2: 0x0024, 0x25b3: 0x0024, 0x25b4: 0x0024, + // Block 0x97, offset 0x25c0 + 0x25c0: 0x0010, 0x25c1: 0x0010, 0x25c2: 0x0010, 0x25c3: 0x0010, 0x25c4: 0x0010, 0x25c5: 0x0010, + 0x25c6: 0x0010, 0x25c7: 0x0010, 0x25c8: 0x0010, 0x25c9: 0x0010, 0x25cb: 0x0010, + 0x25ce: 0x0010, 0x25d0: 0x0010, 0x25d1: 0x0010, + 0x25d2: 0x0010, 0x25d3: 0x0010, 0x25d4: 0x0010, 0x25d5: 0x0010, 0x25d6: 0x0010, 0x25d7: 0x0010, + 0x25d8: 0x0010, 0x25d9: 0x0010, 0x25da: 0x0010, 0x25db: 0x0010, 0x25dc: 0x0010, 0x25dd: 0x0010, + 0x25de: 0x0010, 0x25df: 0x0010, 0x25e0: 0x0010, 0x25e1: 0x0010, 0x25e2: 0x0010, 0x25e3: 0x0010, + 0x25e4: 0x0010, 0x25e5: 0x0010, 0x25e6: 0x0010, 0x25e7: 0x0010, 0x25e8: 0x0010, 0x25e9: 0x0010, + 0x25ea: 0x0010, 0x25eb: 0x0010, 0x25ec: 0x0010, 0x25ed: 0x0010, 0x25ee: 0x0010, 0x25ef: 0x0010, + 0x25f0: 0x0010, 0x25f1: 0x0010, 0x25f2: 0x0010, 0x25f3: 0x0010, 0x25f4: 0x0010, 0x25f5: 0x0010, + 0x25f8: 0x0024, 0x25f9: 0x2000, 0x25fa: 0x2000, 0x25fb: 0x0024, + 0x25fc: 0x0024, 0x25fd: 0x0024, 0x25fe: 0x0024, 0x25ff: 0x0024, + // Block 0x98, offset 0x2600 + 0x2600: 0x0024, 0x2602: 0x0024, 0x2605: 0x0024, + 0x2607: 0x0024, 0x2608: 0x0024, 0x2609: 0x0024, 0x260a: 0x2000, + 0x260c: 0x2000, 0x260d: 0x2000, 0x260e: 0x0024, 0x260f: 0x0024, 0x2610: 0x0044, 0x2611: 0x0800, + 0x2612: 0x0024, + 0x2621: 0x0024, 0x2622: 0x0024, + // Block 0x99, offset 0x2640 + 0x2675: 0x2000, + 0x2676: 0x2000, 0x2677: 0x2000, 0x2678: 0x0024, 0x2679: 0x0024, 0x267a: 0x0024, 0x267b: 0x0024, + 0x267c: 0x0024, 0x267d: 0x0024, 0x267e: 0x0024, 0x267f: 0x0024, + // Block 0x9a, offset 0x2680 + 0x2680: 0x2000, 0x2681: 0x2000, 0x2682: 0x0024, 0x2683: 0x0024, 0x2684: 0x0024, 0x2685: 0x2000, + 0x2686: 0x0024, + 0x269e: 0x0024, + // Block 0x9b, offset 0x26c0 + 0x26f0: 0x0024, 0x26f1: 0x2000, 0x26f2: 0x2000, 0x26f3: 0x0024, 0x26f4: 0x0024, 0x26f5: 0x0024, + 0x26f6: 0x0024, 0x26f7: 0x0024, 0x26f8: 0x0024, 0x26f9: 0x2000, 0x26fa: 0x0024, 0x26fb: 0x2000, + 0x26fc: 0x2000, 0x26fd: 0x0024, 0x26fe: 0x2000, 0x26ff: 0x0024, + // Block 0x9c, offset 0x2700 + 0x2700: 0x0024, 0x2701: 0x2000, 0x2702: 0x0024, 0x2703: 0x0024, + // Block 0x9d, offset 0x2740 + 0x276f: 0x0024, + 0x2770: 0x2000, 0x2771: 0x2000, 0x2772: 0x0024, 0x2773: 0x0024, 0x2774: 0x0024, 0x2775: 0x0024, + 0x2778: 0x2000, 0x2779: 0x2000, 0x277a: 0x2000, 0x277b: 0x2000, + 0x277c: 0x0024, 0x277d: 0x0024, 0x277e: 0x2000, 0x277f: 0x0024, + // Block 0x9e, offset 0x2780 + 0x2780: 0x0024, + 0x279c: 0x0024, 0x279d: 0x0024, + // Block 0x9f, offset 0x27c0 + 0x27f0: 0x2000, 0x27f1: 0x2000, 0x27f2: 0x2000, 0x27f3: 0x0024, 0x27f4: 0x0024, 0x27f5: 0x0024, + 0x27f6: 0x0024, 0x27f7: 0x0024, 0x27f8: 0x0024, 0x27f9: 0x0024, 0x27fa: 0x0024, 0x27fb: 0x2000, + 0x27fc: 0x2000, 0x27fd: 0x0024, 0x27fe: 0x2000, 0x27ff: 0x0024, + // Block 0xa0, offset 0x2800 + 0x2800: 0x0024, + // Block 0xa1, offset 0x2840 + 0x286b: 0x0024, 0x286c: 0x2000, 0x286d: 0x0024, 0x286e: 0x2000, 0x286f: 0x2000, + 0x2870: 0x0024, 0x2871: 0x0024, 0x2872: 0x0024, 0x2873: 0x0024, 0x2874: 0x0024, 0x2875: 0x0024, + 0x2876: 0x0024, 0x2877: 0x0024, + // Block 0xa2, offset 0x2880 + 0x289d: 0x0024, + 0x289e: 0x2000, 0x289f: 0x0024, 0x28a2: 0x0024, 0x28a3: 0x0024, + 0x28a4: 0x0024, 0x28a5: 0x0024, 0x28a6: 0x2000, 0x28a7: 0x0024, 0x28a8: 0x0024, 0x28a9: 0x0024, + 0x28aa: 0x0024, 0x28ab: 0x0024, + // Block 0xa3, offset 0x28c0 + 0x28ec: 0x2000, 0x28ed: 0x2000, 0x28ee: 0x2000, 0x28ef: 0x0024, + 0x28f0: 0x0024, 0x28f1: 0x0024, 0x28f2: 0x0024, 0x28f3: 0x0024, 0x28f4: 0x0024, 0x28f5: 0x0024, + 0x28f6: 0x0024, 0x28f7: 0x0024, 0x28f8: 0x2000, 0x28f9: 0x0024, 0x28fa: 0x0024, + // Block 0xa4, offset 0x2900 + 0x2900: 0x0010, 0x2901: 0x0010, 0x2902: 0x0010, 0x2903: 0x0010, 0x2904: 0x0010, 0x2905: 0x0010, + 0x2906: 0x0010, 0x2909: 0x0010, + 0x290c: 0x0010, 0x290d: 0x0010, 0x290e: 0x0010, 0x290f: 0x0010, 0x2910: 0x0010, 0x2911: 0x0010, + 0x2912: 0x0010, 0x2913: 0x0010, 0x2915: 0x0010, 0x2916: 0x0010, + 0x2918: 0x0010, 0x2919: 0x0010, 0x291a: 0x0010, 0x291b: 0x0010, 0x291c: 0x0010, 0x291d: 0x0010, + 0x291e: 0x0010, 0x291f: 0x0010, 0x2920: 0x0010, 0x2921: 0x0010, 0x2922: 0x0010, 0x2923: 0x0010, + 0x2924: 0x0010, 0x2925: 0x0010, 0x2926: 0x0010, 0x2927: 0x0010, 0x2928: 0x0010, 0x2929: 0x0010, + 0x292a: 0x0010, 0x292b: 0x0010, 0x292c: 0x0010, 0x292d: 0x0010, 0x292e: 0x0010, 0x292f: 0x0010, + 0x2930: 0x0024, 0x2931: 0x2000, 0x2932: 0x2000, 0x2933: 0x2000, 0x2934: 0x2000, 0x2935: 0x2000, + 0x2937: 0x2000, 0x2938: 0x2000, 0x293b: 0x0024, + 0x293c: 0x0024, 0x293d: 0x0024, 0x293e: 0x0044, 0x293f: 0x0800, + // Block 0xa5, offset 0x2940 + 0x2940: 0x2000, 0x2941: 0x0800, 0x2942: 0x2000, 0x2943: 0x0024, + // Block 0xa6, offset 0x2980 + 0x2991: 0x2000, + 0x2992: 0x2000, 0x2993: 0x2000, 0x2994: 0x0024, 0x2995: 0x0024, 0x2996: 0x0024, 0x2997: 0x0024, + 0x299a: 0x0024, 0x299b: 0x0024, 0x299c: 0x2000, 0x299d: 0x2000, + 0x299e: 0x2000, 0x299f: 0x2000, 0x29a0: 0x0024, + 0x29a4: 0x2000, + // Block 0xa7, offset 0x29c0 + 0x29c0: 0x0010, 0x29c1: 0x0024, 0x29c2: 0x0024, 0x29c3: 0x0024, 0x29c4: 0x0024, 0x29c5: 0x0024, + 0x29c6: 0x0024, 0x29c7: 0x0024, 0x29c8: 0x0024, 0x29c9: 0x0024, 0x29ca: 0x0024, 0x29cb: 0x0010, + 0x29cc: 0x0010, 0x29cd: 0x0010, 0x29ce: 0x0010, 0x29cf: 0x0010, 0x29d0: 0x0010, 0x29d1: 0x0010, + 0x29d2: 0x0010, 0x29d3: 0x0010, 0x29d4: 0x0010, 0x29d5: 0x0010, 0x29d6: 0x0010, 0x29d7: 0x0010, + 0x29d8: 0x0010, 0x29d9: 0x0010, 0x29da: 0x0010, 0x29db: 0x0010, 0x29dc: 0x0010, 0x29dd: 0x0010, + 0x29de: 0x0010, 0x29df: 0x0010, 0x29e0: 0x0010, 0x29e1: 0x0010, 0x29e2: 0x0010, 0x29e3: 0x0010, + 0x29e4: 0x0010, 0x29e5: 0x0010, 0x29e6: 0x0010, 0x29e7: 0x0010, 0x29e8: 0x0010, 0x29e9: 0x0010, + 0x29ea: 0x0010, 0x29eb: 0x0010, 0x29ec: 0x0010, 0x29ed: 0x0010, 0x29ee: 0x0010, 0x29ef: 0x0010, + 0x29f0: 0x0010, 0x29f1: 0x0010, 0x29f2: 0x0010, 0x29f3: 0x0024, 0x29f4: 0x0024, 0x29f5: 0x0024, + 0x29f6: 0x0024, 0x29f7: 0x0024, 0x29f8: 0x0024, 0x29f9: 0x2000, 0x29fb: 0x0024, + 0x29fc: 0x0024, 0x29fd: 0x0024, 0x29fe: 0x0024, + // Block 0xa8, offset 0x2a00 + 0x2a07: 0x0044, + 0x2a10: 0x0010, 0x2a11: 0x0024, + 0x2a12: 0x0024, 0x2a13: 0x0024, 0x2a14: 0x0024, 0x2a15: 0x0024, 0x2a16: 0x0024, 0x2a17: 0x2000, + 0x2a18: 0x2000, 0x2a19: 0x0024, 0x2a1a: 0x0024, 0x2a1b: 0x0024, 0x2a1c: 0x0010, 0x2a1d: 0x0010, + 0x2a1e: 0x0010, 0x2a1f: 0x0010, 0x2a20: 0x0010, 0x2a21: 0x0010, 0x2a22: 0x0010, 0x2a23: 0x0010, + 0x2a24: 0x0010, 0x2a25: 0x0010, 0x2a26: 0x0010, 0x2a27: 0x0010, 0x2a28: 0x0010, 0x2a29: 0x0010, + 0x2a2a: 0x0010, 0x2a2b: 0x0010, 0x2a2c: 0x0010, 0x2a2d: 0x0010, 0x2a2e: 0x0010, 0x2a2f: 0x0010, + 0x2a30: 0x0010, 0x2a31: 0x0010, 0x2a32: 0x0010, 0x2a33: 0x0010, 0x2a34: 0x0010, 0x2a35: 0x0010, + 0x2a36: 0x0010, 0x2a37: 0x0010, 0x2a38: 0x0010, 0x2a39: 0x0010, 0x2a3a: 0x0010, 0x2a3b: 0x0010, + 0x2a3c: 0x0010, 0x2a3d: 0x0010, 0x2a3e: 0x0010, 0x2a3f: 0x0010, + // Block 0xa9, offset 0x2a40 + 0x2a40: 0x0010, 0x2a41: 0x0010, 0x2a42: 0x0010, 0x2a43: 0x0010, 0x2a44: 0x0800, 0x2a45: 0x0800, + 0x2a46: 0x0800, 0x2a47: 0x0800, 0x2a48: 0x0800, 0x2a49: 0x0800, 0x2a4a: 0x0024, 0x2a4b: 0x0024, + 0x2a4c: 0x0024, 0x2a4d: 0x0024, 0x2a4e: 0x0024, 0x2a4f: 0x0024, 0x2a50: 0x0024, 0x2a51: 0x0024, + 0x2a52: 0x0024, 0x2a53: 0x0024, 0x2a54: 0x0024, 0x2a55: 0x0024, 0x2a56: 0x0024, 0x2a57: 0x2000, + 0x2a58: 0x0024, 0x2a59: 0x0044, + // Block 0xaa, offset 0x2a80 + 0x2aa0: 0x0024, 0x2aa1: 0x2000, 0x2aa2: 0x0024, 0x2aa3: 0x0024, + 0x2aa4: 0x0024, 0x2aa5: 0x2000, 0x2aa6: 0x0024, 0x2aa7: 0x2000, + // Block 0xab, offset 0x2ac0 + 0x2aef: 0x2000, + 0x2af0: 0x0024, 0x2af1: 0x0024, 0x2af2: 0x0024, 0x2af3: 0x0024, 0x2af4: 0x0024, 0x2af5: 0x0024, + 0x2af6: 0x0024, 0x2af8: 0x0024, 0x2af9: 0x0024, 0x2afa: 0x0024, 0x2afb: 0x0024, + 0x2afc: 0x0024, 0x2afd: 0x0024, 0x2afe: 0x2000, 0x2aff: 0x0024, + // Block 0xac, offset 0x2b00 + 0x2b12: 0x0024, 0x2b13: 0x0024, 0x2b14: 0x0024, 0x2b15: 0x0024, 0x2b16: 0x0024, 0x2b17: 0x0024, + 0x2b18: 0x0024, 0x2b19: 0x0024, 0x2b1a: 0x0024, 0x2b1b: 0x0024, 0x2b1c: 0x0024, 0x2b1d: 0x0024, + 0x2b1e: 0x0024, 0x2b1f: 0x0024, 0x2b20: 0x0024, 0x2b21: 0x0024, 0x2b22: 0x0024, 0x2b23: 0x0024, + 0x2b24: 0x0024, 0x2b25: 0x0024, 0x2b26: 0x0024, 0x2b27: 0x0024, 0x2b29: 0x2000, + 0x2b2a: 0x0024, 0x2b2b: 0x0024, 0x2b2c: 0x0024, 0x2b2d: 0x0024, 0x2b2e: 0x0024, 0x2b2f: 0x0024, + 0x2b30: 0x0024, 0x2b31: 0x2000, 0x2b32: 0x0024, 0x2b33: 0x0024, 0x2b34: 0x2000, 0x2b35: 0x0024, + 0x2b36: 0x0024, + // Block 0xad, offset 0x2b40 + 0x2b71: 0x0024, 0x2b72: 0x0024, 0x2b73: 0x0024, 0x2b74: 0x0024, 0x2b75: 0x0024, + 0x2b76: 0x0024, 0x2b7a: 0x0024, + 0x2b7c: 0x0024, 0x2b7d: 0x0024, 0x2b7f: 0x0024, + // Block 0xae, offset 0x2b80 + 0x2b80: 0x0024, 0x2b81: 0x0024, 0x2b82: 0x0024, 0x2b83: 0x0024, 0x2b84: 0x0024, 0x2b85: 0x0024, + 0x2b86: 0x0800, 0x2b87: 0x0024, + // Block 0xaf, offset 0x2bc0 + 0x2bca: 0x2000, 0x2bcb: 0x2000, + 0x2bcc: 0x2000, 0x2bcd: 0x2000, 0x2bce: 0x2000, 0x2bd0: 0x0024, 0x2bd1: 0x0024, + 0x2bd3: 0x2000, 0x2bd4: 0x2000, 0x2bd5: 0x0024, 0x2bd6: 0x2000, 0x2bd7: 0x0024, + // Block 0xb0, offset 0x2c00 + 0x2c33: 0x0024, 0x2c34: 0x0024, 0x2c35: 0x2000, + 0x2c36: 0x2000, + // Block 0xb1, offset 0x2c40 + 0x2c40: 0x0024, 0x2c41: 0x0024, 0x2c42: 0x0800, 0x2c43: 0x2000, 0x2c44: 0x0010, 0x2c45: 0x0010, + 0x2c46: 0x0010, 0x2c47: 0x0010, 0x2c48: 0x0010, 0x2c49: 0x0010, 0x2c4a: 0x0010, 0x2c4b: 0x0010, + 0x2c4c: 0x0010, 0x2c4d: 0x0010, 0x2c4e: 0x0010, 0x2c4f: 0x0010, 0x2c50: 0x0010, + 0x2c52: 0x0010, 0x2c53: 0x0010, 0x2c54: 0x0010, 0x2c55: 0x0010, 0x2c56: 0x0010, 0x2c57: 0x0010, + 0x2c58: 0x0010, 0x2c59: 0x0010, 0x2c5a: 0x0010, 0x2c5b: 0x0010, 0x2c5c: 0x0010, 0x2c5d: 0x0010, + 0x2c5e: 0x0010, 0x2c5f: 0x0010, 0x2c60: 0x0010, 0x2c61: 0x0010, 0x2c62: 0x0010, 0x2c63: 0x0010, + 0x2c64: 0x0010, 0x2c65: 0x0010, 0x2c66: 0x0010, 0x2c67: 0x0010, 0x2c68: 0x0010, 0x2c69: 0x0010, + 0x2c6a: 0x0010, 0x2c6b: 0x0010, 0x2c6c: 0x0010, 0x2c6d: 0x0010, 0x2c6e: 0x0010, 0x2c6f: 0x0010, + 0x2c70: 0x0010, 0x2c71: 0x0010, 0x2c72: 0x0010, 0x2c73: 0x0010, 0x2c74: 0x2000, 0x2c75: 0x2000, + 0x2c76: 0x0024, 0x2c77: 0x0024, 0x2c78: 0x0024, 0x2c79: 0x0024, 0x2c7a: 0x0024, + 0x2c7e: 0x2000, 0x2c7f: 0x2000, + // Block 0xb2, offset 0x2c80 + 0x2c80: 0x0024, 0x2c81: 0x0024, 0x2c82: 0x0044, + 0x2c9a: 0x0024, + // Block 0xb3, offset 0x2cc0 + 0x2cf0: 0x0002, 0x2cf1: 0x0002, 0x2cf2: 0x0002, 0x2cf3: 0x0002, 0x2cf4: 0x0002, 0x2cf5: 0x0002, + 0x2cf6: 0x0002, 0x2cf7: 0x0002, 0x2cf8: 0x0002, 0x2cf9: 0x0002, 0x2cfa: 0x0002, 0x2cfb: 0x0002, + 0x2cfc: 0x0002, 0x2cfd: 0x0002, 0x2cfe: 0x0002, 0x2cff: 0x0002, + // Block 0xb4, offset 0x2d00 + 0x2d00: 0x0024, + 0x2d07: 0x0024, 0x2d08: 0x0024, 0x2d09: 0x0024, 0x2d0a: 0x0024, 0x2d0b: 0x0024, + 0x2d0c: 0x0024, 0x2d0d: 0x0024, 0x2d0e: 0x0024, 0x2d0f: 0x0024, 0x2d10: 0x0024, 0x2d11: 0x0024, + 0x2d12: 0x0024, 0x2d13: 0x0024, 0x2d14: 0x0024, 0x2d15: 0x0024, + // Block 0xb5, offset 0x2d40 + 0x2d5e: 0x0024, 0x2d5f: 0x0024, 0x2d60: 0x0024, 0x2d61: 0x0024, 0x2d62: 0x0024, 0x2d63: 0x0024, + 0x2d64: 0x0024, 0x2d65: 0x0024, 0x2d66: 0x0024, 0x2d67: 0x0024, 0x2d68: 0x0024, 0x2d69: 0x0024, + 0x2d6a: 0x2000, 0x2d6b: 0x2000, 0x2d6c: 0x2000, 0x2d6d: 0x0024, 0x2d6e: 0x0024, 0x2d6f: 0x0024, + // Block 0xb6, offset 0x2d80 + 0x2db0: 0x0024, 0x2db1: 0x0024, 0x2db2: 0x0024, 0x2db3: 0x0024, 0x2db4: 0x0024, + // Block 0xb7, offset 0x2dc0 + 0x2df0: 0x0024, 0x2df1: 0x0024, 0x2df2: 0x0024, 0x2df3: 0x0024, 0x2df4: 0x0024, 0x2df5: 0x0024, + 0x2df6: 0x0024, + // Block 0xb8, offset 0x2e00 + 0x2e23: 0x8000, + 0x2e27: 0x8000, 0x2e28: 0x8000, 0x2e29: 0x8000, + 0x2e2a: 0x8000, + // Block 0xb9, offset 0x2e40 + 0x2e4f: 0x0024, 0x2e51: 0x2000, + 0x2e52: 0x2000, 0x2e53: 0x2000, 0x2e54: 0x2000, 0x2e55: 0x2000, 0x2e56: 0x2000, 0x2e57: 0x2000, + 0x2e58: 0x2000, 0x2e59: 0x2000, 0x2e5a: 0x2000, 0x2e5b: 0x2000, 0x2e5c: 0x2000, 0x2e5d: 0x2000, + 0x2e5e: 0x2000, 0x2e5f: 0x2000, 0x2e60: 0x2000, 0x2e61: 0x2000, 0x2e62: 0x2000, 0x2e63: 0x2000, + 0x2e64: 0x2000, 0x2e65: 0x2000, 0x2e66: 0x2000, 0x2e67: 0x2000, 0x2e68: 0x2000, 0x2e69: 0x2000, + 0x2e6a: 0x2000, 0x2e6b: 0x2000, 0x2e6c: 0x2000, 0x2e6d: 0x2000, 0x2e6e: 0x2000, 0x2e6f: 0x2000, + 0x2e70: 0x2000, 0x2e71: 0x2000, 0x2e72: 0x2000, 0x2e73: 0x2000, 0x2e74: 0x2000, 0x2e75: 0x2000, + 0x2e76: 0x2000, 0x2e77: 0x2000, 0x2e78: 0x2000, 0x2e79: 0x2000, 0x2e7a: 0x2000, 0x2e7b: 0x2000, + 0x2e7c: 0x2000, 0x2e7d: 0x2000, 0x2e7e: 0x2000, 0x2e7f: 0x2000, + // Block 0xba, offset 0x2e80 + 0x2e80: 0x2000, 0x2e81: 0x2000, 0x2e82: 0x2000, 0x2e83: 0x2000, 0x2e84: 0x2000, 0x2e85: 0x2000, + 0x2e86: 0x2000, 0x2e87: 0x2000, + 0x2e8f: 0x0024, 0x2e90: 0x0024, 0x2e91: 0x0024, + 0x2e92: 0x0024, + // Block 0xbb, offset 0x2ec0 + 0x2ee4: 0x0024, + 0x2ef0: 0x0024, 0x2ef1: 0x0024, + // Block 0xbc, offset 0x2f00 + 0x2f1d: 0x0024, + 0x2f1e: 0x0024, 0x2f20: 0x0002, 0x2f21: 0x0002, 0x2f22: 0x0002, 0x2f23: 0x0002, + // Block 0xbd, offset 0x2f40 + 0x2f40: 0x0024, 0x2f41: 0x0024, 0x2f42: 0x0024, 0x2f43: 0x0024, 0x2f44: 0x0024, 0x2f45: 0x0024, + 0x2f46: 0x0024, 0x2f47: 0x0024, 0x2f48: 0x0024, 0x2f49: 0x0024, 0x2f4a: 0x0024, 0x2f4b: 0x0024, + 0x2f4c: 0x0024, 0x2f4d: 0x0024, 0x2f4e: 0x0024, 0x2f4f: 0x0024, 0x2f50: 0x0024, 0x2f51: 0x0024, + 0x2f52: 0x0024, 0x2f53: 0x0024, 0x2f54: 0x0024, 0x2f55: 0x0024, 0x2f56: 0x0024, 0x2f57: 0x0024, + 0x2f58: 0x0024, 0x2f59: 0x0024, 0x2f5a: 0x0024, 0x2f5b: 0x0024, 0x2f5c: 0x0024, 0x2f5d: 0x0024, + 0x2f5e: 0x0024, 0x2f5f: 0x0024, 0x2f60: 0x0024, 0x2f61: 0x0024, 0x2f62: 0x0024, 0x2f63: 0x0024, + 0x2f64: 0x0024, 0x2f65: 0x0024, 0x2f66: 0x0024, 0x2f67: 0x0024, 0x2f68: 0x0024, 0x2f69: 0x0024, + 0x2f6a: 0x0024, 0x2f6b: 0x0024, 0x2f6c: 0x0024, 0x2f6d: 0x0024, + 0x2f70: 0x0024, 0x2f71: 0x0024, 0x2f72: 0x0024, 0x2f73: 0x0024, 0x2f74: 0x0024, 0x2f75: 0x0024, + 0x2f76: 0x0024, 0x2f77: 0x0024, 0x2f78: 0x0024, 0x2f79: 0x0024, 0x2f7a: 0x0024, 0x2f7b: 0x0024, + 0x2f7c: 0x0024, 0x2f7d: 0x0024, 0x2f7e: 0x0024, 0x2f7f: 0x0024, + // Block 0xbe, offset 0x2f80 + 0x2f80: 0x0024, 0x2f81: 0x0024, 0x2f82: 0x0024, 0x2f83: 0x0024, 0x2f84: 0x0024, 0x2f85: 0x0024, + 0x2f86: 0x0024, + // Block 0xbf, offset 0x2fc0 + 0x2fe5: 0x0024, 0x2fe6: 0x0024, 0x2fe7: 0x0024, 0x2fe8: 0x0024, 0x2fe9: 0x0024, + 0x2fed: 0x0024, 0x2fee: 0x0024, 0x2fef: 0x0024, + 0x2ff0: 0x0024, 0x2ff1: 0x0024, 0x2ff2: 0x0024, 0x2ff3: 0x0002, 0x2ff4: 0x0002, 0x2ff5: 0x0002, + 0x2ff6: 0x0002, 0x2ff7: 0x0002, 0x2ff8: 0x0002, 0x2ff9: 0x0002, 0x2ffa: 0x0002, 0x2ffb: 0x0024, + 0x2ffc: 0x0024, 0x2ffd: 0x0024, 0x2ffe: 0x0024, 0x2fff: 0x0024, + // Block 0xc0, offset 0x3000 + 0x3000: 0x0024, 0x3001: 0x0024, 0x3002: 0x0024, 0x3005: 0x0024, + 0x3006: 0x0024, 0x3007: 0x0024, 0x3008: 0x0024, 0x3009: 0x0024, 0x300a: 0x0024, 0x300b: 0x0024, + 0x302a: 0x0024, 0x302b: 0x0024, 0x302c: 0x0024, 0x302d: 0x0024, + // Block 0xc1, offset 0x3040 + 0x3042: 0x0024, 0x3043: 0x0024, 0x3044: 0x0024, + // Block 0xc2, offset 0x3080 + 0x3080: 0x0024, 0x3081: 0x0024, 0x3082: 0x0024, 0x3083: 0x0024, 0x3084: 0x0024, 0x3085: 0x0024, + 0x3086: 0x0024, 0x3087: 0x0024, 0x3088: 0x0024, 0x3089: 0x0024, 0x308a: 0x0024, 0x308b: 0x0024, + 0x308c: 0x0024, 0x308d: 0x0024, 0x308e: 0x0024, 0x308f: 0x0024, 0x3090: 0x0024, 0x3091: 0x0024, + 0x3092: 0x0024, 0x3093: 0x0024, 0x3094: 0x0024, 0x3095: 0x0024, 0x3096: 0x0024, 0x3097: 0x0024, + 0x3098: 0x0024, 0x3099: 0x0024, 0x309a: 0x0024, 0x309b: 0x0024, 0x309c: 0x0024, 0x309d: 0x0024, + 0x309e: 0x0024, 0x309f: 0x0024, 0x30a0: 0x0024, 0x30a1: 0x0024, 0x30a2: 0x0024, 0x30a3: 0x0024, + 0x30a4: 0x0024, 0x30a5: 0x0024, 0x30a6: 0x0024, 0x30a7: 0x0024, 0x30a8: 0x0024, 0x30a9: 0x0024, + 0x30aa: 0x0024, 0x30ab: 0x0024, 0x30ac: 0x0024, 0x30ad: 0x0024, 0x30ae: 0x0024, 0x30af: 0x0024, + 0x30b0: 0x0024, 0x30b1: 0x0024, 0x30b2: 0x0024, 0x30b3: 0x0024, 0x30b4: 0x0024, 0x30b5: 0x0024, + 0x30b6: 0x0024, 0x30bb: 0x0024, + 0x30bc: 0x0024, 0x30bd: 0x0024, 0x30be: 0x0024, 0x30bf: 0x0024, + // Block 0xc3, offset 0x30c0 + 0x30c0: 0x0024, 0x30c1: 0x0024, 0x30c2: 0x0024, 0x30c3: 0x0024, 0x30c4: 0x0024, 0x30c5: 0x0024, + 0x30c6: 0x0024, 0x30c7: 0x0024, 0x30c8: 0x0024, 0x30c9: 0x0024, 0x30ca: 0x0024, 0x30cb: 0x0024, + 0x30cc: 0x0024, 0x30cd: 0x0024, 0x30ce: 0x0024, 0x30cf: 0x0024, 0x30d0: 0x0024, 0x30d1: 0x0024, + 0x30d2: 0x0024, 0x30d3: 0x0024, 0x30d4: 0x0024, 0x30d5: 0x0024, 0x30d6: 0x0024, 0x30d7: 0x0024, + 0x30d8: 0x0024, 0x30d9: 0x0024, 0x30da: 0x0024, 0x30db: 0x0024, 0x30dc: 0x0024, 0x30dd: 0x0024, + 0x30de: 0x0024, 0x30df: 0x0024, 0x30e0: 0x0024, 0x30e1: 0x0024, 0x30e2: 0x0024, 0x30e3: 0x0024, + 0x30e4: 0x0024, 0x30e5: 0x0024, 0x30e6: 0x0024, 0x30e7: 0x0024, 0x30e8: 0x0024, 0x30e9: 0x0024, + 0x30ea: 0x0024, 0x30eb: 0x0024, 0x30ec: 0x0024, + 0x30f5: 0x0024, + // Block 0xc4, offset 0x3100 + 0x3104: 0x0024, + 0x311b: 0x0024, 0x311c: 0x0024, 0x311d: 0x0024, + 0x311e: 0x0024, 0x311f: 0x0024, 0x3121: 0x0024, 0x3122: 0x0024, 0x3123: 0x0024, + 0x3124: 0x0024, 0x3125: 0x0024, 0x3126: 0x0024, 0x3127: 0x0024, 0x3128: 0x0024, 0x3129: 0x0024, + 0x312a: 0x0024, 0x312b: 0x0024, 0x312c: 0x0024, 0x312d: 0x0024, 0x312e: 0x0024, 0x312f: 0x0024, + // Block 0xc5, offset 0x3140 + 0x3140: 0x0024, 0x3141: 0x0024, 0x3142: 0x0024, 0x3143: 0x0024, 0x3144: 0x0024, 0x3145: 0x0024, + 0x3146: 0x0024, 0x3148: 0x0024, 0x3149: 0x0024, 0x314a: 0x0024, 0x314b: 0x0024, + 0x314c: 0x0024, 0x314d: 0x0024, 0x314e: 0x0024, 0x314f: 0x0024, 0x3150: 0x0024, 0x3151: 0x0024, + 0x3152: 0x0024, 0x3153: 0x0024, 0x3154: 0x0024, 0x3155: 0x0024, 0x3156: 0x0024, 0x3157: 0x0024, + 0x3158: 0x0024, 0x315b: 0x0024, 0x315c: 0x0024, 0x315d: 0x0024, + 0x315e: 0x0024, 0x315f: 0x0024, 0x3160: 0x0024, 0x3161: 0x0024, 0x3163: 0x0024, + 0x3164: 0x0024, 0x3166: 0x0024, 0x3167: 0x0024, 0x3168: 0x0024, 0x3169: 0x0024, + 0x316a: 0x0024, + // Block 0xc6, offset 0x3180 + 0x318f: 0x0024, + // Block 0xc7, offset 0x31c0 + 0x31ee: 0x0024, + // Block 0xc8, offset 0x3200 + 0x322c: 0x0024, 0x322d: 0x0024, 0x322e: 0x0024, 0x322f: 0x0024, + // Block 0xc9, offset 0x3240 + 0x326e: 0x0024, 0x326f: 0x0024, + // Block 0xca, offset 0x3280 + 0x32a3: 0x0024, + 0x32a6: 0x0024, + 0x32ae: 0x0024, 0x32af: 0x0024, + 0x32b5: 0x0024, + // Block 0xcb, offset 0x32c0 + 0x32d0: 0x0024, 0x32d1: 0x0024, + 0x32d2: 0x0024, 0x32d3: 0x0024, 0x32d4: 0x0024, 0x32d5: 0x0024, 0x32d6: 0x0024, + // Block 0xcc, offset 0x3300 + 0x3304: 0x0024, 0x3305: 0x0024, + 0x3306: 0x0024, 0x3307: 0x0024, 0x3308: 0x0024, 0x3309: 0x0024, 0x330a: 0x0024, + // Block 0xcd, offset 0x3340 + 0x3344: 0x0008, + 0x336c: 0x0008, 0x336d: 0x0008, 0x336e: 0x0008, 0x336f: 0x0008, + // Block 0xce, offset 0x3380 + 0x3394: 0x0008, 0x3395: 0x0008, 0x3396: 0x0008, 0x3397: 0x0008, + 0x3398: 0x0008, 0x3399: 0x0008, 0x339a: 0x0008, 0x339b: 0x0008, 0x339c: 0x0008, 0x339d: 0x0008, + 0x339e: 0x0008, 0x339f: 0x0008, + 0x33af: 0x0008, + 0x33b0: 0x0008, + // Block 0xcf, offset 0x33c0 + 0x33c0: 0x0008, + 0x33cf: 0x0008, 0x33d0: 0x0008, + 0x33f6: 0x0008, 0x33f7: 0x0008, 0x33f8: 0x0008, 0x33f9: 0x0008, 0x33fa: 0x0008, 0x33fb: 0x0008, + 0x33fc: 0x0008, 0x33fd: 0x0008, 0x33fe: 0x0008, 0x33ff: 0x0008, + // Block 0xd0, offset 0x3400 + 0x3430: 0x0008, 0x3431: 0x0008, + 0x343e: 0x0008, 0x343f: 0x0008, + // Block 0xd1, offset 0x3440 + 0x344e: 0x0008, 0x3451: 0x0008, + 0x3452: 0x0008, 0x3453: 0x0008, 0x3454: 0x0008, 0x3455: 0x0008, 0x3456: 0x0008, 0x3457: 0x0008, + 0x3458: 0x0008, 0x3459: 0x0008, 0x345a: 0x0008, + 0x346e: 0x0008, 0x346f: 0x0008, + 0x3470: 0x0008, 0x3471: 0x0008, 0x3472: 0x0008, 0x3473: 0x0008, 0x3474: 0x0008, 0x3475: 0x0008, + 0x3476: 0x0008, 0x3477: 0x0008, 0x3478: 0x0008, 0x3479: 0x0008, 0x347a: 0x0008, 0x347b: 0x0008, + 0x347c: 0x0008, 0x347d: 0x0008, 0x347e: 0x0008, 0x347f: 0x0008, + // Block 0xd2, offset 0x3480 + 0x3480: 0x0008, 0x3481: 0x0008, 0x3482: 0x0008, 0x3483: 0x0008, 0x3484: 0x0008, 0x3485: 0x0008, + 0x3486: 0x0008, 0x3487: 0x0008, 0x3488: 0x0008, 0x3489: 0x0008, 0x348a: 0x0008, 0x348b: 0x0008, + 0x348c: 0x0008, 0x348d: 0x0008, 0x348e: 0x0008, 0x348f: 0x0008, 0x3490: 0x0008, 0x3491: 0x0008, + 0x3492: 0x0008, 0x3493: 0x0008, 0x3494: 0x0008, 0x3495: 0x0008, 0x3496: 0x0008, 0x3497: 0x0008, + 0x3498: 0x0008, 0x3499: 0x0008, 0x349a: 0x0008, 0x349b: 0x0008, 0x349c: 0x0008, 0x349d: 0x0008, + 0x349e: 0x0008, 0x349f: 0x0008, 0x34a0: 0x0008, 0x34a1: 0x0008, 0x34a2: 0x0008, 0x34a3: 0x0008, + 0x34a4: 0x0008, 0x34a5: 0x0008, 0x34a6: 0x1000, 0x34a7: 0x1000, 0x34a8: 0x1000, 0x34a9: 0x1000, + 0x34aa: 0x1000, 0x34ab: 0x1000, 0x34ac: 0x1000, 0x34ad: 0x1000, 0x34ae: 0x1000, 0x34af: 0x1000, + 0x34b0: 0x1000, 0x34b1: 0x1000, 0x34b2: 0x1000, 0x34b3: 0x1000, 0x34b4: 0x1000, 0x34b5: 0x1000, + 0x34b6: 0x1000, 0x34b7: 0x1000, 0x34b8: 0x1000, 0x34b9: 0x1000, 0x34ba: 0x1000, 0x34bb: 0x1000, + 0x34bc: 0x1000, 0x34bd: 0x1000, 0x34be: 0x1000, 0x34bf: 0x1000, + // Block 0xd3, offset 0x34c0 + 0x34c1: 0x0008, 0x34c2: 0x0008, 0x34c3: 0x0008, 0x34c4: 0x0008, 0x34c5: 0x0008, + 0x34c6: 0x0008, 0x34c7: 0x0008, 0x34c8: 0x0008, 0x34c9: 0x0008, 0x34ca: 0x0008, 0x34cb: 0x0008, + 0x34cc: 0x0008, 0x34cd: 0x0008, 0x34ce: 0x0008, 0x34cf: 0x0008, + 0x34da: 0x0008, + 0x34ef: 0x0008, + 0x34f2: 0x0008, 0x34f3: 0x0008, 0x34f4: 0x0008, 0x34f5: 0x0008, + 0x34f6: 0x0008, 0x34f7: 0x0008, 0x34f8: 0x0008, 0x34f9: 0x0008, 0x34fa: 0x0008, + 0x34fc: 0x0008, 0x34fd: 0x0008, 0x34fe: 0x0008, 0x34ff: 0x0008, + // Block 0xd4, offset 0x3500 + 0x3509: 0x0008, 0x350a: 0x0008, 0x350b: 0x0008, + 0x350c: 0x0008, 0x350d: 0x0008, 0x350e: 0x0008, 0x350f: 0x0008, 0x3510: 0x0008, 0x3511: 0x0008, + 0x3512: 0x0008, 0x3513: 0x0008, 0x3514: 0x0008, 0x3515: 0x0008, 0x3516: 0x0008, 0x3517: 0x0008, + 0x3518: 0x0008, 0x3519: 0x0008, 0x351a: 0x0008, 0x351b: 0x0008, 0x351c: 0x0008, 0x351d: 0x0008, + 0x351e: 0x0008, 0x351f: 0x0008, + 0x3526: 0x0008, 0x3527: 0x0008, 0x3528: 0x0008, 0x3529: 0x0008, + 0x352a: 0x0008, 0x352b: 0x0008, 0x352c: 0x0008, 0x352d: 0x0008, 0x352e: 0x0008, 0x352f: 0x0008, + 0x3530: 0x0008, 0x3531: 0x0008, 0x3532: 0x0008, 0x3533: 0x0008, 0x3534: 0x0008, 0x3535: 0x0008, + 0x3536: 0x0008, 0x3537: 0x0008, 0x3538: 0x0008, 0x3539: 0x0008, 0x353a: 0x0008, 0x353b: 0x0008, + 0x353c: 0x0008, 0x353d: 0x0008, 0x353e: 0x0008, 0x353f: 0x0008, + // Block 0xd5, offset 0x3540 + 0x3540: 0x0008, 0x3541: 0x0008, 0x3542: 0x0008, 0x3543: 0x0008, 0x3544: 0x0008, 0x3545: 0x0008, + 0x3546: 0x0008, 0x3547: 0x0008, 0x3548: 0x0008, 0x3549: 0x0008, 0x354a: 0x0008, 0x354b: 0x0008, + 0x354c: 0x0008, 0x354d: 0x0008, 0x354e: 0x0008, 0x354f: 0x0008, 0x3550: 0x0008, 0x3551: 0x0008, + 0x3552: 0x0008, 0x3553: 0x0008, 0x3554: 0x0008, 0x3555: 0x0008, 0x3556: 0x0008, 0x3557: 0x0008, + 0x3558: 0x0008, 0x3559: 0x0008, 0x355a: 0x0008, 0x355b: 0x0008, 0x355c: 0x0008, 0x355d: 0x0008, + 0x355e: 0x0008, 0x355f: 0x0008, 0x3560: 0x0008, 0x3561: 0x0008, 0x3562: 0x0008, 0x3563: 0x0008, + 0x3564: 0x0008, 0x3565: 0x0008, 0x3566: 0x0008, 0x3567: 0x0008, 0x3568: 0x0008, 0x3569: 0x0008, + 0x356a: 0x0008, 0x356b: 0x0008, 0x356c: 0x0008, 0x356d: 0x0008, 0x356e: 0x0008, 0x356f: 0x0008, + 0x3570: 0x0008, 0x3571: 0x0008, 0x3572: 0x0008, 0x3573: 0x0008, 0x3574: 0x0008, 0x3575: 0x0008, + 0x3576: 0x0008, 0x3577: 0x0008, 0x3578: 0x0008, 0x3579: 0x0008, 0x357a: 0x0008, 0x357b: 0x0008, + 0x357c: 0x0008, 0x357d: 0x0008, 0x357e: 0x0008, 0x357f: 0x0008, + // Block 0xd6, offset 0x3580 + 0x3580: 0x0008, 0x3581: 0x0008, 0x3582: 0x0008, 0x3583: 0x0008, 0x3584: 0x0008, 0x3585: 0x0008, + 0x3586: 0x0008, 0x3587: 0x0008, 0x3588: 0x0008, 0x3589: 0x0008, 0x358a: 0x0008, 0x358b: 0x0008, + 0x358c: 0x0008, 0x358d: 0x0008, 0x358e: 0x0008, 0x358f: 0x0008, 0x3590: 0x0008, 0x3591: 0x0008, + 0x3592: 0x0008, 0x3593: 0x0008, 0x3594: 0x0008, 0x3595: 0x0008, 0x3596: 0x0008, 0x3597: 0x0008, + 0x3598: 0x0008, 0x3599: 0x0008, 0x359a: 0x0008, 0x359b: 0x0008, 0x359c: 0x0008, 0x359d: 0x0008, + 0x359e: 0x0008, 0x359f: 0x0008, 0x35a0: 0x0008, 0x35a1: 0x0008, + 0x35a4: 0x0008, 0x35a5: 0x0008, 0x35a6: 0x0008, 0x35a7: 0x0008, 0x35a8: 0x0008, 0x35a9: 0x0008, + 0x35aa: 0x0008, 0x35ab: 0x0008, 0x35ac: 0x0008, 0x35ad: 0x0008, 0x35ae: 0x0008, 0x35af: 0x0008, + 0x35b0: 0x0008, 0x35b1: 0x0008, 0x35b2: 0x0008, 0x35b3: 0x0008, 0x35b4: 0x0008, 0x35b5: 0x0008, + 0x35b6: 0x0008, 0x35b7: 0x0008, 0x35b8: 0x0008, 0x35b9: 0x0008, 0x35ba: 0x0008, 0x35bb: 0x0008, + 0x35bc: 0x0008, 0x35bd: 0x0008, 0x35be: 0x0008, 0x35bf: 0x0008, + // Block 0xd7, offset 0x35c0 + 0x35c0: 0x0008, 0x35c1: 0x0008, 0x35c2: 0x0008, 0x35c3: 0x0008, 0x35c4: 0x0008, 0x35c5: 0x0008, + 0x35c6: 0x0008, 0x35c7: 0x0008, 0x35c8: 0x0008, 0x35c9: 0x0008, 0x35ca: 0x0008, 0x35cb: 0x0008, + 0x35cc: 0x0008, 0x35cd: 0x0008, 0x35ce: 0x0008, 0x35cf: 0x0008, 0x35d0: 0x0008, 0x35d1: 0x0008, + 0x35d2: 0x0008, 0x35d3: 0x0008, 0x35d6: 0x0008, 0x35d7: 0x0008, + 0x35d9: 0x0008, 0x35da: 0x0008, 0x35db: 0x0008, + 0x35de: 0x0008, 0x35df: 0x0008, 0x35e0: 0x0008, 0x35e1: 0x0008, 0x35e2: 0x0008, 0x35e3: 0x0008, + 0x35e4: 0x0008, 0x35e5: 0x0008, 0x35e6: 0x0008, 0x35e7: 0x0008, 0x35e8: 0x0008, 0x35e9: 0x0008, + 0x35ea: 0x0008, 0x35eb: 0x0008, 0x35ec: 0x0008, 0x35ed: 0x0008, 0x35ee: 0x0008, 0x35ef: 0x0008, + 0x35f0: 0x0008, 0x35f1: 0x0008, 0x35f2: 0x0008, 0x35f3: 0x0008, 0x35f4: 0x0008, 0x35f5: 0x0008, + 0x35f6: 0x0008, 0x35f7: 0x0008, 0x35f8: 0x0008, 0x35f9: 0x0008, 0x35fa: 0x0008, 0x35fb: 0x0008, + 0x35fc: 0x0008, 0x35fd: 0x0008, 0x35fe: 0x0008, 0x35ff: 0x0008, + // Block 0xd8, offset 0x3600 + 0x3600: 0x0008, 0x3601: 0x0008, 0x3602: 0x0008, 0x3603: 0x0008, 0x3604: 0x0008, 0x3605: 0x0008, + 0x3606: 0x0008, 0x3607: 0x0008, 0x3608: 0x0008, 0x3609: 0x0008, 0x360a: 0x0008, 0x360b: 0x0008, + 0x360c: 0x0008, 0x360d: 0x0008, 0x360e: 0x0008, 0x360f: 0x0008, 0x3610: 0x0008, 0x3611: 0x0008, + 0x3612: 0x0008, 0x3613: 0x0008, 0x3614: 0x0008, 0x3615: 0x0008, 0x3616: 0x0008, 0x3617: 0x0008, + 0x3618: 0x0008, 0x3619: 0x0008, 0x361a: 0x0008, 0x361b: 0x0008, 0x361c: 0x0008, 0x361d: 0x0008, + 0x361e: 0x0008, 0x361f: 0x0008, 0x3620: 0x0008, 0x3621: 0x0008, 0x3622: 0x0008, 0x3623: 0x0008, + 0x3624: 0x0008, 0x3625: 0x0008, 0x3626: 0x0008, 0x3627: 0x0008, 0x3628: 0x0008, 0x3629: 0x0008, + 0x362a: 0x0008, 0x362b: 0x0008, 0x362c: 0x0008, 0x362d: 0x0008, 0x362e: 0x0008, 0x362f: 0x0008, + 0x3630: 0x0008, 0x3633: 0x0008, 0x3634: 0x0008, 0x3635: 0x0008, + 0x3637: 0x0008, 0x3638: 0x0008, 0x3639: 0x0008, 0x363a: 0x0008, 0x363b: 0x0024, + 0x363c: 0x0024, 0x363d: 0x0024, 0x363e: 0x0024, 0x363f: 0x0024, + // Block 0xd9, offset 0x3640 + 0x3640: 0x0008, 0x3641: 0x0008, 0x3642: 0x0008, 0x3643: 0x0008, 0x3644: 0x0008, 0x3645: 0x0008, + 0x3646: 0x0008, 0x3647: 0x0008, 0x3648: 0x0008, 0x3649: 0x0008, 0x364a: 0x0008, 0x364b: 0x0008, + 0x364c: 0x0008, 0x364d: 0x0008, 0x364e: 0x0008, 0x364f: 0x0008, 0x3650: 0x0008, 0x3651: 0x0008, + 0x3652: 0x0008, 0x3653: 0x0008, 0x3654: 0x0008, 0x3655: 0x0008, 0x3656: 0x0008, 0x3657: 0x0008, + 0x3658: 0x0008, 0x3659: 0x0008, 0x365a: 0x0008, 0x365b: 0x0008, 0x365c: 0x0008, 0x365d: 0x0008, + 0x365e: 0x0008, 0x365f: 0x0008, 0x3660: 0x0008, 0x3661: 0x0008, 0x3662: 0x0008, 0x3663: 0x0008, + 0x3664: 0x0008, 0x3665: 0x0008, 0x3666: 0x0008, 0x3667: 0x0008, 0x3668: 0x0008, 0x3669: 0x0008, + 0x366a: 0x0008, 0x366b: 0x0008, 0x366c: 0x0008, 0x366d: 0x0008, 0x366e: 0x0008, 0x366f: 0x0008, + 0x3670: 0x0008, 0x3671: 0x0008, 0x3672: 0x0008, 0x3673: 0x0008, 0x3674: 0x0008, 0x3675: 0x0008, + 0x3676: 0x0008, 0x3677: 0x0008, 0x3678: 0x0008, 0x3679: 0x0008, 0x367a: 0x0008, 0x367b: 0x0008, + 0x367c: 0x0008, 0x367d: 0x0008, 0x367f: 0x0008, + // Block 0xda, offset 0x3680 + 0x3680: 0x0008, 0x3681: 0x0008, 0x3682: 0x0008, 0x3683: 0x0008, 0x3684: 0x0008, 0x3685: 0x0008, + 0x3686: 0x0008, 0x3687: 0x0008, 0x3688: 0x0008, 0x3689: 0x0008, 0x368a: 0x0008, 0x368b: 0x0008, + 0x368c: 0x0008, 0x368d: 0x0008, 0x368e: 0x0008, 0x368f: 0x0008, 0x3690: 0x0008, 0x3691: 0x0008, + 0x3692: 0x0008, 0x3693: 0x0008, 0x3694: 0x0008, 0x3695: 0x0008, 0x3696: 0x0008, 0x3697: 0x0008, + 0x3698: 0x0008, 0x3699: 0x0008, 0x369a: 0x0008, 0x369b: 0x0008, 0x369c: 0x0008, 0x369d: 0x0008, + 0x369e: 0x0008, 0x369f: 0x0008, 0x36a0: 0x0008, 0x36a1: 0x0008, 0x36a2: 0x0008, 0x36a3: 0x0008, + 0x36a4: 0x0008, 0x36a5: 0x0008, 0x36a6: 0x0008, 0x36a7: 0x0008, 0x36a8: 0x0008, 0x36a9: 0x0008, + 0x36aa: 0x0008, 0x36ab: 0x0008, 0x36ac: 0x0008, 0x36ad: 0x0008, 0x36ae: 0x0008, 0x36af: 0x0008, + 0x36b0: 0x0008, 0x36b1: 0x0008, 0x36b2: 0x0008, 0x36b3: 0x0008, 0x36b4: 0x0008, 0x36b5: 0x0008, + 0x36b6: 0x0008, 0x36b7: 0x0008, 0x36b8: 0x0008, 0x36b9: 0x0008, 0x36ba: 0x0008, 0x36bb: 0x0008, + 0x36bc: 0x0008, 0x36bd: 0x0008, + // Block 0xdb, offset 0x36c0 + 0x36c9: 0x0008, 0x36ca: 0x0008, 0x36cb: 0x0008, + 0x36cc: 0x0008, 0x36cd: 0x0008, 0x36ce: 0x0008, 0x36d0: 0x0008, 0x36d1: 0x0008, + 0x36d2: 0x0008, 0x36d3: 0x0008, 0x36d4: 0x0008, 0x36d5: 0x0008, 0x36d6: 0x0008, 0x36d7: 0x0008, + 0x36d8: 0x0008, 0x36d9: 0x0008, 0x36da: 0x0008, 0x36db: 0x0008, 0x36dc: 0x0008, 0x36dd: 0x0008, + 0x36de: 0x0008, 0x36df: 0x0008, 0x36e0: 0x0008, 0x36e1: 0x0008, 0x36e2: 0x0008, 0x36e3: 0x0008, + 0x36e4: 0x0008, 0x36e5: 0x0008, 0x36e6: 0x0008, 0x36e7: 0x0008, + 0x36ef: 0x0008, + 0x36f0: 0x0008, 0x36f3: 0x0008, 0x36f4: 0x0008, 0x36f5: 0x0008, + 0x36f6: 0x0008, 0x36f7: 0x0008, 0x36f8: 0x0008, 0x36f9: 0x0008, 0x36fa: 0x0008, + // Block 0xdc, offset 0x3700 + 0x3707: 0x0008, 0x370a: 0x0008, 0x370b: 0x0008, + 0x370c: 0x0008, 0x370d: 0x0008, 0x3710: 0x0008, + 0x3715: 0x0008, 0x3716: 0x0008, + 0x3724: 0x0008, 0x3725: 0x0008, 0x3728: 0x0008, + 0x3731: 0x0008, 0x3732: 0x0008, + 0x373c: 0x0008, + // Block 0xdd, offset 0x3740 + 0x3742: 0x0008, 0x3743: 0x0008, 0x3744: 0x0008, + 0x3751: 0x0008, + 0x3752: 0x0008, 0x3753: 0x0008, + 0x375c: 0x0008, 0x375d: 0x0008, + 0x375e: 0x0008, 0x3761: 0x0008, 0x3763: 0x0008, + 0x3768: 0x0008, + 0x376f: 0x0008, + 0x3773: 0x0008, + 0x377a: 0x0008, 0x377b: 0x0008, + 0x377c: 0x0008, 0x377d: 0x0008, 0x377e: 0x0008, 0x377f: 0x0008, + // Block 0xde, offset 0x3780 + 0x3780: 0x0008, 0x3781: 0x0008, 0x3782: 0x0008, 0x3783: 0x0008, 0x3784: 0x0008, 0x3785: 0x0008, + 0x3786: 0x0008, 0x3787: 0x0008, 0x3788: 0x0008, 0x3789: 0x0008, 0x378a: 0x0008, 0x378b: 0x0008, + 0x378c: 0x0008, 0x378d: 0x0008, 0x378e: 0x0008, 0x378f: 0x0008, + // Block 0xdf, offset 0x37c0 + 0x37c0: 0x0008, 0x37c1: 0x0008, 0x37c2: 0x0008, 0x37c3: 0x0008, 0x37c4: 0x0008, 0x37c5: 0x0008, + 0x37cb: 0x0008, + 0x37cc: 0x0008, 0x37cd: 0x0008, 0x37ce: 0x0008, 0x37cf: 0x0008, 0x37d0: 0x0008, 0x37d1: 0x0008, + 0x37d2: 0x0008, 0x37d5: 0x0008, 0x37d6: 0x0008, 0x37d7: 0x0008, + 0x37d8: 0x0008, 0x37d9: 0x0008, 0x37da: 0x0008, 0x37db: 0x0008, 0x37dc: 0x0008, 0x37dd: 0x0008, + 0x37de: 0x0008, 0x37df: 0x0008, 0x37e0: 0x0008, 0x37e1: 0x0008, 0x37e2: 0x0008, 0x37e3: 0x0008, + 0x37e4: 0x0008, 0x37e5: 0x0008, 0x37e9: 0x0008, + 0x37eb: 0x0008, 0x37ec: 0x0008, 0x37ed: 0x0008, 0x37ee: 0x0008, 0x37ef: 0x0008, + 0x37f0: 0x0008, 0x37f3: 0x0008, 0x37f4: 0x0008, 0x37f5: 0x0008, + 0x37f6: 0x0008, 0x37f7: 0x0008, 0x37f8: 0x0008, 0x37f9: 0x0008, 0x37fa: 0x0008, 0x37fb: 0x0008, + 0x37fc: 0x0008, 0x37fd: 0x0008, 0x37fe: 0x0008, 0x37ff: 0x0008, + // Block 0xe0, offset 0x3800 + 0x381a: 0x0008, 0x381b: 0x0008, 0x381c: 0x0008, 0x381d: 0x0008, + 0x381e: 0x0008, 0x381f: 0x0008, 0x3820: 0x0008, 0x3821: 0x0008, 0x3822: 0x0008, 0x3823: 0x0008, + 0x3824: 0x0008, 0x3825: 0x0008, 0x3826: 0x0008, 0x3827: 0x0008, 0x3828: 0x0008, 0x3829: 0x0008, + 0x382a: 0x0008, 0x382b: 0x0008, 0x382c: 0x0008, 0x382d: 0x0008, 0x382e: 0x0008, 0x382f: 0x0008, + 0x3830: 0x0008, 0x3831: 0x0008, 0x3832: 0x0008, 0x3833: 0x0008, 0x3834: 0x0008, 0x3835: 0x0008, + 0x3836: 0x0008, 0x3837: 0x0008, 0x3838: 0x0008, 0x3839: 0x0008, 0x383a: 0x0008, 0x383b: 0x0008, + 0x383c: 0x0008, 0x383d: 0x0008, 0x383e: 0x0008, 0x383f: 0x0008, + // Block 0xe1, offset 0x3840 + 0x384c: 0x0008, 0x384d: 0x0008, 0x384e: 0x0008, 0x384f: 0x0008, + // Block 0xe2, offset 0x3880 + 0x3888: 0x0008, 0x3889: 0x0008, 0x388a: 0x0008, 0x388b: 0x0008, + 0x388c: 0x0008, 0x388d: 0x0008, 0x388e: 0x0008, 0x388f: 0x0008, + 0x389a: 0x0008, 0x389b: 0x0008, 0x389c: 0x0008, 0x389d: 0x0008, + 0x389e: 0x0008, 0x389f: 0x0008, + // Block 0xe3, offset 0x38c0 + 0x38c8: 0x0008, 0x38c9: 0x0008, 0x38ca: 0x0008, 0x38cb: 0x0008, + 0x38cc: 0x0008, 0x38cd: 0x0008, 0x38ce: 0x0008, 0x38cf: 0x0008, + 0x38ee: 0x0008, 0x38ef: 0x0008, + 0x38fc: 0x0008, 0x38fd: 0x0008, 0x38fe: 0x0008, 0x38ff: 0x0008, + // Block 0xe4, offset 0x3900 + 0x3902: 0x0008, 0x3903: 0x0008, 0x3904: 0x0008, 0x3905: 0x0008, + 0x3906: 0x0008, 0x3907: 0x0008, 0x3908: 0x0008, 0x3909: 0x0008, 0x390a: 0x0008, 0x390b: 0x0008, + 0x390c: 0x0008, 0x390d: 0x0008, 0x390e: 0x0008, 0x390f: 0x0008, + 0x3919: 0x0008, 0x391a: 0x0008, 0x391b: 0x0008, 0x391c: 0x0008, 0x391d: 0x0008, + 0x391e: 0x0008, 0x391f: 0x0008, 0x3920: 0x0008, 0x3921: 0x0008, 0x3922: 0x0008, 0x3923: 0x0008, + 0x3924: 0x0008, 0x3925: 0x0008, 0x3926: 0x0008, 0x3927: 0x0008, 0x3928: 0x0008, 0x3929: 0x0008, + 0x392a: 0x0008, 0x392b: 0x0008, 0x392c: 0x0008, 0x392d: 0x0008, 0x392e: 0x0008, 0x392f: 0x0008, + 0x3930: 0x0008, 0x3931: 0x0008, 0x3932: 0x0008, 0x3933: 0x0008, 0x3934: 0x0008, 0x3935: 0x0008, + 0x3936: 0x0008, 0x3937: 0x0008, 0x3938: 0x0008, 0x3939: 0x0008, 0x393a: 0x0008, 0x393b: 0x0008, + 0x393c: 0x0008, 0x393d: 0x0008, 0x393e: 0x0008, 0x393f: 0x0008, + // Block 0xe5, offset 0x3940 + 0x394c: 0x0008, 0x394d: 0x0008, 0x394e: 0x0008, 0x394f: 0x0008, 0x3950: 0x0008, 0x3951: 0x0008, + 0x3952: 0x0008, 0x3953: 0x0008, 0x3954: 0x0008, 0x3955: 0x0008, 0x3956: 0x0008, 0x3957: 0x0008, + 0x3958: 0x0008, 0x3959: 0x0008, 0x395a: 0x0008, 0x395b: 0x0008, 0x395c: 0x0008, 0x395d: 0x0008, + 0x395e: 0x0008, 0x395f: 0x0008, 0x3960: 0x0008, 0x3961: 0x0008, 0x3962: 0x0008, 0x3963: 0x0008, + 0x3964: 0x0008, 0x3965: 0x0008, 0x3966: 0x0008, 0x3967: 0x0008, 0x3968: 0x0008, 0x3969: 0x0008, + 0x396a: 0x0008, 0x396b: 0x0008, 0x396c: 0x0008, 0x396d: 0x0008, 0x396e: 0x0008, 0x396f: 0x0008, + 0x3970: 0x0008, 0x3971: 0x0008, 0x3972: 0x0008, 0x3973: 0x0008, 0x3974: 0x0008, 0x3975: 0x0008, + 0x3976: 0x0008, 0x3977: 0x0008, 0x3978: 0x0008, 0x3979: 0x0008, 0x397a: 0x0008, + 0x397c: 0x0008, 0x397d: 0x0008, 0x397e: 0x0008, 0x397f: 0x0008, + // Block 0xe6, offset 0x3980 + 0x3980: 0x0008, 0x3981: 0x0008, 0x3982: 0x0008, 0x3983: 0x0008, 0x3984: 0x0008, 0x3985: 0x0008, + 0x3987: 0x0008, 0x3988: 0x0008, 0x3989: 0x0008, 0x398a: 0x0008, 0x398b: 0x0008, + 0x398c: 0x0008, 0x398d: 0x0008, 0x398e: 0x0008, 0x398f: 0x0008, 0x3990: 0x0008, 0x3991: 0x0008, + 0x3992: 0x0008, 0x3993: 0x0008, 0x3994: 0x0008, 0x3995: 0x0008, 0x3996: 0x0008, 0x3997: 0x0008, + 0x3998: 0x0008, 0x3999: 0x0008, 0x399a: 0x0008, 0x399b: 0x0008, 0x399c: 0x0008, 0x399d: 0x0008, + 0x399e: 0x0008, 0x399f: 0x0008, 0x39a0: 0x0008, 0x39a1: 0x0008, 0x39a2: 0x0008, 0x39a3: 0x0008, + 0x39a4: 0x0008, 0x39a5: 0x0008, 0x39a6: 0x0008, 0x39a7: 0x0008, 0x39a8: 0x0008, 0x39a9: 0x0008, + 0x39aa: 0x0008, 0x39ab: 0x0008, 0x39ac: 0x0008, 0x39ad: 0x0008, 0x39ae: 0x0008, 0x39af: 0x0008, + 0x39b0: 0x0008, 0x39b1: 0x0008, 0x39b2: 0x0008, 0x39b3: 0x0008, 0x39b4: 0x0008, 0x39b5: 0x0008, + 0x39b6: 0x0008, 0x39b7: 0x0008, 0x39b8: 0x0008, 0x39b9: 0x0008, 0x39ba: 0x0008, 0x39bb: 0x0008, + 0x39bc: 0x0008, 0x39bd: 0x0008, 0x39be: 0x0008, 0x39bf: 0x0008, + // Block 0xe7, offset 0x39c0 + 0x39d8: 0x0008, 0x39d9: 0x0008, 0x39da: 0x0008, 0x39db: 0x0008, 0x39dc: 0x0008, 0x39dd: 0x0008, + 0x39de: 0x0008, 0x39df: 0x0008, + 0x39ee: 0x0008, 0x39ef: 0x0008, + 0x39f0: 0x0008, 0x39f1: 0x0008, 0x39f2: 0x0008, 0x39f3: 0x0008, 0x39f4: 0x0008, 0x39f5: 0x0008, + 0x39f6: 0x0008, 0x39f7: 0x0008, 0x39f8: 0x0008, 0x39f9: 0x0008, 0x39fa: 0x0008, 0x39fb: 0x0008, + 0x39fc: 0x0008, 0x39fd: 0x0008, 0x39fe: 0x0008, 0x39ff: 0x0008, + // Block 0xe8, offset 0x3a00 + 0x3a00: 0x0002, 0x3a01: 0x0002, 0x3a02: 0x0002, 0x3a03: 0x0002, 0x3a04: 0x0002, 0x3a05: 0x0002, + 0x3a06: 0x0002, 0x3a07: 0x0002, 0x3a08: 0x0002, 0x3a09: 0x0002, 0x3a0a: 0x0002, 0x3a0b: 0x0002, + 0x3a0c: 0x0002, 0x3a0d: 0x0002, 0x3a0e: 0x0002, 0x3a0f: 0x0002, 0x3a10: 0x0002, 0x3a11: 0x0002, + 0x3a12: 0x0002, 0x3a13: 0x0002, 0x3a14: 0x0002, 0x3a15: 0x0002, 0x3a16: 0x0002, 0x3a17: 0x0002, + 0x3a18: 0x0002, 0x3a19: 0x0002, 0x3a1a: 0x0002, 0x3a1b: 0x0002, 0x3a1c: 0x0002, 0x3a1d: 0x0002, + 0x3a1e: 0x0002, 0x3a1f: 0x0002, 0x3a20: 0x0024, 0x3a21: 0x0024, 0x3a22: 0x0024, 0x3a23: 0x0024, + 0x3a24: 0x0024, 0x3a25: 0x0024, 0x3a26: 0x0024, 0x3a27: 0x0024, 0x3a28: 0x0024, 0x3a29: 0x0024, + 0x3a2a: 0x0024, 0x3a2b: 0x0024, 0x3a2c: 0x0024, 0x3a2d: 0x0024, 0x3a2e: 0x0024, 0x3a2f: 0x0024, + 0x3a30: 0x0024, 0x3a31: 0x0024, 0x3a32: 0x0024, 0x3a33: 0x0024, 0x3a34: 0x0024, 0x3a35: 0x0024, + 0x3a36: 0x0024, 0x3a37: 0x0024, 0x3a38: 0x0024, 0x3a39: 0x0024, 0x3a3a: 0x0024, 0x3a3b: 0x0024, + 0x3a3c: 0x0024, 0x3a3d: 0x0024, 0x3a3e: 0x0024, 0x3a3f: 0x0024, + // Block 0xe9, offset 0x3a40 + 0x3a40: 0x0002, 0x3a41: 0x0002, 0x3a42: 0x0002, 0x3a43: 0x0002, 0x3a44: 0x0002, 0x3a45: 0x0002, + 0x3a46: 0x0002, 0x3a47: 0x0002, 0x3a48: 0x0002, 0x3a49: 0x0002, 0x3a4a: 0x0002, 0x3a4b: 0x0002, + 0x3a4c: 0x0002, 0x3a4d: 0x0002, 0x3a4e: 0x0002, 0x3a4f: 0x0002, 0x3a50: 0x0002, 0x3a51: 0x0002, + 0x3a52: 0x0002, 0x3a53: 0x0002, 0x3a54: 0x0002, 0x3a55: 0x0002, 0x3a56: 0x0002, 0x3a57: 0x0002, + 0x3a58: 0x0002, 0x3a59: 0x0002, 0x3a5a: 0x0002, 0x3a5b: 0x0002, 0x3a5c: 0x0002, 0x3a5d: 0x0002, + 0x3a5e: 0x0002, 0x3a5f: 0x0002, 0x3a60: 0x0002, 0x3a61: 0x0002, 0x3a62: 0x0002, 0x3a63: 0x0002, + 0x3a64: 0x0002, 0x3a65: 0x0002, 0x3a66: 0x0002, 0x3a67: 0x0002, 0x3a68: 0x0002, 0x3a69: 0x0002, + 0x3a6a: 0x0002, 0x3a6b: 0x0002, 0x3a6c: 0x0002, 0x3a6d: 0x0002, 0x3a6e: 0x0002, 0x3a6f: 0x0002, + 0x3a70: 0x0002, 0x3a71: 0x0002, 0x3a72: 0x0002, 0x3a73: 0x0002, 0x3a74: 0x0002, 0x3a75: 0x0002, + 0x3a76: 0x0002, 0x3a77: 0x0002, 0x3a78: 0x0002, 0x3a79: 0x0002, 0x3a7a: 0x0002, 0x3a7b: 0x0002, + 0x3a7c: 0x0002, 0x3a7d: 0x0002, 0x3a7e: 0x0002, 0x3a7f: 0x0002, + // Block 0xea, offset 0x3a80 + 0x3a80: 0x0024, 0x3a81: 0x0024, 0x3a82: 0x0024, 0x3a83: 0x0024, 0x3a84: 0x0024, 0x3a85: 0x0024, + 0x3a86: 0x0024, 0x3a87: 0x0024, 0x3a88: 0x0024, 0x3a89: 0x0024, 0x3a8a: 0x0024, 0x3a8b: 0x0024, + 0x3a8c: 0x0024, 0x3a8d: 0x0024, 0x3a8e: 0x0024, 0x3a8f: 0x0024, 0x3a90: 0x0024, 0x3a91: 0x0024, + 0x3a92: 0x0024, 0x3a93: 0x0024, 0x3a94: 0x0024, 0x3a95: 0x0024, 0x3a96: 0x0024, 0x3a97: 0x0024, + 0x3a98: 0x0024, 0x3a99: 0x0024, 0x3a9a: 0x0024, 0x3a9b: 0x0024, 0x3a9c: 0x0024, 0x3a9d: 0x0024, + 0x3a9e: 0x0024, 0x3a9f: 0x0024, 0x3aa0: 0x0024, 0x3aa1: 0x0024, 0x3aa2: 0x0024, 0x3aa3: 0x0024, + 0x3aa4: 0x0024, 0x3aa5: 0x0024, 0x3aa6: 0x0024, 0x3aa7: 0x0024, 0x3aa8: 0x0024, 0x3aa9: 0x0024, + 0x3aaa: 0x0024, 0x3aab: 0x0024, 0x3aac: 0x0024, 0x3aad: 0x0024, 0x3aae: 0x0024, 0x3aaf: 0x0024, + 0x3ab0: 0x0002, 0x3ab1: 0x0002, 0x3ab2: 0x0002, 0x3ab3: 0x0002, 0x3ab4: 0x0002, 0x3ab5: 0x0002, + 0x3ab6: 0x0002, 0x3ab7: 0x0002, 0x3ab8: 0x0002, 0x3ab9: 0x0002, 0x3aba: 0x0002, 0x3abb: 0x0002, + 0x3abc: 0x0002, 0x3abd: 0x0002, 0x3abe: 0x0002, 0x3abf: 0x0002, +} + +// graphemesIndex: 25 blocks, 1600 entries, 1600 bytes +// Block 0 is the zero block. +var graphemesIndex = [1600]property{ + // Block 0x0, offset 0x0 + // Block 0x1, offset 0x40 + // Block 0x2, offset 0x80 + // Block 0x3, offset 0xc0 + 0xc2: 0x01, + 0xcc: 0x02, 0xcd: 0x03, + 0xd2: 0x04, 0xd6: 0x05, 0xd7: 0x06, + 0xd8: 0x07, 0xd9: 0x08, 0xdb: 0x09, 0xdc: 0x0a, 0xdd: 0x0b, 0xde: 0x0c, 0xdf: 0x0d, + 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05, + 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a, + 0xf0: 0x14, 0xf3: 0x16, + // Block 0x4, offset 0x100 + 0x120: 0x0e, 0x121: 0x0f, 0x122: 0x10, 0x123: 0x11, 0x124: 0x12, 0x125: 0x13, 0x126: 0x14, 0x127: 0x15, + 0x128: 0x16, 0x129: 0x17, 0x12a: 0x18, 0x12b: 0x19, 0x12c: 0x1a, 0x12d: 0x1b, 0x12e: 0x1c, 0x12f: 0x1d, + 0x130: 0x1e, 0x131: 0x1f, 0x132: 0x20, 0x133: 0x21, 0x134: 0x22, 0x135: 0x23, 0x136: 0x24, 0x137: 0x25, + 0x138: 0x26, 0x139: 0x27, 0x13a: 0x28, 0x13b: 0x29, 0x13c: 0x2a, 0x13d: 0x2b, 0x13e: 0x2c, 0x13f: 0x2d, + // Block 0x5, offset 0x140 + 0x140: 0x2e, 0x141: 0x2f, 0x142: 0x30, 0x144: 0x31, 0x145: 0x32, 0x146: 0x33, 0x147: 0x34, + 0x14d: 0x35, + 0x15c: 0x36, 0x15d: 0x37, 0x15e: 0x38, 0x15f: 0x39, + 0x160: 0x3a, 0x162: 0x3b, 0x164: 0x3c, + 0x168: 0x3d, 0x169: 0x3e, 0x16a: 0x3f, 0x16b: 0x40, 0x16c: 0x41, 0x16d: 0x42, 0x16e: 0x43, 0x16f: 0x44, + 0x170: 0x45, 0x173: 0x46, 0x177: 0x02, + // Block 0x6, offset 0x180 + 0x180: 0x47, 0x181: 0x48, 0x183: 0x49, 0x184: 0x4a, 0x186: 0x4b, + 0x18c: 0x4c, 0x18f: 0x4d, + 0x193: 0x4e, 0x196: 0x4f, 0x197: 0x50, + 0x198: 0x51, 0x199: 0x52, 0x19a: 0x53, 0x19b: 0x54, 0x19c: 0x55, 0x19d: 0x56, 0x19e: 0x57, + 0x1a4: 0x58, + 0x1ac: 0x59, 0x1ad: 0x5a, + 0x1b3: 0x5b, 0x1b5: 0x5c, 0x1b7: 0x5d, + // Block 0x7, offset 0x1c0 + 0x1c0: 0x5e, 0x1c2: 0x5f, + 0x1ca: 0x60, + // Block 0x8, offset 0x200 + 0x219: 0x61, 0x21a: 0x62, 0x21b: 0x63, + 0x220: 0x64, 0x222: 0x65, 0x223: 0x66, 0x224: 0x67, 0x225: 0x68, 0x226: 0x69, 0x227: 0x6a, + 0x228: 0x6b, 0x229: 0x6c, 0x22a: 0x6d, 0x22b: 0x6e, 0x22f: 0x6f, + 0x230: 0x70, 0x231: 0x71, 0x232: 0x72, 0x233: 0x73, 0x234: 0x74, 0x235: 0x75, 0x236: 0x76, 0x237: 0x70, + 0x238: 0x71, 0x239: 0x72, 0x23a: 0x73, 0x23b: 0x74, 0x23c: 0x75, 0x23d: 0x76, 0x23e: 0x70, 0x23f: 0x71, + // Block 0x9, offset 0x240 + 0x240: 0x72, 0x241: 0x73, 0x242: 0x74, 0x243: 0x75, 0x244: 0x76, 0x245: 0x70, 0x246: 0x71, 0x247: 0x72, + 0x248: 0x73, 0x249: 0x74, 0x24a: 0x75, 0x24b: 0x76, 0x24c: 0x70, 0x24d: 0x71, 0x24e: 0x72, 0x24f: 0x73, + 0x250: 0x74, 0x251: 0x75, 0x252: 0x76, 0x253: 0x70, 0x254: 0x71, 0x255: 0x72, 0x256: 0x73, 0x257: 0x74, + 0x258: 0x75, 0x259: 0x76, 0x25a: 0x70, 0x25b: 0x71, 0x25c: 0x72, 0x25d: 0x73, 0x25e: 0x74, 0x25f: 0x75, + 0x260: 0x76, 0x261: 0x70, 0x262: 0x71, 0x263: 0x72, 0x264: 0x73, 0x265: 0x74, 0x266: 0x75, 0x267: 0x76, + 0x268: 0x70, 0x269: 0x71, 0x26a: 0x72, 0x26b: 0x73, 0x26c: 0x74, 0x26d: 0x75, 0x26e: 0x76, 0x26f: 0x70, + 0x270: 0x71, 0x271: 0x72, 0x272: 0x73, 0x273: 0x74, 0x274: 0x75, 0x275: 0x76, 0x276: 0x70, 0x277: 0x71, + 0x278: 0x72, 0x279: 0x73, 0x27a: 0x74, 0x27b: 0x75, 0x27c: 0x76, 0x27d: 0x70, 0x27e: 0x71, 0x27f: 0x72, + // Block 0xa, offset 0x280 + 0x280: 0x73, 0x281: 0x74, 0x282: 0x75, 0x283: 0x76, 0x284: 0x70, 0x285: 0x71, 0x286: 0x72, 0x287: 0x73, + 0x288: 0x74, 0x289: 0x75, 0x28a: 0x76, 0x28b: 0x70, 0x28c: 0x71, 0x28d: 0x72, 0x28e: 0x73, 0x28f: 0x74, + 0x290: 0x75, 0x291: 0x76, 0x292: 0x70, 0x293: 0x71, 0x294: 0x72, 0x295: 0x73, 0x296: 0x74, 0x297: 0x75, + 0x298: 0x76, 0x299: 0x70, 0x29a: 0x71, 0x29b: 0x72, 0x29c: 0x73, 0x29d: 0x74, 0x29e: 0x75, 0x29f: 0x76, + 0x2a0: 0x70, 0x2a1: 0x71, 0x2a2: 0x72, 0x2a3: 0x73, 0x2a4: 0x74, 0x2a5: 0x75, 0x2a6: 0x76, 0x2a7: 0x70, + 0x2a8: 0x71, 0x2a9: 0x72, 0x2aa: 0x73, 0x2ab: 0x74, 0x2ac: 0x75, 0x2ad: 0x76, 0x2ae: 0x70, 0x2af: 0x71, + 0x2b0: 0x72, 0x2b1: 0x73, 0x2b2: 0x74, 0x2b3: 0x75, 0x2b4: 0x76, 0x2b5: 0x70, 0x2b6: 0x71, 0x2b7: 0x72, + 0x2b8: 0x73, 0x2b9: 0x74, 0x2ba: 0x75, 0x2bb: 0x76, 0x2bc: 0x70, 0x2bd: 0x71, 0x2be: 0x72, 0x2bf: 0x73, + // Block 0xb, offset 0x2c0 + 0x2c0: 0x74, 0x2c1: 0x75, 0x2c2: 0x76, 0x2c3: 0x70, 0x2c4: 0x71, 0x2c5: 0x72, 0x2c6: 0x73, 0x2c7: 0x74, + 0x2c8: 0x75, 0x2c9: 0x76, 0x2ca: 0x70, 0x2cb: 0x71, 0x2cc: 0x72, 0x2cd: 0x73, 0x2ce: 0x74, 0x2cf: 0x75, + 0x2d0: 0x76, 0x2d1: 0x70, 0x2d2: 0x71, 0x2d3: 0x72, 0x2d4: 0x73, 0x2d5: 0x74, 0x2d6: 0x75, 0x2d7: 0x76, + 0x2d8: 0x70, 0x2d9: 0x71, 0x2da: 0x72, 0x2db: 0x73, 0x2dc: 0x74, 0x2dd: 0x75, 0x2de: 0x77, 0x2df: 0x78, + // Block 0xc, offset 0x300 + 0x32c: 0x79, + 0x338: 0x7a, 0x33b: 0x7b, 0x33e: 0x62, 0x33f: 0x7c, + // Block 0xd, offset 0x340 + 0x347: 0x7d, + 0x34b: 0x7e, 0x34d: 0x7f, + 0x368: 0x80, 0x36b: 0x81, + 0x374: 0x82, 0x375: 0x83, + 0x37a: 0x84, 0x37b: 0x85, 0x37d: 0x86, 0x37e: 0x87, + // Block 0xe, offset 0x380 + 0x380: 0x88, 0x381: 0x89, 0x382: 0x8a, 0x383: 0x8b, 0x384: 0x8c, 0x385: 0x8d, 0x386: 0x8e, 0x387: 0x8f, + 0x388: 0x90, 0x389: 0x91, 0x38b: 0x92, 0x38c: 0x93, 0x38d: 0x94, 0x38e: 0x95, 0x38f: 0x96, + 0x390: 0x97, 0x391: 0x98, 0x392: 0x99, 0x393: 0x9a, 0x396: 0x9b, 0x397: 0x9c, + 0x398: 0x9d, 0x399: 0x9e, 0x39a: 0x9f, 0x39c: 0xa0, + 0x3a0: 0xa1, 0x3a4: 0xa2, 0x3a5: 0xa3, 0x3a7: 0xa4, + 0x3a8: 0xa5, 0x3a9: 0xa6, 0x3aa: 0xa7, 0x3ad: 0xa8, + 0x3b0: 0xa9, 0x3b2: 0xaa, 0x3b4: 0xab, 0x3b5: 0xac, 0x3b6: 0xad, + 0x3bb: 0xae, 0x3bc: 0xaf, 0x3bd: 0xb0, + // Block 0xf, offset 0x3c0 + 0x3d0: 0xb1, 0x3d1: 0xb2, + // Block 0x10, offset 0x400 + 0x404: 0xb3, + 0x42b: 0xb4, 0x42c: 0xb5, + 0x435: 0xb6, + 0x43d: 0xb7, 0x43e: 0xb8, 0x43f: 0xb9, + // Block 0x11, offset 0x440 + 0x472: 0xba, + // Block 0x12, offset 0x480 + 0x4bc: 0xbb, 0x4bd: 0xbc, + // Block 0x13, offset 0x4c0 + 0x4c5: 0xbd, 0x4c6: 0xbe, + 0x4c9: 0xbf, + 0x4e8: 0xc0, 0x4e9: 0xc1, 0x4ea: 0xc2, + // Block 0x14, offset 0x500 + 0x500: 0xc3, 0x502: 0xc4, 0x504: 0xb5, + 0x50a: 0xc5, 0x50b: 0xc6, + 0x513: 0xc6, 0x517: 0xc7, + 0x51b: 0xc8, + 0x523: 0xc9, 0x525: 0xca, + // Block 0x15, offset 0x540 + 0x540: 0xcb, 0x542: 0xcc, 0x543: 0xcd, 0x545: 0xce, 0x546: 0xcf, 0x547: 0xd0, + 0x548: 0xd1, 0x549: 0xd2, 0x54a: 0xd3, 0x54b: 0xd3, 0x54c: 0xd4, 0x54d: 0xd3, 0x54e: 0xd5, 0x54f: 0xd6, + 0x550: 0xd3, 0x551: 0xd3, 0x552: 0xd3, 0x553: 0xd7, 0x554: 0xd8, 0x555: 0xd9, 0x556: 0xda, 0x557: 0xdb, + 0x558: 0xd3, 0x559: 0xdc, 0x55a: 0xd3, 0x55b: 0xdd, 0x55f: 0xde, + 0x560: 0xdf, 0x561: 0xe0, 0x562: 0xe1, 0x563: 0xe2, 0x564: 0xe3, 0x565: 0xe4, 0x566: 0xd3, 0x567: 0xd3, + 0x569: 0xe5, 0x56a: 0xd3, 0x56b: 0xd3, + 0x570: 0xd3, 0x571: 0xd3, 0x572: 0xd3, 0x573: 0xd3, 0x574: 0xd3, 0x575: 0xd3, 0x576: 0xd3, 0x577: 0xd3, + 0x578: 0xd3, 0x579: 0xd3, 0x57a: 0xd3, 0x57b: 0xd3, 0x57c: 0xd3, 0x57d: 0xd3, 0x57e: 0xd3, 0x57f: 0xd8, + // Block 0x16, offset 0x580 + 0x590: 0x0b, 0x591: 0x0c, 0x593: 0x0d, 0x596: 0x0e, + 0x59b: 0x0f, 0x59c: 0x10, 0x59d: 0x11, 0x59e: 0x12, 0x59f: 0x13, + // Block 0x17, offset 0x5c0 + 0x5c0: 0xe6, 0x5c1: 0x02, 0x5c2: 0xe7, 0x5c3: 0xe7, 0x5c4: 0x02, 0x5c5: 0x02, 0x5c6: 0x02, 0x5c7: 0xe8, + 0x5c8: 0xe7, 0x5c9: 0xe7, 0x5ca: 0xe7, 0x5cb: 0xe7, 0x5cc: 0xe7, 0x5cd: 0xe7, 0x5ce: 0xe7, 0x5cf: 0xe7, + 0x5d0: 0xe7, 0x5d1: 0xe7, 0x5d2: 0xe7, 0x5d3: 0xe7, 0x5d4: 0xe7, 0x5d5: 0xe7, 0x5d6: 0xe7, 0x5d7: 0xe7, + 0x5d8: 0xe7, 0x5d9: 0xe7, 0x5da: 0xe7, 0x5db: 0xe7, 0x5dc: 0xe7, 0x5dd: 0xe7, 0x5de: 0xe7, 0x5df: 0xe7, + 0x5e0: 0xe7, 0x5e1: 0xe7, 0x5e2: 0xe7, 0x5e3: 0xe7, 0x5e4: 0xe7, 0x5e5: 0xe7, 0x5e6: 0xe7, 0x5e7: 0xe7, + 0x5e8: 0xe7, 0x5e9: 0xe7, 0x5ea: 0xe7, 0x5eb: 0xe7, 0x5ec: 0xe7, 0x5ed: 0xe7, 0x5ee: 0xe7, 0x5ef: 0xe7, + 0x5f0: 0xe7, 0x5f1: 0xe7, 0x5f2: 0xe7, 0x5f3: 0xe7, 0x5f4: 0xe7, 0x5f5: 0xe7, 0x5f6: 0xe7, 0x5f7: 0xe7, + 0x5f8: 0xe7, 0x5f9: 0xe7, 0x5fa: 0xe7, 0x5fb: 0xe7, 0x5fc: 0xe7, 0x5fd: 0xe7, 0x5fe: 0xe7, 0x5ff: 0xe7, + // Block 0x18, offset 0x600 + 0x620: 0x15, +} diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go index ee39b40..d3906bf 100644 --- a/vendor/github.com/fatih/color/color.go +++ b/vendor/github.com/fatih/color/color.go @@ -19,15 +19,15 @@ var ( // set (regardless of its value). This is a global option and affects all // colors. For more control over each color block use the methods // DisableColor() individually. - NoColor = noColorIsSet() || os.Getenv("TERM") == "dumb" || - (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) + NoColor = noColorIsSet() || os.Getenv("TERM") == "dumb" || !stdoutIsTerminal() // Output defines the standard output of the print functions. By default, - // os.Stdout is used. - Output = colorable.NewColorableStdout() + // stdOut() is used. + Output = stdOut() - // Error defines a color supporting writer for os.Stderr. - Error = colorable.NewColorableStderr() + // Error defines the standard error of the print functions. By default, + // stdErr() is used. + Error = stdErr() // colorsCache is used to reduce the count of created Color objects and // allows to reuse already created objects with required Attribute. @@ -40,6 +40,33 @@ func noColorIsSet() bool { return os.Getenv("NO_COLOR") != "" } +// stdoutIsTerminal returns true if os.Stdout is a terminal. +// Returns false if os.Stdout is nil (e.g., when running as a Windows service). +func stdoutIsTerminal() bool { + if os.Stdout == nil { + return false + } + return isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) +} + +// stdOut returns a writer for color output. +// Returns io.Discard if os.Stdout is nil (e.g., when running as a Windows service). +func stdOut() io.Writer { + if os.Stdout == nil { + return io.Discard + } + return colorable.NewColorableStdout() +} + +// stdErr returns a writer for color error output. +// Returns io.Discard if os.Stderr is nil (e.g., when running as a Windows service). +func stdErr() io.Writer { + if os.Stderr == nil { + return io.Discard + } + return colorable.NewColorableStderr() +} + // Color defines a custom color object which is defined by SGR parameters. type Color struct { params []Attribute @@ -220,26 +247,30 @@ func (c *Color) unset() { // a low-level function, and users should use the higher-level functions, such // as color.Fprint, color.Print, etc. func (c *Color) SetWriter(w io.Writer) *Color { + _, _ = c.setWriter(w) + return c +} + +func (c *Color) setWriter(w io.Writer) (int, error) { if c.isNoColorSet() { - return c + return 0, nil } - fmt.Fprint(w, c.format()) - return c + return fmt.Fprint(w, c.format()) } // UnsetWriter resets all escape attributes and clears the output with the give // io.Writer. Usually should be called after SetWriter(). func (c *Color) UnsetWriter(w io.Writer) { - if c.isNoColorSet() { - return - } + _, _ = c.unsetWriter(w) +} - if NoColor { - return +func (c *Color) unsetWriter(w io.Writer) (int, error) { + if c.isNoColorSet() { + return 0, nil } - fmt.Fprintf(w, "%s[%dm", escape, Reset) + return fmt.Fprintf(w, "%s[%dm", escape, Reset) } // Add is used to chain SGR parameters. Use as many as parameters to combine @@ -255,10 +286,20 @@ func (c *Color) Add(value ...Attribute) *Color { // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { - c.SetWriter(w) - defer c.UnsetWriter(w) + n, err = c.setWriter(w) + if err != nil { + return n, err + } + + nn, err := fmt.Fprint(w, a...) + n += nn + if err != nil { + return + } - return fmt.Fprint(w, a...) + nn, err = c.unsetWriter(w) + n += nn + return n, err } // Print formats using the default formats for its operands and writes to @@ -278,10 +319,20 @@ func (c *Color) Print(a ...interface{}) (n int, err error) { // On Windows, users should wrap w with colorable.NewColorable() if w is of // type *os.File. func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - c.SetWriter(w) - defer c.UnsetWriter(w) + n, err = c.setWriter(w) + if err != nil { + return n, err + } + + nn, err := fmt.Fprintf(w, format, a...) + n += nn + if err != nil { + return + } - return fmt.Fprintf(w, format, a...) + nn, err = c.unsetWriter(w) + n += nn + return n, err } // Printf formats according to a format specifier and writes to standard output. @@ -475,27 +526,24 @@ func (c *Color) Equals(c2 *Color) bool { if c == nil || c2 == nil { return false } + if len(c.params) != len(c2.params) { return false } + counts := make(map[Attribute]int, len(c.params)) for _, attr := range c.params { - if !c2.attrExists(attr) { - return false - } + counts[attr]++ } - return true -} - -func (c *Color) attrExists(a Attribute) bool { - for _, attr := range c.params { - if attr == a { - return true + for _, attr := range c2.params { + if counts[attr] == 0 { + return false } + counts[attr]-- } - return false + return true } func boolPtr(v bool) *bool { diff --git a/vendor/github.com/fatih/color/color_windows.go b/vendor/github.com/fatih/color/color_windows.go index be01c55..97e5a76 100644 --- a/vendor/github.com/fatih/color/color_windows.go +++ b/vendor/github.com/fatih/color/color_windows.go @@ -9,6 +9,9 @@ import ( func init() { // Opt-in for ansi color support for current process. // https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#output-sequences + if os.Stdout == nil { + return + } var outMode uint32 out := windows.Handle(os.Stdout.Fd()) if err := windows.GetConsoleMode(out, &outMode); err != nil { diff --git a/vendor/github.com/fsnotify/fsnotify/.cirrus.yml b/vendor/github.com/fsnotify/fsnotify/.cirrus.yml deleted file mode 100644 index f4e7dbf..0000000 --- a/vendor/github.com/fsnotify/fsnotify/.cirrus.yml +++ /dev/null @@ -1,14 +0,0 @@ -freebsd_task: - name: 'FreeBSD' - freebsd_instance: - image_family: freebsd-14-1 - install_script: - - pkg update -f - - pkg install -y go - test_script: - # run tests as user "cirrus" instead of root - - pw useradd cirrus -m - - chown -R cirrus:cirrus . - - FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./... - - sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./... - - FSNOTIFY_DEBUG=1 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race -v ./... diff --git a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md index fa85478..3027f3c 100644 --- a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md +++ b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md @@ -1,6 +1,88 @@ # Changelog -1.8.0 2023-10-31 +1.10.1 2026-05-04 +----------------- + +### Changes and fixes + +- inotify: don't remove sibling watches sharing a path prefix ([#754]) + +- inotify, windows: don't rename sibling watches sharing a path prefix + ([#755]) + + +[#754]: https://github.com/fsnotify/fsnotify/pull/754 +[#755]: https://github.com/fsnotify/fsnotify/pull/755 + + +1.10.0 2026-04-30 +----------------- +This version of fsnotify needs Go 1.23. + +### Changes and fixes + +- inotify: improve initialization error message ([#731]) + +- inotify: send Rename event if recursive watch is renamed ([#696]) + +- inotify: avoid copying event buffers when reading names ([#741]) + +- kqueue: skip dangling symlinks (ENOENT) in watchDirectoryFiles, so a + bad entry no longer aborts Watcher.Add for the whole directory ([#748]) + +- kqueue: drop watches directly in Close() to fix a file descriptor leak + when recycling watchers ([#740]) + +- windows: fix nil pointer dereference in remWatch ([#736]) + +- windows: lock watch field updates against concurrent WatchList to fix + a race introduced in v1.9.0 ([#709], [#749]) + + +[#696]: https://github.com/fsnotify/fsnotify/pull/696 +[#709]: https://github.com/fsnotify/fsnotify/pull/709 +[#731]: https://github.com/fsnotify/fsnotify/pull/731 +[#736]: https://github.com/fsnotify/fsnotify/pull/736 +[#740]: https://github.com/fsnotify/fsnotify/pull/740 +[#741]: https://github.com/fsnotify/fsnotify/pull/741 +[#748]: https://github.com/fsnotify/fsnotify/pull/748 +[#749]: https://github.com/fsnotify/fsnotify/pull/749 + + +1.9.0 2024-04-04 +---------------- + +### Changes and fixes + +- all: make BufferedWatcher buffered again ([#657]) + +- inotify: fix race when adding/removing watches while a watched path is being + deleted ([#678], [#686]) + +- inotify: don't send empty event if a watched path is unmounted ([#655]) + +- inotify: don't register duplicate watches when watching both a symlink and its + target; previously that would get "half-added" and removing the second would + panic ([#679]) + +- kqueue: fix watching relative symlinks ([#681]) + +- kqueue: correctly mark pre-existing entries when watching a link to a dir on + kqueue ([#682]) + +- illumos: don't send error if changed file is deleted while processing the + event ([#678]) + + +[#657]: https://github.com/fsnotify/fsnotify/pull/657 +[#678]: https://github.com/fsnotify/fsnotify/pull/678 +[#686]: https://github.com/fsnotify/fsnotify/pull/686 +[#655]: https://github.com/fsnotify/fsnotify/pull/655 +[#681]: https://github.com/fsnotify/fsnotify/pull/681 +[#679]: https://github.com/fsnotify/fsnotify/pull/679 +[#682]: https://github.com/fsnotify/fsnotify/pull/682 + +1.8.0 2024-10-31 ---------------- ### Additions diff --git a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md index e4ac2a2..cd0ee61 100644 --- a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md +++ b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md @@ -77,6 +77,9 @@ End-of-line escapes with `\` are not supported. debug [yes/no] # Enable/disable FSNOTIFY_DEBUG (tests are run in parallel by default, so -parallel=1 is probably a good idea). + state # Print internal state to stderr (exact output differs + # per backend). + print [any strings] # Print text to stdout; for debugging. touch path mkdir [-p] dir diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md index e480733..2e56ef4 100644 --- a/vendor/github.com/fsnotify/fsnotify/README.md +++ b/vendor/github.com/fsnotify/fsnotify/README.md @@ -1,7 +1,7 @@ fsnotify is a Go library to provide cross-platform filesystem notifications on Windows, Linux, macOS, BSD, and illumos. -Go 1.17 or newer is required; the full documentation is at +Go 1.23 or newer is required; the full documentation is at https://pkg.go.dev/github.com/fsnotify/fsnotify --- @@ -12,10 +12,9 @@ Platform support: | :-------------------- | :--------- | :------------------------------------------------------------------------ | | inotify | Linux | Supported | | kqueue | BSD, macOS | Supported | -| ReadDirectoryChangesW | Windows | Supported | +| ReadDirectoryChangesW | Windows | Supported ([excluding `Chmod` operations][#487]) | | FEN | illumos | Supported | | fanotify | Linux 5.9+ | [Not yet](https://github.com/fsnotify/fsnotify/issues/114) | -| AHAFS | AIX | [aix branch]; experimental due to lack of maintainer and test environment | | FSEvents | macOS | [Needs support in x/sys/unix][fsevents] | | USN Journals | Windows | [Needs support in x/sys/windows][usn] | | Polling | *All* | [Not yet](https://github.com/fsnotify/fsnotify/issues/9) | @@ -23,9 +22,9 @@ Platform support: Linux and illumos should include Android and Solaris, but these are currently untested. +[#487]: https://github.com/fsnotify/fsnotify/issues/487 [fsevents]: https://github.com/fsnotify/fsnotify/issues/11#issuecomment-1279133120 [usn]: https://github.com/fsnotify/fsnotify/issues/53#issuecomment-1279829847 -[aix branch]: https://github.com/fsnotify/fsnotify/issues/353#issuecomment-1284590129 Usage ----- @@ -128,7 +127,7 @@ settings* until we have a native FSEvents implementation (see [#11]). ### Watching a file doesn't work well Watching individual files (rather than directories) is generally not recommended as many programs (especially editors) update files atomically: it will write to -a temporary file which is then moved to to destination, overwriting the original +a temporary file which is then moved to a destination, overwriting the original (or some variant thereof). The watcher on the original file is now lost, as that no longer exists. @@ -153,26 +152,57 @@ This is the event that inotify sends, so not much can be changed about this. The `fs.inotify.max_user_watches` sysctl variable specifies the upper limit for the number of watches per user, and `fs.inotify.max_user_instances` specifies the maximum number of inotify instances per user. Every Watcher you create is an -"instance", and every path you add is a "watch". +"instance", and every path you add is a "watch". Reaching the limit will result +in a "no space left on device" or "too many open files" error. These are also exposed in `/proc` as `/proc/sys/fs/inotify/max_user_watches` and -`/proc/sys/fs/inotify/max_user_instances` +`/proc/sys/fs/inotify/max_user_instances`. The default values differ per distro +and available memory. To increase them you can use `sysctl` or write the value to proc file: - # The default values on Linux 5.18 - sysctl fs.inotify.max_user_watches=124983 - sysctl fs.inotify.max_user_instances=128 + sysctl fs.inotify.max_user_watches=200000 + sysctl fs.inotify.max_user_instances=256 To make the changes persist on reboot edit `/etc/sysctl.conf` or `/usr/lib/sysctl.d/50-default.conf` (details differ per Linux distro; check your distro's documentation): - fs.inotify.max_user_watches=124983 - fs.inotify.max_user_instances=128 + fs.inotify.max_user_watches=200000 + fs.inotify.max_user_instances=256 + +### Windows +Recursive watching is not currently enabled through fsnotify's public API +(see the FAQ "Are subdirectories watched?" above). The notes below +describe Windows backend behavior observed when recursive watching is +enabled internally (for example, in fsnotify's own tests). They are kept +here as a reference for maintainers and contributors who encounter the +behavior, since the recursive code path still exists in the backend. + +When recursive watching is enabled and you watch a directory, you may +receive a `Write` event for an intermediate directory whenever a child +entry inside it is created, renamed, or removed. For example, with a +recursive watch on `/a` and a new file `/a/b/c`, you will receive +`Create /a/b/c` and may also receive `Write /a/b`. + +This happens because, on NTFS-backed volumes, modifying the entries of a +directory updates that directory's last-write time, and the Windows +backend requests `FILE_NOTIFY_CHANGE_LAST_WRITE` to support `Write` events +on files. The same `Write` filter therefore picks up the directory's +metadata update. + +kqueue has the same "directory `Write` = directory contents changed" +semantics, so portable code that treats `Write` on a directory as +"something inside it changed" works on Windows and BSD/macOS, but not on +Linux (inotify uses `Write` only for file-content changes). If you only +care about file content, filter out `Write` events whose path refers to a +directory. + +Whether the directory `Write` is actually delivered alongside the child +events is not guaranteed: it depends on `ReadDirectoryChangesW` buffering, +NTFS metadata update timing, and event coalescing, none of which fsnotify +controls. -Reaching the limit will result in a "no space left on device" or "too many open -files" error. ### kqueue (macOS, all BSD systems) kqueue requires opening a file descriptor for every file that's being watched; diff --git a/vendor/github.com/fsnotify/fsnotify/backend_fen.go b/vendor/github.com/fsnotify/fsnotify/backend_fen.go index c349c32..e43c6d0 100644 --- a/vendor/github.com/fsnotify/fsnotify/backend_fen.go +++ b/vendor/github.com/fsnotify/fsnotify/backend_fen.go @@ -9,6 +9,7 @@ package fsnotify import ( "errors" "fmt" + "io/fs" "os" "path/filepath" "sync" @@ -19,27 +20,25 @@ import ( ) type fen struct { + *shared Events chan Event Errors chan error mu sync.Mutex port *unix.EventPort - done chan struct{} // Channel for sending a "quit message" to the reader goroutine dirs map[string]Op // Explicitly watched directories watches map[string]Op // Explicitly watched non-directories } -func newBackend(ev chan Event, errs chan error) (backend, error) { - return newBufferedBackend(0, ev, errs) -} +var defaultBufferSize = 0 -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { +func newBackend(ev chan Event, errs chan error) (backend, error) { w := &fen{ + shared: newShared(ev, errs), Events: ev, Errors: errs, dirs: make(map[string]Op), watches: make(map[string]Op), - done: make(chan struct{}), } var err error @@ -52,49 +51,10 @@ func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error return w, nil } -// sendEvent attempts to send an event to the user, returning true if the event -// was put in the channel successfully and false if the watcher has been closed. -func (w *fen) sendEvent(name string, op Op) (sent bool) { - select { - case <-w.done: - return false - case w.Events <- Event{Name: name, Op: op}: - return true - } -} - -// sendError attempts to send an error to the user, returning true if the error -// was put in the channel successfully and false if the watcher has been closed. -func (w *fen) sendError(err error) (sent bool) { - if err == nil { - return true - } - select { - case <-w.done: - return false - case w.Errors <- err: - return true - } -} - -func (w *fen) isClosed() bool { - select { - case <-w.done: - return true - default: - return false - } -} - func (w *fen) Close() error { - // Take the lock used by associateFile to prevent lingering events from - // being processed after the close - w.mu.Lock() - defer w.mu.Unlock() - if w.isClosed() { + if w.shared.close() { return nil } - close(w.done) return w.port.Close() } @@ -198,7 +158,9 @@ func (w *fen) readEvents() { pevents := make([]unix.PortEvent, 8) for { - count, err := w.port.Get(pevents, 1, nil) + count, err := internal.IgnoringEINTR(func() (int, error) { + return w.port.Get(pevents, 1, nil) + }) if err != nil && err != unix.ETIME { // Interrupted system call (count should be 0) ignore and continue if errors.Is(err, unix.EINTR) && count == 0 { @@ -209,7 +171,7 @@ func (w *fen) readEvents() { return } // There was an error not caused by calling w.Close() - if !w.sendError(err) { + if !w.sendError(fmt.Errorf("port.Get: %w", err)) { return } } @@ -277,13 +239,13 @@ func (w *fen) handleEvent(event *unix.PortEvent) error { isWatched := watchedDir || watchedPath if events&unix.FILE_DELETE != 0 { - if !w.sendEvent(path, Remove) { + if !w.sendEvent(Event{Name: path, Op: Remove}) { return nil } reRegister = false } if events&unix.FILE_RENAME_FROM != 0 { - if !w.sendEvent(path, Rename) { + if !w.sendEvent(Event{Name: path, Op: Rename}) { return nil } // Don't keep watching the new file name @@ -297,7 +259,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error { // inotify reports a Remove event in this case, so we simulate this // here. - if !w.sendEvent(path, Remove) { + if !w.sendEvent(Event{Name: path, Op: Remove}) { return nil } // Don't keep watching the file that was removed @@ -331,7 +293,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error { // get here, the sudirectory is already gone. Clearly we were watching // this path but now it is gone. Let's tell the user that it was // removed. - if !w.sendEvent(path, Remove) { + if !w.sendEvent(Event{Name: path, Op: Remove}) { return nil } // Suppress extra write events on removed directories; they are not @@ -346,7 +308,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error { if err != nil { // The symlink still exists, but the target is gone. Report the // Remove similar to above. - if !w.sendEvent(path, Remove) { + if !w.sendEvent(Event{Name: path, Op: Remove}) { return nil } // Don't return the error @@ -359,7 +321,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error { return err } } else { - if !w.sendEvent(path, Write) { + if !w.sendEvent(Event{Name: path, Op: Write}) { return nil } } @@ -367,7 +329,7 @@ func (w *fen) handleEvent(event *unix.PortEvent) error { if events&unix.FILE_ATTRIB != 0 && stat != nil { // Only send Chmod if perms changed if stat.Mode().Perm() != fmode.Perm() { - if !w.sendEvent(path, Chmod) { + if !w.sendEvent(Event{Name: path, Op: Chmod}) { return nil } } @@ -376,17 +338,27 @@ func (w *fen) handleEvent(event *unix.PortEvent) error { if stat != nil { // If we get here, it means we've hit an event above that requires us to // continue watching the file or directory - return w.associateFile(path, stat, isWatched) + err := w.associateFile(path, stat, isWatched) + if errors.Is(err, fs.ErrNotExist) { + // Path may have been removed since the stat. + err = nil + } + return err } return nil } +// The directory was modified, so we must find unwatched entities and watch +// them. If something was removed from the directory, nothing will happen, as +// everything else should still be watched. func (w *fen) updateDirectory(path string) error { - // The directory was modified, so we must find unwatched entities and watch - // them. If something was removed from the directory, nothing will happen, - // as everything else should still be watched. files, err := os.ReadDir(path) if err != nil { + // Directory no longer exists: probably just deleted since we got the + // event. + if errors.Is(err, fs.ErrNotExist) { + return nil + } return err } @@ -401,10 +373,15 @@ func (w *fen) updateDirectory(path string) error { return err } err = w.associateFile(path, finfo, false) + if errors.Is(err, fs.ErrNotExist) { + // File may have disappeared between getting the dir listing and + // adding the port: that's okay to ignore. + continue + } if !w.sendError(err) { return nil } - if !w.sendEvent(path, Create) { + if !w.sendEvent(Event{Name: path, Op: Create}) { return nil } } @@ -430,7 +407,7 @@ func (w *fen) associateFile(path string, stat os.FileInfo, follow bool) error { // has fired but we haven't processed it yet. err := w.port.DissociatePath(path) if err != nil && !errors.Is(err, unix.ENOENT) { - return err + return fmt.Errorf("port.DissociatePath(%q): %w", path, err) } } @@ -446,14 +423,22 @@ func (w *fen) associateFile(path string, stat os.FileInfo, follow bool) error { if true { events |= unix.FILE_ATTRIB } - return w.port.AssociatePath(path, stat, events, stat.Mode()) + err := w.port.AssociatePath(path, stat, events, stat.Mode()) + if err != nil { + return fmt.Errorf("port.AssociatePath(%q): %w", path, err) + } + return nil } func (w *fen) dissociateFile(path string, stat os.FileInfo, unused bool) error { if !w.port.PathIsWatched(path) { return nil } - return w.port.DissociatePath(path) + err := w.port.DissociatePath(path) + if err != nil { + return fmt.Errorf("port.DissociatePath(%q): %w", path, err) + } + return nil } func (w *fen) WatchList() []string { diff --git a/vendor/github.com/fsnotify/fsnotify/backend_inotify.go b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go index 36c3116..4c3f6f7 100644 --- a/vendor/github.com/fsnotify/fsnotify/backend_inotify.go +++ b/vendor/github.com/fsnotify/fsnotify/backend_inotify.go @@ -19,6 +19,7 @@ import ( ) type inotify struct { + *shared Events chan Event Errors chan error @@ -27,8 +28,6 @@ type inotify struct { fd int inotifyFile *os.File watches *watches - done chan struct{} // Channel for sending a "quit message" to the reader goroutine - doneMu sync.Mutex doneResp chan struct{} // Channel to respond to Close // Store rename cookies in an array, with the index wrapping to 0. Almost @@ -52,15 +51,14 @@ type inotify struct { type ( watches struct { - mu sync.RWMutex wd map[uint32]*watch // wd → watch path map[string]uint32 // pathname → wd } watch struct { - wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) - flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) - path string // Watch path. - recurse bool // Recursion with ./...? + wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall) + flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags) + path string // Watch path. + watchFlags watchFlag } koekje struct { cookie uint32 @@ -68,6 +66,9 @@ type ( } ) +func (w watch) byUser() bool { return w.watchFlags&flagByUser != 0 } +func (w watch) recurse() bool { return w.watchFlags&flagRecurse != 0 } + func newWatches() *watches { return &watches{ wd: make(map[uint32]*watch), @@ -75,34 +76,20 @@ func newWatches() *watches { } } -func (w *watches) len() int { - w.mu.RLock() - defer w.mu.RUnlock() - return len(w.wd) -} +func (w *watches) byPath(path string) *watch { return w.wd[w.path[path]] } +func (w *watches) byWd(wd uint32) *watch { return w.wd[wd] } +func (w *watches) len() int { return len(w.wd) } +func (w *watches) add(ww *watch) { w.wd[ww.wd] = ww; w.path[ww.path] = ww.wd } +func (w *watches) remove(watch *watch) { delete(w.path, watch.path); delete(w.wd, watch.wd) } -func (w *watches) add(ww *watch) { - w.mu.Lock() - defer w.mu.Unlock() - w.wd[ww.wd] = ww - w.path[ww.path] = ww.wd -} - -func (w *watches) remove(wd uint32) { - w.mu.Lock() - defer w.mu.Unlock() - watch := w.wd[wd] // Could have had Remove() called. See #616. - if watch == nil { - return +func isSameOrDescendantPath(path, root string) bool { + if path == root { + return true } - delete(w.path, watch.path) - delete(w.wd, wd) + return strings.HasPrefix(path, root+string(os.PathSeparator)) } func (w *watches) removePath(path string) ([]uint32, error) { - w.mu.Lock() - defer w.mu.Unlock() - path, recurse := recursivePath(path) wd, ok := w.path[path] if !ok { @@ -110,20 +97,20 @@ func (w *watches) removePath(path string) ([]uint32, error) { } watch := w.wd[wd] - if recurse && !watch.recurse { + if recurse && !watch.recurse() { return nil, fmt.Errorf("can't use /... with non-recursive watch %q", path) } delete(w.path, path) delete(w.wd, wd) - if !watch.recurse { + if !watch.recurse() { return []uint32{wd}, nil } wds := make([]uint32, 0, 8) wds = append(wds, wd) for p, rwd := range w.path { - if filepath.HasPrefix(p, path) { + if isSameOrDescendantPath(p, path) { delete(w.path, p) delete(w.wd, rwd) wds = append(wds, rwd) @@ -132,22 +119,7 @@ func (w *watches) removePath(path string) ([]uint32, error) { return wds, nil } -func (w *watches) byPath(path string) *watch { - w.mu.RLock() - defer w.mu.RUnlock() - return w.wd[w.path[path]] -} - -func (w *watches) byWd(wd uint32) *watch { - w.mu.RLock() - defer w.mu.RUnlock() - return w.wd[wd] -} - func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error { - w.mu.Lock() - defer w.mu.Unlock() - var existing *watch wd, ok := w.path[path] if ok { @@ -170,25 +142,23 @@ func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error return nil } -func newBackend(ev chan Event, errs chan error) (backend, error) { - return newBufferedBackend(0, ev, errs) -} +var defaultBufferSize = 0 -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { +func newBackend(ev chan Event, errs chan error) (backend, error) { // Need to set nonblocking mode for SetDeadline to work, otherwise blocking // I/O operations won't terminate on close. fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK) if fd == -1 { - return nil, errno + return nil, fmt.Errorf("couldn't initialize inotify: %w", errno) } w := &inotify{ + shared: newShared(ev, errs), Events: ev, Errors: errs, fd: fd, inotifyFile: os.NewFile(uintptr(fd), ""), watches: newWatches(), - done: make(chan struct{}), doneResp: make(chan struct{}), } @@ -196,46 +166,10 @@ func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error return w, nil } -// Returns true if the event was sent, or false if watcher is closed. -func (w *inotify) sendEvent(e Event) bool { - select { - case <-w.done: - return false - case w.Events <- e: - return true - } -} - -// Returns true if the error was sent, or false if watcher is closed. -func (w *inotify) sendError(err error) bool { - if err == nil { - return true - } - select { - case <-w.done: - return false - case w.Errors <- err: - return true - } -} - -func (w *inotify) isClosed() bool { - select { - case <-w.done: - return true - default: - return false - } -} - func (w *inotify) Close() error { - w.doneMu.Lock() - if w.isClosed() { - w.doneMu.Unlock() + if w.shared.close() { return nil } - close(w.done) - w.doneMu.Unlock() // Causes any blocking reads to return with an error, provided the file // still supports deadline operations. @@ -244,9 +178,7 @@ func (w *inotify) Close() error { return err } - // Wait for goroutine to close - <-w.doneResp - + <-w.doneResp // Wait for readEvents() to finish. return nil } @@ -266,6 +198,40 @@ func (w *inotify) AddWith(path string, opts ...addOpt) error { return fmt.Errorf("%w: %s", xErrUnsupported, with.op) } + add := func(path string, with withOpts, wf watchFlag) error { + var flags uint32 + if with.op.Has(Create) { + flags |= unix.IN_CREATE + } + if with.op.Has(Write) { + flags |= unix.IN_MODIFY + } + if with.op.Has(Remove) { + flags |= unix.IN_DELETE | unix.IN_DELETE_SELF + } + if with.op.Has(Rename) { + flags |= unix.IN_MOVED_TO | unix.IN_MOVED_FROM | unix.IN_MOVE_SELF + } + if with.op.Has(Chmod) { + flags |= unix.IN_ATTRIB + } + if with.op.Has(xUnportableOpen) { + flags |= unix.IN_OPEN + } + if with.op.Has(xUnportableRead) { + flags |= unix.IN_ACCESS + } + if with.op.Has(xUnportableCloseWrite) { + flags |= unix.IN_CLOSE_WRITE + } + if with.op.Has(xUnportableCloseRead) { + flags |= unix.IN_CLOSE_NOWRITE + } + return w.register(path, flags, wf) + } + + w.mu.Lock() + defer w.mu.Unlock() path, recurse := recursivePath(path) if recurse { return filepath.WalkDir(path, func(root string, d fs.DirEntry, err error) error { @@ -289,49 +255,18 @@ func (w *inotify) AddWith(path string, opts ...addOpt) error { w.sendEvent(Event{Name: root, Op: Create}) } - return w.add(root, with, true) + wf := flagRecurse + if root == path { + wf |= flagByUser + } + return add(root, with, wf) }) } - return w.add(path, with, false) + return add(path, with, 0) } -func (w *inotify) add(path string, with withOpts, recurse bool) error { - var flags uint32 - if with.noFollow { - flags |= unix.IN_DONT_FOLLOW - } - if with.op.Has(Create) { - flags |= unix.IN_CREATE - } - if with.op.Has(Write) { - flags |= unix.IN_MODIFY - } - if with.op.Has(Remove) { - flags |= unix.IN_DELETE | unix.IN_DELETE_SELF - } - if with.op.Has(Rename) { - flags |= unix.IN_MOVED_TO | unix.IN_MOVED_FROM | unix.IN_MOVE_SELF - } - if with.op.Has(Chmod) { - flags |= unix.IN_ATTRIB - } - if with.op.Has(xUnportableOpen) { - flags |= unix.IN_OPEN - } - if with.op.Has(xUnportableRead) { - flags |= unix.IN_ACCESS - } - if with.op.Has(xUnportableCloseWrite) { - flags |= unix.IN_CLOSE_WRITE - } - if with.op.Has(xUnportableCloseRead) { - flags |= unix.IN_CLOSE_NOWRITE - } - return w.register(path, flags, recurse) -} - -func (w *inotify) register(path string, flags uint32, recurse bool) error { +func (w *inotify) register(path string, flags uint32, wf watchFlag) error { return w.watches.updatePath(path, func(existing *watch) (*watch, error) { if existing != nil { flags |= existing.flags | unix.IN_MASK_ADD @@ -342,12 +277,16 @@ func (w *inotify) register(path string, flags uint32, recurse bool) error { return nil, err } + if e, ok := w.watches.wd[uint32(wd)]; ok { + return e, nil + } + if existing == nil { return &watch{ - wd: uint32(wd), - path: path, - flags: flags, - recurse: recurse, + wd: uint32(wd), + path: path, + flags: flags, + watchFlags: wf, }, nil } @@ -365,6 +304,9 @@ func (w *inotify) Remove(name string) error { fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n", time.Now().Format("15:04:05.000000000"), name) } + + w.mu.Lock() + defer w.mu.Unlock() return w.remove(filepath.Clean(name)) } @@ -399,13 +341,12 @@ func (w *inotify) WatchList() []string { return nil } + w.mu.Lock() + defer w.mu.Unlock() entries := make([]string, 0, w.watches.len()) - w.watches.mu.RLock() for pathname := range w.watches.path { entries = append(entries, pathname) } - w.watches.mu.RUnlock() - return entries } @@ -418,21 +359,17 @@ func (w *inotify) readEvents() { close(w.Events) }() - var ( - buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events - errno error // Syscall errno - ) + var buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events for { - // See if we have been closed. if w.isClosed() { return } n, err := w.inotifyFile.Read(buf[:]) - switch { - case errors.Unwrap(err) == os.ErrClosed: - return - case err != nil: + if err != nil { + if errors.Is(err, os.ErrClosed) { + return + } if !w.sendError(err) { return } @@ -440,13 +377,9 @@ func (w *inotify) readEvents() { } if n < unix.SizeofInotifyEvent { - var err error + err := errors.New("notify: short read in readEvents()") // Read was too short. if n == 0 { err = io.EOF // If EOF is received. This should really never happen. - } else if n < 0 { - err = errno // If an error occurred while reading. - } else { - err = errors.New("notify: short read in readEvents()") // Read was too short. } if !w.sendError(err) { return @@ -454,140 +387,146 @@ func (w *inotify) readEvents() { continue } - // We don't know how many events we just read into the buffer - // While the offset points to at least one whole event... + // We don't know how many events we just read into the buffer While the + // offset points to at least one whole event. var offset uint32 for offset <= uint32(n-unix.SizeofInotifyEvent) { - var ( - // Point "raw" to the event in the buffer - raw = (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) - mask = uint32(raw.Mask) - nameLen = uint32(raw.Len) - // Move to the next event in the buffer - next = func() { offset += unix.SizeofInotifyEvent + nameLen } - ) - - if mask&unix.IN_Q_OVERFLOW != 0 { + // Point to the event in the buffer. + inEvent := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) + + if inEvent.Mask&unix.IN_Q_OVERFLOW != 0 { if !w.sendError(ErrEventOverflow) { return } } - /// If the event happened to the watched directory or the watched - /// file, the kernel doesn't append the filename to the event, but - /// we would like to always fill the the "Name" field with a valid - /// filename. We retrieve the path of the watch from the "paths" - /// map. - watch := w.watches.byWd(uint32(raw.Wd)) - /// Can be nil if Remove() was called in another goroutine for this - /// path inbetween reading the events from the kernel and reading - /// the internal state. Not much we can do about it, so just skip. - /// See #616. - if watch == nil { - next() - continue + ev, ok := w.handleEvent(inEvent, &buf, offset) + if !ok { + return } - - name := watch.path - if nameLen > 0 { - /// Point "bytes" at the first byte of the filename - bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen] - /// The filename is padded with NULL bytes. TrimRight() gets rid of those. - name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") + if !w.sendEvent(ev) { + return } - if debug { - internal.Debug(name, raw.Mask, raw.Cookie) - } + // Move to the next event in the buffer + offset += unix.SizeofInotifyEvent + inEvent.Len + } + } +} - if mask&unix.IN_IGNORED != 0 { //&& event.Op != 0 - next() - continue - } +func (w *inotify) handleEvent(inEvent *unix.InotifyEvent, buf *[65536]byte, offset uint32) (Event, bool) { + w.mu.Lock() + defer w.mu.Unlock() - // inotify will automatically remove the watch on deletes; just need - // to clean our state here. - if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { - w.watches.remove(watch.wd) - } + /// If the event happened to the watched directory or the watched file, the + /// kernel doesn't append the filename to the event, but we would like to + /// always fill the the "Name" field with a valid filename. We retrieve the + /// path of the watch from the "paths" map. + /// + /// Can be nil if Remove() was called in another goroutine for this path + /// inbetween reading the events from the kernel and reading the internal + /// state. Not much we can do about it, so just skip. See #616. + watch := w.watches.byWd(uint32(inEvent.Wd)) + if watch == nil { + return Event{}, true + } - // We can't really update the state when a watched path is moved; - // only IN_MOVE_SELF is sent and not IN_MOVED_{FROM,TO}. So remove - // the watch. - if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF { - if watch.recurse { - next() // Do nothing - continue - } + var ( + name = watch.path + nameLen = uint32(inEvent.Len) + ) + if nameLen > 0 { + name += "/" + inotifyEventName(buf, offset, nameLen) + } - err := w.remove(watch.path) - if err != nil && !errors.Is(err, ErrNonExistentWatch) { - if !w.sendError(err) { - return - } - } + if debug { + internal.Debug(name, inEvent.Mask, inEvent.Cookie) + } + + if inEvent.Mask&unix.IN_IGNORED != 0 || inEvent.Mask&unix.IN_UNMOUNT != 0 { + w.watches.remove(watch) + return Event{}, true + } + + // inotify will automatically remove the watch on deletes; just need + // to clean our state here. + if inEvent.Mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { + w.watches.remove(watch) + } + + // We can't really update the state when a watched path is moved; only + // IN_MOVE_SELF is sent and not IN_MOVED_{FROM,TO}. So remove the watch. + if inEvent.Mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF { + // Watch is set up as part of recurse: do nothing as the move gets + // registered from the parent directory. + if watch.recurse() && !watch.byUser() { + return Event{}, true + } + + err := w.remove(watch.path) + if err != nil && !errors.Is(err, ErrNonExistentWatch) { + if !w.sendError(err) { + return Event{}, false } + } - /// Skip if we're watching both this path and the parent; the parent - /// will already send a delete so no need to do it twice. - if mask&unix.IN_DELETE_SELF != 0 { - if _, ok := w.watches.path[filepath.Dir(watch.path)]; ok { - next() - continue - } + if watch.recurse() { + return Event{Name: watch.path, Op: Rename}, true + } + } + + /// Skip if we're watching both this path and the parent; the parent will + /// already send a delete so no need to do it twice. + if inEvent.Mask&unix.IN_DELETE_SELF != 0 { + _, ok := w.watches.path[filepath.Dir(watch.path)] + if ok { + return Event{}, true + } + } + + ev := w.newEvent(name, inEvent.Mask, inEvent.Cookie) + // Need to update watch path for recurse. + if watch.recurse() { + isDir := inEvent.Mask&unix.IN_ISDIR == unix.IN_ISDIR + /// New directory created: set up watch on it. + if isDir && ev.Has(Create) { + err := w.register(ev.Name, watch.flags, flagRecurse) + if !w.sendError(err) { + return Event{}, false } - ev := w.newEvent(name, mask, raw.Cookie) - // Need to update watch path for recurse. - if watch.recurse { - isDir := mask&unix.IN_ISDIR == unix.IN_ISDIR - /// New directory created: set up watch on it. - if isDir && ev.Has(Create) { - err := w.register(ev.Name, watch.flags, true) - if !w.sendError(err) { - return + // This was a directory rename, so we need to update all the + // children. + // + // TODO: this is of course pretty slow; we should use a better data + // structure for storing all of this, e.g. store children in the + // watch. I have some code for this in my kqueue refactor we can use + // in the future. For now I'm okay with this as it's not publicly + // available. Correctness first, performance second. + if ev.renamedFrom != "" { + for k, ww := range w.watches.wd { + if k == watch.wd || ww.path == ev.Name { + continue } - - // This was a directory rename, so we need to update all - // the children. - // - // TODO: this is of course pretty slow; we should use a - // better data structure for storing all of this, e.g. store - // children in the watch. I have some code for this in my - // kqueue refactor we can use in the future. For now I'm - // okay with this as it's not publicly available. - // Correctness first, performance second. - if ev.renamedFrom != "" { - w.watches.mu.Lock() - for k, ww := range w.watches.wd { - if k == watch.wd || ww.path == ev.Name { - continue - } - if strings.HasPrefix(ww.path, ev.renamedFrom) { - ww.path = strings.Replace(ww.path, ev.renamedFrom, ev.Name, 1) - w.watches.wd[k] = ww - } - } - w.watches.mu.Unlock() + if isSameOrDescendantPath(ww.path, ev.renamedFrom) { + ww.path = strings.Replace(ww.path, ev.renamedFrom, ev.Name, 1) + w.watches.wd[k] = ww } } } - - /// Send the events that are not ignored on the events channel - if !w.sendEvent(ev) { - return - } - next() } } + + return ev, true } -func (w *inotify) isRecursive(path string) bool { - ww := w.watches.byPath(path) - if ww == nil { // path could be a file, so also check the Dir. - ww = w.watches.byPath(filepath.Dir(path)) +func inotifyEventName(buf *[65536]byte, offset, nameLen uint32) string { + start := int(offset + unix.SizeofInotifyEvent) + bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[start]))[:nameLen:nameLen] + for nameLen > 0 && bytes[nameLen-1] == 0 { + nameLen-- } - return ww != nil && ww.recurse + return string(bytes[:nameLen]) } func (w *inotify) newEvent(name string, mask, cookie uint32) Event { @@ -650,9 +589,9 @@ func (w *inotify) xSupports(op Op) bool { } func (w *inotify) state() { - w.watches.mu.Lock() - defer w.watches.mu.Unlock() + w.mu.Lock() + defer w.mu.Unlock() for wd, ww := range w.watches.wd { - fmt.Fprintf(os.Stderr, "%4d: recurse=%t %q\n", wd, ww.recurse, ww.path) + fmt.Fprintf(os.Stderr, "%4d: %q watchFlags=0x%x\n", wd, ww.path, ww.watchFlags) } } diff --git a/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go index d8de5ab..d2c8cfb 100644 --- a/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go +++ b/vendor/github.com/fsnotify/fsnotify/backend_kqueue.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "runtime" + "sort" "sync" "time" @@ -16,14 +17,13 @@ import ( ) type kqueue struct { + *shared Events chan Event Errors chan error kq int // File descriptor (as returned by the kqueue() syscall). closepipe [2]int // Pipe used for closing kq. watches *watches - done chan struct{} - doneMu sync.Mutex } type ( @@ -132,14 +132,18 @@ func (w *watches) byPath(path string) (watch, bool) { return info, ok } -func (w *watches) updateDirFlags(path string, flags uint32) { +func (w *watches) updateDirFlags(path string, flags uint32) bool { w.mu.Lock() defer w.mu.Unlock() - fd := w.path[path] + fd, ok := w.path[path] + if !ok { // Already deleted: don't re-set it here. + return false + } info := w.wd[fd] info.dirFlags = flags w.wd[fd] = info + return true } func (w *watches) remove(fd int, path string) bool { @@ -179,22 +183,20 @@ func (w *watches) seenBefore(path string) bool { return ok } -func newBackend(ev chan Event, errs chan error) (backend, error) { - return newBufferedBackend(0, ev, errs) -} +var defaultBufferSize = 0 -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { +func newBackend(ev chan Event, errs chan error) (backend, error) { kq, closepipe, err := newKqueue() if err != nil { return nil, err } w := &kqueue{ + shared: newShared(ev, errs), Events: ev, Errors: errs, kq: kq, closepipe: closepipe, - done: make(chan struct{}), watches: newWatches(), } @@ -210,7 +212,7 @@ func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error // all. func newKqueue() (kq int, closepipe [2]int, err error) { kq, err = unix.Kqueue() - if kq == -1 { + if err != nil { return kq, closepipe, err } @@ -239,54 +241,34 @@ func newKqueue() (kq int, closepipe [2]int, err error) { return kq, closepipe, nil } -// Returns true if the event was sent, or false if watcher is closed. -func (w *kqueue) sendEvent(e Event) bool { - select { - case <-w.done: - return false - case w.Events <- e: - return true - } -} - -// Returns true if the error was sent, or false if watcher is closed. -func (w *kqueue) sendError(err error) bool { - if err == nil { - return true - } - select { - case <-w.done: - return false - case w.Errors <- err: - return true - } -} - -func (w *kqueue) isClosed() bool { - select { - case <-w.done: - return true - default: - return false - } -} - func (w *kqueue) Close() error { - w.doneMu.Lock() - if w.isClosed() { - w.doneMu.Unlock() + if w.shared.close() { return nil } - close(w.done) - w.doneMu.Unlock() + // Snapshot and drop all watches directly. w.Remove -> w.remove + // short-circuits on isClosed() (which is already true after + // w.shared.close() above), so calling Remove here in the happy path + // leaked every watched directory + file descriptor. On macOS a + // single directory watch opens an fd for every file in the dir, so + // long-running processes that recreate watchers (hot-reload dev + // servers, etc.) ran out of fds with EMFILE (#732). pathsToRemove := w.watches.listPaths(false) for _, name := range pathsToRemove { - w.Remove(name) + info, ok := w.watches.byPath(name) + if !ok { + // w.path has an entry for name but w.wd doesn't -- + // drop the stale lookup entry so the map state is + // consistent after Close. + w.watches.remove(0, name) + continue + } + _ = w.register([]int{info.wd}, unix.EV_DELETE, 0) + unix.Close(info.wd) + w.watches.remove(info.wd, name) } - // Send "quit" message to the reader goroutine. - unix.Close(w.closepipe[1]) + unix.Close(w.closepipe[1]) // Send "quit" message to readEvents return nil } @@ -303,7 +285,7 @@ func (w *kqueue) AddWith(name string, opts ...addOpt) error { return fmt.Errorf("%w: %s", xErrUnsupported, with.op) } - _, err := w.addWatch(name, noteAllEvents) + _, err := w.addWatch(name, noteAllEvents, false) if err != nil { return err } @@ -366,7 +348,7 @@ const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | un // described in kevent(2). // // Returns the real path to the file which was added, with symlinks resolved. -func (w *kqueue) addWatch(name string, flags uint32) (string, error) { +func (w *kqueue) addWatch(name string, flags uint32, listDir bool) (string, error) { if w.isClosed() { return "", ErrClosed } @@ -385,15 +367,15 @@ func (w *kqueue) addWatch(name string, flags uint32) (string, error) { return "", nil } - // Follow symlinks. - if fi.Mode()&os.ModeSymlink == os.ModeSymlink { + // Follow symlinks, but only for paths added with Add(), and not paths + // we're adding from internalWatch from a listdir. + if !listDir && fi.Mode()&os.ModeSymlink == os.ModeSymlink { link, err := os.Readlink(name) if err != nil { - // Return nil because Linux can add unresolvable symlinks to the - // watch list without problems, so maintain consistency with - // that. There will be no file events for broken symlinks. - // TODO: more specific check; returns os.PathError; ENOENT? - return "", nil + return "", err + } + if !filepath.IsAbs(link) { + link = filepath.Join(filepath.Dir(name), link) } _, alreadyWatching = w.watches.byPath(link) @@ -408,24 +390,16 @@ func (w *kqueue) addWatch(name string, flags uint32) (string, error) { name = link fi, err = os.Lstat(name) if err != nil { - return "", nil + return "", err } } - // Retry on EINTR; open() can return EINTR in practice on macOS. - // See #354, and Go issues 11180 and 39237. - for { - info.wd, err = unix.Open(name, openMode, 0) - if err == nil { - break - } - if errors.Is(err, unix.EINTR) { - continue - } - + info.wd, err = internal.IgnoringEINTR(func() (int, error) { + return unix.Open(name, openMode, 0) + }) + if err != nil { return "", err } - info.isDir = fi.IsDir() } @@ -444,10 +418,16 @@ func (w *kqueue) addWatch(name string, flags uint32) (string, error) { if info.isDir { watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && (!alreadyWatching || (info.dirFlags&unix.NOTE_WRITE) != unix.NOTE_WRITE) - w.watches.updateDirFlags(name, flags) + if !w.watches.updateDirFlags(name, flags) { + return "", nil + } if watchDir { - if err := w.watchDirectoryFiles(name); err != nil { + d := name + if info.linkName != "" { + d = info.linkName + } + if err := w.watchDirectoryFiles(d); err != nil { return "", err } } @@ -467,9 +447,10 @@ func (w *kqueue) readEvents() { eventBuffer := make([]unix.Kevent_t, 10) for { - kevents, err := w.read(eventBuffer) - // EINTR is okay, the syscall was interrupted before timeout expired. - if err != nil && err != unix.EINTR { + kevents, err := internal.IgnoringEINTR(func() ([]unix.Kevent_t, error) { + return w.read(eventBuffer) + }) + if err != nil { if !w.sendError(fmt.Errorf("fsnotify.readEvents: %w", err)) { return } @@ -614,12 +595,14 @@ func (w *kqueue) watchDirectoryFiles(dirPath string) error { cleanPath, err := w.internalWatch(path, fi) if err != nil { - // No permission to read the file; that's not a problem: just skip. - // But do add it to w.fileExists to prevent it from being picked up - // as a "new" file later (it still shows up in the directory + // No permission, or the entry resolved to a missing target + // (e.g. a dangling symlink): not a problem, just skip. But + // do mark it as seen to prevent it from being picked up as + // a "new" file later (it still shows up in the directory // listing). switch { - case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM): + case errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) || + errors.Is(err, os.ErrNotExist): cleanPath = filepath.Clean(path) default: return fmt.Errorf("%q: %w", path, err) @@ -644,19 +627,22 @@ func (w *kqueue) dirChange(dir string) error { if errors.Is(err, os.ErrNotExist) { return nil } - return fmt.Errorf("fsnotify.dirChange: %w", err) + return fmt.Errorf("fsnotify.dirChange %q: %w", dir, err) } for _, f := range files { fi, err := f.Info() if err != nil { + if errors.Is(err, os.ErrNotExist) { + return nil + } return fmt.Errorf("fsnotify.dirChange: %w", err) } err = w.sendCreateIfNew(filepath.Join(dir, fi.Name()), fi) if err != nil { // Don't need to send an error if this file isn't readable. - if errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) { + if errors.Is(err, unix.EACCES) || errors.Is(err, unix.EPERM) || errors.Is(err, os.ErrNotExist) { return nil } return fmt.Errorf("fsnotify.dirChange: %w", err) @@ -688,11 +674,11 @@ func (w *kqueue) internalWatch(name string, fi os.FileInfo) (string, error) { // mimic Linux providing delete events for subdirectories, but preserve // the flags used if currently watching subdirectory info, _ := w.watches.byPath(name) - return w.addWatch(name, info.dirFlags|unix.NOTE_DELETE|unix.NOTE_RENAME) + return w.addWatch(name, info.dirFlags|unix.NOTE_DELETE|unix.NOTE_RENAME, true) } - // watch file to mimic Linux inotify - return w.addWatch(name, noteAllEvents) + // Watch file to mimic Linux inotify. + return w.addWatch(name, noteAllEvents, true) } // Register events with the queue. @@ -722,12 +708,28 @@ func (w *kqueue) read(events []unix.Kevent_t) ([]unix.Kevent_t, error) { } func (w *kqueue) xSupports(op Op) bool { - if runtime.GOOS == "freebsd" { - //return true // Supports everything. - } + //if runtime.GOOS == "freebsd" { + // return true // Supports everything. + //} if op.Has(xUnportableOpen) || op.Has(xUnportableRead) || op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) { return false } return true } + +func (w *kqueue) state() { + w.watches.mu.Lock() + defer w.watches.mu.Unlock() + + all := make([]int, 0, len(w.watches.wd)) + for wd := range w.watches.wd { + all = append(all, wd) + } + sort.Ints(all) + + for _, wd := range all { + ww := w.watches.wd[wd] + fmt.Fprintf(os.Stderr, "%4d %q linkname=%q\n", wd, ww.name, ww.linkName) + } +} diff --git a/vendor/github.com/fsnotify/fsnotify/backend_other.go b/vendor/github.com/fsnotify/fsnotify/backend_other.go index 5eb5dbc..b8c0ad7 100644 --- a/vendor/github.com/fsnotify/fsnotify/backend_other.go +++ b/vendor/github.com/fsnotify/fsnotify/backend_other.go @@ -9,12 +9,11 @@ type other struct { Errors chan error } +var defaultBufferSize = 0 + func newBackend(ev chan Event, errs chan error) (backend, error) { return nil, errors.New("fsnotify not supported on the current platform") } -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { - return newBackend(ev, errs) -} func (w *other) Close() error { return nil } func (w *other) WatchList() []string { return nil } func (w *other) Add(name string) error { return nil } diff --git a/vendor/github.com/fsnotify/fsnotify/backend_windows.go b/vendor/github.com/fsnotify/fsnotify/backend_windows.go index c54a630..fb9210f 100644 --- a/vendor/github.com/fsnotify/fsnotify/backend_windows.go +++ b/vendor/github.com/fsnotify/fsnotify/backend_windows.go @@ -11,7 +11,6 @@ import ( "fmt" "os" "path/filepath" - "reflect" "runtime" "strings" "sync" @@ -28,18 +27,23 @@ type readDirChangesW struct { port windows.Handle // Handle to completion port input chan *input // Inputs to the reader are sent on this channel - quit chan chan<- error + done chan chan<- error mu sync.Mutex // Protects access to watches, closed watches watchMap // Map of watches (key: i-number) closed bool // Set to true when Close() is first called } -func newBackend(ev chan Event, errs chan error) (backend, error) { - return newBufferedBackend(50, ev, errs) +var defaultBufferSize = 50 + +func isSameOrDescendantPath(path, root string) bool { + if path == root { + return true + } + return strings.HasPrefix(path, root+string(os.PathSeparator)) } -func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) { +func newBackend(ev chan Event, errs chan error) (backend, error) { port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0) if err != nil { return nil, os.NewSyscallError("CreateIoCompletionPort", err) @@ -50,7 +54,7 @@ func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error port: port, watches: make(watchMap), input: make(chan *input, 1), - quit: make(chan chan<- error, 1), + done: make(chan chan<- error, 1), } go w.readEvents() return w, nil @@ -70,8 +74,8 @@ func (w *readDirChangesW) sendEvent(name, renamedFrom string, mask uint64) bool event := w.newEvent(name, uint32(mask)) event.renamedFrom = renamedFrom select { - case ch := <-w.quit: - w.quit <- ch + case ch := <-w.done: + w.done <- ch case w.Events <- event: } return true @@ -83,10 +87,10 @@ func (w *readDirChangesW) sendError(err error) bool { return true } select { + case <-w.done: + return false case w.Errors <- err: return true - case <-w.quit: - return false } } @@ -99,9 +103,9 @@ func (w *readDirChangesW) Close() error { w.closed = true w.mu.Unlock() - // Send "quit" message to the reader goroutine + // Send "done" message to the reader goroutine ch := make(chan error) - w.quit <- ch + w.done <- ch if err := w.wakeupReader(); err != nil { return err } @@ -361,22 +365,26 @@ func (w *readDirChangesW) addWatch(pathname string, flags uint64, bufsize int) e } else { windows.CloseHandle(ino.handle) } + w.mu.Lock() if pathname == dir { watchEntry.mask |= flags } else { watchEntry.names[filepath.Base(pathname)] |= flags } + w.mu.Unlock() err = w.startRead(watchEntry) if err != nil { return err } + w.mu.Lock() if pathname == dir { watchEntry.mask &= ^provisional } else { watchEntry.names[filepath.Base(pathname)] &= ^provisional } + w.mu.Unlock() return nil } @@ -396,8 +404,13 @@ func (w *readDirChangesW) remWatch(pathname string) error { w.mu.Lock() watch := w.watches.get(ino) w.mu.Unlock() + if watch == nil { + windows.CloseHandle(ino.handle) + return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname) + } if recurse && !watch.recurse { + windows.CloseHandle(ino.handle) return fmt.Errorf("can't use \\... with non-recursive watch %q", pathname) } @@ -405,16 +418,19 @@ func (w *readDirChangesW) remWatch(pathname string) error { if err != nil { w.sendError(os.NewSyscallError("CloseHandle", err)) } - if watch == nil { - return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname) - } if pathname == dir { - w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED) + w.mu.Lock() + mask := watch.mask watch.mask = 0 + w.mu.Unlock() + w.sendEvent(watch.path, "", mask&sysFSIGNORED) } else { name := filepath.Base(pathname) - w.sendEvent(filepath.Join(watch.path, name), "", watch.names[name]&sysFSIGNORED) + w.mu.Lock() + mask := watch.names[name] delete(watch.names, name) + w.mu.Unlock() + w.sendEvent(filepath.Join(watch.path, name), "", mask&sysFSIGNORED) } return w.startRead(watch) @@ -422,17 +438,23 @@ func (w *readDirChangesW) remWatch(pathname string) error { // Must run within the I/O thread. func (w *readDirChangesW) deleteWatch(watch *watch) { - for name, mask := range watch.names { - if mask&provisional == 0 { - w.sendEvent(filepath.Join(watch.path, name), "", mask&sysFSIGNORED) + // Snapshot+clear under the lock so concurrent WatchList() readers see a + // consistent state. sendEvent must run outside the lock since it can + // block on the user-facing Events channel. + w.mu.Lock() + names := watch.names + watch.names = make(map[string]uint64) + mask := watch.mask + watch.mask = 0 + w.mu.Unlock() + + for name, m := range names { + if m&provisional == 0 { + w.sendEvent(filepath.Join(watch.path, name), "", m&sysFSIGNORED) } - delete(watch.names, name) } - if watch.mask != 0 { - if watch.mask&provisional == 0 { - w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED) - } - watch.mask = 0 + if mask != 0 && mask&provisional == 0 { + w.sendEvent(watch.path, "", mask&sysFSIGNORED) } } @@ -459,9 +481,8 @@ func (w *readDirChangesW) startRead(watch *watch) error { } // We need to pass the array, rather than the slice. - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&watch.buf)) rdErr := windows.ReadDirectoryChanges(watch.ino.handle, - (*byte)(unsafe.Pointer(hdr.Data)), uint32(hdr.Len), + unsafe.SliceData(watch.buf), uint32(len(watch.buf)), watch.recurse, mask, nil, &watch.ov, 0) if rdErr != nil { err := os.NewSyscallError("ReadDirectoryChanges", rdErr) @@ -495,7 +516,7 @@ func (w *readDirChangesW) readEvents() { watch := (*watch)(unsafe.Pointer(ov)) if watch == nil { select { - case ch := <-w.quit: + case ch := <-w.done: w.mu.Lock() var indexes []indexMap for _, index := range w.watches { @@ -567,12 +588,7 @@ func (w *readDirChangesW) readEvents() { // Create a buf that is the size of the path name size := int(raw.FileNameLength / 2) - var buf []uint16 - // TODO: Use unsafe.Slice in Go 1.17; https://stackoverflow.com/questions/51187973 - sh := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) - sh.Data = uintptr(unsafe.Pointer(&raw.FileName)) - sh.Len = size - sh.Cap = size + buf := unsafe.Slice(&raw.FileName, size) name := windows.UTF16ToString(buf) fullname := filepath.Join(watch.path, name) @@ -589,31 +605,35 @@ func (w *readDirChangesW) readEvents() { case windows.FILE_ACTION_RENAMED_OLD_NAME: watch.rename = name case windows.FILE_ACTION_RENAMED_NEW_NAME: - // Update saved path of all sub-watches. + // Update saved path of all sub-watches and rename the + // names entry under the lock so WatchList() can't observe + // a torn state. old := filepath.Join(watch.path, watch.rename) w.mu.Lock() for _, watchMap := range w.watches { for _, ww := range watchMap { - if strings.HasPrefix(ww.path, old) { + if isSameOrDescendantPath(ww.path, old) { ww.path = filepath.Join(fullname, strings.TrimPrefix(ww.path, old)) } } } - w.mu.Unlock() - if watch.names[watch.rename] != 0 { watch.names[name] |= watch.names[watch.rename] delete(watch.names, watch.rename) mask = sysFSMOVESELF } + w.mu.Unlock() } if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME { w.sendEvent(fullname, "", watch.names[name]&mask) } if raw.Action == windows.FILE_ACTION_REMOVED { - w.sendEvent(fullname, "", watch.names[name]&sysFSIGNORED) + w.mu.Lock() + ignored := watch.names[name] & sysFSIGNORED delete(watch.names, name) + w.mu.Unlock() + w.sendEvent(fullname, "", ignored) } if watch.rename != "" && raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME { diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go index 0760efe..38cb4dd 100644 --- a/vendor/github.com/fsnotify/fsnotify/fsnotify.go +++ b/vendor/github.com/fsnotify/fsnotify/fsnotify.go @@ -51,26 +51,25 @@ import ( // The fs.inotify.max_user_watches sysctl variable specifies the upper limit // for the number of watches per user, and fs.inotify.max_user_instances // specifies the maximum number of inotify instances per user. Every Watcher you -// create is an "instance", and every path you add is a "watch". +// create is an "instance", and every path you add is a "watch". Reaching the +// limit will result in a "no space left on device" or "too many open files" +// error. // // These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and -// /proc/sys/fs/inotify/max_user_instances +// /proc/sys/fs/inotify/max_user_instances. The default values differ per distro +// and available memory. // // To increase them you can use sysctl or write the value to the /proc file: // -// # Default values on Linux 5.18 -// sysctl fs.inotify.max_user_watches=124983 -// sysctl fs.inotify.max_user_instances=128 +// sysctl fs.inotify.max_user_watches=200000 +// sysctl fs.inotify.max_user_instances=256 // // To make the changes persist on reboot edit /etc/sysctl.conf or // /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check // your distro's documentation): // -// fs.inotify.max_user_watches=124983 -// fs.inotify.max_user_instances=128 -// -// Reaching the limit will result in a "no space left on device" or "too many open -// files" error. +// fs.inotify.max_user_watches=200000 +// fs.inotify.max_user_instances=256 // // # kqueue notes (macOS, BSD) // @@ -93,6 +92,28 @@ import ( // Sometimes it will send events for all files, sometimes it will send no // events, and often only for some files. // +// Recursive watching is not currently enabled through fsnotify's public +// API; the recursive code path is gated and only exercised by fsnotify's +// own tests. The note below describes backend behavior observed when +// recursive watching is enabled internally, and is kept here as a +// reference for maintainers and contributors who encounter it. +// +// When recursive watching is enabled and you watch a directory, you may +// receive a Write event for an intermediate directory whenever a child +// entry inside it is created, renamed, or removed. For example, with a +// recursive watch on /a and a new file /a/b/c, you will receive +// Create /a/b/c and may also receive Write /a/b. +// +// This happens because, on NTFS-backed volumes, modifying the entries of a +// directory updates that directory's last-write time, and the Windows +// backend requests FILE_NOTIFY_CHANGE_LAST_WRITE to support Write events +// on files. The same Write filter therefore picks up the directory's +// metadata update. +// +// Whether the directory Write is actually delivered alongside the child +// events is not guaranteed; it depends on ReadDirectoryChangesW buffering, +// NTFS metadata update timing, and event coalescing. +// // The default ReadDirectoryChangesW() buffer size is 64K, which is the largest // value that is guaranteed to work with SMB filesystems. If you have many // events in quick succession this may not be enough, and you will have to use @@ -129,8 +150,12 @@ type Watcher struct { // want to wait until you've stopped receiving them // (see the dedup example in cmd/fsnotify). // - // Some systems may send Write event for directories - // when the directory content changes. + // Some systems also send Write events for directories + // when the directory contents change. This is the + // case for kqueue, and on Windows for the directory + // that contains a created, renamed, or removed child + // entry. It does not happen on inotify. See the + // per-platform notes on [Watcher]. // // fsnotify.Chmod Attributes were changed. On Linux this is also sent // when a file is removed (or more accurately, when a @@ -179,7 +204,9 @@ const ( Create Op = 1 << iota // The pathname was written to; this does *not* mean the write has finished, - // and a write can be followed by more writes. + // and a write can be followed by more writes. On Windows and kqueue, a + // Write on a directory can also indicate that its contents changed; see + // the per-platform notes on [Watcher]. Write // The path was removed; any watches on it will be removed. Some "remove" @@ -220,7 +247,7 @@ const ( // File opened for reading was closed. // - // Only works on Linux and FreeBSD. + // Only works on Linux. xUnportableCloseRead ) @@ -244,12 +271,13 @@ var ( // ErrUnsupported is returned by AddWith() when WithOps() specified an // Unportable event that's not supported on this platform. + //lint:ignore ST1012 not relevant xErrUnsupported = errors.New("fsnotify: not supported with this backend") ) // NewWatcher creates a new Watcher. func NewWatcher() (*Watcher, error) { - ev, errs := make(chan Event), make(chan error) + ev, errs := make(chan Event, defaultBufferSize), make(chan error) b, err := newBackend(ev, errs) if err != nil { return nil, err @@ -266,8 +294,8 @@ func NewWatcher() (*Watcher, error) { // cases, and whenever possible you will be better off increasing the kernel // buffers instead of adding a large userspace buffer. func NewBufferedWatcher(sz uint) (*Watcher, error) { - ev, errs := make(chan Event), make(chan error) - b, err := newBufferedBackend(sz, ev, errs) + ev, errs := make(chan Event, sz), make(chan error) + b, err := newBackend(ev, errs) if err != nil { return nil, err } @@ -337,7 +365,8 @@ func (w *Watcher) Close() error { return w.b.Close() } // WatchList returns all paths explicitly added with [Watcher.Add] (and are not // yet removed). // -// Returns nil if [Watcher.Close] was called. +// The order is undefined, and may differ per call. Returns nil if +// [Watcher.Close] was called. func (w *Watcher) WatchList() []string { return w.b.WatchList() } // Supports reports if all the listed operations are supported by this platform. @@ -408,7 +437,6 @@ type ( withOpts struct { bufsize int op Op - noFollow bool sendCreate bool } ) @@ -467,12 +495,6 @@ func withOps(op Op) addOpt { return func(opt *withOpts) { opt.op = op } } -// WithNoFollow disables following symlinks, so the symlinks themselves are -// watched. -func withNoFollow() addOpt { - return func(opt *withOpts) { opt.noFollow = true } -} - // "Internal" option for recursive watches on inotify. func withCreate() addOpt { return func(opt *withOpts) { opt.sendCreate = true } @@ -492,3 +514,13 @@ func recursivePath(path string) (string, bool) { } return path, false } + +type watchFlag uint8 + +const ( + // Added by user with Add(), rather than an internal watch. + flagByUser = watchFlag(0x01) + // Part of recursive watch; as the top-level path added by the user or an + // "internal" watch. + flagRecurse = watchFlag(0x02) +) diff --git a/vendor/github.com/fsnotify/fsnotify/internal/darwin.go b/vendor/github.com/fsnotify/fsnotify/internal/darwin.go index b0eab10..6721aa6 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/darwin.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/darwin.go @@ -9,31 +9,12 @@ import ( ) var ( - SyscallEACCES = syscall.EACCES - UnixEACCES = unix.EACCES + ErrSyscallEACCES = syscall.EACCES + ErrUnixEACCES = unix.EACCES ) var maxfiles uint64 -// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/ -func SetRlimit() { - var l syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l) - if err == nil && l.Cur != l.Max { - l.Cur = l.Max - syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l) - } - maxfiles = l.Cur - - if n, err := syscall.SysctlUint32("kern.maxfiles"); err == nil && uint64(n) < maxfiles { - maxfiles = uint64(n) - } - - if n, err := syscall.SysctlUint32("kern.maxfilesperproc"); err == nil && uint64(n) < maxfiles { - maxfiles = uint64(n) - } -} - func Maxfiles() uint64 { return maxfiles } func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) } func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go index 928319f..7600180 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go @@ -6,52 +6,10 @@ var names = []struct { n string m uint32 }{ - {"NOTE_ABSOLUTE", unix.NOTE_ABSOLUTE}, {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - {"NOTE_BACKGROUND", unix.NOTE_BACKGROUND}, - {"NOTE_CHILD", unix.NOTE_CHILD}, - {"NOTE_CRITICAL", unix.NOTE_CRITICAL}, {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, - {"NOTE_EXITSTATUS", unix.NOTE_EXITSTATUS}, - {"NOTE_EXIT_CSERROR", unix.NOTE_EXIT_CSERROR}, - {"NOTE_EXIT_DECRYPTFAIL", unix.NOTE_EXIT_DECRYPTFAIL}, - {"NOTE_EXIT_DETAIL", unix.NOTE_EXIT_DETAIL}, - {"NOTE_EXIT_DETAIL_MASK", unix.NOTE_EXIT_DETAIL_MASK}, - {"NOTE_EXIT_MEMORY", unix.NOTE_EXIT_MEMORY}, - {"NOTE_EXIT_REPARENTED", unix.NOTE_EXIT_REPARENTED}, {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FFAND", unix.NOTE_FFAND}, - {"NOTE_FFCOPY", unix.NOTE_FFCOPY}, - {"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK}, - {"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK}, - {"NOTE_FFNOP", unix.NOTE_FFNOP}, - {"NOTE_FFOR", unix.NOTE_FFOR}, - {"NOTE_FORK", unix.NOTE_FORK}, - {"NOTE_FUNLOCK", unix.NOTE_FUNLOCK}, - {"NOTE_LEEWAY", unix.NOTE_LEEWAY}, {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_MACHTIME", unix.NOTE_MACHTIME}, - {"NOTE_MACH_CONTINUOUS_TIME", unix.NOTE_MACH_CONTINUOUS_TIME}, - {"NOTE_NONE", unix.NOTE_NONE}, - {"NOTE_NSECONDS", unix.NOTE_NSECONDS}, - {"NOTE_OOB", unix.NOTE_OOB}, - //{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, -0x100000 (?!) - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, - {"NOTE_REAP", unix.NOTE_REAP}, {"NOTE_RENAME", unix.NOTE_RENAME}, - {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_SECONDS", unix.NOTE_SECONDS}, - {"NOTE_SIGNAL", unix.NOTE_SIGNAL}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, - {"NOTE_TRIGGER", unix.NOTE_TRIGGER}, - {"NOTE_USECONDS", unix.NOTE_USECONDS}, - {"NOTE_VM_ERROR", unix.NOTE_VM_ERROR}, - {"NOTE_VM_PRESSURE", unix.NOTE_VM_PRESSURE}, - {"NOTE_VM_PRESSURE_SUDDEN_TERMINATE", unix.NOTE_VM_PRESSURE_SUDDEN_TERMINATE}, - {"NOTE_VM_PRESSURE_TERMINATE", unix.NOTE_VM_PRESSURE_TERMINATE}, {"NOTE_WRITE", unix.NOTE_WRITE}, } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go index 3186b0c..7600180 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go @@ -7,27 +7,9 @@ var names = []struct { m uint32 }{ {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - {"NOTE_CHILD", unix.NOTE_CHILD}, {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FFAND", unix.NOTE_FFAND}, - {"NOTE_FFCOPY", unix.NOTE_FFCOPY}, - {"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK}, - {"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK}, - {"NOTE_FFNOP", unix.NOTE_FFNOP}, - {"NOTE_FFOR", unix.NOTE_FFOR}, - {"NOTE_FORK", unix.NOTE_FORK}, {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_OOB", unix.NOTE_OOB}, - {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, {"NOTE_RENAME", unix.NOTE_RENAME}, - {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, - {"NOTE_TRIGGER", unix.NOTE_TRIGGER}, {"NOTE_WRITE", unix.NOTE_WRITE}, } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go index f69fdb9..b9e45f5 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go @@ -6,37 +6,15 @@ var names = []struct { n string m uint32 }{ - {"NOTE_ABSTIME", unix.NOTE_ABSTIME}, - {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - {"NOTE_CHILD", unix.NOTE_CHILD}, - {"NOTE_CLOSE", unix.NOTE_CLOSE}, - {"NOTE_CLOSE_WRITE", unix.NOTE_CLOSE_WRITE}, {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, + {"NOTE_WRITE", unix.NOTE_WRITE}, {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FFAND", unix.NOTE_FFAND}, - {"NOTE_FFCOPY", unix.NOTE_FFCOPY}, - {"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK}, - {"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK}, - {"NOTE_FFNOP", unix.NOTE_FFNOP}, - {"NOTE_FFOR", unix.NOTE_FFOR}, - {"NOTE_FILE_POLL", unix.NOTE_FILE_POLL}, - {"NOTE_FORK", unix.NOTE_FORK}, + {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_MSECONDS", unix.NOTE_MSECONDS}, - {"NOTE_NSECONDS", unix.NOTE_NSECONDS}, - {"NOTE_OPEN", unix.NOTE_OPEN}, - {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, - {"NOTE_READ", unix.NOTE_READ}, {"NOTE_RENAME", unix.NOTE_RENAME}, {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_SECONDS", unix.NOTE_SECONDS}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, - {"NOTE_TRIGGER", unix.NOTE_TRIGGER}, - {"NOTE_USECONDS", unix.NOTE_USECONDS}, - {"NOTE_WRITE", unix.NOTE_WRITE}, + {"NOTE_OPEN", unix.NOTE_OPEN}, + {"NOTE_CLOSE", unix.NOTE_CLOSE}, + {"NOTE_CLOSE_WRITE", unix.NOTE_CLOSE_WRITE}, + {"NOTE_READ", unix.NOTE_READ}, } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go index 607e683..5d81164 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go @@ -27,6 +27,6 @@ func Debug(name string, kevent *unix.Kevent_t) { if unknown > 0 { l = append(l, fmt.Sprintf("0x%x", unknown)) } - fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-60s → %q\n", + fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-20s → %q\n", time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name) } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go index e5b3b6f..7600180 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go @@ -7,19 +7,9 @@ var names = []struct { m uint32 }{ {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - {"NOTE_CHILD", unix.NOTE_CHILD}, {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FORK", unix.NOTE_FORK}, {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, {"NOTE_RENAME", unix.NOTE_RENAME}, - {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, {"NOTE_WRITE", unix.NOTE_WRITE}, } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go b/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go index 1dd455b..871766d 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go @@ -7,22 +7,10 @@ var names = []struct { m uint32 }{ {"NOTE_ATTRIB", unix.NOTE_ATTRIB}, - // {"NOTE_CHANGE", unix.NOTE_CHANGE}, // Not on 386? - {"NOTE_CHILD", unix.NOTE_CHILD}, {"NOTE_DELETE", unix.NOTE_DELETE}, - {"NOTE_EOF", unix.NOTE_EOF}, - {"NOTE_EXEC", unix.NOTE_EXEC}, - {"NOTE_EXIT", unix.NOTE_EXIT}, {"NOTE_EXTEND", unix.NOTE_EXTEND}, - {"NOTE_FORK", unix.NOTE_FORK}, {"NOTE_LINK", unix.NOTE_LINK}, - {"NOTE_LOWAT", unix.NOTE_LOWAT}, - {"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, - {"NOTE_PDATAMASK", unix.NOTE_PDATAMASK}, {"NOTE_RENAME", unix.NOTE_RENAME}, - {"NOTE_REVOKE", unix.NOTE_REVOKE}, - {"NOTE_TRACK", unix.NOTE_TRACK}, - {"NOTE_TRACKERR", unix.NOTE_TRACKERR}, {"NOTE_TRUNCATE", unix.NOTE_TRUNCATE}, {"NOTE_WRITE", unix.NOTE_WRITE}, } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go b/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go index 547df1d..758a249 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/freebsd.go @@ -9,23 +9,12 @@ import ( ) var ( - SyscallEACCES = syscall.EACCES - UnixEACCES = unix.EACCES + ErrSyscallEACCES = syscall.EACCES + ErrUnixEACCES = unix.EACCES ) var maxfiles uint64 -func SetRlimit() { - // Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/ - var l syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l) - if err == nil && l.Cur != l.Max { - l.Cur = l.Max - syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l) - } - maxfiles = uint64(l.Cur) -} - func Maxfiles() uint64 { return maxfiles } func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) } func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, uint64(dev)) } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/unix.go b/vendor/github.com/fsnotify/fsnotify/internal/unix.go index 30976ce..9c66f5d 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/unix.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/unix.go @@ -1,4 +1,4 @@ -//go:build !windows && !darwin && !freebsd +//go:build !windows && !darwin && !freebsd && !plan9 package internal @@ -9,23 +9,12 @@ import ( ) var ( - SyscallEACCES = syscall.EACCES - UnixEACCES = unix.EACCES + ErrSyscallEACCES = syscall.EACCES + ErrUnixEACCES = unix.EACCES ) var maxfiles uint64 -func SetRlimit() { - // Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/ - var l syscall.Rlimit - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l) - if err == nil && l.Cur != l.Max { - l.Cur = l.Max - syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l) - } - maxfiles = uint64(l.Cur) -} - func Maxfiles() uint64 { return maxfiles } func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) } func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) } diff --git a/vendor/github.com/fsnotify/fsnotify/internal/unix2.go b/vendor/github.com/fsnotify/fsnotify/internal/unix2.go index 37dfedd..b2d8959 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/unix2.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/unix2.go @@ -2,6 +2,24 @@ package internal +import "syscall" + func HasPrivilegesForSymlink() bool { return true } + +// IgnoringEINTR makes a function call and repeats it if it returns an +// EINTR error. This appears to be required even though we install all +// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846. +// Also #20400 and #36644 are issues in which a signal handler is +// installed without setting SA_RESTART. None of these are the common case, +// but there are enough of them that it seems that we can't avoid +// an EINTR loop. +func IgnoringEINTR[T any](fn func() (T, error)) (T, error) { + for { + v, err := fn() + if err != syscall.EINTR { + return v, err + } + } +} diff --git a/vendor/github.com/fsnotify/fsnotify/internal/windows.go b/vendor/github.com/fsnotify/fsnotify/internal/windows.go index a72c649..e24d569 100644 --- a/vendor/github.com/fsnotify/fsnotify/internal/windows.go +++ b/vendor/github.com/fsnotify/fsnotify/internal/windows.go @@ -10,11 +10,10 @@ import ( // Just a dummy. var ( - SyscallEACCES = errors.New("dummy") - UnixEACCES = errors.New("dummy") + ErrSyscallEACCES = errors.New("dummy") + ErrUnixEACCES = errors.New("dummy") ) -func SetRlimit() {} func Maxfiles() uint64 { return 1<<64 - 1 } func Mkfifo(path string, mode uint32) error { return errors.New("no FIFOs on Windows") } func Mknod(path string, mode uint32, dev int) error { return errors.New("no device nodes on Windows") } diff --git a/vendor/github.com/fsnotify/fsnotify/shared.go b/vendor/github.com/fsnotify/fsnotify/shared.go new file mode 100644 index 0000000..3ee9b58 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/shared.go @@ -0,0 +1,64 @@ +package fsnotify + +import "sync" + +type shared struct { + Events chan Event + Errors chan error + done chan struct{} + mu sync.Mutex +} + +func newShared(ev chan Event, errs chan error) *shared { + return &shared{ + Events: ev, + Errors: errs, + done: make(chan struct{}), + } +} + +// Returns true if the event was sent, or false if watcher is closed. +func (w *shared) sendEvent(e Event) bool { + if e.Op == 0 { + return true + } + select { + case <-w.done: + return false + case w.Events <- e: + return true + } +} + +// Returns true if the error was sent, or false if watcher is closed. +func (w *shared) sendError(err error) bool { + if err == nil { + return true + } + select { + case <-w.done: + return false + case w.Errors <- err: + return true + } +} + +func (w *shared) isClosed() bool { + select { + case <-w.done: + return true + default: + return false + } +} + +// Mark as closed; returns true if it was already closed. +func (w *shared) close() bool { + w.mu.Lock() + defer w.mu.Unlock() + if w.isClosed() { + return true + } + close(w.done) + return false +} diff --git a/vendor/github.com/fsnotify/fsnotify/staticcheck.conf b/vendor/github.com/fsnotify/fsnotify/staticcheck.conf new file mode 100644 index 0000000..8fa7351 --- /dev/null +++ b/vendor/github.com/fsnotify/fsnotify/staticcheck.conf @@ -0,0 +1,3 @@ +checks = ['all', + '-U1000', # Don't complain about unused functions. +] diff --git a/vendor/github.com/go-logfmt/logfmt/CHANGELOG.md b/vendor/github.com/go-logfmt/logfmt/CHANGELOG.md index 8f349c4..9a7c0ca 100644 --- a/vendor/github.com/go-logfmt/logfmt/CHANGELOG.md +++ b/vendor/github.com/go-logfmt/logfmt/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.1] - 2025-10-05 + +### Fixed + +- Encode DEL (0x7f) control character by [@spaceone] +- Modernize code through Go 1.21 by [@ChrisHines] + +[0.6.1]: https://github.com/go-logfmt/logfmt/compare/v0.6.0...v0.6.1 + ## [0.6.0] - 2023-01-30 [0.6.0]: https://github.com/go-logfmt/logfmt/compare/v0.5.1...v0.6.0 @@ -80,3 +89,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [@judwhite]: https://github.com/judwhite [@nussjustin]: https://github.com/nussjustin [@alexanderjophus]: https://github.com/alexanderjophus +[@spaceone]: https://github.com/spaceone diff --git a/vendor/github.com/go-logfmt/logfmt/encode.go b/vendor/github.com/go-logfmt/logfmt/encode.go index 4ea9d23..d8f6935 100644 --- a/vendor/github.com/go-logfmt/logfmt/encode.go +++ b/vendor/github.com/go-logfmt/logfmt/encode.go @@ -13,7 +13,7 @@ import ( // MarshalKeyvals returns the logfmt encoding of keyvals, a variadic sequence // of alternating keys and values. -func MarshalKeyvals(keyvals ...interface{}) ([]byte, error) { +func MarshalKeyvals(keyvals ...any) ([]byte, error) { buf := &bytes.Buffer{} if err := NewEncoder(buf).EncodeKeyvals(keyvals...); err != nil { return nil, err @@ -45,7 +45,7 @@ var ( // EncodeKeyval writes the logfmt encoding of key and value to the stream. A // single space is written before the second and subsequent keys in a record. // Nothing is written if a non-nil error is returned. -func (enc *Encoder) EncodeKeyval(key, value interface{}) error { +func (enc *Encoder) EncodeKeyval(key, value any) error { enc.scratch.Reset() if enc.needSep { if _, err := enc.scratch.Write(space); err != nil { @@ -72,7 +72,7 @@ func (enc *Encoder) EncodeKeyval(key, value interface{}) error { // unsupported type or that cause a MarshalerError are replaced by their error // but do not cause EncodeKeyvals to return an error. If a non-nil error is // returned some key/value pairs may not have be written. -func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error { +func (enc *Encoder) EncodeKeyvals(keyvals ...any) error { if len(keyvals) == 0 { return nil } @@ -122,7 +122,7 @@ var ErrUnsupportedKeyType = errors.New("unsupported key type") // unsupported type. var ErrUnsupportedValueType = errors.New("unsupported value type") -func writeKey(w io.Writer, key interface{}) error { +func writeKey(w io.Writer, key any) error { if key == nil { return ErrNilKey } @@ -155,7 +155,7 @@ func writeKey(w io.Writer, key interface{}) error { switch rkey.Kind() { case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct: return ErrUnsupportedKeyType - case reflect.Ptr: + case reflect.Pointer: if rkey.IsNil() { return ErrNilKey } @@ -170,7 +170,7 @@ func writeKey(w io.Writer, key interface{}) error { // functions it causes them to remove invalid key runes from strings or byte // slices respectively. func keyRuneFilter(r rune) rune { - if r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError { + if r <= ' ' || r == '=' || r == '"' || r == 0x7f || r == utf8.RuneError { return -1 } return r @@ -194,7 +194,7 @@ func writeBytesKey(w io.Writer, key []byte) error { return err } -func writeValue(w io.Writer, value interface{}) error { +func writeValue(w io.Writer, value any) error { switch v := value.(type) { case nil: return writeBytesValue(w, null) @@ -222,7 +222,7 @@ func writeValue(w io.Writer, value interface{}) error { switch rvalue.Kind() { case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct: return ErrUnsupportedValueType - case reflect.Ptr: + case reflect.Pointer: if rvalue.IsNil() { return writeBytesValue(w, null) } @@ -233,7 +233,7 @@ func writeValue(w io.Writer, value interface{}) error { } func needsQuotedValueRune(r rune) bool { - return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError + return r <= ' ' || r == '=' || r == '"' || r == 0x7f || r == utf8.RuneError } func writeStringValue(w io.Writer, value string, ok bool) error { @@ -276,7 +276,7 @@ func (enc *Encoder) Reset() { func safeError(err error) (s string, ok bool) { defer func() { if panicVal := recover(); panicVal != nil { - if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() { + if v := reflect.ValueOf(err); v.Kind() == reflect.Pointer && v.IsNil() { s, ok = "null", false } else { s, ok = fmt.Sprintf("PANIC:%v", panicVal), false @@ -290,7 +290,7 @@ func safeError(err error) (s string, ok bool) { func safeString(str fmt.Stringer) (s string, ok bool) { defer func() { if panicVal := recover(); panicVal != nil { - if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() { + if v := reflect.ValueOf(str); v.Kind() == reflect.Pointer && v.IsNil() { s, ok = "null", false } else { s, ok = fmt.Sprintf("PANIC:%v", panicVal), true @@ -304,7 +304,7 @@ func safeString(str fmt.Stringer) (s string, ok bool) { func safeMarshal(tm encoding.TextMarshaler) (b []byte, err error) { defer func() { if panicVal := recover(); panicVal != nil { - if v := reflect.ValueOf(tm); v.Kind() == reflect.Ptr && v.IsNil() { + if v := reflect.ValueOf(tm); v.Kind() == reflect.Pointer && v.IsNil() { b, err = nil, nil } else { b, err = nil, fmt.Errorf("panic when marshalling: %s", panicVal) diff --git a/vendor/github.com/go-logfmt/logfmt/jsonstring.go b/vendor/github.com/go-logfmt/logfmt/jsonstring.go index 030ac85..26e1b1c 100644 --- a/vendor/github.com/go-logfmt/logfmt/jsonstring.go +++ b/vendor/github.com/go-logfmt/logfmt/jsonstring.go @@ -19,7 +19,7 @@ import ( var hex = "0123456789abcdef" var bufferPool = sync.Pool{ - New: func() interface{} { + New: func() any { return &bytes.Buffer{} }, } @@ -40,7 +40,7 @@ func writeQuotedString(w io.Writer, s string) (int, error) { start := 0 for i := 0; i < len(s); { if b := s[i]; b < utf8.RuneSelf { - if 0x20 <= b && b != '\\' && b != '"' { + if 0x20 <= b && b != '\\' && b != '"' && b != 0x7f { i++ continue } @@ -91,14 +91,14 @@ func writeQuotedString(w io.Writer, s string) (int, error) { return n, err } -// NOTE: keep in sync with writeQuoteString above. +// NOTE: keep in sync with writeQuotedString above. func writeQuotedBytes(w io.Writer, s []byte) (int, error) { buf := getBuffer() buf.WriteByte('"') start := 0 for i := 0; i < len(s); { if b := s[i]; b < utf8.RuneSelf { - if 0x20 <= b && b != '\\' && b != '"' { + if 0x20 <= b && b != '\\' && b != '"' && b != 0x7f { i++ continue } diff --git a/vendor/github.com/go-sql-driver/mysql/AUTHORS b/vendor/github.com/go-sql-driver/mysql/AUTHORS index 4021b96..42c7f02 100644 --- a/vendor/github.com/go-sql-driver/mysql/AUTHORS +++ b/vendor/github.com/go-sql-driver/mysql/AUTHORS @@ -18,9 +18,14 @@ Alex Snast Alexey Palazhchenko Andrew Reid Animesh Ray -Arne Hormann Ariel Mashraki +Arne Hormann +Artur Melanchyk Asta Xie +B Lamarche +Bes Dollma +Bogdan Constantinescu +Brad Higgins Brian Hendriks Bulat Gaifullin Caine Jette @@ -33,6 +38,9 @@ Daniel Montoya Daniel Nichter Daniël van Eeden Dave Protasowski +Demouth +Diego Dupin +Dirkjan Bussink DisposaBoy Egor Smolyakov Erwan Martin @@ -50,6 +58,7 @@ ICHINOSE Shogo Ilia Cimpoes INADA Naoki Jacek Szwec +Jakub Adamus James Harr Janek Vedock Jason Ng @@ -58,8 +67,10 @@ Jeff Hodges Jeffrey Charles Jennifer Purevsuren Jerome Meyer +Jiabin Zhang Jiajia Zhong Jian Zhen +Joe Mann Joshua Prunier Julien Lefevre Julien Schmidt @@ -76,10 +87,13 @@ Linh Tran Tuan Lion Yang Luca Looz Lucas Liu -Lunny Xiao Luke Scott +Lunny Xiao Maciej Zimnoch Michael Woolnough +Minh Quang +Morgan Tocker +Nao Yokotsuka Nathanial Murphy Nicola Peduzzi Oliver Bone @@ -123,7 +137,9 @@ Ziheng Lyu # Organizations Barracuda Networks, Inc. +Block, Inc. Counting Ltd. +Defined Networking Inc. DigitalOcean Inc. Dolthub Inc. dyves labs AG @@ -139,4 +155,5 @@ PingCAP Inc. Pivotal Inc. Shattered Silicon Ltd. Stripe Inc. +ThousandEyes Zendesk Inc. diff --git a/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md b/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md index 0c9bd9b..b24af9b 100644 --- a/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md +++ b/vendor/github.com/go-sql-driver/mysql/CHANGELOG.md @@ -1,3 +1,68 @@ +# Changelog + +## v1.10.0 (2026-04-28) + +* Fix `getSystemVar("max_allowed_packet")` potentially returned wrong value. (#1754) + This affects only when `maxAllowedPacket=0` is set. + +* Bump filippo.io/edwards25519 from 1.1.1 to 1.2.0. (#1756) + While older versions have reported CVEs, they do not affect go-mysql. + +* Update Go versions to 1.24-1.26. (#1763) + +* Enhance interpolateParams to correctly handle placeholders. (#1732) + The question mark (?) within strings and comments will no longer be treated as a placeholder. + + +## v1.9.3 (2025-06-13) + +* `tx.Commit()` and `tx.Rollback()` returned `ErrInvalidConn` always. + Now they return cached real error if present. (#1690) + +* Optimize reading small result sets to fix a performance regression + introduced by compression protocol support. (`#1707`) +* Fix `db.Ping()` on compressed connection. (#1723) + + +## v1.9.2 (2025-04-07) + +v1.9.2 is a re-release of v1.9.1 due to a release process issue; no changes were made to the content. + + +## v1.9.1 (2025-03-21) + +### Major Changes + +* Add Charset() option. (#1679) + +### Bugfixes + +* go.mod: fix go version format (#1682) +* Fix FormatDSN missing ConnectionAttributes (#1619) + +## v1.9.0 (2025-02-18) + +### Major Changes + +- Implement zlib compression. (#1487) +- Supported Go version is updated to Go 1.21+. (#1639) +- Add support for VECTOR type introduced in MySQL 9.0. (#1609) +- Config object can have custom dial function. (#1527) + +### Bugfixes + +- Fix auth errors when username/password are too long. (#1625) +- Check if MySQL supports CLIENT_CONNECT_ATTRS before sending client attributes. (#1640) +- Fix auth switch request handling. (#1666) + +### Other changes + +- Add "filename:line" prefix to log in go-mysql. Custom loggers now show it. (#1589) +- Improve error handling. It reduces the "busy buffer" errors. (#1595, #1601, #1641) +- Use `strconv.Atoi` to parse max_allowed_packet. (#1661) +- `rejectReadOnly` option now handles ER_READ_ONLY_MODE (1290) error too. (#1660) + + ## Version 1.8.1 (2024-03-26) Bugfixes: diff --git a/vendor/github.com/go-sql-driver/mysql/README.md b/vendor/github.com/go-sql-driver/mysql/README.md index 4968cb0..3da0538 100644 --- a/vendor/github.com/go-sql-driver/mysql/README.md +++ b/vendor/github.com/go-sql-driver/mysql/README.md @@ -1,5 +1,8 @@ # Go-MySQL-Driver +[![DeepWiki](https://img.shields.io/badge/DeepWiki-go--sql--driver%2Fmysql-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/go-sql-driver/mysql) + + A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package ![Go-MySQL-Driver logo](https://raw.github.com/wiki/go-sql-driver/mysql/gomysql_m.png "Golang Gopher holding the MySQL Dolphin") @@ -38,11 +41,12 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac * Secure `LOAD DATA LOCAL INFILE` support with file allowlisting and `io.Reader` support * Optional `time.Time` parsing * Optional placeholder interpolation + * Supports zlib compression. ## Requirements -* Go 1.19 or higher. We aim to support the 3 latest versions of Go. -* MySQL (5.7+) and MariaDB (10.3+) are supported. +* Go 1.24 or higher. We aim to support the 3 latest versions of Go. +* MySQL (5.7+) and MariaDB (10.5+) are supported by maintainers. * [TiDB](https://github.com/pingcap/tidb) is supported by PingCAP. * Do not ask questions about TiDB in our issue tracker or forum. * [Document](https://docs.pingcap.com/tidb/v6.1/dev-guide-sample-application-golang) @@ -267,6 +271,16 @@ SELECT u.id FROM users as u will return `u.id` instead of just `id` if `columnsWithAlias=true`. +##### `compress` + +``` +Type: bool +Valid Values: true, false +Default: false +``` + +Toggles zlib compression. false by default. + ##### `interpolateParams` ``` @@ -519,6 +533,9 @@ This driver supports the [`ColumnType` interface](https://golang.org/pkg/databas Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts. See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details. +> [!IMPORTANT] +> The `QueryContext`, `ExecContext`, etc. variants provided by `database/sql` will cause the connection to be closed if the provided context is cancelled or timed out before the result is received by the driver. + ### `LOAD DATA LOCAL INFILE` support For this feature you need direct access to the package. Therefore you must change the import path (no `_`): diff --git a/vendor/github.com/go-sql-driver/mysql/atomic_bool.go b/vendor/github.com/go-sql-driver/mysql/atomic_bool.go deleted file mode 100644 index 1b7e19f..0000000 --- a/vendor/github.com/go-sql-driver/mysql/atomic_bool.go +++ /dev/null @@ -1,19 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package. -// -// Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. -//go:build go1.19 -// +build go1.19 - -package mysql - -import "sync/atomic" - -/****************************************************************************** -* Sync utils * -******************************************************************************/ - -type atomicBool = atomic.Bool diff --git a/vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go b/vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go deleted file mode 100644 index 2e9a7f0..0000000 --- a/vendor/github.com/go-sql-driver/mysql/atomic_bool_go118.go +++ /dev/null @@ -1,47 +0,0 @@ -// Go MySQL Driver - A MySQL-Driver for Go's database/sql package. -// -// Copyright 2022 The Go-MySQL-Driver Authors. All rights reserved. -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this file, -// You can obtain one at http://mozilla.org/MPL/2.0/. -//go:build !go1.19 -// +build !go1.19 - -package mysql - -import "sync/atomic" - -/****************************************************************************** -* Sync utils * -******************************************************************************/ - -// atomicBool is an implementation of atomic.Bool for older version of Go. -// it is a wrapper around uint32 for usage as a boolean value with -// atomic access. -type atomicBool struct { - _ noCopy - value uint32 -} - -// Load returns whether the current boolean value is true -func (ab *atomicBool) Load() bool { - return atomic.LoadUint32(&ab.value) > 0 -} - -// Store sets the value of the bool regardless of the previous value -func (ab *atomicBool) Store(value bool) { - if value { - atomic.StoreUint32(&ab.value, 1) - } else { - atomic.StoreUint32(&ab.value, 0) - } -} - -// Swap sets the value of the bool and returns the old value. -func (ab *atomicBool) Swap(value bool) bool { - if value { - return atomic.SwapUint32(&ab.value, 1) > 0 - } - return atomic.SwapUint32(&ab.value, 0) > 0 -} diff --git a/vendor/github.com/go-sql-driver/mysql/auth.go b/vendor/github.com/go-sql-driver/mysql/auth.go index 74e1bd0..610044f 100644 --- a/vendor/github.com/go-sql-driver/mysql/auth.go +++ b/vendor/github.com/go-sql-driver/mysql/auth.go @@ -305,7 +305,7 @@ func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) { if !mc.cfg.AllowNativePasswords { return nil, ErrNativePassword } - // https://dev.mysql.com/doc/internals/en/secure-password-authentication.html + // https://dev.mysql.com/doc/dev/mysql-server/8.4.5/page_protocol_connection_phase_authentication_methods_native_password_authentication.html // Native password authentication only need and will need 20-byte challenge. authResp := scramblePassword(authData[:20], mc.cfg.Passwd) return authResp, nil diff --git a/vendor/github.com/go-sql-driver/mysql/buffer.go b/vendor/github.com/go-sql-driver/mysql/buffer.go index 0774c5c..f895e87 100644 --- a/vendor/github.com/go-sql-driver/mysql/buffer.go +++ b/vendor/github.com/go-sql-driver/mysql/buffer.go @@ -10,54 +10,47 @@ package mysql import ( "io" - "net" - "time" ) const defaultBufSize = 4096 const maxCachedBufSize = 256 * 1024 +// readerFunc is a function that compatible with io.Reader. +// We use this function type instead of io.Reader because we want to +// just pass mc.readWithTimeout. +type readerFunc func([]byte) (int, error) + // A buffer which is used for both reading and writing. // This is possible since communication on each connection is synchronous. // In other words, we can't write and read simultaneously on the same connection. // The buffer is similar to bufio.Reader / Writer but zero-copy-ish // Also highly optimized for this particular use case. -// This buffer is backed by two byte slices in a double-buffering scheme type buffer struct { - buf []byte // buf is a byte buffer who's length and capacity are equal. - nc net.Conn - idx int - length int - timeout time.Duration - dbuf [2][]byte // dbuf is an array with the two byte slices that back this buffer - flipcnt uint // flipccnt is the current buffer counter for double-buffering + buf []byte // read buffer. + cachedBuf []byte // buffer that will be reused. len(cachedBuf) <= maxCachedBufSize. } // newBuffer allocates and returns a new buffer. -func newBuffer(nc net.Conn) buffer { - fg := make([]byte, defaultBufSize) +func newBuffer() buffer { return buffer{ - buf: fg, - nc: nc, - dbuf: [2][]byte{fg, nil}, + cachedBuf: make([]byte, defaultBufSize), } } -// flip replaces the active buffer with the background buffer -// this is a delayed flip that simply increases the buffer counter; -// the actual flip will be performed the next time we call `buffer.fill` -func (b *buffer) flip() { - b.flipcnt += 1 +// busy returns true if the read buffer is not empty. +func (b *buffer) busy() bool { + return len(b.buf) > 0 +} + +// len returns how many bytes in the read buffer. +func (b *buffer) len() int { + return len(b.buf) } -// fill reads into the buffer until at least _need_ bytes are in it -func (b *buffer) fill(need int) error { - n := b.length - // fill data into its double-buffering target: if we've called - // flip on this buffer, we'll be copying to the background buffer, - // and then filling it with network data; otherwise we'll just move - // the contents of the current buffer to the front before filling it - dest := b.dbuf[b.flipcnt&1] +// fill reads into the read buffer until at least _need_ bytes are in it. +func (b *buffer) fill(need int, r readerFunc) error { + // we'll move the contents of the current buffer to dest before filling it. + dest := b.cachedBuf // grow buffer if necessary to fit the whole packet. if need > len(dest) { @@ -67,64 +60,41 @@ func (b *buffer) fill(need int) error { // if the allocated buffer is not too large, move it to backing storage // to prevent extra allocations on applications that perform large reads if len(dest) <= maxCachedBufSize { - b.dbuf[b.flipcnt&1] = dest + b.cachedBuf = dest } } - // if we're filling the fg buffer, move the existing data to the start of it. - // if we're filling the bg buffer, copy over the data - if n > 0 { - copy(dest[:n], b.buf[b.idx:]) - } - - b.buf = dest - b.idx = 0 + // move the existing data to the start of the buffer. + n := len(b.buf) + copy(dest[:n], b.buf) for { - if b.timeout > 0 { - if err := b.nc.SetReadDeadline(time.Now().Add(b.timeout)); err != nil { - return err - } + nn, err := r(dest[n:]) + n += nn + + if err == nil && n < need { + continue } - nn, err := b.nc.Read(b.buf[n:]) - n += nn + b.buf = dest[:n] - switch err { - case nil: + if err == io.EOF { if n < need { - continue - } - b.length = n - return nil - - case io.EOF: - if n >= need { - b.length = n - return nil + err = io.ErrUnexpectedEOF + } else { + err = nil } - return io.ErrUnexpectedEOF - - default: - return err } + return err } } // returns next N bytes from buffer. // The returned slice is only guaranteed to be valid until the next read -func (b *buffer) readNext(need int) ([]byte, error) { - if b.length < need { - // refill - if err := b.fill(need); err != nil { - return nil, err - } - } - - offset := b.idx - b.idx += need - b.length -= need - return b.buf[offset:b.idx], nil +func (b *buffer) readNext(need int) []byte { + data := b.buf[:need:need] + b.buf = b.buf[need:] + return data } // takeBuffer returns a buffer with the requested size. @@ -132,18 +102,18 @@ func (b *buffer) readNext(need int) ([]byte, error) { // Otherwise a bigger buffer is made. // Only one buffer (total) can be used at a time. func (b *buffer) takeBuffer(length int) ([]byte, error) { - if b.length > 0 { + if b.busy() { return nil, ErrBusyBuffer } // test (cheap) general case first - if length <= cap(b.buf) { - return b.buf[:length], nil + if length <= len(b.cachedBuf) { + return b.cachedBuf[:length], nil } - if length < maxPacketSize { - b.buf = make([]byte, length) - return b.buf, nil + if length < maxCachedBufSize { + b.cachedBuf = make([]byte, length) + return b.cachedBuf, nil } // buffer is larger than we want to store. @@ -154,10 +124,10 @@ func (b *buffer) takeBuffer(length int) ([]byte, error) { // known to be smaller than defaultBufSize. // Only one buffer (total) can be used at a time. func (b *buffer) takeSmallBuffer(length int) ([]byte, error) { - if b.length > 0 { + if b.busy() { return nil, ErrBusyBuffer } - return b.buf[:length], nil + return b.cachedBuf[:length], nil } // takeCompleteBuffer returns the complete existing buffer. @@ -165,18 +135,15 @@ func (b *buffer) takeSmallBuffer(length int) ([]byte, error) { // cap and len of the returned buffer will be equal. // Only one buffer (total) can be used at a time. func (b *buffer) takeCompleteBuffer() ([]byte, error) { - if b.length > 0 { + if b.busy() { return nil, ErrBusyBuffer } - return b.buf, nil + return b.cachedBuf, nil } // store stores buf, an updated buffer, if its suitable to do so. -func (b *buffer) store(buf []byte) error { - if b.length > 0 { - return ErrBusyBuffer - } else if cap(buf) <= maxPacketSize && cap(buf) > cap(b.buf) { - b.buf = buf[:cap(buf)] +func (b *buffer) store(buf []byte) { + if cap(buf) <= maxCachedBufSize && cap(buf) > cap(b.cachedBuf) { + b.cachedBuf = buf[:cap(buf)] } - return nil } diff --git a/vendor/github.com/go-sql-driver/mysql/collations.go b/vendor/github.com/go-sql-driver/mysql/collations.go index 1cdf97b..29b1aa4 100644 --- a/vendor/github.com/go-sql-driver/mysql/collations.go +++ b/vendor/github.com/go-sql-driver/mysql/collations.go @@ -8,7 +8,7 @@ package mysql -const defaultCollation = "utf8mb4_general_ci" +const defaultCollationID = 45 // utf8mb4_general_ci const binaryCollationID = 63 // A list of available collations mapped to the internal ID. diff --git a/vendor/github.com/go-sql-driver/mysql/compress.go b/vendor/github.com/go-sql-driver/mysql/compress.go new file mode 100644 index 0000000..38bfa00 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/compress.go @@ -0,0 +1,213 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2024 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "bytes" + "compress/zlib" + "fmt" + "io" + "sync" +) + +var ( + zrPool *sync.Pool // Do not use directly. Use zDecompress() instead. + zwPool *sync.Pool // Do not use directly. Use zCompress() instead. +) + +func init() { + zrPool = &sync.Pool{ + New: func() any { return nil }, + } + zwPool = &sync.Pool{ + New: func() any { + zw, err := zlib.NewWriterLevel(new(bytes.Buffer), 2) + if err != nil { + panic(err) // compress/zlib return non-nil error only if level is invalid + } + return zw + }, + } +} + +func zDecompress(src []byte, dst *bytes.Buffer) (int, error) { + br := bytes.NewReader(src) + var zr io.ReadCloser + var err error + + if a := zrPool.Get(); a == nil { + if zr, err = zlib.NewReader(br); err != nil { + return 0, err + } + } else { + zr = a.(io.ReadCloser) + if err := zr.(zlib.Resetter).Reset(br, nil); err != nil { + return 0, err + } + } + + n, _ := dst.ReadFrom(zr) // ignore err because zr.Close() will return it again. + err = zr.Close() // zr.Close() may return chuecksum error. + zrPool.Put(zr) + return int(n), err +} + +func zCompress(src []byte, dst io.Writer) error { + zw := zwPool.Get().(*zlib.Writer) + zw.Reset(dst) + if _, err := zw.Write(src); err != nil { + return err + } + err := zw.Close() + zwPool.Put(zw) + return err +} + +type compIO struct { + mc *mysqlConn + buff bytes.Buffer +} + +func newCompIO(mc *mysqlConn) *compIO { + return &compIO{ + mc: mc, + } +} + +func (c *compIO) reset() { + c.buff.Reset() +} + +func (c *compIO) readNext(need int) ([]byte, error) { + for c.buff.Len() < need { + if err := c.readCompressedPacket(); err != nil { + return nil, err + } + } + data := c.buff.Next(need) + return data[:need:need], nil // prevent caller writes into c.buff +} + +func (c *compIO) readCompressedPacket() error { + header, err := c.mc.readNext(7) + if err != nil { + return err + } + _ = header[6] // bounds check hint to compiler; guaranteed by readNext + + // compressed header structure + comprLength := getUint24(header[0:3]) + compressionSequence := header[3] + uncompressedLength := getUint24(header[4:7]) + if debug { + fmt.Printf("uncompress cmplen=%v uncomplen=%v pkt_cmp_seq=%v expected_cmp_seq=%v\n", + comprLength, uncompressedLength, compressionSequence, c.mc.sequence) + } + // Do not return ErrPktSync here. + // Server may return error packet (e.g. 1153 Got a packet bigger than 'max_allowed_packet' bytes) + // before receiving all packets from client. In this case, seqnr is younger than expected. + // NOTE: Both of mariadbclient and mysqlclient do not check seqnr. Only server checks it. + if debug && compressionSequence != c.mc.compressSequence { + fmt.Printf("WARN: unexpected cmpress seq nr: expected %v, got %v", + c.mc.compressSequence, compressionSequence) + } + c.mc.compressSequence = compressionSequence + 1 + + comprData, err := c.mc.readNext(comprLength) + if err != nil { + return err + } + + // if payload is uncompressed, its length will be specified as zero, and its + // true length is contained in comprLength + if uncompressedLength == 0 { + c.buff.Write(comprData) + return nil + } + + // use existing capacity in bytesBuf if possible + c.buff.Grow(uncompressedLength) + nread, err := zDecompress(comprData, &c.buff) + if err != nil { + return err + } + if nread != uncompressedLength { + return fmt.Errorf("invalid compressed packet: uncompressed length in header is %d, actual %d", + uncompressedLength, nread) + } + return nil +} + +const minCompressLength = 150 +const maxPayloadLen = maxPacketSize - 4 + +// writePackets sends one or some packets with compression. +// Use this instead of mc.netConn.Write() when mc.compress is true. +func (c *compIO) writePackets(packets []byte) (int, error) { + totalBytes := len(packets) + blankHeader := make([]byte, 7) + buf := &c.buff + + for len(packets) > 0 { + payloadLen := min(maxPayloadLen, len(packets)) + payload := packets[:payloadLen] + uncompressedLen := payloadLen + + buf.Reset() + buf.Write(blankHeader) // Buffer.Write() never returns error + + // If payload is less than minCompressLength, don't compress. + if uncompressedLen < minCompressLength { + buf.Write(payload) + uncompressedLen = 0 + } else { + err := zCompress(payload, buf) + if debug && err != nil { + fmt.Printf("zCompress error: %v", err) + } + // do not compress if compressed data is larger than uncompressed data + // I intentionally miss 7 byte header in the buf; zCompress must compress more than 7 bytes. + if err != nil || buf.Len() >= uncompressedLen { + buf.Reset() + buf.Write(blankHeader) + buf.Write(payload) + uncompressedLen = 0 + } + } + + if n, err := c.writeCompressedPacket(buf.Bytes(), uncompressedLen); err != nil { + // To allow returning ErrBadConn when sending really 0 bytes, we sum + // up compressed bytes that is returned by underlying Write(). + return totalBytes - len(packets) + n, err + } + packets = packets[payloadLen:] + } + + return totalBytes, nil +} + +// writeCompressedPacket writes a compressed packet with header. +// data should start with 7 size space for header followed by payload. +func (c *compIO) writeCompressedPacket(data []byte, uncompressedLen int) (int, error) { + mc := c.mc + comprLength := len(data) - 7 + if debug { + fmt.Printf( + "writeCompressedPacket: comprLength=%v, uncompressedLen=%v, seq=%v\n", + comprLength, uncompressedLen, mc.compressSequence) + } + + // compression header + putUint24(data[0:3], comprLength) + data[3] = mc.compressSequence + putUint24(data[4:7], uncompressedLen) + + mc.compressSequence++ + return mc.writeWithTimeout(data) +} diff --git a/vendor/github.com/go-sql-driver/mysql/conncheck.go b/vendor/github.com/go-sql-driver/mysql/conncheck.go index 0ea7217..f9c5cb6 100644 --- a/vendor/github.com/go-sql-driver/mysql/conncheck.go +++ b/vendor/github.com/go-sql-driver/mysql/conncheck.go @@ -7,7 +7,6 @@ // You can obtain one at http://mozilla.org/MPL/2.0/. //go:build linux || darwin || dragonfly || freebsd || netbsd || openbsd || solaris || illumos -// +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos package mysql diff --git a/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go b/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go index a56c138..0ebf05c 100644 --- a/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go +++ b/vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go @@ -7,7 +7,6 @@ // You can obtain one at http://mozilla.org/MPL/2.0/. //go:build !linux && !darwin && !dragonfly && !freebsd && !netbsd && !openbsd && !solaris && !illumos -// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!illumos package mysql diff --git a/vendor/github.com/go-sql-driver/mysql/connection.go b/vendor/github.com/go-sql-driver/mysql/connection.go index eff978d..65204e2 100644 --- a/vendor/github.com/go-sql-driver/mysql/connection.go +++ b/vendor/github.com/go-sql-driver/mysql/connection.go @@ -13,10 +13,13 @@ import ( "database/sql" "database/sql/driver" "encoding/json" + "fmt" "io" "net" + "runtime" "strconv" "strings" + "sync/atomic" "time" ) @@ -25,15 +28,18 @@ type mysqlConn struct { netConn net.Conn rawConn net.Conn // underlying connection when netConn is TLS connection. result mysqlResult // managed by clearResult() and handleOkPacket(). + compIO *compIO cfg *Config connector *connector maxAllowedPacket int maxWriteSize int - writeTimeout time.Duration - flags clientFlag + capabilities capabilityFlag + extCapabilities extendedCapabilityFlag status statusFlag sequence uint8 + compressSequence uint8 parseTime bool + compress bool // for context support (Go 1.8+) watching bool @@ -41,71 +47,92 @@ type mysqlConn struct { closech chan struct{} finished chan<- struct{} canceled atomicError // set non-nil if conn is canceled - closed atomicBool // set when conn is closed, before closech is closed + closed atomic.Bool // set when conn is closed, before closech is closed } // Helper function to call per-connection logger. func (mc *mysqlConn) log(v ...any) { + _, filename, lineno, ok := runtime.Caller(1) + if ok { + pos := strings.LastIndexByte(filename, '/') + if pos != -1 { + filename = filename[pos+1:] + } + prefix := fmt.Sprintf("%s:%d ", filename, lineno) + v = append([]any{prefix}, v...) + } + mc.cfg.Logger.Print(v...) } +func (mc *mysqlConn) readWithTimeout(b []byte) (int, error) { + to := mc.cfg.ReadTimeout + if to > 0 { + if err := mc.netConn.SetReadDeadline(time.Now().Add(to)); err != nil { + return 0, err + } + } + return mc.netConn.Read(b) +} + +func (mc *mysqlConn) writeWithTimeout(b []byte) (int, error) { + to := mc.cfg.WriteTimeout + if to > 0 { + if err := mc.netConn.SetWriteDeadline(time.Now().Add(to)); err != nil { + return 0, err + } + } + return mc.netConn.Write(b) +} + +func (mc *mysqlConn) resetSequence() { + mc.sequence = 0 + mc.compressSequence = 0 +} + +// syncSequence must be called when finished writing some packet and before start reading. +func (mc *mysqlConn) syncSequence() { + // Syncs compressionSequence to sequence. + // This is not documented but done in `net_flush()` in MySQL and MariaDB. + // https://github.com/mariadb-corporation/mariadb-connector-c/blob/8228164f850b12353da24df1b93a1e53cc5e85e9/libmariadb/ma_net.c#L170-L171 + // https://github.com/mysql/mysql-server/blob/824e2b4064053f7daf17d7f3f84b7a3ed92e5fb4/sql-common/net_serv.cc#L293 + if mc.compress { + mc.sequence = mc.compressSequence + mc.compIO.reset() + } +} + // Handles parameters set in DSN after the connection is established func (mc *mysqlConn) handleParams() (err error) { var cmdSet strings.Builder for param, val := range mc.cfg.Params { - switch param { - // Charset: character_set_connection, character_set_client, character_set_results - case "charset": - charsets := strings.Split(val, ",") - for _, cs := range charsets { - // ignore errors here - a charset may not exist - if mc.cfg.Collation != "" { - err = mc.exec("SET NAMES " + cs + " COLLATE " + mc.cfg.Collation) - } else { - err = mc.exec("SET NAMES " + cs) - } - if err == nil { - break - } - } - if err != nil { - return - } - - // Other system vars accumulated in a single SET command - default: - if cmdSet.Len() == 0 { - // Heuristic: 29 chars for each other key=value to reduce reallocations - cmdSet.Grow(4 + len(param) + 3 + len(val) + 30*(len(mc.cfg.Params)-1)) - cmdSet.WriteString("SET ") - } else { - cmdSet.WriteString(", ") - } - cmdSet.WriteString(param) - cmdSet.WriteString(" = ") - cmdSet.WriteString(val) + if cmdSet.Len() == 0 { + // Heuristic: 29 chars for each other key=value to reduce reallocations + cmdSet.Grow(4 + len(param) + 3 + len(val) + 30*(len(mc.cfg.Params)-1)) + cmdSet.WriteString("SET ") + } else { + cmdSet.WriteString(", ") } + cmdSet.WriteString(param) + cmdSet.WriteString(" = ") + cmdSet.WriteString(val) } if cmdSet.Len() > 0 { err = mc.exec(cmdSet.String()) - if err != nil { - return - } } return } +// markBadConn replaces errBadConnNoWrite with driver.ErrBadConn. +// This function is used to return driver.ErrBadConn only when safe to retry. func (mc *mysqlConn) markBadConn(err error) error { - if mc == nil { - return err - } - if err != errBadConnNoWrite { - return err + if err == errBadConnNoWrite { + return driver.ErrBadConn } - return driver.ErrBadConn + return err } func (mc *mysqlConn) Begin() (driver.Tx, error) { @@ -114,7 +141,6 @@ func (mc *mysqlConn) Begin() (driver.Tx, error) { func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) { if mc.closed.Load() { - mc.log(ErrInvalidConn) return nil, driver.ErrBadConn } var q string @@ -135,14 +161,18 @@ func (mc *mysqlConn) Close() (err error) { if !mc.closed.Load() { err = mc.writeCommandPacket(comQuit) } + mc.close() + return +} +// close closes the network connection and clear results without sending COM_QUIT. +func (mc *mysqlConn) close() { mc.cleanup() mc.clearResult() - return } // Closes the network connection and unsets internal variables. Do not call this -// function after successfully authentication, call Close instead. This function +// function after successful authentication, call Close instead. This function // is called before auth or on auth failure because MySQL will have already // closed the network connection. func (mc *mysqlConn) cleanup() { @@ -157,7 +187,7 @@ func (mc *mysqlConn) cleanup() { return } if err := conn.Close(); err != nil { - mc.log(err) + mc.log("closing connection:", err) } // This function can be called from multiple goroutines. // So we can not mc.clearResult() here. @@ -176,7 +206,6 @@ func (mc *mysqlConn) error() error { func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { if mc.closed.Load() { - mc.log(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command @@ -195,13 +224,21 @@ func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { columnCount, err := stmt.readPrepareResultPacket() if err == nil { if stmt.paramCount > 0 { - if err = mc.readUntilEOF(); err != nil { + if err = mc.skipColumns(stmt.paramCount); err != nil { return nil, err } } if columnCount > 0 { - err = mc.readUntilEOF() + if mc.extCapabilities&clientCacheMetadata != 0 { + if stmt.columns, err = mc.readColumns(int(columnCount), nil); err != nil { + return nil, err + } + } else { + if err = mc.skipColumns(int(columnCount)); err != nil { + return nil, err + } + } } } @@ -209,98 +246,184 @@ func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { } func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (string, error) { - // Number of ? should be same to len(args) - if strings.Count(query, "?") != len(args) { - return "", driver.ErrSkip - } + noBackslashEscapes := (mc.status & statusNoBackslashEscapes) != 0 + const ( + stateNormal = iota + stateString + stateEscape + stateEOLComment + stateSlashStarComment + stateBacktick + ) + + const ( + QUOTE_BYTE = byte('\'') + DBL_QUOTE_BYTE = byte('"') + BACKSLASH_BYTE = byte('\\') + QUESTION_MARK_BYTE = byte('?') + SLASH_BYTE = byte('/') + STAR_BYTE = byte('*') + HASH_BYTE = byte('#') + MINUS_BYTE = byte('-') + LINE_FEED_BYTE = byte('\n') + BACKTICK_BYTE = byte('`') + ) buf, err := mc.buf.takeCompleteBuffer() if err != nil { - // can not take the buffer. Something must be wrong with the connection - mc.log(err) - return "", ErrInvalidConn + mc.cleanup() + return "", driver.ErrBadConn } buf = buf[:0] + state := stateNormal + singleQuotes := false + lastChar := byte(0) argPos := 0 - - for i := 0; i < len(query); i++ { - q := strings.IndexByte(query[i:], '?') - if q == -1 { - buf = append(buf, query[i:]...) - break - } - buf = append(buf, query[i:i+q]...) - i += q - - arg := args[argPos] - argPos++ - - if arg == nil { - buf = append(buf, "NULL"...) + lenQuery := len(query) + lastIdx := 0 + + for i := range lenQuery { + currentChar := query[i] + if state == stateEscape && !((currentChar == QUOTE_BYTE && singleQuotes) || (currentChar == DBL_QUOTE_BYTE && !singleQuotes)) { + state = stateString + lastChar = currentChar continue } - - switch v := arg.(type) { - case int64: - buf = strconv.AppendInt(buf, v, 10) - case uint64: - // Handle uint64 explicitly because our custom ConvertValue emits unsigned values - buf = strconv.AppendUint(buf, v, 10) - case float64: - buf = strconv.AppendFloat(buf, v, 'g', -1, 64) - case bool: - if v { - buf = append(buf, '1') - } else { - buf = append(buf, '0') + switch currentChar { + case STAR_BYTE: + if state == stateNormal && lastChar == SLASH_BYTE { + state = stateSlashStarComment } - case time.Time: - if v.IsZero() { - buf = append(buf, "'0000-00-00'"...) - } else { - buf = append(buf, '\'') - buf, err = appendDateTime(buf, v.In(mc.cfg.Loc), mc.cfg.timeTruncate) - if err != nil { - return "", err - } - buf = append(buf, '\'') + case SLASH_BYTE: + if state == stateSlashStarComment && lastChar == STAR_BYTE { + state = stateNormal + // Clear lastChar so the '/' that closed the comment isn't + // reused to start a new comment with a following '*'. + lastChar = 0 + continue } - case json.RawMessage: - buf = append(buf, '\'') - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeBytesBackslash(buf, v) - } else { - buf = escapeBytesQuotes(buf, v) + case HASH_BYTE: + if state == stateNormal { + state = stateEOLComment } - buf = append(buf, '\'') - case []byte: - if v == nil { - buf = append(buf, "NULL"...) - } else { - buf = append(buf, "_binary'"...) - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeBytesBackslash(buf, v) + case MINUS_BYTE: + if state == stateNormal && lastChar == MINUS_BYTE { + // -- only starts a comment if followed by whitespace or control char + if i+1 < lenQuery { + nextChar := query[i+1] + if nextChar == ' ' || nextChar == '\t' || nextChar == '\n' || nextChar == '\r' { + state = stateEOLComment + } } else { - buf = escapeBytesQuotes(buf, v) + state = stateEOLComment } - buf = append(buf, '\'') } - case string: - buf = append(buf, '\'') - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeStringBackslash(buf, v) - } else { - buf = escapeStringQuotes(buf, v) + case LINE_FEED_BYTE: + if state == stateEOLComment { + state = stateNormal } - buf = append(buf, '\'') - default: - return "", driver.ErrSkip - } + case DBL_QUOTE_BYTE: + if state == stateNormal { + state = stateString + singleQuotes = false + } else if state == stateString && !singleQuotes { + state = stateNormal + } else if state == stateEscape { + state = stateString + } + case QUOTE_BYTE: + if state == stateNormal { + state = stateString + singleQuotes = true + } else if state == stateString && singleQuotes { + state = stateNormal + } else if state == stateEscape { + state = stateString + } + case BACKSLASH_BYTE: + if state == stateString && !noBackslashEscapes { + state = stateEscape + } + case QUESTION_MARK_BYTE: + if state == stateNormal { + if argPos >= len(args) { + return "", driver.ErrSkip + } + buf = append(buf, query[lastIdx:i]...) + arg := args[argPos] + argPos++ + + if arg == nil { + buf = append(buf, "NULL"...) + lastIdx = i + 1 + break + } + + switch v := arg.(type) { + case int64: + buf = strconv.AppendInt(buf, v, 10) + case uint64: + buf = strconv.AppendUint(buf, v, 10) + case float64: + buf = strconv.AppendFloat(buf, v, 'g', -1, 64) + case bool: + if v { + buf = append(buf, '1') + } else { + buf = append(buf, '0') + } + case time.Time: + if v.IsZero() { + buf = append(buf, "'0000-00-00'"...) + } else { + buf = append(buf, '\'') + buf, err = appendDateTime(buf, v.In(mc.cfg.Loc), mc.cfg.timeTruncate) + if err != nil { + return "", err + } + buf = append(buf, '\'') + } + case json.RawMessage: + if noBackslashEscapes { + buf = escapeBytesQuotes(buf, v, false) + } else { + buf = escapeBytesBackslash(buf, v, false) + } + case []byte: + if v == nil { + buf = append(buf, "NULL"...) + } else { + if noBackslashEscapes { + buf = escapeBytesQuotes(buf, v, true) + } else { + buf = escapeBytesBackslash(buf, v, true) + } + } + case string: + if noBackslashEscapes { + buf = escapeStringQuotes(buf, v) + } else { + buf = escapeStringBackslash(buf, v) + } + default: + return "", driver.ErrSkip + } - if len(buf)+4 > mc.maxAllowedPacket { - return "", driver.ErrSkip + if len(buf)+4 > mc.maxAllowedPacket { + return "", driver.ErrSkip + } + lastIdx = i + 1 + } + case BACKTICK_BYTE: + if state == stateBacktick { + state = stateNormal + } else if state == stateNormal { + state = stateBacktick + } } + lastChar = currentChar } + buf = append(buf, query[lastIdx:]...) if argPos != len(args) { return "", driver.ErrSkip } @@ -309,7 +432,6 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { if mc.closed.Load() { - mc.log(ErrInvalidConn) return nil, driver.ErrBadConn } if len(args) != 0 { @@ -341,19 +463,19 @@ func (mc *mysqlConn) exec(query string) error { } // Read Result - resLen, err := handleOk.readResultSetHeaderPacket() + resLen, _, err := handleOk.readResultSetHeaderPacket() if err != nil { return err } if resLen > 0 { // columns - if err := mc.readUntilEOF(); err != nil { + if err := mc.skipColumns(resLen); err != nil { return err } // rows - if err := mc.readUntilEOF(); err != nil { + if err := mc.skipRows(); err != nil { return err } } @@ -369,7 +491,6 @@ func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) handleOk := mc.clearResult() if mc.closed.Load() { - mc.log(ErrInvalidConn) return nil, driver.ErrBadConn } if len(args) != 0 { @@ -385,44 +506,46 @@ func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) } // Send command err := mc.writeCommandPacketStr(comQuery, query) - if err == nil { - // Read Result - var resLen int - resLen, err = handleOk.readResultSetHeaderPacket() - if err == nil { - rows := new(textRows) - rows.mc = mc + if err != nil { + return nil, mc.markBadConn(err) + } - if resLen == 0 { - rows.rs.done = true + // Read Result + var resLen int + resLen, _, err = handleOk.readResultSetHeaderPacket() + if err != nil { + return nil, err + } - switch err := rows.NextResultSet(); err { - case nil, io.EOF: - return rows, nil - default: - return nil, err - } - } + rows := new(textRows) + rows.mc = mc - // Columns - rows.rs.columns, err = mc.readColumns(resLen) - return rows, err + if resLen == 0 { + rows.rs.done = true + + switch err := rows.NextResultSet(); err { + case nil, io.EOF: + return rows, nil + default: + return nil, err } } - return nil, mc.markBadConn(err) + + // Columns + rows.rs.columns, err = mc.readColumns(resLen, nil) + return rows, err } // Gets the value of the given MySQL System Variable -// The returned byte slice is only valid until the next read -func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { +func (mc *mysqlConn) getSystemVar(name string) (string, error) { // Send command handleOk := mc.clearResult() if err := mc.writeCommandPacketStr(comQuery, "SELECT @@"+name); err != nil { - return nil, err + return "", err } // Read Result - resLen, err := handleOk.readResultSetHeaderPacket() + resLen, _, err := handleOk.readResultSetHeaderPacket() if err == nil { rows := new(textRows) rows.mc = mc @@ -430,20 +553,23 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { if resLen > 0 { // Columns - if err := mc.readUntilEOF(); err != nil { - return nil, err + if err := mc.skipColumns(resLen); err != nil { + return "", err } } dest := make([]driver.Value, resLen) if err = rows.readRow(dest); err == nil { - return dest[0].([]byte), mc.readUntilEOF() + // Convert to string before skipRows, which may + // overwrite the read buffer that dest[0] points into. + val := string(dest[0].([]byte)) + return val, mc.skipRows() } } - return nil, err + return "", err } -// finish is called when the query has canceled. +// cancel is called when the query has canceled. func (mc *mysqlConn) cancel(err error) { mc.canceled.Set(err) mc.cleanup() @@ -464,7 +590,6 @@ func (mc *mysqlConn) finish() { // Ping implements driver.Pinger interface func (mc *mysqlConn) Ping(ctx context.Context) (err error) { if mc.closed.Load() { - mc.log(ErrInvalidConn) return driver.ErrBadConn } @@ -650,7 +775,7 @@ func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) { // ResetSession implements driver.SessionResetter. // (From Go 1.10) func (mc *mysqlConn) ResetSession(ctx context.Context) error { - if mc.closed.Load() { + if mc.closed.Load() || mc.buf.busy() { return driver.ErrBadConn } @@ -684,5 +809,8 @@ func (mc *mysqlConn) ResetSession(ctx context.Context) error { // IsValid implements driver.Validator interface // (From Go 1.15) func (mc *mysqlConn) IsValid() bool { - return !mc.closed.Load() + return !mc.closed.Load() && !mc.buf.busy() } + +var _ driver.SessionResetter = &mysqlConn{} +var _ driver.Validator = &mysqlConn{} diff --git a/vendor/github.com/go-sql-driver/mysql/connector.go b/vendor/github.com/go-sql-driver/mysql/connector.go index b670775..3d37604 100644 --- a/vendor/github.com/go-sql-driver/mysql/connector.go +++ b/vendor/github.com/go-sql-driver/mysql/connector.go @@ -11,6 +11,7 @@ package mysql import ( "context" "database/sql/driver" + "fmt" "net" "os" "strconv" @@ -41,7 +42,7 @@ func encodeConnectionAttributes(cfg *Config) string { } // user-defined connection attributes - for _, connAttr := range strings.Split(cfg.ConnectionAttributes, ",") { + for connAttr := range strings.SplitSeq(cfg.ConnectionAttributes, ",") { k, v, found := strings.Cut(connAttr, ":") if !found { continue @@ -87,20 +88,25 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { mc.parseTime = mc.cfg.ParseTime // Connect to Server - dialsLock.RLock() - dial, ok := dials[mc.cfg.Net] - dialsLock.RUnlock() - if ok { - dctx := ctx - if mc.cfg.Timeout > 0 { - var cancel context.CancelFunc - dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout) - defer cancel() - } - mc.netConn, err = dial(dctx, mc.cfg.Addr) + dctx := ctx + if mc.cfg.Timeout > 0 { + var cancel context.CancelFunc + dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout) + defer cancel() + } + + if c.cfg.DialFunc != nil { + mc.netConn, err = c.cfg.DialFunc(dctx, mc.cfg.Net, mc.cfg.Addr) } else { - nd := net.Dialer{Timeout: mc.cfg.Timeout} - mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr) + dialsLock.RLock() + dial, ok := dials[mc.cfg.Net] + dialsLock.RUnlock() + if ok { + mc.netConn, err = dial(dctx, mc.cfg.Addr) + } else { + nd := net.Dialer{} + mc.netConn, err = nd.DialContext(dctx, mc.cfg.Net, mc.cfg.Addr) + } } if err != nil { return nil, err @@ -122,14 +128,10 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { } defer mc.finish() - mc.buf = newBuffer(mc.netConn) - - // Set I/O timeouts - mc.buf.timeout = mc.cfg.ReadTimeout - mc.writeTimeout = mc.cfg.WriteTimeout + mc.buf = newBuffer() // Reading Handshake Initialization Packet - authData, plugin, err := mc.readHandshakePacket() + authData, serverCapabilities, serverExtCapabilities, plugin, err := mc.readHandshakePacket() if err != nil { mc.cleanup() return nil, err @@ -151,6 +153,7 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { return nil, err } } + mc.initCapabilities(serverCapabilities, serverExtCapabilities, mc.cfg) if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil { mc.cleanup() return nil, err @@ -159,12 +162,17 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { // Handle response to auth packet, switch methods if possible if err = mc.handleAuthResult(authData, plugin); err != nil { // Authentication failed and MySQL has already closed the connection - // (https://dev.mysql.com/doc/internals/en/authentication-fails.html). + // (https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase.html#sect_protocol_connection_phase_fast_path_fails). // Do not send COM_QUIT, just cleanup and return the error. mc.cleanup() return nil, err } + // compression is enabled after auth, not right after sending handshake response. + if mc.capabilities&clientCompress > 0 { + mc.compress = true + mc.compIO = newCompIO(mc) + } if mc.cfg.MaxAllowedPacket > 0 { mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket } else { @@ -174,12 +182,36 @@ func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { mc.Close() return nil, err } - mc.maxAllowedPacket = stringToInt(maxap) - 1 + n, err := strconv.Atoi(maxap) + if err != nil { + mc.Close() + return nil, fmt.Errorf("invalid max_allowed_packet value (%q): %w", maxap, err) + } + mc.maxAllowedPacket = n - 1 } if mc.maxAllowedPacket < maxPacketSize { mc.maxWriteSize = mc.maxAllowedPacket } + // Charset: character_set_connection, character_set_client, character_set_results + if len(mc.cfg.charsets) > 0 { + for _, cs := range mc.cfg.charsets { + // ignore errors here - a charset may not exist + if mc.cfg.Collation != "" { + err = mc.exec("SET NAMES " + cs + " COLLATE " + mc.cfg.Collation) + } else { + err = mc.exec("SET NAMES " + cs) + } + if err == nil { + break + } + } + if err != nil { + mc.Close() + return nil, err + } + } + // Handle DSN Params err = mc.handleParams() if err != nil { diff --git a/vendor/github.com/go-sql-driver/mysql/const.go b/vendor/github.com/go-sql-driver/mysql/const.go index 22526e0..6f0cdf3 100644 --- a/vendor/github.com/go-sql-driver/mysql/const.go +++ b/vendor/github.com/go-sql-driver/mysql/const.go @@ -11,6 +11,8 @@ package mysql import "runtime" const ( + debug = false // for debugging. Set true only in development. + defaultAuthPlugin = "mysql_native_password" defaultMaxAllowedPacket = 64 << 20 // 64 MiB. See https://github.com/go-sql-driver/mysql/issues/1355 minProtocolVersion = 10 @@ -30,7 +32,7 @@ const ( ) // MySQL constants documentation: -// http://dev.mysql.com/doc/internals/en/client-server-protocol.html +// https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_PROTOCOL.html const ( iOK byte = 0x00 @@ -40,11 +42,12 @@ const ( iERR byte = 0xff ) -// https://dev.mysql.com/doc/internals/en/capability-flags.html#packet-Protocol::CapabilityFlags -type clientFlag uint32 +// https://dev.mysql.com/doc/dev/mysql-server/latest/group__group__cs__capabilities__flags.html +// https://mariadb.com/kb/en/connection/#capabilities +type capabilityFlag uint32 const ( - clientLongPassword clientFlag = 1 << iota + clientMySQL capabilityFlag = 1 << iota clientFoundRows clientLongFlag clientConnectWithDB @@ -71,6 +74,18 @@ const ( clientDeprecateEOF ) +// https://mariadb.com/kb/en/connection/#capabilities +type extendedCapabilityFlag uint32 + +const ( + progressIndicator extendedCapabilityFlag = 1 << iota + clientComMulti + clientStmtBulkOperations + clientExtendedMetadata + clientCacheMetadata + clientUnitBulkResult +) + const ( comQuit byte = iota + 1 comInitDB @@ -125,7 +140,10 @@ const ( fieldTypeBit ) const ( - fieldTypeJSON fieldType = iota + 0xf5 + fieldTypeVector fieldType = iota + 0xf2 + fieldTypeInvalid + fieldTypeBool + fieldTypeJSON fieldTypeNewDecimal fieldTypeEnum fieldTypeSet diff --git a/vendor/github.com/go-sql-driver/mysql/dsn.go b/vendor/github.com/go-sql-driver/mysql/dsn.go index 65f5a02..491e10f 100644 --- a/vendor/github.com/go-sql-driver/mysql/dsn.go +++ b/vendor/github.com/go-sql-driver/mysql/dsn.go @@ -15,6 +15,7 @@ import ( "crypto/tls" "errors" "fmt" + "maps" "math/big" "net" "net/url" @@ -44,7 +45,7 @@ type Config struct { DBName string // Database name Params map[string]string // Connection parameters ConnectionAttributes string // Connection Attributes, comma-delimited string of user-defined "key:value" pairs - Collation string // Connection collation + Collation string // Connection collation. When set, this will be set in SET NAMES COLLATE query Loc *time.Location // Location for time.Time values MaxAllowedPacket int // Max packet size allowed ServerPubKey string // Server public key name @@ -54,6 +55,8 @@ type Config struct { ReadTimeout time.Duration // I/O read timeout WriteTimeout time.Duration // I/O write timeout Logger Logger // Logger + // DialFunc specifies the dial function for creating connections + DialFunc func(ctx context.Context, network, addr string) (net.Conn, error) // boolean fields @@ -70,11 +73,15 @@ type Config struct { ParseTime bool // Parse time values to time.Time RejectReadOnly bool // Reject read-only connections - // unexported fields. new options should be come here + // unexported fields. new options should be come here. + // boolean first. alphabetical order. + + compress bool // Enable zlib compression beforeConnect func(context.Context, *Config) error // Invoked before a connection is established pubKey *rsa.PublicKey // Server public key timeTruncate time.Duration // Truncate time.Time values to the specified duration + charsets []string // Connection charset. When set, this will be set in SET NAMES query } // Functional Options Pattern @@ -90,7 +97,6 @@ func NewConfig() *Config { AllowNativePasswords: true, CheckConnLiveness: true, } - return cfg } @@ -122,6 +128,29 @@ func BeforeConnect(fn func(context.Context, *Config) error) Option { } } +// EnableCompress sets the compression mode. +func EnableCompression(yes bool) Option { + return func(cfg *Config) error { + cfg.compress = yes + return nil + } +} + +// Charset sets the connection charset and collation. +// +// charset is the connection charset. +// collation is the connection collation. It can be null or empty string. +// +// When collation is not specified, `SET NAMES ` command is sent when the connection is established. +// When collation is specified, `SET NAMES COLLATE ` command is sent when the connection is established. +func Charset(charset, collation string) Option { + return func(cfg *Config) error { + cfg.charsets = []string{charset} + cfg.Collation = collation + return nil + } +} + func (cfg *Config) Clone() *Config { cp := *cfg if cp.TLS != nil { @@ -129,9 +158,7 @@ func (cfg *Config) Clone() *Config { } if len(cp.Params) > 0 { cp.Params = make(map[string]string, len(cfg.Params)) - for k, v := range cfg.Params { - cp.Params[k] = v - } + maps.Copy(cp.Params, cfg.Params) } if cfg.pubKey != nil { cp.pubKey = &rsa.PublicKey{ @@ -282,6 +309,10 @@ func (cfg *Config) FormatDSN() string { writeDSNParam(&buf, &hasParam, "clientFoundRows", "true") } + if charsets := cfg.charsets; len(charsets) > 0 { + writeDSNParam(&buf, &hasParam, "charset", strings.Join(charsets, ",")) + } + if col := cfg.Collation; col != "" { writeDSNParam(&buf, &hasParam, "collation", col) } @@ -290,6 +321,14 @@ func (cfg *Config) FormatDSN() string { writeDSNParam(&buf, &hasParam, "columnsWithAlias", "true") } + if cfg.ConnectionAttributes != "" { + writeDSNParam(&buf, &hasParam, "connectionAttributes", url.QueryEscape(cfg.ConnectionAttributes)) + } + + if cfg.compress { + writeDSNParam(&buf, &hasParam, "compress", "true") + } + if cfg.InterpolateParams { writeDSNParam(&buf, &hasParam, "interpolateParams", "true") } @@ -374,7 +413,7 @@ func ParseDSN(dsn string) (cfg *Config, err error) { if dsn[j] == '@' { // username[:password] // Find the first ':' in dsn[:j] - for k = 0; k < j; k++ { + for k = 0; k < j; k++ { // We cannot use k = range j here, because we use dsn[:k] below if dsn[k] == ':' { cfg.Passwd = dsn[k+1 : j] break @@ -437,7 +476,7 @@ func ParseDSN(dsn string) (cfg *Config, err error) { // parseDSNParams parses the DSN "query string" // Values must be url.QueryEscape'ed func parseDSNParams(cfg *Config, params string) (err error) { - for _, v := range strings.Split(params, "&") { + for v := range strings.SplitSeq(params, "&") { key, value, found := strings.Cut(v, "=") if !found { continue @@ -501,6 +540,10 @@ func parseDSNParams(cfg *Config, params string) (err error) { return errors.New("invalid bool value: " + value) } + // charset + case "charset": + cfg.charsets = strings.Split(value, ",") + // Collation case "collation": cfg.Collation = value @@ -514,7 +557,11 @@ func parseDSNParams(cfg *Config, params string) (err error) { // Compression case "compress": - return errors.New("compression not implemented yet") + var isBool bool + cfg.compress, isBool = readBool(value) + if !isBool { + return errors.New("invalid bool value: " + value) + } // Enable client side placeholder substitution case "interpolateParams": diff --git a/vendor/github.com/go-sql-driver/mysql/errors.go b/vendor/github.com/go-sql-driver/mysql/errors.go index a7ef889..584617b 100644 --- a/vendor/github.com/go-sql-driver/mysql/errors.go +++ b/vendor/github.com/go-sql-driver/mysql/errors.go @@ -32,12 +32,12 @@ var ( // errBadConnNoWrite is used for connection errors where nothing was sent to the database yet. // If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn - // to trigger a resend. + // to trigger a resend. Use mc.markBadConn(err) to do this. // See https://github.com/go-sql-driver/mysql/pull/302 errBadConnNoWrite = errors.New("bad connection") ) -var defaultLogger = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile)) +var defaultLogger = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime)) // Logger is used to log critical error messages. type Logger interface { diff --git a/vendor/github.com/go-sql-driver/mysql/fields.go b/vendor/github.com/go-sql-driver/mysql/fields.go index 2860842..ee9d964 100644 --- a/vendor/github.com/go-sql-driver/mysql/fields.go +++ b/vendor/github.com/go-sql-driver/mysql/fields.go @@ -112,29 +112,32 @@ func (mf *mysqlField) typeDatabaseName() string { return "VARCHAR" case fieldTypeYear: return "YEAR" + case fieldTypeVector: + return "VECTOR" default: return "" } } var ( - scanTypeFloat32 = reflect.TypeOf(float32(0)) - scanTypeFloat64 = reflect.TypeOf(float64(0)) - scanTypeInt8 = reflect.TypeOf(int8(0)) - scanTypeInt16 = reflect.TypeOf(int16(0)) - scanTypeInt32 = reflect.TypeOf(int32(0)) - scanTypeInt64 = reflect.TypeOf(int64(0)) - scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) - scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) - scanTypeNullTime = reflect.TypeOf(sql.NullTime{}) - scanTypeUint8 = reflect.TypeOf(uint8(0)) - scanTypeUint16 = reflect.TypeOf(uint16(0)) - scanTypeUint32 = reflect.TypeOf(uint32(0)) - scanTypeUint64 = reflect.TypeOf(uint64(0)) - scanTypeString = reflect.TypeOf("") - scanTypeNullString = reflect.TypeOf(sql.NullString{}) - scanTypeBytes = reflect.TypeOf([]byte{}) - scanTypeUnknown = reflect.TypeOf(new(any)) + scanTypeFloat32 = reflect.TypeFor[float32]() + scanTypeFloat64 = reflect.TypeFor[float64]() + scanTypeInt8 = reflect.TypeFor[int8]() + scanTypeInt16 = reflect.TypeFor[int16]() + scanTypeInt32 = reflect.TypeFor[int32]() + scanTypeInt64 = reflect.TypeFor[int64]() + scanTypeNullFloat = reflect.TypeFor[sql.NullFloat64]() + scanTypeNullInt = reflect.TypeFor[sql.NullInt64]() + scanTypeNullUint = reflect.TypeFor[sql.Null[uint64]]() + scanTypeNullTime = reflect.TypeFor[sql.NullTime]() + scanTypeUint8 = reflect.TypeFor[uint8]() + scanTypeUint16 = reflect.TypeFor[uint16]() + scanTypeUint32 = reflect.TypeFor[uint32]() + scanTypeUint64 = reflect.TypeFor[uint64]() + scanTypeString = reflect.TypeFor[string]() + scanTypeNullString = reflect.TypeFor[sql.NullString]() + scanTypeBytes = reflect.TypeFor[[]byte]() + scanTypeUnknown = reflect.TypeFor[*any]() ) type mysqlField struct { @@ -183,6 +186,9 @@ func (mf *mysqlField) scanType() reflect.Type { } return scanTypeInt64 } + if mf.flags&flagUnsigned != 0 { + return scanTypeNullUint + } return scanTypeNullInt case fieldTypeFloat: @@ -198,7 +204,7 @@ func (mf *mysqlField) scanType() reflect.Type { return scanTypeNullFloat case fieldTypeBit, fieldTypeTinyBLOB, fieldTypeMediumBLOB, fieldTypeLongBLOB, - fieldTypeBLOB, fieldTypeVarString, fieldTypeString, fieldTypeGeometry: + fieldTypeBLOB, fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeVector: if mf.charSet == binaryCollationID { return scanTypeBytes } diff --git a/vendor/github.com/go-sql-driver/mysql/infile.go b/vendor/github.com/go-sql-driver/mysql/infile.go index 0c8af9f..597b5e7 100644 --- a/vendor/github.com/go-sql-driver/mysql/infile.go +++ b/vendor/github.com/go-sql-driver/mysql/infile.go @@ -17,7 +17,7 @@ import ( ) var ( - fileRegister map[string]bool + fileRegister map[string]struct{} fileRegisterLock sync.RWMutex readerRegister map[string]func() io.Reader readerRegisterLock sync.RWMutex @@ -37,10 +37,10 @@ func RegisterLocalFile(filePath string) { fileRegisterLock.Lock() // lazy map init if fileRegister == nil { - fileRegister = make(map[string]bool) + fileRegister = make(map[string]struct{}) } - fileRegister[strings.Trim(filePath, `"`)] = true + fileRegister[strings.Trim(filePath, `"`)] = struct{}{} fileRegisterLock.Unlock() } @@ -95,11 +95,7 @@ const defaultPacketSize = 16 * 1024 // 16KB is small enough for disk readahead a func (mc *okHandler) handleInFileRequest(name string) (err error) { var rdr io.Reader - var data []byte - packetSize := defaultPacketSize - if mc.maxWriteSize < packetSize { - packetSize = mc.maxWriteSize - } + packetSize := min(mc.maxWriteSize, defaultPacketSize) if idx := strings.Index(name, "Reader::"); idx == 0 || (idx > 0 && name[idx-1] == '/') { // io.Reader // The server might return an an absolute path. See issue #355. @@ -124,9 +120,9 @@ func (mc *okHandler) handleInFileRequest(name string) (err error) { } else { // File name = strings.Trim(name, `"`) fileRegisterLock.RLock() - fr := fileRegister[name] + _, exists := fileRegister[name] fileRegisterLock.RUnlock() - if mc.cfg.AllowAllFiles || fr { + if mc.cfg.AllowAllFiles || exists { var file *os.File var fi os.FileInfo @@ -147,9 +143,11 @@ func (mc *okHandler) handleInFileRequest(name string) (err error) { } // send content packets + var data []byte + // if packetSize == 0, the Reader contains no data if err == nil && packetSize > 0 { - data := make([]byte, 4+packetSize) + data = make([]byte, 4+packetSize) var n int for err == nil { n, err = rdr.Read(data[4:]) @@ -171,6 +169,7 @@ func (mc *okHandler) handleInFileRequest(name string) (err error) { if ioErr := mc.conn().writePacket(data[:4]); ioErr != nil { return ioErr } + mc.conn().syncSequence() // read OK packet if err == nil { diff --git a/vendor/github.com/go-sql-driver/mysql/packets.go b/vendor/github.com/go-sql-driver/mysql/packets.go index 90a3472..d0b21b0 100644 --- a/vendor/github.com/go-sql-driver/mysql/packets.go +++ b/vendor/github.com/go-sql-driver/mysql/packets.go @@ -17,40 +17,66 @@ import ( "fmt" "io" "math" + "os" "strconv" "time" ) -// Packets documentation: -// http://dev.mysql.com/doc/internals/en/client-server-protocol.html +// MySQL client/server protocol documentations. +// https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_PROTOCOL.html +// https://mariadb.com/kb/en/clientserver-protocol/ + +// read n bytes from mc.buf +func (mc *mysqlConn) readNext(n int) ([]byte, error) { + if mc.buf.len() < n { + err := mc.buf.fill(n, mc.readWithTimeout) + if err != nil { + return nil, err + } + } + return mc.buf.readNext(n), nil +} // Read packet to buffer 'data' func (mc *mysqlConn) readPacket() ([]byte, error) { var prevData []byte + invalidSequence := false + + readNext := mc.readNext + if mc.compress { + readNext = mc.compIO.readNext + } + for { // read packet header - data, err := mc.buf.readNext(4) + data, err := readNext(4) if err != nil { + mc.close() if cerr := mc.canceled.Value(); cerr != nil { return nil, cerr } mc.log(err) - mc.Close() return nil, ErrInvalidConn } // packet length [24 bit] - pktLen := int(uint32(data[0]) | uint32(data[1])<<8 | uint32(data[2])<<16) + pktLen := getUint24(data[:3]) + seq := data[3] // check packet sync [8 bit] - if data[3] != mc.sequence { - mc.Close() - if data[3] > mc.sequence { - return nil, ErrPktSyncMul + if seq != mc.sequence { + mc.log(fmt.Sprintf("[warn] unexpected sequence nr: expected %v, got %v", mc.sequence, seq)) + // MySQL and MariaDB doesn't check packet nr in compressed packet. + if !mc.compress { + // For large packets, we stop reading as soon as sync error. + if len(prevData) > 0 { + mc.close() + return nil, ErrPktSyncMul + } + invalidSequence = true } - return nil, ErrPktSync } - mc.sequence++ + mc.sequence = seq + 1 // packets with length 0 terminate a previous packet which is a // multiple of (2^24)-1 bytes long @@ -58,32 +84,38 @@ func (mc *mysqlConn) readPacket() ([]byte, error) { // there was no previous packet if prevData == nil { mc.log(ErrMalformPkt) - mc.Close() + mc.close() return nil, ErrInvalidConn } - return prevData, nil } // read packet body [pktLen bytes] - data, err = mc.buf.readNext(pktLen) + data, err = readNext(pktLen) if err != nil { + mc.close() if cerr := mc.canceled.Value(); cerr != nil { return nil, cerr } mc.log(err) - mc.Close() return nil, ErrInvalidConn } // return data if this was the last packet if pktLen < maxPacketSize { // zero allocations for non-split packets - if prevData == nil { - return data, nil + if prevData != nil { + data = append(prevData, data...) } - - return append(prevData, data...), nil + if invalidSequence { + mc.close() + // return sync error only for regular packet. + // error packets may have wrong sequence number. + if data[0] != iERR { + return nil, ErrPktSync + } + } + return data, nil } prevData = append(prevData, data...) @@ -93,60 +125,52 @@ func (mc *mysqlConn) readPacket() ([]byte, error) { // Write packet buffer 'data' func (mc *mysqlConn) writePacket(data []byte) error { pktLen := len(data) - 4 - if pktLen > mc.maxAllowedPacket { return ErrPktTooLarge } + writeFunc := mc.writeWithTimeout + if mc.compress { + writeFunc = mc.compIO.writePackets + } + for { - var size int - if pktLen >= maxPacketSize { - data[0] = 0xff - data[1] = 0xff - data[2] = 0xff - size = maxPacketSize - } else { - data[0] = byte(pktLen) - data[1] = byte(pktLen >> 8) - data[2] = byte(pktLen >> 16) - size = pktLen - } + size := min(maxPacketSize, pktLen) + putUint24(data[:3], size) data[3] = mc.sequence // Write packet - if mc.writeTimeout > 0 { - if err := mc.netConn.SetWriteDeadline(time.Now().Add(mc.writeTimeout)); err != nil { - return err - } - } - - n, err := mc.netConn.Write(data[:4+size]) - if err == nil && n == 4+size { - mc.sequence++ - if size != maxPacketSize { - return nil - } - pktLen -= size - data = data[size:] - continue + if debug { + fmt.Fprintf(os.Stderr, "writePacket: size=%v seq=%v\n", size, mc.sequence) } - // Handle error - if err == nil { // n != len(data) + n, err := writeFunc(data[:4+size]) + if err != nil { mc.cleanup() - mc.log(ErrMalformPkt) - } else { if cerr := mc.canceled.Value(); cerr != nil { return cerr } if n == 0 && pktLen == len(data)-4 { // only for the first loop iteration when nothing was written yet + mc.log(err) return errBadConnNoWrite + } else { + return err } + } + if n != 4+size { + // io.Writer(b) must return a non-nil error if it cannot write len(b) bytes. + // The io.ErrShortWrite error is used to indicate that this rule has not been followed. mc.cleanup() - mc.log(err) + return io.ErrShortWrite + } + + mc.sequence++ + if size != maxPacketSize { + return nil } - return ErrInvalidConn + pktLen -= size + data = data[size:] } } @@ -155,25 +179,22 @@ func (mc *mysqlConn) writePacket(data []byte) error { ******************************************************************************/ // Handshake Initialization Packet -// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake -func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) { +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake_v10.html +// https://mariadb.com/kb/en/connection/#initial-handshake-packet +func (mc *mysqlConn) readHandshakePacket() (data []byte, capabilities capabilityFlag, extendedCapabilities extendedCapabilityFlag, plugin string, err error) { data, err = mc.readPacket() if err != nil { - // for init we can rewrite this to ErrBadConn for sql.Driver to retry, since - // in connection initialization we don't risk retrying non-idempotent actions. - if err == ErrInvalidConn { - return nil, "", driver.ErrBadConn - } return } if data[0] == iERR { - return nil, "", mc.handleErrorPacket(data) + err = mc.handleErrorPacket(data) + return } // protocol version [1 byte] if data[0] < minProtocolVersion { - return nil, "", fmt.Errorf( + return nil, 0, 0, "", fmt.Errorf( "unsupported protocol version %d. Version %d or higher is required", data[0], minProtocolVersion, @@ -191,15 +212,15 @@ func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err erro pos += 8 + 1 // capability flags (lower 2 bytes) [2 bytes] - mc.flags = clientFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) - if mc.flags&clientProtocol41 == 0 { - return nil, "", ErrOldProtocol + capabilities = capabilityFlag(binary.LittleEndian.Uint16(data[pos : pos+2])) + if capabilities&clientProtocol41 == 0 { + return nil, capabilities, 0, "", ErrOldProtocol } - if mc.flags&clientSSL == 0 && mc.cfg.TLS != nil { + if capabilities&clientSSL == 0 && mc.cfg.TLS != nil { if mc.cfg.AllowFallbackToPlaintext { mc.cfg.TLS = nil } else { - return nil, "", ErrNoTLS + return nil, capabilities, 0, "", ErrNoTLS } } pos += 2 @@ -207,10 +228,18 @@ func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err erro if len(data) > pos { // character set [1 byte] // status flags [2 bytes] + pos += 3 // capability flags (upper 2 bytes) [2 bytes] + capabilities |= capabilityFlag(binary.LittleEndian.Uint16(data[pos:pos+2])) << 16 + pos += 2 // length of auth-plugin-data [1 byte] - // reserved (all [00]) [10 bytes] - pos += 1 + 2 + 2 + 1 + 10 + // reserved (all [00]) [6 bytes] + pos += 7 + if capabilities&clientMySQL == 0 { + // MariaDB server extended flag + extendedCapabilities = extendedCapabilityFlag(binary.LittleEndian.Uint32(data[pos : pos+4])) + } + pos += 4 // second part of the password cipher [minimum 13 bytes], // where len=MAX(13, length of auth-plugin-data - 8) @@ -238,161 +267,160 @@ func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err erro // make a memory safe copy of the cipher slice var b [20]byte copy(b[:], authData) - return b[:], plugin, nil + return b[:], capabilities, extendedCapabilities, plugin, nil } // make a memory safe copy of the cipher slice var b [8]byte copy(b[:], authData) - return b[:], plugin, nil + return b[:], capabilities, 0, plugin, nil } -// Client Authentication Packet -// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse -func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string) error { - // Adjust client flags based on server support - clientFlags := clientProtocol41 | - clientSecureConn | - clientLongPassword | - clientTransactions | - clientLocalFiles | - clientPluginAuth | - clientMultiResults | - clientConnectAttrs | - mc.flags&clientLongFlag - - if mc.cfg.ClientFoundRows { - clientFlags |= clientFoundRows +// initCapabilities initializes the capabilities based on server support and configuration +func (mc *mysqlConn) initCapabilities(serverCapabilities capabilityFlag, serverExtCapabilities extendedCapabilityFlag, cfg *Config) { + clientCapabilities := + clientMySQL | + clientLongFlag | + clientProtocol41 | + clientSecureConn | + clientTransactions | + clientPluginAuthLenEncClientData | + clientLocalFiles | + clientPluginAuth | + clientMultiResults | + clientConnectAttrs | + clientDeprecateEOF + + if cfg.ClientFoundRows { + clientCapabilities |= clientFoundRows + } + if cfg.compress { + clientCapabilities |= clientCompress } - // To enable TLS / SSL if mc.cfg.TLS != nil { - clientFlags |= clientSSL + clientCapabilities |= clientSSL } if mc.cfg.MultiStatements { - clientFlags |= clientMultiStatements + clientCapabilities |= clientMultiStatements } - - // encode length of the auth plugin data - var authRespLEIBuf [9]byte - authRespLen := len(authResp) - authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(authRespLen)) - if len(authRespLEI) > 1 { - // if the length can not be written in 1 byte, it must be written as a - // length encoded integer - clientFlags |= clientPluginAuthLenEncClientData + if n := len(cfg.DBName); n > 0 { + clientCapabilities |= clientConnectWithDB } - pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1 + // only keep client capabilities that server have + mc.capabilities = clientCapabilities & serverCapabilities - // To specify a db name - if n := len(mc.cfg.DBName); n > 0 { - clientFlags |= clientConnectWithDB - pktLen += n + 1 - } - - // encode length of the connection attributes - var connAttrsLEIBuf [9]byte - connAttrsLen := len(mc.connector.encodedAttributes) - connAttrsLEI := appendLengthEncodedInteger(connAttrsLEIBuf[:0], uint64(connAttrsLen)) - pktLen += len(connAttrsLEI) + len(mc.connector.encodedAttributes) + // set MariaDB extended clientCacheMetadata capability if server support it + mc.extCapabilities = clientCacheMetadata & serverExtCapabilities +} - // Calculate packet length and get buffer with that size - data, err := mc.buf.takeBuffer(pktLen + 4) +// Client Authentication Packet +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake_response.html +func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string) error { + // packet header 4 + // capabilities 4 + // maxPacketSize 4 + // collation id 1 + // filler 23 + data, err := mc.buf.takeSmallBuffer(4*3 + 24) if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite + mc.cleanup() + return err } + _ = data[4*3+23] // boundery check - // ClientFlags [32 bit] - data[4] = byte(clientFlags) - data[5] = byte(clientFlags >> 8) - data[6] = byte(clientFlags >> 16) - data[7] = byte(clientFlags >> 24) + // clientCapabilities [32 bit] + binary.LittleEndian.PutUint32(data[4:], uint32(mc.capabilities)) // MaxPacketSize [32 bit] (none) - data[8] = 0x00 - data[9] = 0x00 - data[10] = 0x00 - data[11] = 0x00 + binary.LittleEndian.PutUint32(data[8:], 0) // Collation ID [1 byte] - cname := mc.cfg.Collation - if cname == "" { - cname = defaultCollation - } - var found bool - data[12], found = collations[cname] - if !found { - // Note possibility for false negatives: - // could be triggered although the collation is valid if the - // collations map does not contain entries the server supports. - return fmt.Errorf("unknown collation: %q", cname) + data[12] = defaultCollationID + if cname := mc.cfg.Collation; cname != "" { + colID, ok := collations[cname] + if ok { + data[12] = colID + } else if len(mc.cfg.charsets) > 0 { + // When cfg.charset is set, the collation is set by `SET NAMES COLLATE `. + return fmt.Errorf("unknown collation: %q", cname) + } } // Filler [23 bytes] (all 0x00) + // or filler 19bytes + mariadb extCapabilities pos := 13 - for ; pos < 13+23; pos++ { - data[pos] = 0 + if mc.capabilities&clientMySQL == 0 { + for ; pos < 13+19; pos++ { + data[pos] = 0 + } + // MariaDB Extended Capabilities + binary.LittleEndian.PutUint32(data[13+19:], uint32(mc.extCapabilities)) + } else { + for ; pos < 13+23; pos++ { + data[pos] = 0 + } } // SSL Connection Request Packet - // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest + // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_ssl_request.html + // https://mariadb.com/kb/en/connection/#sslrequest-packet if mc.cfg.TLS != nil { // Send TLS / SSL request packet - if err := mc.writePacket(data[:(4+4+1+23)+4]); err != nil { + if err := mc.writePacket(data); err != nil { return err } // Switch to TLS tlsConn := tls.Client(mc.netConn, mc.cfg.TLS) if err := tlsConn.Handshake(); err != nil { + if cerr := mc.canceled.Value(); cerr != nil { + return cerr + } return err } mc.netConn = tlsConn - mc.buf.nc = tlsConn } // User [null terminated string] if len(mc.cfg.User) > 0 { - pos += copy(data[pos:], mc.cfg.User) + data = append(data, mc.cfg.User...) } - data[pos] = 0x00 - pos++ + data = append(data, 0) // Auth Data [length encoded integer] - pos += copy(data[pos:], authRespLEI) - pos += copy(data[pos:], authResp) + data = appendLengthEncodedInteger(data, uint64(len(authResp))) + data = append(data, authResp...) - // Databasename [null terminated string] - if len(mc.cfg.DBName) > 0 { - pos += copy(data[pos:], mc.cfg.DBName) - data[pos] = 0x00 - pos++ + // Database name [null terminated string] + if mc.capabilities&clientConnectWithDB != 0 { + data = append(data, mc.cfg.DBName...) + data = append(data, 0) } - pos += copy(data[pos:], plugin) - data[pos] = 0x00 - pos++ + data = append(data, plugin...) + data = append(data, 0) // Connection Attributes - pos += copy(data[pos:], connAttrsLEI) - pos += copy(data[pos:], []byte(mc.connector.encodedAttributes)) + if mc.capabilities&clientConnectAttrs != 0 { + connAttrsLen := len(mc.connector.encodedAttributes) + data = appendLengthEncodedInteger(data, uint64(connAttrsLen)) + data = append(data, mc.connector.encodedAttributes...) + } // Send Auth packet - return mc.writePacket(data[:pos]) + return mc.writePacket(data) } -// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_auth_switch_response.html func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error { pktLen := 4 + len(authData) - data, err := mc.buf.takeSmallBuffer(pktLen) + data, err := mc.buf.takeBuffer(pktLen) if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite + mc.cleanup() + return err } // Add the auth data [EOF] @@ -406,32 +434,30 @@ func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error { func (mc *mysqlConn) writeCommandPacket(command byte) error { // Reset Packet Sequence - mc.sequence = 0 + mc.resetSequence() data, err := mc.buf.takeSmallBuffer(4 + 1) if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite + return err } // Add command byte data[4] = command // Send CMD packet - return mc.writePacket(data) + err = mc.writePacket(data) + mc.syncSequence() + return err } func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { // Reset Packet Sequence - mc.sequence = 0 + mc.resetSequence() pktLen := 1 + len(arg) data, err := mc.buf.takeBuffer(pktLen + 4) if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite + return err } // Add command byte @@ -441,31 +467,30 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { copy(data[5:], arg) // Send CMD packet - return mc.writePacket(data) + err = mc.writePacket(data) + mc.syncSequence() + return err } func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error { // Reset Packet Sequence - mc.sequence = 0 + mc.resetSequence() data, err := mc.buf.takeSmallBuffer(4 + 1 + 4) if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite + return err } // Add command byte data[4] = command // Add arg [32 bit] - data[5] = byte(arg) - data[6] = byte(arg >> 8) - data[7] = byte(arg >> 16) - data[8] = byte(arg >> 24) + binary.LittleEndian.PutUint32(data[5:], arg) // Send CMD packet - return mc.writePacket(data) + err = mc.writePacket(data) + mc.syncSequence() + return err } /****************************************************************************** @@ -491,7 +516,7 @@ func (mc *mysqlConn) readAuthResult() ([]byte, string, error) { case iEOF: if len(data) == 1 { - // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest + // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_old_auth_switch_request.html return nil, "mysql_old_password", nil } pluginEndIndex := bytes.IndexByte(data, 0x00) @@ -500,6 +525,9 @@ func (mc *mysqlConn) readAuthResult() ([]byte, string, error) { } plugin := string(data[1:pluginEndIndex]) authData := data[pluginEndIndex+1:] + if len(authData) > 0 && authData[len(authData)-1] == 0 { + authData = authData[:len(authData)-1] + } return authData, plugin, nil default: // Error otherwise @@ -521,36 +549,42 @@ func (mc *okHandler) readResultOK() error { } // Result Set Header Packet -// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::Resultset -func (mc *okHandler) readResultSetHeaderPacket() (int, error) { +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response.html +func (mc *okHandler) readResultSetHeaderPacket() (int, bool, error) { // handleOkPacket replaces both values; other cases leave the values unchanged. mc.result.affectedRows = append(mc.result.affectedRows, 0) mc.result.insertIds = append(mc.result.insertIds, 0) data, err := mc.conn().readPacket() - if err == nil { - switch data[0] { + if err != nil { + return 0, false, err + } - case iOK: - return 0, mc.handleOkPacket(data) + switch data[0] { + case iOK: + return 0, false, mc.handleOkPacket(data) - case iERR: - return 0, mc.conn().handleErrorPacket(data) + case iERR: + return 0, false, mc.conn().handleErrorPacket(data) - case iLocalInFile: - return 0, mc.handleInFileRequest(string(data[1:])) - } + case iLocalInFile: + return 0, false, mc.handleInFileRequest(string(data[1:])) + } - // column count - num, _, _ := readLengthEncodedInteger(data) - // ignore remaining data in the packet. see #1478. - return int(num), nil + // column count + // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_text_resultset.html + // https://mariadb.com/kb/en/result-set-packets/#column-count-packet + num, _, len := readLengthEncodedInteger(data) + + if mc.extCapabilities&clientCacheMetadata != 0 { + return int(num), data[len] == 0x01, nil } - return 0, err + // ignore remaining data in the packet. see #1478. + return int(num), true, nil } // Error Packet -// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-ERR_Packet +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_err_packet.html func (mc *mysqlConn) handleErrorPacket(data []byte) error { if data[0] != iERR { return ErrMalformPkt @@ -563,7 +597,8 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error { // 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION // 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover) - if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly { + // 1836: ER_READ_ONLY_MODE + if (errno == 1792 || errno == 1290 || errno == 1836) && mc.cfg.RejectReadOnly { // Oops; we are connected to a read-only connection, and won't be able // to issue any write statements. Since RejectReadOnly is configured, // we throw away this connection hoping this one would have write @@ -631,7 +666,7 @@ func (mc *mysqlConn) clearResult() *okHandler { } // Ok Packet -// http://dev.mysql.com/doc/internals/en/generic-response-packets.html#packet-OK_Packet +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html func (mc *okHandler) handleOkPacket(data []byte) error { var n, m int var affectedRows, insertId uint64 @@ -665,24 +700,19 @@ func (mc *okHandler) handleOkPacket(data []byte) error { } // Read Packets as Field Packets until EOF-Packet or an Error appears -// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41 -func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_text_resultset_column_definition.html#sect_protocol_com_query_response_text_resultset_column_definition_41 +func (mc *mysqlConn) readColumns(count int, old []mysqlField) ([]mysqlField, error) { columns := make([]mysqlField, count) + if len(old) != count { + old = nil + } - for i := 0; ; i++ { + for i := range count { data, err := mc.readPacket() if err != nil { return nil, err } - // EOF Packet - if data[0] == iEOF && (len(data) == 5 || len(data) == 1) { - if i == count { - return columns, nil - } - return nil, fmt.Errorf("column count mismatch n:%d len:%d", count, len(columns)) - } - // Catalog pos, err := skipLengthEncodedString(data) if err != nil { @@ -703,7 +733,12 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { return nil, err } pos += n - columns[i].tableName = string(tableName) + if old != nil && old[i].tableName == string(tableName) { + // avoid allocating new string + columns[i].tableName = old[i].tableName + } else { + columns[i].tableName = string(tableName) + } } else { n, err = skipLengthEncodedString(data[pos:]) if err != nil { @@ -724,7 +759,12 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { if err != nil { return nil, err } - columns[i].name = string(name) + if old != nil && old[i].name == string(name) { + // avoid allocating new string + columns[i].name = old[i].name + } else { + columns[i].name = string(name) + } pos += n // Original name [len coded string] @@ -755,17 +795,17 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { // Decimals [uint8] columns[i].decimals = data[pos] - //pos++ + } - // Default value [len coded binary] - //if pos < len(data) { - // defaultVal, _, err = bytesToLengthCodedBinary(data[pos:]) - //} + // skip EOF packet if client does not support deprecateEOF + if err := mc.skipEof(); err != nil { + return nil, err } + return columns, nil } // Read Packets as Field Packets until EOF-Packet or an Error appears -// http://dev.mysql.com/doc/internals/en/com-query-response.html#packet-ProtocolText::ResultsetRow +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_text_resultset_row.html func (rows *textRows) readRow(dest []driver.Value) error { mc := rows.mc @@ -779,9 +819,20 @@ func (rows *textRows) readRow(dest []driver.Value) error { } // EOF Packet - if data[0] == iEOF && len(data) == 5 { - // server_status [2 bytes] - rows.mc.status = readStatus(data[3:]) + // text row packets may starts with LengthEncodedString. + // In such case, 0xFE can mean string larger than 0xffffff. + // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_dt_integers.html#sect_protocol_basic_dt_int_le + if data[0] == iEOF && len(data) <= 0xffffff { + if mc.capabilities&clientDeprecateEOF == 0 { + // Deprecated EOF packet + // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_eof_packet.html + mc.status = readStatus(data[3:]) + } else { + // Ok Packet with an 0xFE header + _, _, n := readLengthEncodedInteger(data[1:]) // affected_rows + _, _, m := readLengthEncodedInteger(data[1+n:]) // last_insert_id + mc.status = readStatus(data[1+n+m:]) + } rows.rs.done = true if !rows.HasNextResultSet() { rows.mc = nil @@ -855,8 +906,34 @@ func (rows *textRows) readRow(dest []driver.Value) error { return nil } -// Reads Packets until EOF-Packet or an Error appears. Returns count of Packets read -func (mc *mysqlConn) readUntilEOF() error { +func (mc *mysqlConn) skipPackets(n int) error { + for range n { + if _, err := mc.readPacket(); err != nil { + return err + } + } + return nil +} + +// skips EOF packet after n * ColumnDefinition packets when clientDeprecateEOF is not set +func (mc *mysqlConn) skipEof() error { + if mc.capabilities&clientDeprecateEOF == 0 { + if _, err := mc.readPacket(); err != nil { + return err + } + } + return nil +} + +func (mc *mysqlConn) skipColumns(n int) error { + if err := mc.skipPackets(n); err != nil { + return err + } + return mc.skipEof() +} + +// Reads Packets until EOF-Packet or an Error appears. +func (mc *mysqlConn) skipRows() error { for { data, err := mc.readPacket() if err != nil { @@ -867,10 +944,20 @@ func (mc *mysqlConn) readUntilEOF() error { case iERR: return mc.handleErrorPacket(data) case iEOF: - if len(data) == 5 { - mc.status = readStatus(data[3:]) + // text row packets may starts with LengthEncodedString. + // In such case, 0xFE can mean string larger than 0xffffff. + if len(data) <= 0xffffff { + if mc.capabilities&clientDeprecateEOF == 0 { + // EOF packet + mc.status = readStatus(data[3:]) + } else { + // OK packet with an 0xFE header + _, _, n := readLengthEncodedInteger(data[1:]) // affected_rows + _, _, m := readLengthEncodedInteger(data[1+n:]) // last_insert_id + mc.status = readStatus(data[1+n+m:]) + } + return nil } - return nil } } } @@ -880,7 +967,7 @@ func (mc *mysqlConn) readUntilEOF() error { ******************************************************************************/ // Prepare Result Packets -// http://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_prepare.html#sect_protocol_com_stmt_prepare_response func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) { data, err := stmt.mc.readPacket() if err == nil { @@ -907,7 +994,7 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) { return 0, err } -// http://dev.mysql.com/doc/internals/en/com-stmt-send-long-data.html +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_send_long_data.html func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error { maxLen := stmt.mc.maxAllowedPacket - 1 pktLen := maxLen @@ -930,37 +1017,31 @@ func (stmt *mysqlStmt) writeCommandLongData(paramID int, arg []byte) error { pktLen = dataOffset + argLen } - stmt.mc.sequence = 0 // Add command byte [1 byte] data[4] = comStmtSendLongData // Add stmtID [32 bit] - data[5] = byte(stmt.id) - data[6] = byte(stmt.id >> 8) - data[7] = byte(stmt.id >> 16) - data[8] = byte(stmt.id >> 24) + binary.LittleEndian.PutUint32(data[5:], stmt.id) // Add paramID [16 bit] - data[9] = byte(paramID) - data[10] = byte(paramID >> 8) + binary.LittleEndian.PutUint16(data[9:], uint16(paramID)) // Send CMD packet err := stmt.mc.writePacket(data[:4+pktLen]) + // Every COM_LONG_DATA packet reset Packet Sequence + stmt.mc.resetSequence() if err == nil { data = data[pktLen-dataOffset:] continue } return err - } - // Reset Packet Sequence - stmt.mc.sequence = 0 return nil } // Execute Prepared Statement -// http://dev.mysql.com/doc/internals/en/com-stmt-execute.html +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_execute.html func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { if len(args) != stmt.paramCount { return fmt.Errorf( @@ -974,13 +1055,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { mc := stmt.mc // Determine threshold dynamically to avoid packet size shortage. - longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) - if longDataSize < 64 { - longDataSize = 64 - } + longDataSize := max(mc.maxAllowedPacket/(stmt.paramCount+1), 64) // Reset packet-sequence - mc.sequence = 0 + mc.resetSequence() var data []byte var err error @@ -992,28 +1070,20 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { // In this case the len(data) == cap(data) which is used to optimise the flow below. } if err != nil { - // cannot take the buffer. Something must be wrong with the connection - mc.log(err) - return errBadConnNoWrite + return err } // command [1 byte] data[4] = comStmtExecute // statement_id [4 bytes] - data[5] = byte(stmt.id) - data[6] = byte(stmt.id >> 8) - data[7] = byte(stmt.id >> 16) - data[8] = byte(stmt.id >> 24) + binary.LittleEndian.PutUint32(data[5:], stmt.id) // flags (0: CURSOR_TYPE_NO_CURSOR) [1 byte] data[9] = 0x00 // iteration_count (uint32(1)) [4 bytes] - data[10] = 0x01 - data[11] = 0x00 - data[12] = 0x00 - data[13] = 0x00 + binary.LittleEndian.PutUint32(data[10:], 1) if len(args) > 0 { pos := minPktLen @@ -1067,50 +1137,17 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { case int64: paramTypes[i+i] = byte(fieldTypeLongLong) paramTypes[i+i+1] = 0x00 - - if cap(paramValues)-len(paramValues)-8 >= 0 { - paramValues = paramValues[:len(paramValues)+8] - binary.LittleEndian.PutUint64( - paramValues[len(paramValues)-8:], - uint64(v), - ) - } else { - paramValues = append(paramValues, - uint64ToBytes(uint64(v))..., - ) - } + paramValues = binary.LittleEndian.AppendUint64(paramValues, uint64(v)) case uint64: paramTypes[i+i] = byte(fieldTypeLongLong) paramTypes[i+i+1] = 0x80 // type is unsigned - - if cap(paramValues)-len(paramValues)-8 >= 0 { - paramValues = paramValues[:len(paramValues)+8] - binary.LittleEndian.PutUint64( - paramValues[len(paramValues)-8:], - uint64(v), - ) - } else { - paramValues = append(paramValues, - uint64ToBytes(uint64(v))..., - ) - } + paramValues = binary.LittleEndian.AppendUint64(paramValues, uint64(v)) case float64: paramTypes[i+i] = byte(fieldTypeDouble) paramTypes[i+i+1] = 0x00 - - if cap(paramValues)-len(paramValues)-8 >= 0 { - paramValues = paramValues[:len(paramValues)+8] - binary.LittleEndian.PutUint64( - paramValues[len(paramValues)-8:], - math.Float64bits(v), - ) - } else { - paramValues = append(paramValues, - uint64ToBytes(math.Float64bits(v))..., - ) - } + paramValues = binary.LittleEndian.AppendUint64(paramValues, math.Float64bits(v)) case bool: paramTypes[i+i] = byte(fieldTypeTiny) @@ -1191,34 +1228,33 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { // In that case we must build the data packet with the new values buffer if valuesCap != cap(paramValues) { data = append(data[:pos], paramValues...) - if err = mc.buf.store(data); err != nil { - mc.log(err) - return errBadConnNoWrite - } + mc.buf.store(data) // allow this buffer to be reused } pos += len(paramValues) data = data[:pos] } - return mc.writePacket(data) + err = mc.writePacket(data) + mc.syncSequence() + return err } // For each remaining resultset in the stream, discards its rows and updates // mc.affectedRows and mc.insertIds. func (mc *okHandler) discardResults() error { for mc.status&statusMoreResultsExists != 0 { - resLen, err := mc.readResultSetHeaderPacket() + resLen, _, err := mc.readResultSetHeaderPacket() if err != nil { return err } if resLen > 0 { // columns - if err := mc.conn().readUntilEOF(); err != nil { + if err := mc.conn().skipColumns(resLen); err != nil { return err } // rows - if err := mc.conn().readUntilEOF(); err != nil { + if err := mc.conn().skipRows(); err != nil { return err } } @@ -1226,7 +1262,7 @@ func (mc *okHandler) discardResults() error { return nil } -// http://dev.mysql.com/doc/internals/en/binary-protocol-resultset-row.html +// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_binary_resultset.html#sect_protocol_binary_resultset_row func (rows *binaryRows) readRow(dest []driver.Value) error { data, err := rows.mc.readPacket() if err != nil { @@ -1235,9 +1271,17 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { // packet indicator [1 byte] if data[0] != iOK { - // EOF Packet - if data[0] == iEOF && len(data) == 5 { - rows.mc.status = readStatus(data[3:]) + // EOF/OK Packet + if data[0] == iEOF { + if rows.mc.capabilities&clientDeprecateEOF == 0 { + // EOF packet + rows.mc.status = readStatus(data[3:]) + } else { + // OK Packet with an 0xFE header + _, _, n := readLengthEncodedInteger(data[1:]) + _, _, m := readLengthEncodedInteger(data[1+n:]) + rows.mc.status = readStatus(data[1+n+m:]) + } rows.rs.done = true if !rows.HasNextResultSet() { rows.mc = nil @@ -1325,7 +1369,8 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, - fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON: + fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON, + fieldTypeVector: var isNull bool var n int dest[i], isNull, n, err = readLengthEncodedString(data[pos:]) diff --git a/vendor/github.com/go-sql-driver/mysql/result.go b/vendor/github.com/go-sql-driver/mysql/result.go index d516314..82dc0f9 100644 --- a/vendor/github.com/go-sql-driver/mysql/result.go +++ b/vendor/github.com/go-sql-driver/mysql/result.go @@ -8,6 +8,8 @@ package mysql +import "slices" + import "database/sql/driver" // Result exposes data not available through *connection.Result. @@ -42,9 +44,9 @@ func (res *mysqlResult) RowsAffected() (int64, error) { } func (res *mysqlResult) AllLastInsertIds() []int64 { - return append([]int64{}, res.insertIds...) // defensive copy + return slices.Clone(res.insertIds) // defensive copy } func (res *mysqlResult) AllRowsAffected() []int64 { - return append([]int64{}, res.affectedRows...) // defensive copy + return slices.Clone(res.affectedRows) // defensive copy } diff --git a/vendor/github.com/go-sql-driver/mysql/rows.go b/vendor/github.com/go-sql-driver/mysql/rows.go index 81fa606..190e75f 100644 --- a/vendor/github.com/go-sql-driver/mysql/rows.go +++ b/vendor/github.com/go-sql-driver/mysql/rows.go @@ -111,16 +111,9 @@ func (rows *mysqlRows) Close() (err error) { return err } - // flip the buffer for this connection if we need to drain it. - // note that for a successful query (i.e. one where rows.next() - // has been called until it returns false), `rows.mc` will be nil - // by the time the user calls `(*Rows).Close`, so we won't reach this - // see: https://github.com/golang/go/commit/651ddbdb5056ded455f47f9c494c67b389622a47 - mc.buf.flip() - // Remove unread packets from stream if !rows.rs.done { - err = mc.readUntilEOF() + err = mc.skipRows() } if err == nil { handleOk := mc.clearResult() @@ -150,7 +143,7 @@ func (rows *mysqlRows) nextResultSet() (int, error) { // Remove unread packets from stream if !rows.rs.done { - if err := rows.mc.readUntilEOF(); err != nil { + if err := rows.mc.skipRows(); err != nil { return 0, err } rows.rs.done = true @@ -163,7 +156,7 @@ func (rows *mysqlRows) nextResultSet() (int, error) { rows.rs = resultSet{} // rows.mc.affectedRows and rows.mc.insertIds accumulate on each call to // nextResultSet. - resLen, err := rows.mc.resultUnchanged().readResultSetHeaderPacket() + resLen, _, err := rows.mc.resultUnchanged().readResultSetHeaderPacket() if err != nil { // Clean up about multi-results flag rows.rs.done = true @@ -193,7 +186,7 @@ func (rows *binaryRows) NextResultSet() error { return err } - rows.rs.columns, err = rows.mc.readColumns(resLen) + rows.rs.columns, err = rows.mc.readColumns(resLen, nil) return err } @@ -215,7 +208,7 @@ func (rows *textRows) NextResultSet() (err error) { return err } - rows.rs.columns, err = rows.mc.readColumns(resLen) + rows.rs.columns, err = rows.mc.readColumns(resLen, nil) return err } diff --git a/vendor/github.com/go-sql-driver/mysql/statement.go b/vendor/github.com/go-sql-driver/mysql/statement.go index 0436f22..0261903 100644 --- a/vendor/github.com/go-sql-driver/mysql/statement.go +++ b/vendor/github.com/go-sql-driver/mysql/statement.go @@ -20,15 +20,17 @@ type mysqlStmt struct { mc *mysqlConn id uint32 paramCount int + columns []mysqlField } func (stmt *mysqlStmt) Close() error { if stmt.mc == nil || stmt.mc.closed.Load() { - // driver.Stmt.Close can be called more than once, thus this function - // has to be idempotent. - // See also Issue #450 and golang/go#16019. - //errLog.Print(ErrInvalidConn) - return driver.ErrBadConn + // driver.Stmt.Close could be called more than once, thus this function + // had to be idempotent. See also Issue #450 and golang/go#16019. + // This bug has been fixed in Go 1.8. + // https://github.com/golang/go/commit/90b8a0ca2d0b565c7c7199ffcf77b15ea6b6db3a + // But we keep this function idempotent because it is safer. + return nil } err := stmt.mc.writeCommandPacketUint32(comStmtClose, stmt.id) @@ -51,7 +53,6 @@ func (stmt *mysqlStmt) CheckNamedValue(nv *driver.NamedValue) (err error) { func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { if stmt.mc.closed.Load() { - stmt.mc.log(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command @@ -64,19 +65,26 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { handleOk := stmt.mc.clearResult() // Read Result - resLen, err := handleOk.readResultSetHeaderPacket() + resLen, metadataFollows, err := handleOk.readResultSetHeaderPacket() if err != nil { return nil, err } if resLen > 0 { // Columns - if err = mc.readUntilEOF(); err != nil { - return nil, err + if metadataFollows && stmt.mc.extCapabilities&clientCacheMetadata != 0 { + // we can not skip column metadata because next stmt.Query() may use it. + if stmt.columns, err = mc.readColumns(resLen, stmt.columns); err != nil { + return nil, err + } + } else { + if err = mc.skipColumns(resLen); err != nil { + return nil, err + } } // Rows - if err := mc.readUntilEOF(); err != nil { + if err = mc.skipRows(); err != nil { return nil, err } } @@ -95,7 +103,6 @@ func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { if stmt.mc.closed.Load() { - stmt.mc.log(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command @@ -108,7 +115,7 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { // Read Result handleOk := stmt.mc.clearResult() - resLen, err := handleOk.readResultSetHeaderPacket() + resLen, metadataFollows, err := handleOk.readResultSetHeaderPacket() if err != nil { return nil, err } @@ -117,7 +124,17 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { if resLen > 0 { rows.mc = mc - rows.rs.columns, err = mc.readColumns(resLen) + if metadataFollows { + if rows.rs.columns, err = mc.readColumns(resLen, stmt.columns); err != nil { + return nil, err + } + stmt.columns = rows.rs.columns + } else { + if err = mc.skipEof(); err != nil { + return nil, err + } + rows.rs.columns = stmt.columns + } } else { rows.rs.done = true @@ -132,7 +149,7 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { return rows, err } -var jsonType = reflect.TypeOf(json.RawMessage{}) +var jsonType = reflect.TypeFor[json.RawMessage]() type converter struct{} @@ -194,7 +211,7 @@ func (c converter) ConvertValue(v any) (driver.Value, error) { return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) } -var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() +var valuerReflectType = reflect.TypeFor[driver.Valuer]() // callValuerValue returns vr.Value(), with one exception: // If vr.Value is an auto-generated method on a pointer type and the diff --git a/vendor/github.com/go-sql-driver/mysql/transaction.go b/vendor/github.com/go-sql-driver/mysql/transaction.go index 4a4b610..8c502f4 100644 --- a/vendor/github.com/go-sql-driver/mysql/transaction.go +++ b/vendor/github.com/go-sql-driver/mysql/transaction.go @@ -13,18 +13,32 @@ type mysqlTx struct { } func (tx *mysqlTx) Commit() (err error) { - if tx.mc == nil || tx.mc.closed.Load() { + if tx.mc == nil { return ErrInvalidConn } + if tx.mc.closed.Load() { + err = tx.mc.error() + if err == nil { + err = ErrInvalidConn + } + return + } err = tx.mc.exec("COMMIT") tx.mc = nil return } func (tx *mysqlTx) Rollback() (err error) { - if tx.mc == nil || tx.mc.closed.Load() { + if tx.mc == nil { return ErrInvalidConn } + if tx.mc.closed.Load() { + err = tx.mc.error() + if err == nil { + err = ErrInvalidConn + } + return + } err = tx.mc.exec("ROLLBACK") tx.mc = nil return diff --git a/vendor/github.com/go-sql-driver/mysql/utils.go b/vendor/github.com/go-sql-driver/mysql/utils.go index cda24fe..2dccb7d 100644 --- a/vendor/github.com/go-sql-driver/mysql/utils.go +++ b/vendor/github.com/go-sql-driver/mysql/utils.go @@ -182,7 +182,7 @@ func parseDateTime(b []byte, loc *time.Location) (time.Time, error) { func parseByteYear(b []byte) (int, error) { year, n := 0, 1000 - for i := 0; i < 4; i++ { + for i := range 4 { v, err := bToi(b[i]) if err != nil { return 0, err @@ -207,7 +207,7 @@ func parseByte2Digits(b1, b2 byte) (int, error) { func parseByteNanoSec(b []byte) (int, error) { ns, digit := 0, 100000 // max is 6-digits - for i := 0; i < len(b); i++ { + for i := range b { v, err := bToi(b[i]) if err != nil { return 0, err @@ -490,17 +490,16 @@ func formatBinaryTime(src []byte, length uint8) (driver.Value, error) { * Convert from and to bytes * ******************************************************************************/ -func uint64ToBytes(n uint64) []byte { - return []byte{ - byte(n), - byte(n >> 8), - byte(n >> 16), - byte(n >> 24), - byte(n >> 32), - byte(n >> 40), - byte(n >> 48), - byte(n >> 56), - } +// 24bit integer: used for packet headers. + +func putUint24(data []byte, n int) { + data[2] = byte(n >> 16) + data[1] = byte(n >> 8) + data[0] = byte(n) +} + +func getUint24(data []byte) int { + return int(data[2])<<16 | int(data[1])<<8 | int(data[0]) } func uint64ToString(n uint64) []byte { @@ -525,16 +524,6 @@ func uint64ToString(n uint64) []byte { return a[i:] } -// treats string value as unsigned integer representation -func stringToInt(b []byte) int { - val := 0 - for i := range b { - val *= 10 - val += int(b[i] - 0x30) - } - return val -} - // returns the string read as a bytes slice, whether the value is NULL, // the number of bytes read and an error, in case the string is longer than // the input slice @@ -586,18 +575,15 @@ func readLengthEncodedInteger(b []byte) (uint64, bool, int) { // 252: value of following 2 case 0xfc: - return uint64(b[1]) | uint64(b[2])<<8, false, 3 + return uint64(binary.LittleEndian.Uint16(b[1:])), false, 3 // 253: value of following 3 case 0xfd: - return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16, false, 4 + return uint64(getUint24(b[1:])), false, 4 // 254: value of following 8 case 0xfe: - return uint64(b[1]) | uint64(b[2])<<8 | uint64(b[3])<<16 | - uint64(b[4])<<24 | uint64(b[5])<<32 | uint64(b[6])<<40 | - uint64(b[7])<<48 | uint64(b[8])<<56, - false, 9 + return uint64(binary.LittleEndian.Uint64(b[1:])), false, 9 } // 0-250: value of first byte @@ -611,13 +597,14 @@ func appendLengthEncodedInteger(b []byte, n uint64) []byte { return append(b, byte(n)) case n <= 0xffff: - return append(b, 0xfc, byte(n), byte(n>>8)) + b = append(b, 0xfc) + return binary.LittleEndian.AppendUint16(b, uint16(n)) case n <= 0xffffff: return append(b, 0xfd, byte(n), byte(n>>8), byte(n>>16)) } - return append(b, 0xfe, byte(n), byte(n>>8), byte(n>>16), byte(n>>24), - byte(n>>32), byte(n>>40), byte(n>>48), byte(n>>56)) + b = append(b, 0xfe) + return binary.LittleEndian.AppendUint64(b, n) } func appendLengthEncodedString(b []byte, s string) []byte { @@ -638,108 +625,80 @@ func reserveBuffer(buf []byte, appendSize int) []byte { return buf[:newSize] } -// escapeBytesBackslash escapes []byte with backslashes (\) -// This escapes the contents of a string (provided as []byte) by adding backslashes before special -// characters, and turning others into specific escape sequences, such as -// turning newlines into \n and null bytes into \0. -// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L823-L932 -func escapeBytesBackslash(buf, v []byte) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) +// Lookup table for backslash escapes (used for both string and bytes) +var backslashEscapeTable [256]byte - for _, c := range v { - switch c { - case '\x00': - buf[pos+1] = '0' - buf[pos] = '\\' - pos += 2 - case '\n': - buf[pos+1] = 'n' - buf[pos] = '\\' - pos += 2 - case '\r': - buf[pos+1] = 'r' - buf[pos] = '\\' - pos += 2 - case '\x1a': - buf[pos+1] = 'Z' - buf[pos] = '\\' - pos += 2 - case '\'': - buf[pos+1] = '\'' - buf[pos] = '\\' - pos += 2 - case '"': - buf[pos+1] = '"' - buf[pos] = '\\' - pos += 2 - case '\\': - buf[pos+1] = '\\' +func init() { + backslashEscapeTable['\x00'] = '0' + backslashEscapeTable['\n'] = 'n' + backslashEscapeTable['\r'] = 'r' + backslashEscapeTable['\x1a'] = 'Z' + backslashEscapeTable['\''] = '\'' + backslashEscapeTable['"'] = '"' + backslashEscapeTable['\\'] = '\\' +} + +// escapeStringBackslash is similar to escapeBytesBackslash but for string. +func escapeStringBackslash(buf []byte, v string) []byte { + pos := len(buf) + buf = reserveBuffer(buf, len(v)*2+2) + buf[pos] = '\'' + pos++ + for i := 0; i < len(v); i++ { + c := v[i] + if esc := backslashEscapeTable[c]; esc != 0 { + buf[pos+1] = esc buf[pos] = '\\' pos += 2 - default: + } else { buf[pos] = c pos++ } } - + buf[pos] = '\'' + pos++ return buf[:pos] } -// escapeStringBackslash is similar to escapeBytesBackslash but for string. -func escapeStringBackslash(buf []byte, v string) []byte { +// escapeBytesBackslash appends _binary'...' or '...' with backslash escaping for bytes. +func escapeBytesBackslash(buf, v []byte, binary bool) []byte { pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for i := 0; i < len(v); i++ { - c := v[i] - switch c { - case '\x00': - buf[pos+1] = '0' - buf[pos] = '\\' - pos += 2 - case '\n': - buf[pos+1] = 'n' - buf[pos] = '\\' - pos += 2 - case '\r': - buf[pos+1] = 'r' - buf[pos] = '\\' - pos += 2 - case '\x1a': - buf[pos+1] = 'Z' - buf[pos] = '\\' - pos += 2 - case '\'': - buf[pos+1] = '\'' - buf[pos] = '\\' - pos += 2 - case '"': - buf[pos+1] = '"' - buf[pos] = '\\' - pos += 2 - case '\\': - buf[pos+1] = '\\' + if binary { + buf = reserveBuffer(buf, len(v)*2+9) + copy(buf[pos:], []byte("_binary'")) + pos += 8 + } else { + buf = reserveBuffer(buf, len(v)*2+2) + buf[pos] = '\'' + pos++ + } + for _, c := range v { + if esc := backslashEscapeTable[c]; esc != 0 { + buf[pos+1] = esc buf[pos] = '\\' pos += 2 - default: + } else { buf[pos] = c pos++ } } - + buf[pos] = '\'' + pos++ return buf[:pos] } -// escapeBytesQuotes escapes apostrophes in []byte by doubling them up. -// This escapes the contents of a string by doubling up any apostrophes that -// it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in -// effect on the server. -// https://github.com/mysql/mysql-server/blob/mysql-5.7.5/mysys/charset.c#L963-L1038 -func escapeBytesQuotes(buf, v []byte) []byte { +// escapeBytesQuotes appends _binary'...' or '...' with single-quote escaping for bytes. +func escapeBytesQuotes(buf, v []byte, binary bool) []byte { pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - + if binary { + buf = reserveBuffer(buf, len(v)*2+9) + copy(buf[pos:], []byte("_binary'")) + pos += 8 + } else { + buf = reserveBuffer(buf, len(v)*2+2) + buf[pos] = '\'' + pos++ + } for _, c := range v { if c == '\'' { buf[pos+1] = '\'' @@ -750,16 +709,18 @@ func escapeBytesQuotes(buf, v []byte) []byte { pos++ } } - + buf[pos] = '\'' + pos++ return buf[:pos] } // escapeStringQuotes is similar to escapeBytesQuotes but for string. func escapeStringQuotes(buf []byte, v string) []byte { pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for i := 0; i < len(v); i++ { + buf = reserveBuffer(buf, len(v)*2+2) + buf[pos] = '\'' + pos++ + for i := range len(v) { c := v[i] if c == '\'' { buf[pos+1] = '\'' @@ -770,7 +731,8 @@ func escapeStringQuotes(buf []byte, v string) []byte { pos++ } } - + buf[pos] = '\'' + pos++ return buf[:pos] } 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 0000000..e981345 --- /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 0000000..3782838 --- /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 0000000..977acca --- /dev/null +++ b/vendor/github.com/goccy/go-json/.golangci.yml @@ -0,0 +1,86 @@ +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 + - varnamelen + - nilnil + - ireturn + - govet + - forcetypeassert + - cyclop + - containedctx + - revive + - nosnakecase + - exhaustruct + - depguard + +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 0000000..d09bb89 --- /dev/null +++ b/vendor/github.com/goccy/go-json/CHANGELOG.md @@ -0,0 +1,425 @@ +# v0.10.2 - 2023/03/20 + +### New features + +* Support DebugDOT option for debugging encoder ( #440 ) + +### Fix bugs + +* Fix combination of embedding structure and omitempty option ( #442 ) + +# v0.10.1 - 2023/03/13 + +### Fix bugs + +* Fix checkptr error for array decoder ( #415 ) +* Fix added buffer size check when decoding key ( #430 ) +* Fix handling of anonymous fields other than struct ( #431 ) +* Fix to not optimize when lower conversion can't handle byte-by-byte ( #432 ) +* Fix a problem that MarshalIndent does not work when UnorderedMap is specified ( #435 ) +* Fix mapDecoder.DecodeStream() for empty objects containing whitespace ( #425 ) +* Fix an issue that could not set the correct NextField for fields in the embedded structure ( #438 ) + +# v0.10.0 - 2022/11/29 + +### New features + +* Support JSON Path ( #250 ) + +### Fix bugs + +* Fix marshaler for map's key ( #409 ) + +# v0.9.11 - 2022/08/18 + +### Fix bugs + +* Fix unexpected behavior when buffer ends with backslash ( #383 ) +* Fix stream decoding of escaped character ( #387 ) + +# v0.9.10 - 2022/07/15 + +### Fix bugs + +* Fix boundary exception of type caching ( #382 ) + +# v0.9.9 - 2022/07/15 + +### Fix bugs + +* Fix encoding of directed interface with typed nil ( #377 ) +* Fix embedded primitive type encoding using alias ( #378 ) +* Fix slice/array type encoding with types implementing MarshalJSON ( #379 ) +* Fix unicode decoding when the expected buffer state is not met after reading ( #380 ) + +# v0.9.8 - 2022/06/30 + +### Fix bugs + +* Fix decoding of surrogate-pair ( #365 ) +* Fix handling of embedded primitive type ( #366 ) +* Add validation of escape sequence for decoder ( #367 ) +* Fix stream tokenizing respecting UseNumber ( #369 ) +* Fix encoding when struct pointer type that implements Marshal JSON is embedded ( #375 ) + +### Improve performance + +* Improve performance of linkRecursiveCode ( #368 ) + +# v0.9.7 - 2022/04/22 + +### Fix bugs + +#### Encoder + +* Add filtering process for encoding on slow path ( #355 ) +* Fix encoding of interface{} with pointer type ( #363 ) + +#### Decoder + +* Fix map key decoder that implements UnmarshalJSON ( #353 ) +* Fix decoding of []uint8 type ( #361 ) + +### New features + +* Add DebugWith option for encoder ( #356 ) + +# v0.9.6 - 2022/03/22 + +### Fix bugs + +* Correct the handling of the minimum value of int type for decoder ( #344 ) +* Fix bugs of stream decoder's bufferSize ( #349 ) +* Add a guard to use typeptr more safely ( #351 ) + +### Improve decoder performance + +* Improve escapeString's performance ( #345 ) + +### Others + +* Update go version for CI ( #347 ) + +# v0.9.5 - 2022/03/04 + +### Fix bugs + +* Fix panic when decoding time.Time with context ( #328 ) +* Fix reading the next character in buffer to nul consideration ( #338 ) +* Fix incorrect handling on skipValue ( #341 ) + +### Improve decoder performance + +* Improve performance when a payload contains escape sequence ( #334 ) + +# v0.9.4 - 2022/01/21 + +* Fix IsNilForMarshaler for string type with omitempty ( #323 ) +* Fix the case where the embedded field is at the end ( #326 ) + +# v0.9.3 - 2022/01/14 + +* Fix logic of removing struct field for decoder ( #322 ) + +# v0.9.2 - 2022/01/14 + +* Add invalid decoder to delay type error judgment at decode ( #321 ) + +# v0.9.1 - 2022/01/11 + +* Fix encoding of MarshalText/MarshalJSON operation with head offset ( #319 ) + +# v0.9.0 - 2022/01/05 + +### New feature + +* Supports dynamic filtering of struct fields ( #314 ) + +### Improve encoding performance + +* Improve map encoding performance ( #310 ) +* Optimize encoding path for escaped string ( #311 ) +* Add encoding option for performance ( #312 ) + +### Fix bugs + +* Fix panic at encoding map value on 1.18 ( #310 ) +* Fix MarshalIndent for interface type ( #317 ) + +# v0.8.1 - 2021/12/05 + +* Fix operation conversion from PtrHead to Head in Recursive type ( #305 ) + +# v0.8.0 - 2021/12/02 + +* Fix embedded field conflict behavior ( #300 ) +* Refactor compiler for encoder ( #301 #302 ) + +# v0.7.10 - 2021/10/16 + +* Fix conversion from pointer to uint64 ( #294 ) + +# v0.7.9 - 2021/09/28 + +* Fix encoding of nil value about interface type that has method ( #291 ) + +# v0.7.8 - 2021/09/01 + +* Fix mapassign_faststr for indirect struct type ( #283 ) +* Fix encoding of not empty interface type ( #284 ) +* Fix encoding of empty struct interface type ( #286 ) + +# v0.7.7 - 2021/08/25 + +* Fix invalid utf8 on stream decoder ( #279 ) +* Fix buffer length bug on string stream decoder ( #280 ) + +Thank you @orisano !! + +# v0.7.6 - 2021/08/13 + +* Fix nil slice assignment ( #276 ) +* Improve error message ( #277 ) + +# v0.7.5 - 2021/08/12 + +* Fix encoding of embedded struct with tags ( #265 ) +* Fix encoding of embedded struct that isn't first field ( #272 ) +* Fix decoding of binary type with escaped char ( #273 ) + +# 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 0000000..6449c8b --- /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 0000000..c030577 --- /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 + $(BIN_DIR)/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 install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.54.2; \ + 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 0000000..7bacc54 --- /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.9.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.9.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). + +# 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` +- Can dynamically filter the fields of the structure type-safely + +# 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 escaped 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 0000000..e80b22b --- /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 0000000..74c6ac3 --- /dev/null +++ b/vendor/github.com/goccy/go-json/decode.go @@ -0,0 +1,263 @@ +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) +} + +var ( + pathDecoder = decoder.NewPathDecoder() +) + +func extractFromPath(path *Path, data []byte, optFuncs ...DecodeOptionFunc) ([][]byte, error) { + if path.path.RootSelectorOnly { + return [][]byte{data}, nil + } + src := make([]byte, len(data)+1) // append nul byte to the end + copy(src, data) + + ctx := decoder.TakeRuntimeContext() + ctx.Buf = src + ctx.Option.Flags = 0 + ctx.Option.Flags |= decoder.PathOption + ctx.Option.Path = path.path + for _, optFunc := range optFuncs { + optFunc(ctx.Option) + } + paths, cursor, err := pathDecoder.DecodePath(ctx, 0, 0) + if err != nil { + decoder.ReleaseRuntimeContext(ctx) + return nil, err + } + decoder.ReleaseRuntimeContext(ctx) + if err := validateEndBuf(src, cursor); err != nil { + return nil, err + } + return paths, nil +} + +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 0000000..db40c79 --- /dev/null +++ b/vendor/github.com/goccy/go-json/docker-compose.yml @@ -0,0 +1,13 @@ +version: '2' +services: + go-json: + image: golang:1.18 + 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 0000000..c517382 --- /dev/null +++ b/vendor/github.com/goccy/go-json/encode.go @@ -0,0 +1,326 @@ +package json + +import ( + "context" + "io" + "os" + "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...) //nolint: contextcheck + + 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 + } + ctx.Option.Flag |= encoder.NormalizeUTF8Option + ctx.Option.DebugOut = os.Stdout + 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.NormalizeUTF8Option | encoder.ContextOption + rctx.Option.Context = ctx + for _, optFunc := range optFuncs { + optFunc(rctx.Option) + } + + buf, err := encode(rctx, v) //nolint: contextcheck + 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 | encoder.NormalizeUTF8Option) + 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 | encoder.NormalizeUTF8Option) + + 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.NormalizeUTF8Option | 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(ctx, 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(ctx, 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(ctx, 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 0000000..5b2dcee --- /dev/null +++ b/vendor/github.com/goccy/go-json/error.go @@ -0,0 +1,41 @@ +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 + +type PathError = errors.PathError 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 0000000..b6876cf --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/anonymous_field.go @@ -0,0 +1,41 @@ +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)) +} + +func (d *anonymousFieldDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return d.dec.DecodePath(ctx, cursor, depth) +} 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 0000000..4b23ed4 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/array.go @@ -0,0 +1,176 @@ +package decoder + +import ( + "fmt" + "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 { + // workaround to avoid checkptr errors. cannot use `*(*unsafe.Pointer)(unsafe_New(elemType))` directly. + zeroValuePtr := unsafe_New(elemType) + zeroValue := **(**unsafe.Pointer)(unsafe.Pointer(&zeroValuePtr)) + 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) + } + } +} + +func (d *arrayDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: array decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/assign.go b/vendor/github.com/goccy/go-json/internal/decoder/assign.go new file mode 100644 index 0000000..c53e6ad --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/assign.go @@ -0,0 +1,438 @@ +package decoder + +import ( + "fmt" + "reflect" + "strconv" +) + +var ( + nilValue = reflect.ValueOf(nil) +) + +func AssignValue(src, dst reflect.Value) error { + if dst.Type().Kind() != reflect.Ptr { + return fmt.Errorf("invalid dst type. required pointer type: %T", dst.Type()) + } + casted, err := castValue(dst.Elem().Type(), src) + if err != nil { + return err + } + dst.Elem().Set(casted) + return nil +} + +func castValue(t reflect.Type, v reflect.Value) (reflect.Value, error) { + switch t.Kind() { + case reflect.Int: + vv, err := castInt(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(int(vv.Int())), nil + case reflect.Int8: + vv, err := castInt(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(int8(vv.Int())), nil + case reflect.Int16: + vv, err := castInt(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(int16(vv.Int())), nil + case reflect.Int32: + vv, err := castInt(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(int32(vv.Int())), nil + case reflect.Int64: + return castInt(v) + case reflect.Uint: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uint(vv.Uint())), nil + case reflect.Uint8: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uint8(vv.Uint())), nil + case reflect.Uint16: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uint16(vv.Uint())), nil + case reflect.Uint32: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uint32(vv.Uint())), nil + case reflect.Uint64: + return castUint(v) + case reflect.Uintptr: + vv, err := castUint(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(uintptr(vv.Uint())), nil + case reflect.String: + return castString(v) + case reflect.Bool: + return castBool(v) + case reflect.Float32: + vv, err := castFloat(v) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(float32(vv.Float())), nil + case reflect.Float64: + return castFloat(v) + case reflect.Array: + return castArray(t, v) + case reflect.Slice: + return castSlice(t, v) + case reflect.Map: + return castMap(t, v) + case reflect.Struct: + return castStruct(t, v) + } + return v, nil +} + +func castInt(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v, nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return reflect.ValueOf(int64(v.Uint())), nil + case reflect.String: + i64, err := strconv.ParseInt(v.String(), 10, 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(i64), nil + case reflect.Bool: + if v.Bool() { + return reflect.ValueOf(int64(1)), nil + } + return reflect.ValueOf(int64(0)), nil + case reflect.Float32, reflect.Float64: + return reflect.ValueOf(int64(v.Float())), nil + case reflect.Array: + if v.Len() > 0 { + return castInt(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to int64 from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castInt(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to int64 from empty slice") + case reflect.Interface: + return castInt(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to int64 from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to int64 from struct") + case reflect.Ptr: + return castInt(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to int64 from %s", v.Type().Kind()) +} + +func castUint(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return reflect.ValueOf(uint64(v.Int())), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v, nil + case reflect.String: + u64, err := strconv.ParseUint(v.String(), 10, 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(u64), nil + case reflect.Bool: + if v.Bool() { + return reflect.ValueOf(uint64(1)), nil + } + return reflect.ValueOf(uint64(0)), nil + case reflect.Float32, reflect.Float64: + return reflect.ValueOf(uint64(v.Float())), nil + case reflect.Array: + if v.Len() > 0 { + return castUint(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to uint64 from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castUint(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to uint64 from empty slice") + case reflect.Interface: + return castUint(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to uint64 from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to uint64 from struct") + case reflect.Ptr: + return castUint(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to uint64 from %s", v.Type().Kind()) +} + +func castString(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return reflect.ValueOf(fmt.Sprint(v.Int())), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return reflect.ValueOf(fmt.Sprint(v.Uint())), nil + case reflect.String: + return v, nil + case reflect.Bool: + if v.Bool() { + return reflect.ValueOf("true"), nil + } + return reflect.ValueOf("false"), nil + case reflect.Float32, reflect.Float64: + return reflect.ValueOf(fmt.Sprint(v.Float())), nil + case reflect.Array: + if v.Len() > 0 { + return castString(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to string from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castString(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to string from empty slice") + case reflect.Interface: + return castString(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to string from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to string from struct") + case reflect.Ptr: + return castString(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to string from %s", v.Type().Kind()) +} + +func castBool(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch v.Int() { + case 0: + return reflect.ValueOf(false), nil + case 1: + return reflect.ValueOf(true), nil + } + return nilValue, fmt.Errorf("failed to cast to bool from %d", v.Int()) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + switch v.Uint() { + case 0: + return reflect.ValueOf(false), nil + case 1: + return reflect.ValueOf(true), nil + } + return nilValue, fmt.Errorf("failed to cast to bool from %d", v.Uint()) + case reflect.String: + b, err := strconv.ParseBool(v.String()) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(b), nil + case reflect.Bool: + return v, nil + case reflect.Float32, reflect.Float64: + switch v.Float() { + case 0: + return reflect.ValueOf(false), nil + case 1: + return reflect.ValueOf(true), nil + } + return nilValue, fmt.Errorf("failed to cast to bool from %f", v.Float()) + case reflect.Array: + if v.Len() > 0 { + return castBool(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to string from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castBool(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to string from empty slice") + case reflect.Interface: + return castBool(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to string from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to string from struct") + case reflect.Ptr: + return castBool(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to bool from %s", v.Type().Kind()) +} + +func castFloat(v reflect.Value) (reflect.Value, error) { + switch v.Type().Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return reflect.ValueOf(float64(v.Int())), nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return reflect.ValueOf(float64(v.Uint())), nil + case reflect.String: + f64, err := strconv.ParseFloat(v.String(), 64) + if err != nil { + return nilValue, err + } + return reflect.ValueOf(f64), nil + case reflect.Bool: + if v.Bool() { + return reflect.ValueOf(float64(1)), nil + } + return reflect.ValueOf(float64(0)), nil + case reflect.Float32, reflect.Float64: + return v, nil + case reflect.Array: + if v.Len() > 0 { + return castFloat(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to float64 from empty array") + case reflect.Slice: + if v.Len() > 0 { + return castFloat(v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to float64 from empty slice") + case reflect.Interface: + return castFloat(reflect.ValueOf(v.Interface())) + case reflect.Map: + return nilValue, fmt.Errorf("failed to cast to float64 from map") + case reflect.Struct: + return nilValue, fmt.Errorf("failed to cast to float64 from struct") + case reflect.Ptr: + return castFloat(v.Elem()) + } + return nilValue, fmt.Errorf("failed to cast to float64 from %s", v.Type().Kind()) +} + +func castArray(t reflect.Type, v reflect.Value) (reflect.Value, error) { + kind := v.Type().Kind() + if kind == reflect.Interface { + return castArray(t, reflect.ValueOf(v.Interface())) + } + if kind != reflect.Slice && kind != reflect.Array { + return nilValue, fmt.Errorf("failed to cast to array from %s", kind) + } + if t.Elem() == v.Type().Elem() { + return v, nil + } + if t.Len() != v.Len() { + return nilValue, fmt.Errorf("failed to cast [%d]array from slice of %d length", t.Len(), v.Len()) + } + ret := reflect.New(t).Elem() + for i := 0; i < v.Len(); i++ { + vv, err := castValue(t.Elem(), v.Index(i)) + if err != nil { + return nilValue, err + } + ret.Index(i).Set(vv) + } + return ret, nil +} + +func castSlice(t reflect.Type, v reflect.Value) (reflect.Value, error) { + kind := v.Type().Kind() + if kind == reflect.Interface { + return castSlice(t, reflect.ValueOf(v.Interface())) + } + if kind != reflect.Slice && kind != reflect.Array { + return nilValue, fmt.Errorf("failed to cast to slice from %s", kind) + } + if t.Elem() == v.Type().Elem() { + return v, nil + } + ret := reflect.MakeSlice(t, v.Len(), v.Len()) + for i := 0; i < v.Len(); i++ { + vv, err := castValue(t.Elem(), v.Index(i)) + if err != nil { + return nilValue, err + } + ret.Index(i).Set(vv) + } + return ret, nil +} + +func castMap(t reflect.Type, v reflect.Value) (reflect.Value, error) { + ret := reflect.MakeMap(t) + switch v.Type().Kind() { + case reflect.Map: + iter := v.MapRange() + for iter.Next() { + key, err := castValue(t.Key(), iter.Key()) + if err != nil { + return nilValue, err + } + value, err := castValue(t.Elem(), iter.Value()) + if err != nil { + return nilValue, err + } + ret.SetMapIndex(key, value) + } + return ret, nil + case reflect.Interface: + return castMap(t, reflect.ValueOf(v.Interface())) + case reflect.Slice: + if v.Len() > 0 { + return castMap(t, v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to map from empty slice") + } + return nilValue, fmt.Errorf("failed to cast to map from %s", v.Type().Kind()) +} + +func castStruct(t reflect.Type, v reflect.Value) (reflect.Value, error) { + ret := reflect.New(t).Elem() + switch v.Type().Kind() { + case reflect.Map: + iter := v.MapRange() + for iter.Next() { + key := iter.Key() + k, err := castString(key) + if err != nil { + return nilValue, err + } + fieldName := k.String() + field, ok := t.FieldByName(fieldName) + if ok { + value, err := castValue(field.Type, iter.Value()) + if err != nil { + return nilValue, err + } + ret.FieldByName(fieldName).Set(value) + } + } + return ret, nil + case reflect.Struct: + for i := 0; i < v.Type().NumField(); i++ { + name := v.Type().Field(i).Name + ret.FieldByName(name).Set(v.FieldByName(name)) + } + return ret, nil + case reflect.Interface: + return castStruct(t, reflect.ValueOf(v.Interface())) + case reflect.Slice: + if v.Len() > 0 { + return castStruct(t, v.Index(0)) + } + return nilValue, fmt.Errorf("failed to cast to struct from empty slice") + default: + return nilValue, fmt.Errorf("failed to cast to struct from %s", v.Type().Kind()) + } +} 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 0000000..ba6cf5b --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/bool.go @@ -0,0 +1,83 @@ +package decoder + +import ( + "fmt" + "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) +} + +func (d *boolDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: bool decoder does not support decode path") +} 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 0000000..939bf43 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/bytes.go @@ -0,0 +1,118 @@ +package decoder + +import ( + "encoding/base64" + "fmt" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type bytesDecoder struct { + typ *runtime.Type + sliceDecoder Decoder + stringDecoder *stringDecoder + 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) + default: + unmarshalDecoder, _ = compileUint8(typ, structName, fieldName) + } + 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), + stringDecoder: newStringDecoder(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 (d *bytesDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: []byte decoder does not support decode path") +} + +func (d *bytesDecoder) decodeStreamBinary(s *Stream, depth int64, p unsafe.Pointer) ([]byte, error) { + c := s.skipWhiteSpace() + if c == '[' { + if d.sliceDecoder == nil { + return nil, &errors.UnmarshalTypeError{ + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + } + } + err := d.sliceDecoder.DecodeStream(s, depth, p) + return nil, err + } + return d.stringDecoder.decodeStreamByte(s) +} + +func (d *bytesDecoder) decodeBinary(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) ([]byte, int64, error) { + buf := ctx.Buf + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == '[' { + 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 + } + return d.stringDecoder.decodeByte(buf, 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 0000000..8ad5093 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/compile.go @@ -0,0 +1,493 @@ +package decoder + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" + "sync" + "sync/atomic" + "unicode" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +var ( + jsonNumberType = reflect.TypeOf(json.Number("")) + typeAddr *runtime.TypeAddr + cachedDecoderMap unsafe.Pointer // map[uintptr]decoder + cachedDecoder []Decoder + initOnce sync.Once +) + +func initDecoder() { + initOnce.Do(func() { + typeAddr = runtime.AnalyzeTypeAddr() + if typeAddr == nil { + typeAddr = &runtime.TypeAddr{} + } + cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1) + }) +} + +func loadDecoderMap() map[uintptr]Decoder { + initDecoder() + p := atomic.LoadPointer(&cachedDecoderMap) + return *(*map[uintptr]Decoder)(unsafe.Pointer(&p)) +} + +func storeDecoder(typ uintptr, dec Decoder, m map[uintptr]Decoder) { + initDecoder() + 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 newInvalidDecoder(typ, structName, fieldName), nil +} + +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 + } + if typ.Kind() == reflect.String { + return newStringDecoder(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: + return newInvalidDecoder(typ, structName, fieldName), nil + } + } +} + +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 typeToStructTags(typ *runtime.Type) runtime.StructTags { + tags := runtime.StructTags{} + fieldNum := typ.NumField() + for i := 0; i < fieldNum; i++ { + field := typ.Field(i) + if runtime.IsIgnoredStructField(field) { + continue + } + tags = append(tags, runtime.StructTagFromField(field)) + } + return tags +} + +func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeToDecoder map[uintptr]Decoder) (Decoder, error) { + fieldNum := typ.NumField() + 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() + tags := typeToStructTags(typ) + allFields := []*structFieldSet{} + 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 + } + for k, v := range stDec.fieldMap { + if tags.ExistsKey(k) { + continue + } + fieldSet := &structFieldSet{ + dec: v.dec, + offset: field.Offset + v.offset, + isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), + } + allFields = append(allFields, fieldSet) + } + } 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 tags.ExistsKey(k) { + continue + } + fieldSet := &structFieldSet{ + dec: newAnonymousFieldDecoder(pdec.typ, v.offset, v.dec), + offset: field.Offset, + isTaggedKey: v.isTaggedKey, + key: k, + keyLen: int64(len(k)), + err: fieldSetErr, + } + allFields = append(allFields, fieldSet) + } + } else { + fieldSet := &structFieldSet{ + dec: pdec, + offset: field.Offset, + isTaggedKey: tag.IsTaggedKey, + key: field.Name, + keyLen: int64(len(field.Name)), + } + allFields = append(allFields, fieldSet) + } + } else { + fieldSet := &structFieldSet{ + dec: dec, + offset: field.Offset, + isTaggedKey: tag.IsTaggedKey, + key: field.Name, + keyLen: int64(len(field.Name)), + } + allFields = append(allFields, fieldSet) + } + } 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)), + } + allFields = append(allFields, fieldSet) + } + } + for _, set := range filterDuplicatedFields(allFields) { + fieldMap[set.key] = set + lower := strings.ToLower(set.key) + if _, exists := fieldMap[lower]; !exists { + // first win + fieldMap[lower] = set + } + } + delete(structTypeToDecoder, typeptr) + structDec.tryOptimize() + return structDec, nil +} + +func filterDuplicatedFields(allFields []*structFieldSet) []*structFieldSet { + fieldMap := map[string][]*structFieldSet{} + for _, field := range allFields { + fieldMap[field.key] = append(fieldMap[field.key], field) + } + duplicatedFieldMap := map[string]struct{}{} + for k, sets := range fieldMap { + sets = filterFieldSets(sets) + if len(sets) != 1 { + duplicatedFieldMap[k] = struct{}{} + } + } + + filtered := make([]*structFieldSet, 0, len(allFields)) + for _, field := range allFields { + if _, exists := duplicatedFieldMap[field.key]; exists { + continue + } + filtered = append(filtered, field) + } + return filtered +} + +func filterFieldSets(sets []*structFieldSet) []*structFieldSet { + if len(sets) == 1 { + return sets + } + filtered := make([]*structFieldSet, 0, len(sets)) + for _, set := range sets { + if set.isTaggedKey { + filtered = append(filtered, set) + } + } + return filtered +} + +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 0000000..025ca85 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/compile_norace.go @@ -0,0 +1,30 @@ +//go:build !race +// +build !race + +package decoder + +import ( + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) { + initDecoder() + 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 0000000..023b817 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/compile_race.go @@ -0,0 +1,38 @@ +//go:build race +// +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) { + initDecoder() + 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 0000000..cb2ffda --- /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 0000000..9b2eb8b --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/float.go @@ -0,0 +1,170 @@ +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 +} + +func (d *floatDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + buf := ctx.Buf + bytes, c, err := d.decodeByte(buf, cursor) + if err != nil { + return nil, 0, err + } + if bytes == nil { + return [][]byte{nullbytes}, c, nil + } + return [][]byte{bytes}, c, 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 0000000..4cc12ca --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/func.go @@ -0,0 +1,146 @@ +package decoder + +import ( + "bytes" + "fmt" + "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.ErrInvalidBeginningOfValue(s.buf[s.cursor], s.totalOffset()) +} + +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 cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor) +} + +func (d *funcDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: func decoder does not support decode path") +} 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 0000000..1a7f081 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/int.go @@ -0,0 +1,246 @@ +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 +} + +func (d *intDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: int decoder does not support decode path") +} 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 0000000..45c69ab --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/interface.go @@ -0,0 +1,528 @@ +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()) + EmptyInterfaceType = emptyInterfaceType + 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.ErrInvalidBeginningOfValue(c, 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.ErrInvalidBeginningOfValue(buf[cursor], cursor) +} + +func NewPathDecoder() Decoder { + ifaceDecoder := &interfaceDecoder{ + typ: emptyInterfaceType, + structName: "", + fieldName: "", + floatDecoder: newFloatDecoder("", "", func(p unsafe.Pointer, v float64) { + *(*interface{})(p) = v + }), + numberDecoder: newNumberDecoder("", "", func(p unsafe.Pointer, v json.Number) { + *(*interface{})(p) = v + }), + stringDecoder: newStringDecoder("", ""), + } + ifaceDecoder.sliceDecoder = newSliceDecoder( + ifaceDecoder, + emptyInterfaceType, + emptyInterfaceType.Size(), + "", "", + ) + ifaceDecoder.mapDecoder = newMapDecoder( + interfaceMapType, + stringType, + ifaceDecoder.stringDecoder, + interfaceMapType.Elem(), + ifaceDecoder, + "", "", + ) + return ifaceDecoder +} + +var ( + truebytes = []byte("true") + falsebytes = []byte("false") +) + +func (d *interfaceDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + buf := ctx.Buf + cursor = skipWhiteSpace(buf, cursor) + switch buf[cursor] { + case '{': + return d.mapDecoder.DecodePath(ctx, cursor, depth) + case '[': + return d.sliceDecoder.DecodePath(ctx, cursor, depth) + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return d.floatDecoder.DecodePath(ctx, cursor, depth) + case '"': + return d.stringDecoder.DecodePath(ctx, cursor, depth) + case 't': + if err := validateTrue(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return [][]byte{truebytes}, cursor, nil + case 'f': + if err := validateFalse(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 5 + return [][]byte{falsebytes}, cursor, nil + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return [][]byte{nullbytes}, cursor, nil + } + return nil, cursor, errors.ErrInvalidBeginningOfValue(buf[cursor], cursor) +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/invalid.go b/vendor/github.com/goccy/go-json/internal/decoder/invalid.go new file mode 100644 index 0000000..4c9721b --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/invalid.go @@ -0,0 +1,55 @@ +package decoder + +import ( + "reflect" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type invalidDecoder struct { + typ *runtime.Type + kind reflect.Kind + structName string + fieldName string +} + +func newInvalidDecoder(typ *runtime.Type, structName, fieldName string) *invalidDecoder { + return &invalidDecoder{ + typ: typ, + kind: typ.Kind(), + structName: structName, + fieldName: fieldName, + } +} + +func (d *invalidDecoder) DecodeStream(s *Stream, depth int64, p unsafe.Pointer) error { + return &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(d.typ), + Offset: s.totalOffset(), + Struct: d.structName, + Field: d.fieldName, + } +} + +func (d *invalidDecoder) Decode(ctx *RuntimeContext, cursor, depth int64, p unsafe.Pointer) (int64, error) { + return 0, &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(d.typ), + Offset: cursor, + Struct: d.structName, + Field: d.fieldName, + } +} + +func (d *invalidDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, &errors.UnmarshalTypeError{ + Value: "object", + Type: runtime.RType2Type(d.typ), + Offset: cursor, + Struct: d.structName, + Field: d.fieldName, + } +} 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 0000000..07a9cae --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/map.go @@ -0,0 +1,280 @@ +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 + canUseAssignFaststrType 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, + canUseAssignFaststrType: canUseAssignFaststrType(keyType, valueType), + valueType: valueType, + valueDecoder: valueDec, + structName: structName, + fieldName: fieldName, + } +} + +const ( + mapMaxElemSize = 128 +) + +// See detail: https://github.com/goccy/go-json/pull/283 +func canUseAssignFaststrType(key *runtime.Type, value *runtime.Type) bool { + indirectElem := value.Size() > mapMaxElemSize + if indirectElem { + return false + } + return key.Kind() == reflect.String +} + +//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.canUseAssignFaststrType { + mapV := mapassign_faststr(t, 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) + } + s.cursor++ + if s.skipWhiteSpace() == '}' { + *(*unsafe.Pointer)(p) = mapValue + s.cursor++ + return nil + } + for { + 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()) + } + s.cursor++ + } +} + +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++ + } +} + +func (d *mapDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + buf := ctx.Buf + depth++ + if depth > maxDecodeNestingDepth { + return nil, 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + + cursor = skipWhiteSpace(buf, cursor) + buflen := int64(len(buf)) + if buflen < 2 { + return nil, 0, errors.ErrExpected("{} for map", cursor) + } + switch buf[cursor] { + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return [][]byte{nullbytes}, cursor, nil + case '{': + default: + return nil, 0, errors.ErrExpected("{ character for map value", cursor) + } + cursor++ + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == '}' { + cursor++ + return nil, cursor, nil + } + keyDecoder, ok := d.keyDecoder.(*stringDecoder) + if !ok { + return nil, 0, &errors.UnmarshalTypeError{ + Value: "string", + Type: reflect.TypeOf(""), + Offset: cursor, + Struct: d.structName, + Field: d.fieldName, + } + } + ret := [][]byte{} + for { + key, keyCursor, err := keyDecoder.decodeByte(buf, cursor) + if err != nil { + return nil, 0, err + } + cursor = skipWhiteSpace(buf, keyCursor) + if buf[cursor] != ':' { + return nil, 0, errors.ErrExpected("colon after object key", cursor) + } + cursor++ + child, found, err := ctx.Option.Path.Field(string(key)) + if err != nil { + return nil, 0, err + } + if found { + if child != nil { + oldPath := ctx.Option.Path.node + ctx.Option.Path.node = child + paths, c, err := d.valueDecoder.DecodePath(ctx, cursor, depth) + if err != nil { + return nil, 0, err + } + ctx.Option.Path.node = oldPath + ret = append(ret, paths...) + cursor = c + } else { + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return nil, 0, err + } + ret = append(ret, buf[start:end]) + cursor = end + } + } else { + c, err := skipValue(buf, cursor, depth) + if err != nil { + return nil, 0, err + } + cursor = c + } + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == '}' { + cursor++ + return ret, cursor, nil + } + if buf[cursor] != ',' { + return nil, 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 0000000..10e5435 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/number.go @@ -0,0 +1,123 @@ +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) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + bytes, c, err := d.decodeByte(ctx.Buf, cursor) + if err != nil { + return nil, 0, err + } + if bytes == nil { + return [][]byte{nullbytes}, c, nil + } + return [][]byte{bytes}, c, nil +} + +func (d *numberDecoder) decodeStreamByte(s *Stream) ([]byte, error) { + start := s.cursor + 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: + if s.cursor == start { + return nil, errors.ErrInvalidBeginningOfValue(s.char(), s.totalOffset()) + } + 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 0000000..502f772 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/option.go @@ -0,0 +1,17 @@ +package decoder + +import "context" + +type OptionFlags uint8 + +const ( + FirstWinOption OptionFlags = 1 << iota + ContextOption + PathOption +) + +type Option struct { + Flags OptionFlags + Context context.Context + Path *Path +} diff --git a/vendor/github.com/goccy/go-json/internal/decoder/path.go b/vendor/github.com/goccy/go-json/internal/decoder/path.go new file mode 100644 index 0000000..a15ff69 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/path.go @@ -0,0 +1,670 @@ +package decoder + +import ( + "fmt" + "reflect" + "strconv" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +type PathString string + +func (s PathString) Build() (*Path, error) { + builder := new(PathBuilder) + return builder.Build([]rune(s)) +} + +type PathBuilder struct { + root PathNode + node PathNode + singleQuotePathSelector bool + doubleQuotePathSelector bool +} + +func (b *PathBuilder) Build(buf []rune) (*Path, error) { + node, err := b.build(buf) + if err != nil { + return nil, err + } + return &Path{ + node: node, + RootSelectorOnly: node == nil, + SingleQuotePathSelector: b.singleQuotePathSelector, + DoubleQuotePathSelector: b.doubleQuotePathSelector, + }, nil +} + +func (b *PathBuilder) build(buf []rune) (PathNode, error) { + if len(buf) == 0 { + return nil, errors.ErrEmptyPath() + } + if buf[0] != '$' { + return nil, errors.ErrInvalidPath("JSON Path must start with a $ character") + } + if len(buf) == 1 { + return nil, nil + } + buf = buf[1:] + offset, err := b.buildNext(buf) + if err != nil { + return nil, err + } + if len(buf) > offset { + return nil, errors.ErrInvalidPath("remain invalid path %q", buf[offset:]) + } + return b.root, nil +} + +func (b *PathBuilder) buildNextCharIfExists(buf []rune, cursor int) (int, error) { + if len(buf) > cursor { + offset, err := b.buildNext(buf[cursor:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + } + return cursor, nil +} + +func (b *PathBuilder) buildNext(buf []rune) (int, error) { + switch buf[0] { + case '.': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with dot character") + } + offset, err := b.buildSelector(buf[1:]) + if err != nil { + return 0, err + } + return offset + 1, nil + case '[': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character") + } + offset, err := b.buildIndex(buf[1:]) + if err != nil { + return 0, err + } + return offset + 1, nil + default: + return 0, errors.ErrInvalidPath("expect dot or left bracket character. but found %c character", buf[0]) + } +} + +func (b *PathBuilder) buildSelector(buf []rune) (int, error) { + switch buf[0] { + case '.': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with double dot character") + } + offset, err := b.buildPathRecursive(buf[1:]) + if err != nil { + return 0, err + } + return 1 + offset, nil + case '[', ']', '$', '*': + return 0, errors.ErrInvalidPath("found invalid path character %c after dot", buf[0]) + } + for cursor := 0; cursor < len(buf); cursor++ { + switch buf[cursor] { + case '$', '*', ']': + return 0, errors.ErrInvalidPath("found %c character in field selector context", buf[cursor]) + case '.': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with dot character") + } + selector := buf[:cursor] + b.addSelectorNode(string(selector)) + offset, err := b.buildSelector(buf[cursor+1:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + case '[': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character") + } + selector := buf[:cursor] + b.addSelectorNode(string(selector)) + offset, err := b.buildIndex(buf[cursor+1:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + case '"': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with double quote character") + } + offset, err := b.buildQuoteSelector(buf[cursor+1:], DoubleQuotePathSelector) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + } + } + b.addSelectorNode(string(buf)) + return len(buf), nil +} + +func (b *PathBuilder) buildQuoteSelector(buf []rune, sel QuotePathSelector) (int, error) { + switch buf[0] { + case '[', ']', '$', '.', '*', '\'', '"': + return 0, errors.ErrInvalidPath("found invalid path character %c after quote", buf[0]) + } + for cursor := 0; cursor < len(buf); cursor++ { + switch buf[cursor] { + case '\'': + if sel != SingleQuotePathSelector { + return 0, errors.ErrInvalidPath("found double quote character in field selector with single quote context") + } + if len(buf) <= cursor+1 { + return 0, errors.ErrInvalidPath("JSON Path ends with single quote character in field selector context") + } + if buf[cursor+1] != ']' { + return 0, errors.ErrInvalidPath("expect right bracket for field selector with single quote but found %c", buf[cursor+1]) + } + selector := buf[:cursor] + b.addSelectorNode(string(selector)) + b.singleQuotePathSelector = true + return b.buildNextCharIfExists(buf, cursor+2) + case '"': + if sel != DoubleQuotePathSelector { + return 0, errors.ErrInvalidPath("found single quote character in field selector with double quote context") + } + selector := buf[:cursor] + b.addSelectorNode(string(selector)) + b.doubleQuotePathSelector = true + return b.buildNextCharIfExists(buf, cursor+1) + } + } + return 0, errors.ErrInvalidPath("couldn't find quote character in selector quote path context") +} + +func (b *PathBuilder) buildPathRecursive(buf []rune) (int, error) { + switch buf[0] { + case '.', '[', ']', '$', '*': + return 0, errors.ErrInvalidPath("found invalid path character %c after double dot", buf[0]) + } + for cursor := 0; cursor < len(buf); cursor++ { + switch buf[cursor] { + case '$', '*', ']': + return 0, errors.ErrInvalidPath("found %c character in field selector context", buf[cursor]) + case '.': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with dot character") + } + selector := buf[:cursor] + b.addRecursiveNode(string(selector)) + offset, err := b.buildSelector(buf[cursor+1:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + case '[': + if cursor+1 >= len(buf) { + return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character") + } + selector := buf[:cursor] + b.addRecursiveNode(string(selector)) + offset, err := b.buildIndex(buf[cursor+1:]) + if err != nil { + return 0, err + } + return cursor + 1 + offset, nil + } + } + b.addRecursiveNode(string(buf)) + return len(buf), nil +} + +func (b *PathBuilder) buildIndex(buf []rune) (int, error) { + switch buf[0] { + case '.', '[', ']', '$': + return 0, errors.ErrInvalidPath("found invalid path character %c after left bracket", buf[0]) + case '\'': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with single quote character") + } + offset, err := b.buildQuoteSelector(buf[1:], SingleQuotePathSelector) + if err != nil { + return 0, err + } + return 1 + offset, nil + case '*': + if len(buf) == 1 { + return 0, errors.ErrInvalidPath("JSON Path ends with star character") + } + if buf[1] != ']' { + return 0, errors.ErrInvalidPath("expect right bracket character for index all path but found %c character", buf[1]) + } + b.addIndexAllNode() + offset := len("*]") + if len(buf) > 2 { + buildOffset, err := b.buildNext(buf[2:]) + if err != nil { + return 0, err + } + return offset + buildOffset, nil + } + return offset, nil + } + + for cursor := 0; cursor < len(buf); cursor++ { + switch buf[cursor] { + case ']': + index, err := strconv.ParseInt(string(buf[:cursor]), 10, 64) + if err != nil { + return 0, errors.ErrInvalidPath("%q is unexpected index path", buf[:cursor]) + } + b.addIndexNode(int(index)) + return b.buildNextCharIfExists(buf, cursor+1) + } + } + return 0, errors.ErrInvalidPath("couldn't find right bracket character in index path context") +} + +func (b *PathBuilder) addIndexAllNode() { + node := newPathIndexAllNode() + if b.root == nil { + b.root = node + b.node = node + } else { + b.node = b.node.chain(node) + } +} + +func (b *PathBuilder) addRecursiveNode(selector string) { + node := newPathRecursiveNode(selector) + if b.root == nil { + b.root = node + b.node = node + } else { + b.node = b.node.chain(node) + } +} + +func (b *PathBuilder) addSelectorNode(name string) { + node := newPathSelectorNode(name) + if b.root == nil { + b.root = node + b.node = node + } else { + b.node = b.node.chain(node) + } +} + +func (b *PathBuilder) addIndexNode(idx int) { + node := newPathIndexNode(idx) + if b.root == nil { + b.root = node + b.node = node + } else { + b.node = b.node.chain(node) + } +} + +type QuotePathSelector int + +const ( + SingleQuotePathSelector QuotePathSelector = 1 + DoubleQuotePathSelector QuotePathSelector = 2 +) + +type Path struct { + node PathNode + RootSelectorOnly bool + SingleQuotePathSelector bool + DoubleQuotePathSelector bool +} + +func (p *Path) Field(sel string) (PathNode, bool, error) { + if p.node == nil { + return nil, false, nil + } + return p.node.Field(sel) +} + +func (p *Path) Get(src, dst reflect.Value) error { + if p.node == nil { + return nil + } + return p.node.Get(src, dst) +} + +func (p *Path) String() string { + if p.node == nil { + return "$" + } + return p.node.String() +} + +type PathNode interface { + fmt.Stringer + Index(idx int) (PathNode, bool, error) + Field(fieldName string) (PathNode, bool, error) + Get(src, dst reflect.Value) error + chain(PathNode) PathNode + target() bool + single() bool +} + +type BasePathNode struct { + child PathNode +} + +func (n *BasePathNode) chain(node PathNode) PathNode { + n.child = node + return node +} + +func (n *BasePathNode) target() bool { + return n.child == nil +} + +func (n *BasePathNode) single() bool { + return true +} + +type PathSelectorNode struct { + *BasePathNode + selector string +} + +func newPathSelectorNode(selector string) *PathSelectorNode { + return &PathSelectorNode{ + BasePathNode: &BasePathNode{}, + selector: selector, + } +} + +func (n *PathSelectorNode) Index(idx int) (PathNode, bool, error) { + return nil, false, &errors.PathError{} +} + +func (n *PathSelectorNode) Field(fieldName string) (PathNode, bool, error) { + if n.selector == fieldName { + return n.child, true, nil + } + return nil, false, nil +} + +func (n *PathSelectorNode) Get(src, dst reflect.Value) error { + switch src.Type().Kind() { + case reflect.Map: + iter := src.MapRange() + for iter.Next() { + key, ok := iter.Key().Interface().(string) + if !ok { + return fmt.Errorf("invalid map key type %T", src.Type().Key()) + } + child, found, err := n.Field(key) + if err != nil { + return err + } + if found { + if child != nil { + return child.Get(iter.Value(), dst) + } + return AssignValue(iter.Value(), dst) + } + } + case reflect.Struct: + typ := src.Type() + for i := 0; i < typ.Len(); i++ { + tag := runtime.StructTagFromField(typ.Field(i)) + child, found, err := n.Field(tag.Key) + if err != nil { + return err + } + if found { + if child != nil { + return child.Get(src.Field(i), dst) + } + return AssignValue(src.Field(i), dst) + } + } + case reflect.Ptr: + return n.Get(src.Elem(), dst) + case reflect.Interface: + return n.Get(reflect.ValueOf(src.Interface()), dst) + case reflect.Float64, reflect.String, reflect.Bool: + return AssignValue(src, dst) + } + return fmt.Errorf("failed to get %s value from %s", n.selector, src.Type()) +} + +func (n *PathSelectorNode) String() string { + s := fmt.Sprintf(".%s", n.selector) + if n.child != nil { + s += n.child.String() + } + return s +} + +type PathIndexNode struct { + *BasePathNode + selector int +} + +func newPathIndexNode(selector int) *PathIndexNode { + return &PathIndexNode{ + BasePathNode: &BasePathNode{}, + selector: selector, + } +} + +func (n *PathIndexNode) Index(idx int) (PathNode, bool, error) { + if n.selector == idx { + return n.child, true, nil + } + return nil, false, nil +} + +func (n *PathIndexNode) Field(fieldName string) (PathNode, bool, error) { + return nil, false, &errors.PathError{} +} + +func (n *PathIndexNode) Get(src, dst reflect.Value) error { + switch src.Type().Kind() { + case reflect.Array, reflect.Slice: + if src.Len() > n.selector { + if n.child != nil { + return n.child.Get(src.Index(n.selector), dst) + } + return AssignValue(src.Index(n.selector), dst) + } + case reflect.Ptr: + return n.Get(src.Elem(), dst) + case reflect.Interface: + return n.Get(reflect.ValueOf(src.Interface()), dst) + } + return fmt.Errorf("failed to get [%d] value from %s", n.selector, src.Type()) +} + +func (n *PathIndexNode) String() string { + s := fmt.Sprintf("[%d]", n.selector) + if n.child != nil { + s += n.child.String() + } + return s +} + +type PathIndexAllNode struct { + *BasePathNode +} + +func newPathIndexAllNode() *PathIndexAllNode { + return &PathIndexAllNode{ + BasePathNode: &BasePathNode{}, + } +} + +func (n *PathIndexAllNode) Index(idx int) (PathNode, bool, error) { + return n.child, true, nil +} + +func (n *PathIndexAllNode) Field(fieldName string) (PathNode, bool, error) { + return nil, false, &errors.PathError{} +} + +func (n *PathIndexAllNode) Get(src, dst reflect.Value) error { + switch src.Type().Kind() { + case reflect.Array, reflect.Slice: + var arr []interface{} + for i := 0; i < src.Len(); i++ { + var v interface{} + rv := reflect.ValueOf(&v) + if n.child != nil { + if err := n.child.Get(src.Index(i), rv); err != nil { + return err + } + } else { + if err := AssignValue(src.Index(i), rv); err != nil { + return err + } + } + arr = append(arr, v) + } + if err := AssignValue(reflect.ValueOf(arr), dst); err != nil { + return err + } + return nil + case reflect.Ptr: + return n.Get(src.Elem(), dst) + case reflect.Interface: + return n.Get(reflect.ValueOf(src.Interface()), dst) + } + return fmt.Errorf("failed to get all value from %s", src.Type()) +} + +func (n *PathIndexAllNode) String() string { + s := "[*]" + if n.child != nil { + s += n.child.String() + } + return s +} + +type PathRecursiveNode struct { + *BasePathNode + selector string +} + +func newPathRecursiveNode(selector string) *PathRecursiveNode { + node := newPathSelectorNode(selector) + return &PathRecursiveNode{ + BasePathNode: &BasePathNode{ + child: node, + }, + selector: selector, + } +} + +func (n *PathRecursiveNode) Field(fieldName string) (PathNode, bool, error) { + if n.selector == fieldName { + return n.child, true, nil + } + return nil, false, nil +} + +func (n *PathRecursiveNode) Index(_ int) (PathNode, bool, error) { + return n, true, nil +} + +func valueToSliceValue(v interface{}) []interface{} { + rv := reflect.ValueOf(v) + ret := []interface{}{} + if rv.Type().Kind() == reflect.Slice || rv.Type().Kind() == reflect.Array { + for i := 0; i < rv.Len(); i++ { + ret = append(ret, rv.Index(i).Interface()) + } + return ret + } + return []interface{}{v} +} + +func (n *PathRecursiveNode) Get(src, dst reflect.Value) error { + if n.child == nil { + return fmt.Errorf("failed to get by recursive path ..%s", n.selector) + } + var arr []interface{} + switch src.Type().Kind() { + case reflect.Map: + iter := src.MapRange() + for iter.Next() { + key, ok := iter.Key().Interface().(string) + if !ok { + return fmt.Errorf("invalid map key type %T", src.Type().Key()) + } + child, found, err := n.Field(key) + if err != nil { + return err + } + if found { + var v interface{} + rv := reflect.ValueOf(&v) + _ = child.Get(iter.Value(), rv) + arr = append(arr, valueToSliceValue(v)...) + } else { + var v interface{} + rv := reflect.ValueOf(&v) + _ = n.Get(iter.Value(), rv) + if v != nil { + arr = append(arr, valueToSliceValue(v)...) + } + } + } + _ = AssignValue(reflect.ValueOf(arr), dst) + return nil + case reflect.Struct: + typ := src.Type() + for i := 0; i < typ.Len(); i++ { + tag := runtime.StructTagFromField(typ.Field(i)) + child, found, err := n.Field(tag.Key) + if err != nil { + return err + } + if found { + var v interface{} + rv := reflect.ValueOf(&v) + _ = child.Get(src.Field(i), rv) + arr = append(arr, valueToSliceValue(v)...) + } else { + var v interface{} + rv := reflect.ValueOf(&v) + _ = n.Get(src.Field(i), rv) + if v != nil { + arr = append(arr, valueToSliceValue(v)...) + } + } + } + _ = AssignValue(reflect.ValueOf(arr), dst) + return nil + case reflect.Array, reflect.Slice: + for i := 0; i < src.Len(); i++ { + var v interface{} + rv := reflect.ValueOf(&v) + _ = n.Get(src.Index(i), rv) + if v != nil { + arr = append(arr, valueToSliceValue(v)...) + } + } + _ = AssignValue(reflect.ValueOf(arr), dst) + return nil + case reflect.Ptr: + return n.Get(src.Elem(), dst) + case reflect.Interface: + return n.Get(reflect.ValueOf(src.Interface()), dst) + } + return fmt.Errorf("failed to get %s value from %s", n.selector, src.Type()) +} + +func (n *PathRecursiveNode) String() string { + s := fmt.Sprintf("..%s", n.selector) + if n.child != nil { + s += n.child.String() + } + return s +} 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 0000000..ae22994 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/ptr.go @@ -0,0 +1,97 @@ +package decoder + +import ( + "fmt" + "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 UnsafeNew(t *runtime.Type) unsafe.Pointer { + return unsafe_New(t) +} + +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 { + *(*unsafe.Pointer)(p) = nil + return 0, err + } + cursor = c + return cursor, nil +} + +func (d *ptrDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: ptr decoder does not support decode path") +} 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 0000000..30a23e4 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/slice.go @@ -0,0 +1,380 @@ +package decoder + +import ( + "reflect" + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/errors" + "github.com/goccy/go-json/internal/runtime" +) + +var ( + sliceType = runtime.Type2RType( + reflect.TypeOf((*sliceHeader)(nil)).Elem(), + ) + nilSlice = unsafe.Pointer(&sliceHeader{}) +) + +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 + } + typedmemmove(sliceType, p, nilSlice) + 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 + typedmemmove(sliceType, p, nilSlice) + 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) + } + } +} + +func (d *sliceDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + buf := ctx.Buf + depth++ + if depth > maxDecodeNestingDepth { + return nil, 0, errors.ErrExceededMaxDepth(buf[cursor], cursor) + } + + ret := [][]byte{} + for { + switch buf[cursor] { + case ' ', '\n', '\t', '\r': + cursor++ + continue + case 'n': + if err := validateNull(buf, cursor); err != nil { + return nil, 0, err + } + cursor += 4 + return [][]byte{nullbytes}, cursor, nil + case '[': + cursor++ + cursor = skipWhiteSpace(buf, cursor) + if buf[cursor] == ']' { + cursor++ + return ret, cursor, nil + } + idx := 0 + for { + child, found, err := ctx.Option.Path.node.Index(idx) + if err != nil { + return nil, 0, err + } + if found { + if child != nil { + oldPath := ctx.Option.Path.node + ctx.Option.Path.node = child + paths, c, err := d.valueDecoder.DecodePath(ctx, cursor, depth) + if err != nil { + return nil, 0, err + } + ctx.Option.Path.node = oldPath + ret = append(ret, paths...) + cursor = c + } else { + start := cursor + end, err := skipValue(buf, cursor, depth) + if err != nil { + return nil, 0, err + } + ret = append(ret, buf[start:end]) + cursor = end + } + } else { + c, err := skipValue(buf, cursor, depth) + if err != nil { + return nil, 0, err + } + cursor = c + } + cursor = skipWhiteSpace(buf, cursor) + switch buf[cursor] { + case ']': + cursor++ + return ret, cursor, nil + case ',': + idx++ + default: + return nil, 0, errors.ErrInvalidCharacter(buf[cursor], "slice", cursor) + } + cursor++ + } + case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return nil, 0, d.errNumber(cursor) + default: + return nil, 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 0000000..a383f72 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/stream.go @@ -0,0 +1,556 @@ +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 = int64(len(s.buf)) +} + +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) + str := *(*string)(unsafe.Pointer(&bytes)) + if s.UseNumber { + return json.Number(str), nil + } + f64, err := strconv.ParseFloat(str, 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.stat() + 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.stat() + 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.stat() + 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() { + _, 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 0000000..32602c9 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/string.go @@ -0,0 +1,452 @@ +package decoder + +import ( + "bytes" + "fmt" + "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 +} + +func (d *stringDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + bytes, c, err := d.decodeByte(ctx.Buf, cursor) + if err != nil { + return nil, 0, err + } + if bytes == nil { + return [][]byte{nullbytes}, c, nil + } + return [][]byte{bytes}, c, 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 readAtLeast(s *Stream, n int64, p *unsafe.Pointer) bool { + for s.cursor+n >= s.length { + if !s.read() { + return false + } + *p = s.bufptr() + } + return true +} + +func decodeUnicodeRune(s *Stream, p unsafe.Pointer) (rune, int64, unsafe.Pointer, error) { + const defaultOffset = 5 + const surrogateOffset = 11 + + if !readAtLeast(s, defaultOffset, &p) { + return rune(0), 0, nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset()) + } + + r := unicodeToRune(s.buf[s.cursor+1 : s.cursor+defaultOffset]) + if utf16.IsSurrogate(r) { + if !readAtLeast(s, surrogateOffset, &p) { + return unicode.ReplacementChar, defaultOffset, p, nil + } + if 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()) + } + p = s.bufptr() + 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-- + p = s.bufptr() + 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 + if !utf8.FullRune(s.buf[cursor : len(s.buf)-1]) { + s.cursor = cursor + if s.read() { + _, cursor, p = s.stat() + continue + } + goto ERROR + } + r, size := utf8.DecodeRune(s.buf[cursor:]) + if r == utf8.RuneError { + s.buf = append(append(append([]byte{}, s.buf[:cursor]...), runeErrBytes...), s.buf[cursor+1:]...) + cursor += runeErrBytesLen + s.length += runeErrBytesLen + _, _, p = s.stat() + } else { + cursor += int64(size) + } + 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.ErrInvalidBeginningOfValue(s.char(), 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 + escaped := 0 + for { + switch char(b, cursor) { + case '\\': + escaped++ + cursor++ + switch char(b, cursor) { + case '"', '\\', '/', 'b', 'f', 'n', 'r', 't': + cursor++ + case 'u': + buflen := int64(len(buf)) + if cursor+5 >= buflen { + return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) + } + for i := int64(1); i <= 4; i++ { + c := char(b, cursor+i) + if !(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) { + return nil, 0, errors.ErrSyntax(fmt.Sprintf("json: invalid character %c in \\u hexadecimal character escape", c), cursor+i) + } + } + cursor += 5 + default: + return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) + } + continue + case '"': + literal := buf[start:cursor] + if escaped > 0 { + literal = literal[:unescapeString(literal)] + } + 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.ErrInvalidBeginningOfValue(buf[cursor], cursor) + } + } +} + +var unescapeMap = [256]byte{ + '"': '"', + '\\': '\\', + '/': '/', + 'b': '\b', + 'f': '\f', + 'n': '\n', + 'r': '\r', + 't': '\t', +} + +func unsafeAdd(ptr unsafe.Pointer, offset int) unsafe.Pointer { + return unsafe.Pointer(uintptr(ptr) + uintptr(offset)) +} + +func unescapeString(buf []byte) int { + p := (*sliceHeader)(unsafe.Pointer(&buf)).data + end := unsafeAdd(p, len(buf)) + src := unsafeAdd(p, bytes.IndexByte(buf, '\\')) + dst := src + for src != end { + c := char(src, 0) + if c == '\\' { + escapeChar := char(src, 1) + if escapeChar != 'u' { + *(*byte)(dst) = unescapeMap[escapeChar] + src = unsafeAdd(src, 2) + dst = unsafeAdd(dst, 1) + } else { + v1 := hexToInt[char(src, 2)] + v2 := hexToInt[char(src, 3)] + v3 := hexToInt[char(src, 4)] + v4 := hexToInt[char(src, 5)] + code := rune((v1 << 12) | (v2 << 8) | (v3 << 4) | v4) + if code >= 0xd800 && code < 0xdc00 && uintptr(unsafeAdd(src, 11)) < uintptr(end) { + if char(src, 6) == '\\' && char(src, 7) == 'u' { + v1 := hexToInt[char(src, 8)] + v2 := hexToInt[char(src, 9)] + v3 := hexToInt[char(src, 10)] + v4 := hexToInt[char(src, 11)] + lo := rune((v1 << 12) | (v2 << 8) | (v3 << 4) | v4) + if lo >= 0xdc00 && lo < 0xe000 { + code = (code-0xd800)<<10 | (lo - 0xdc00) + 0x10000 + src = unsafeAdd(src, 6) + } + } + } + var b [utf8.UTFMax]byte + n := utf8.EncodeRune(b[:], code) + switch n { + case 4: + *(*byte)(unsafeAdd(dst, 3)) = b[3] + fallthrough + case 3: + *(*byte)(unsafeAdd(dst, 2)) = b[2] + fallthrough + case 2: + *(*byte)(unsafeAdd(dst, 1)) = b[1] + fallthrough + case 1: + *(*byte)(unsafeAdd(dst, 0)) = b[0] + } + src = unsafeAdd(src, 6) + dst = unsafeAdd(dst, n) + } + } else { + *(*byte)(dst) = c + src = unsafeAdd(src, 1) + dst = unsafeAdd(dst, 1) + } + } + return int(uintptr(dst) - uintptr(p)) +} 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 0000000..313da15 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/struct.go @@ -0,0 +1,845 @@ +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 toASCIILower(s string) string { + b := []byte(s) + for i := range b { + b[i] = largeToSmallTable[b[i]] + } + return string(b) +} + +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 { + if key != toASCIILower(k) { + d.isTriedOptimize = true + return + } + // 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, error) { + const defaultOffset = 4 + const surrogateOffset = 6 + + if cursor+defaultOffset >= int64(len(buf)) { + return nil, 0, errors.ErrUnexpectedEndOfJSON("escaped string", cursor) + } + + 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, nil + } + cursor += 2 + r2 := unicodeToRune(buf[cursor : cursor+defaultOffset]) + if r := utf16.DecodeRune(r, r2); r != unicode.ReplacementChar { + return []byte(string(r)), cursor + defaultOffset - 1, nil + } + } + return []byte(string(r)), cursor + defaultOffset - 1, nil +} + +func decodeKeyCharByEscapedChar(buf []byte, cursor int64) ([]byte, int64, error) { + c := buf[cursor] + cursor++ + switch c { + case '"': + return []byte{'"'}, cursor, nil + case '\\': + return []byte{'\\'}, cursor, nil + case '/': + return []byte{'/'}, cursor, nil + case 'b': + return []byte{'\b'}, cursor, nil + case 'f': + return []byte{'\f'}, cursor, nil + case 'n': + return []byte{'\n'}, cursor, nil + case 'r': + return []byte{'\r'}, cursor, nil + case 't': + return []byte{'\t'}, cursor, nil + case 'u': + return decodeKeyCharByUnicodeRune(buf, cursor) + } + return nil, cursor, nil +} + +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, err := decodeKeyCharByEscapedChar(buf, cursor) + if err != nil { + return 0, nil, err + } + 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.ErrInvalidBeginningOfValue(char(b, cursor), 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, err := decodeKeyCharByEscapedChar(buf, cursor) + if err != nil { + return 0, nil, err + } + 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.ErrInvalidBeginningOfValue(char(b, cursor), 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.ErrInvalidBeginningOfValue(char(p, cursor), 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.ErrInvalidBeginningOfValue(char(p, cursor), 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.ErrInvalidBeginningOfValue(char(p, cursor), 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.ErrInvalidBeginningOfValue(char(p, cursor), 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.ErrInvalidBeginningOfValue(s.char(), 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.ErrInvalidBeginningOfValue(char(b, cursor), 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++ + } +} + +func (d *structDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: struct decoder does not support decode path") +} 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 0000000..beaf3ab --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/type.go @@ -0,0 +1,30 @@ +package decoder + +import ( + "context" + "encoding" + "encoding/json" + "reflect" + "unsafe" +) + +type Decoder interface { + Decode(*RuntimeContext, int64, int64, unsafe.Pointer) (int64, error) + DecodePath(*RuntimeContext, int64, int64) ([][]byte, 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 0000000..4131731 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/uint.go @@ -0,0 +1,194 @@ +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 +} + +func (d *uintDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: uint decoder does not support decode path") +} 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 0000000..4cd6dbd --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_json.go @@ -0,0 +1,104 @@ +package decoder + +import ( + "context" + "encoding/json" + "fmt" + "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, + })) + switch v := v.(type) { + case unmarshalerContext: + var ctx context.Context + if (s.Option.Flags & ContextOption) != 0 { + ctx = s.Option.Context + } else { + ctx = context.Background() + } + if err := v.UnmarshalJSON(ctx, dst); err != nil { + d.annotateError(s.cursor, err) + return err + } + case json.Unmarshaler: + if err := v.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 +} + +func (d *unmarshalJSONDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: unmarshal json decoder does not support decode path") +} 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 0000000..d711d0f --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/unmarshal_text.go @@ -0,0 +1,285 @@ +package decoder + +import ( + "bytes" + "encoding" + "fmt" + "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 (d *unmarshalTextDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: unmarshal text decoder does not support decode path") +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { //nolint: nonamedreturns + 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 0000000..0c4e2e6 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/decoder/wrapped_string.go @@ -0,0 +1,73 @@ +package decoder + +import ( + "fmt" + "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 +} + +func (d *wrappedStringDecoder) DecodePath(ctx *RuntimeContext, cursor, depth int64) ([][]byte, int64, error) { + return nil, 0, fmt.Errorf("json: wrapped string decoder does not support decode path") +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/code.go b/vendor/github.com/goccy/go-json/internal/encoder/code.go new file mode 100644 index 0000000..fec45a4 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/code.go @@ -0,0 +1,1024 @@ +package encoder + +import ( + "fmt" + "reflect" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +type Code interface { + Kind() CodeKind + ToOpcode(*compileContext) Opcodes + Filter(*FieldQuery) Code +} + +type AnonymousCode interface { + ToAnonymousOpcode(*compileContext) Opcodes +} + +type Opcodes []*Opcode + +func (o Opcodes) First() *Opcode { + if len(o) == 0 { + return nil + } + return o[0] +} + +func (o Opcodes) Last() *Opcode { + if len(o) == 0 { + return nil + } + return o[len(o)-1] +} + +func (o Opcodes) Add(codes ...*Opcode) Opcodes { + return append(o, codes...) +} + +type CodeKind int + +const ( + CodeKindInterface CodeKind = iota + CodeKindPtr + CodeKindInt + CodeKindUint + CodeKindFloat + CodeKindString + CodeKindBool + CodeKindStruct + CodeKindMap + CodeKindSlice + CodeKindArray + CodeKindBytes + CodeKindMarshalJSON + CodeKindMarshalText + CodeKindRecursive +) + +type IntCode struct { + typ *runtime.Type + bitSize uint8 + isString bool + isPtr bool +} + +func (c *IntCode) Kind() CodeKind { + return CodeKindInt +} + +func (c *IntCode) ToOpcode(ctx *compileContext) Opcodes { + var code *Opcode + switch { + case c.isPtr: + code = newOpCode(ctx, c.typ, OpIntPtr) + case c.isString: + code = newOpCode(ctx, c.typ, OpIntString) + default: + code = newOpCode(ctx, c.typ, OpInt) + } + code.NumBitSize = c.bitSize + ctx.incIndex() + return Opcodes{code} +} + +func (c *IntCode) Filter(_ *FieldQuery) Code { + return c +} + +type UintCode struct { + typ *runtime.Type + bitSize uint8 + isString bool + isPtr bool +} + +func (c *UintCode) Kind() CodeKind { + return CodeKindUint +} + +func (c *UintCode) ToOpcode(ctx *compileContext) Opcodes { + var code *Opcode + switch { + case c.isPtr: + code = newOpCode(ctx, c.typ, OpUintPtr) + case c.isString: + code = newOpCode(ctx, c.typ, OpUintString) + default: + code = newOpCode(ctx, c.typ, OpUint) + } + code.NumBitSize = c.bitSize + ctx.incIndex() + return Opcodes{code} +} + +func (c *UintCode) Filter(_ *FieldQuery) Code { + return c +} + +type FloatCode struct { + typ *runtime.Type + bitSize uint8 + isPtr bool +} + +func (c *FloatCode) Kind() CodeKind { + return CodeKindFloat +} + +func (c *FloatCode) ToOpcode(ctx *compileContext) Opcodes { + var code *Opcode + switch { + case c.isPtr: + switch c.bitSize { + case 32: + code = newOpCode(ctx, c.typ, OpFloat32Ptr) + default: + code = newOpCode(ctx, c.typ, OpFloat64Ptr) + } + default: + switch c.bitSize { + case 32: + code = newOpCode(ctx, c.typ, OpFloat32) + default: + code = newOpCode(ctx, c.typ, OpFloat64) + } + } + ctx.incIndex() + return Opcodes{code} +} + +func (c *FloatCode) Filter(_ *FieldQuery) Code { + return c +} + +type StringCode struct { + typ *runtime.Type + isPtr bool +} + +func (c *StringCode) Kind() CodeKind { + return CodeKindString +} + +func (c *StringCode) ToOpcode(ctx *compileContext) Opcodes { + isJSONNumberType := c.typ == runtime.Type2RType(jsonNumberType) + var code *Opcode + if c.isPtr { + if isJSONNumberType { + code = newOpCode(ctx, c.typ, OpNumberPtr) + } else { + code = newOpCode(ctx, c.typ, OpStringPtr) + } + } else { + if isJSONNumberType { + code = newOpCode(ctx, c.typ, OpNumber) + } else { + code = newOpCode(ctx, c.typ, OpString) + } + } + ctx.incIndex() + return Opcodes{code} +} + +func (c *StringCode) Filter(_ *FieldQuery) Code { + return c +} + +type BoolCode struct { + typ *runtime.Type + isPtr bool +} + +func (c *BoolCode) Kind() CodeKind { + return CodeKindBool +} + +func (c *BoolCode) ToOpcode(ctx *compileContext) Opcodes { + var code *Opcode + switch { + case c.isPtr: + code = newOpCode(ctx, c.typ, OpBoolPtr) + default: + code = newOpCode(ctx, c.typ, OpBool) + } + ctx.incIndex() + return Opcodes{code} +} + +func (c *BoolCode) Filter(_ *FieldQuery) Code { + return c +} + +type BytesCode struct { + typ *runtime.Type + isPtr bool +} + +func (c *BytesCode) Kind() CodeKind { + return CodeKindBytes +} + +func (c *BytesCode) ToOpcode(ctx *compileContext) Opcodes { + var code *Opcode + switch { + case c.isPtr: + code = newOpCode(ctx, c.typ, OpBytesPtr) + default: + code = newOpCode(ctx, c.typ, OpBytes) + } + ctx.incIndex() + return Opcodes{code} +} + +func (c *BytesCode) Filter(_ *FieldQuery) Code { + return c +} + +type SliceCode struct { + typ *runtime.Type + value Code +} + +func (c *SliceCode) Kind() CodeKind { + return CodeKindSlice +} + +func (c *SliceCode) ToOpcode(ctx *compileContext) Opcodes { + // header => opcode => elem => end + // ^ | + // |________| + size := c.typ.Elem().Size() + header := newSliceHeaderCode(ctx, c.typ) + ctx.incIndex() + + ctx.incIndent() + codes := c.value.ToOpcode(ctx) + ctx.decIndent() + + codes.First().Flags |= IndirectFlags + elemCode := newSliceElemCode(ctx, c.typ.Elem(), header, size) + ctx.incIndex() + end := newOpCode(ctx, c.typ, OpSliceEnd) + ctx.incIndex() + header.End = end + header.Next = codes.First() + codes.Last().Next = elemCode + elemCode.Next = codes.First() + elemCode.End = end + return Opcodes{header}.Add(codes...).Add(elemCode).Add(end) +} + +func (c *SliceCode) Filter(_ *FieldQuery) Code { + return c +} + +type ArrayCode struct { + typ *runtime.Type + value Code +} + +func (c *ArrayCode) Kind() CodeKind { + return CodeKindArray +} + +func (c *ArrayCode) ToOpcode(ctx *compileContext) Opcodes { + // header => opcode => elem => end + // ^ | + // |________| + elem := c.typ.Elem() + alen := c.typ.Len() + size := elem.Size() + + header := newArrayHeaderCode(ctx, c.typ, alen) + ctx.incIndex() + + ctx.incIndent() + codes := c.value.ToOpcode(ctx) + ctx.decIndent() + + codes.First().Flags |= IndirectFlags + + elemCode := newArrayElemCode(ctx, elem, header, alen, size) + ctx.incIndex() + + end := newOpCode(ctx, c.typ, OpArrayEnd) + ctx.incIndex() + + header.End = end + header.Next = codes.First() + codes.Last().Next = elemCode + elemCode.Next = codes.First() + elemCode.End = end + + return Opcodes{header}.Add(codes...).Add(elemCode).Add(end) +} + +func (c *ArrayCode) Filter(_ *FieldQuery) Code { + return c +} + +type MapCode struct { + typ *runtime.Type + key Code + value Code +} + +func (c *MapCode) Kind() CodeKind { + return CodeKindMap +} + +func (c *MapCode) ToOpcode(ctx *compileContext) Opcodes { + // header => code => value => code => key => code => value => code => end + // ^ | + // |_______________________| + header := newMapHeaderCode(ctx, c.typ) + ctx.incIndex() + + keyCodes := c.key.ToOpcode(ctx) + + value := newMapValueCode(ctx, c.typ.Elem(), header) + ctx.incIndex() + + ctx.incIndent() + valueCodes := c.value.ToOpcode(ctx) + ctx.decIndent() + + valueCodes.First().Flags |= IndirectFlags + + key := newMapKeyCode(ctx, c.typ.Key(), header) + ctx.incIndex() + + end := newMapEndCode(ctx, c.typ, header) + ctx.incIndex() + + header.Next = keyCodes.First() + keyCodes.Last().Next = value + value.Next = valueCodes.First() + valueCodes.Last().Next = key + key.Next = keyCodes.First() + + header.End = end + key.End = end + value.End = end + return Opcodes{header}.Add(keyCodes...).Add(value).Add(valueCodes...).Add(key).Add(end) +} + +func (c *MapCode) Filter(_ *FieldQuery) Code { + return c +} + +type StructCode struct { + typ *runtime.Type + fields []*StructFieldCode + isPtr bool + disableIndirectConversion bool + isIndirect bool + isRecursive bool +} + +func (c *StructCode) Kind() CodeKind { + return CodeKindStruct +} + +func (c *StructCode) lastFieldCode(field *StructFieldCode, firstField *Opcode) *Opcode { + if isEmbeddedStruct(field) { + return c.lastAnonymousFieldCode(firstField) + } + lastField := firstField + for lastField.NextField != nil { + lastField = lastField.NextField + } + return lastField +} + +func (c *StructCode) lastAnonymousFieldCode(firstField *Opcode) *Opcode { + // firstField is special StructHead operation for anonymous structure. + // So, StructHead's next operation is truly struct head operation. + for firstField.Op == OpStructHead || firstField.Op == OpStructField { + firstField = firstField.Next + } + lastField := firstField + for lastField.NextField != nil { + lastField = lastField.NextField + } + return lastField +} + +func (c *StructCode) ToOpcode(ctx *compileContext) Opcodes { + // header => code => structField => code => end + // ^ | + // |__________| + if c.isRecursive { + recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{}) + recursive.Type = c.typ + ctx.incIndex() + *ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive) + return Opcodes{recursive} + } + codes := Opcodes{} + var prevField *Opcode + ctx.incIndent() + for idx, field := range c.fields { + isFirstField := idx == 0 + isEndField := idx == len(c.fields)-1 + fieldCodes := field.ToOpcode(ctx, isFirstField, isEndField) + for _, code := range fieldCodes { + if c.isIndirect { + code.Flags |= IndirectFlags + } + } + firstField := fieldCodes.First() + if len(codes) > 0 { + codes.Last().Next = firstField + firstField.Idx = codes.First().Idx + } + if prevField != nil { + prevField.NextField = firstField + } + if isEndField { + endField := fieldCodes.Last() + if len(codes) > 0 { + codes.First().End = endField + } else { + firstField.End = endField + } + codes = codes.Add(fieldCodes...) + break + } + prevField = c.lastFieldCode(field, firstField) + codes = codes.Add(fieldCodes...) + } + if len(codes) == 0 { + head := &Opcode{ + Op: OpStructHead, + Idx: opcodeOffset(ctx.ptrIndex), + Type: c.typ, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } + ctx.incOpcodeIndex() + end := &Opcode{ + Op: OpStructEnd, + Idx: opcodeOffset(ctx.ptrIndex), + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } + head.NextField = end + head.Next = end + head.End = end + codes = codes.Add(head, end) + ctx.incIndex() + } + ctx.decIndent() + ctx.structTypeToCodes[uintptr(unsafe.Pointer(c.typ))] = codes + return codes +} + +func (c *StructCode) ToAnonymousOpcode(ctx *compileContext) Opcodes { + // header => code => structField => code => end + // ^ | + // |__________| + if c.isRecursive { + recursive := newRecursiveCode(ctx, c.typ, &CompiledCode{}) + recursive.Type = c.typ + ctx.incIndex() + *ctx.recursiveCodes = append(*ctx.recursiveCodes, recursive) + return Opcodes{recursive} + } + codes := Opcodes{} + var prevField *Opcode + for idx, field := range c.fields { + isFirstField := idx == 0 + isEndField := idx == len(c.fields)-1 + fieldCodes := field.ToAnonymousOpcode(ctx, isFirstField, isEndField) + for _, code := range fieldCodes { + if c.isIndirect { + code.Flags |= IndirectFlags + } + } + firstField := fieldCodes.First() + if len(codes) > 0 { + codes.Last().Next = firstField + firstField.Idx = codes.First().Idx + } + if prevField != nil { + prevField.NextField = firstField + } + if isEndField { + lastField := fieldCodes.Last() + if len(codes) > 0 { + codes.First().End = lastField + } else { + firstField.End = lastField + } + } + prevField = firstField + codes = codes.Add(fieldCodes...) + } + ctx.structTypeToCodes[uintptr(unsafe.Pointer(c.typ))] = codes + return codes +} + +func (c *StructCode) removeFieldsByTags(tags runtime.StructTags) { + fields := make([]*StructFieldCode, 0, len(c.fields)) + for _, field := range c.fields { + if field.isAnonymous { + structCode := field.getAnonymousStruct() + if structCode != nil && !structCode.isRecursive { + structCode.removeFieldsByTags(tags) + if len(structCode.fields) > 0 { + fields = append(fields, field) + } + continue + } + } + if tags.ExistsKey(field.key) { + continue + } + fields = append(fields, field) + } + c.fields = fields +} + +func (c *StructCode) enableIndirect() { + if c.isIndirect { + return + } + c.isIndirect = true + if len(c.fields) == 0 { + return + } + structCode := c.fields[0].getStruct() + if structCode == nil { + return + } + structCode.enableIndirect() +} + +func (c *StructCode) Filter(query *FieldQuery) Code { + fieldMap := map[string]*FieldQuery{} + for _, field := range query.Fields { + fieldMap[field.Name] = field + } + fields := make([]*StructFieldCode, 0, len(c.fields)) + for _, field := range c.fields { + query, exists := fieldMap[field.key] + if !exists { + continue + } + fieldCode := &StructFieldCode{ + typ: field.typ, + key: field.key, + tag: field.tag, + value: field.value, + offset: field.offset, + isAnonymous: field.isAnonymous, + isTaggedKey: field.isTaggedKey, + isNilableType: field.isNilableType, + isNilCheck: field.isNilCheck, + isAddrForMarshaler: field.isAddrForMarshaler, + isNextOpPtrType: field.isNextOpPtrType, + } + if len(query.Fields) > 0 { + fieldCode.value = fieldCode.value.Filter(query) + } + fields = append(fields, fieldCode) + } + return &StructCode{ + typ: c.typ, + fields: fields, + isPtr: c.isPtr, + disableIndirectConversion: c.disableIndirectConversion, + isIndirect: c.isIndirect, + isRecursive: c.isRecursive, + } +} + +type StructFieldCode struct { + typ *runtime.Type + key string + tag *runtime.StructTag + value Code + offset uintptr + isAnonymous bool + isTaggedKey bool + isNilableType bool + isNilCheck bool + isAddrForMarshaler bool + isNextOpPtrType bool + isMarshalerContext bool +} + +func (c *StructFieldCode) getStruct() *StructCode { + value := c.value + ptr, ok := value.(*PtrCode) + if ok { + value = ptr.value + } + structCode, ok := value.(*StructCode) + if ok { + return structCode + } + return nil +} + +func (c *StructFieldCode) getAnonymousStruct() *StructCode { + if !c.isAnonymous { + return nil + } + return c.getStruct() +} + +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 (c *StructFieldCode) headerOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes { + value := valueCodes.First() + op := optimizeStructHeader(value, c.tag) + field.Op = op + if value.Flags&MarshalerContextFlags != 0 { + field.Flags |= MarshalerContextFlags + } + field.NumBitSize = value.NumBitSize + field.PtrNum = value.PtrNum + field.FieldQuery = value.FieldQuery + fieldCodes := Opcodes{field} + if op.IsMultipleOpHead() { + field.Next = value + fieldCodes = fieldCodes.Add(valueCodes...) + } else { + ctx.decIndex() + } + return fieldCodes +} + +func (c *StructFieldCode) fieldOpcodes(ctx *compileContext, field *Opcode, valueCodes Opcodes) Opcodes { + value := valueCodes.First() + op := optimizeStructField(value, c.tag) + field.Op = op + if value.Flags&MarshalerContextFlags != 0 { + field.Flags |= MarshalerContextFlags + } + field.NumBitSize = value.NumBitSize + field.PtrNum = value.PtrNum + field.FieldQuery = value.FieldQuery + + fieldCodes := Opcodes{field} + if op.IsMultipleOpField() { + field.Next = value + fieldCodes = fieldCodes.Add(valueCodes...) + } else { + ctx.decIndex() + } + return fieldCodes +} + +func (c *StructFieldCode) addStructEndCode(ctx *compileContext, codes Opcodes) Opcodes { + end := &Opcode{ + Op: OpStructEnd, + Idx: opcodeOffset(ctx.ptrIndex), + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } + codes.Last().Next = end + code := codes.First() + for code.Op == OpStructField || code.Op == OpStructHead { + code = code.Next + } + for code.NextField != nil { + code = code.NextField + } + code.NextField = end + + codes = codes.Add(end) + ctx.incOpcodeIndex() + return codes +} + +func (c *StructFieldCode) structKey(ctx *compileContext) string { + if ctx.escapeKey { + rctx := &RuntimeContext{Option: &Option{Flag: HTMLEscapeOption}} + return fmt.Sprintf(`%s:`, string(AppendString(rctx, []byte{}, c.key))) + } + return fmt.Sprintf(`"%s":`, c.key) +} + +func (c *StructFieldCode) flags() OpFlags { + var flags OpFlags + if c.isTaggedKey { + flags |= IsTaggedKeyFlags + } + if c.isNilableType { + flags |= IsNilableTypeFlags + } + if c.isNilCheck { + flags |= NilCheckFlags + } + if c.isAddrForMarshaler { + flags |= AddrForMarshalerFlags + } + if c.isNextOpPtrType { + flags |= IsNextOpPtrTypeFlags + } + if c.isAnonymous { + flags |= AnonymousKeyFlags + } + if c.isMarshalerContext { + flags |= MarshalerContextFlags + } + return flags +} + +func (c *StructFieldCode) toValueOpcodes(ctx *compileContext) Opcodes { + if c.isAnonymous { + anonymCode, ok := c.value.(AnonymousCode) + if ok { + return anonymCode.ToAnonymousOpcode(ctx) + } + } + return c.value.ToOpcode(ctx) +} + +func (c *StructFieldCode) ToOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes { + field := &Opcode{ + Idx: opcodeOffset(ctx.ptrIndex), + Flags: c.flags(), + Key: c.structKey(ctx), + Offset: uint32(c.offset), + Type: c.typ, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + DisplayKey: c.key, + } + ctx.incIndex() + valueCodes := c.toValueOpcodes(ctx) + if isFirstField { + codes := c.headerOpcodes(ctx, field, valueCodes) + if isEndField { + codes = c.addStructEndCode(ctx, codes) + } + return codes + } + codes := c.fieldOpcodes(ctx, field, valueCodes) + if isEndField { + if isEnableStructEndOptimization(c.value) { + field.Op = field.Op.FieldToEnd() + } else { + codes = c.addStructEndCode(ctx, codes) + } + } + return codes +} + +func (c *StructFieldCode) ToAnonymousOpcode(ctx *compileContext, isFirstField, isEndField bool) Opcodes { + field := &Opcode{ + Idx: opcodeOffset(ctx.ptrIndex), + Flags: c.flags() | AnonymousHeadFlags, + Key: c.structKey(ctx), + Offset: uint32(c.offset), + Type: c.typ, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + DisplayKey: c.key, + } + ctx.incIndex() + valueCodes := c.toValueOpcodes(ctx) + if isFirstField { + return c.headerOpcodes(ctx, field, valueCodes) + } + return c.fieldOpcodes(ctx, field, valueCodes) +} + +func isEnableStructEndOptimization(value Code) bool { + switch value.Kind() { + case CodeKindInt, + CodeKindUint, + CodeKindFloat, + CodeKindString, + CodeKindBool, + CodeKindBytes: + return true + case CodeKindPtr: + return isEnableStructEndOptimization(value.(*PtrCode).value) + default: + return false + } +} + +type InterfaceCode struct { + typ *runtime.Type + fieldQuery *FieldQuery + isPtr bool +} + +func (c *InterfaceCode) Kind() CodeKind { + return CodeKindInterface +} + +func (c *InterfaceCode) ToOpcode(ctx *compileContext) Opcodes { + var code *Opcode + switch { + case c.isPtr: + code = newOpCode(ctx, c.typ, OpInterfacePtr) + default: + code = newOpCode(ctx, c.typ, OpInterface) + } + code.FieldQuery = c.fieldQuery + if c.typ.NumMethod() > 0 { + code.Flags |= NonEmptyInterfaceFlags + } + ctx.incIndex() + return Opcodes{code} +} + +func (c *InterfaceCode) Filter(query *FieldQuery) Code { + return &InterfaceCode{ + typ: c.typ, + fieldQuery: query, + isPtr: c.isPtr, + } +} + +type MarshalJSONCode struct { + typ *runtime.Type + fieldQuery *FieldQuery + isAddrForMarshaler bool + isNilableType bool + isMarshalerContext bool +} + +func (c *MarshalJSONCode) Kind() CodeKind { + return CodeKindMarshalJSON +} + +func (c *MarshalJSONCode) ToOpcode(ctx *compileContext) Opcodes { + code := newOpCode(ctx, c.typ, OpMarshalJSON) + code.FieldQuery = c.fieldQuery + if c.isAddrForMarshaler { + code.Flags |= AddrForMarshalerFlags + } + if c.isMarshalerContext { + code.Flags |= MarshalerContextFlags + } + if c.isNilableType { + code.Flags |= IsNilableTypeFlags + } else { + code.Flags &= ^IsNilableTypeFlags + } + ctx.incIndex() + return Opcodes{code} +} + +func (c *MarshalJSONCode) Filter(query *FieldQuery) Code { + return &MarshalJSONCode{ + typ: c.typ, + fieldQuery: query, + isAddrForMarshaler: c.isAddrForMarshaler, + isNilableType: c.isNilableType, + isMarshalerContext: c.isMarshalerContext, + } +} + +type MarshalTextCode struct { + typ *runtime.Type + fieldQuery *FieldQuery + isAddrForMarshaler bool + isNilableType bool +} + +func (c *MarshalTextCode) Kind() CodeKind { + return CodeKindMarshalText +} + +func (c *MarshalTextCode) ToOpcode(ctx *compileContext) Opcodes { + code := newOpCode(ctx, c.typ, OpMarshalText) + code.FieldQuery = c.fieldQuery + if c.isAddrForMarshaler { + code.Flags |= AddrForMarshalerFlags + } + if c.isNilableType { + code.Flags |= IsNilableTypeFlags + } else { + code.Flags &= ^IsNilableTypeFlags + } + ctx.incIndex() + return Opcodes{code} +} + +func (c *MarshalTextCode) Filter(query *FieldQuery) Code { + return &MarshalTextCode{ + typ: c.typ, + fieldQuery: query, + isAddrForMarshaler: c.isAddrForMarshaler, + isNilableType: c.isNilableType, + } +} + +type PtrCode struct { + typ *runtime.Type + value Code + ptrNum uint8 +} + +func (c *PtrCode) Kind() CodeKind { + return CodeKindPtr +} + +func (c *PtrCode) ToOpcode(ctx *compileContext) Opcodes { + codes := c.value.ToOpcode(ctx) + codes.First().Op = convertPtrOp(codes.First()) + codes.First().PtrNum = c.ptrNum + return codes +} + +func (c *PtrCode) ToAnonymousOpcode(ctx *compileContext) Opcodes { + var codes Opcodes + anonymCode, ok := c.value.(AnonymousCode) + if ok { + codes = anonymCode.ToAnonymousOpcode(ctx) + } else { + codes = c.value.ToOpcode(ctx) + } + codes.First().Op = convertPtrOp(codes.First()) + codes.First().PtrNum = c.ptrNum + return codes +} + +func (c *PtrCode) Filter(query *FieldQuery) Code { + return &PtrCode{ + typ: c.typ, + value: c.value.Filter(query), + ptrNum: c.ptrNum, + } +} + +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 isEmbeddedStruct(field *StructFieldCode) bool { + if !field.isAnonymous { + return false + } + t := field.typ + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t.Kind() == reflect.Struct +} 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 0000000..e287a6c --- /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]) + start = cursor + 3 + cursor += 2 + } + } + 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 0000000..b107636 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/compiler.go @@ -0,0 +1,939 @@ +package encoder + +import ( + "context" + "encoding" + "encoding/json" + "reflect" + "sync" + "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 + initEncoderOnce sync.Once +) + +func initEncoder() { + initEncoderOnce.Do(func() { + typeAddr = runtime.AnalyzeTypeAddr() + if typeAddr == nil { + typeAddr = &runtime.TypeAddr{} + } + cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1) + }) +} + +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 + } + codeSet, err := newCompiler().compile(typeptr) + if err != nil { + return nil, err + } + storeOpcodeSet(typeptr, codeSet, opcodeMap) + return codeSet, nil +} + +func getFilteredCodeSetIfNeeded(ctx *RuntimeContext, codeSet *OpcodeSet) (*OpcodeSet, error) { + if (ctx.Option.Flag & ContextOption) == 0 { + return codeSet, nil + } + query := FieldQueryFromContext(ctx.Option.Context) + if query == nil { + return codeSet, nil + } + ctx.Option.Flag |= FieldQueryOption + cacheCodeSet := codeSet.getQueryCache(query.Hash()) + if cacheCodeSet != nil { + return cacheCodeSet, nil + } + queryCodeSet, err := newCompiler().codeToOpcodeSet(codeSet.Type, codeSet.Code.Filter(query)) + if err != nil { + return nil, err + } + codeSet.setQueryCache(query.Hash(), queryCodeSet) + return queryCodeSet, nil +} + +type Compiler struct { + structTypeToCode map[uintptr]*StructCode +} + +func newCompiler() *Compiler { + return &Compiler{ + structTypeToCode: map[uintptr]*StructCode{}, + } +} + +func (c *Compiler) compile(typeptr uintptr) (*OpcodeSet, error) { + // noescape trick for header.typ ( reflect.*rtype ) + typ := *(**runtime.Type)(unsafe.Pointer(&typeptr)) + code, err := c.typeToCode(typ) + if err != nil { + return nil, err + } + return c.codeToOpcodeSet(typ, code) +} + +func (c *Compiler) codeToOpcodeSet(typ *runtime.Type, code Code) (*OpcodeSet, error) { + noescapeKeyCode := c.codeToOpcode(&compileContext{ + structTypeToCodes: map[uintptr]Opcodes{}, + recursiveCodes: &Opcodes{}, + }, typ, code) + if err := noescapeKeyCode.Validate(); err != nil { + return nil, err + } + escapeKeyCode := c.codeToOpcode(&compileContext{ + structTypeToCodes: map[uintptr]Opcodes{}, + recursiveCodes: &Opcodes{}, + escapeKey: true, + }, typ, code) + noescapeKeyCode = copyOpcode(noescapeKeyCode) + escapeKeyCode = copyOpcode(escapeKeyCode) + setTotalLengthToInterfaceOp(noescapeKeyCode) + setTotalLengthToInterfaceOp(escapeKeyCode) + interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode) + interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode) + codeLength := noescapeKeyCode.TotalLength() + return &OpcodeSet{ + Type: typ, + NoescapeKeyCode: noescapeKeyCode, + EscapeKeyCode: escapeKeyCode, + InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode, + InterfaceEscapeKeyCode: interfaceEscapeKeyCode, + CodeLength: codeLength, + EndCode: ToEndCode(interfaceNoescapeKeyCode), + Code: code, + QueryCache: map[string]*OpcodeSet{}, + }, nil +} + +func (c *Compiler) typeToCode(typ *runtime.Type) (Code, error) { + switch { + case c.implementsMarshalJSON(typ): + return c.marshalJSONCode(typ) + case c.implementsMarshalText(typ): + return c.marshalTextCode(typ) + } + + isPtr := false + orgType := typ + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + isPtr = true + } + switch { + case c.implementsMarshalJSON(typ): + return c.marshalJSONCode(orgType) + case c.implementsMarshalText(typ): + return c.marshalTextCode(orgType) + } + switch typ.Kind() { + case reflect.Slice: + elem := typ.Elem() + if elem.Kind() == reflect.Uint8 { + p := runtime.PtrTo(elem) + if !c.implementsMarshalJSONType(p) && !p.Implements(marshalTextType) { + return c.bytesCode(typ, isPtr) + } + } + return c.sliceCode(typ) + case reflect.Map: + if isPtr { + return c.ptrCode(runtime.PtrTo(typ)) + } + return c.mapCode(typ) + case reflect.Struct: + return c.structCode(typ, isPtr) + case reflect.Int: + return c.intCode(typ, isPtr) + case reflect.Int8: + return c.int8Code(typ, isPtr) + case reflect.Int16: + return c.int16Code(typ, isPtr) + case reflect.Int32: + return c.int32Code(typ, isPtr) + case reflect.Int64: + return c.int64Code(typ, isPtr) + case reflect.Uint, reflect.Uintptr: + return c.uintCode(typ, isPtr) + case reflect.Uint8: + return c.uint8Code(typ, isPtr) + case reflect.Uint16: + return c.uint16Code(typ, isPtr) + case reflect.Uint32: + return c.uint32Code(typ, isPtr) + case reflect.Uint64: + return c.uint64Code(typ, isPtr) + case reflect.Float32: + return c.float32Code(typ, isPtr) + case reflect.Float64: + return c.float64Code(typ, isPtr) + case reflect.String: + return c.stringCode(typ, isPtr) + case reflect.Bool: + return c.boolCode(typ, isPtr) + case reflect.Interface: + return c.interfaceCode(typ, isPtr) + default: + if isPtr && typ.Implements(marshalTextType) { + typ = orgType + } + return c.typeToCodeWithPtr(typ, isPtr) + } +} + +func (c *Compiler) typeToCodeWithPtr(typ *runtime.Type, isPtr bool) (Code, error) { + switch { + case c.implementsMarshalJSON(typ): + return c.marshalJSONCode(typ) + case c.implementsMarshalText(typ): + return c.marshalTextCode(typ) + } + switch typ.Kind() { + case reflect.Ptr: + return c.ptrCode(typ) + case reflect.Slice: + elem := typ.Elem() + if elem.Kind() == reflect.Uint8 { + p := runtime.PtrTo(elem) + if !c.implementsMarshalJSONType(p) && !p.Implements(marshalTextType) { + return c.bytesCode(typ, false) + } + } + return c.sliceCode(typ) + case reflect.Array: + return c.arrayCode(typ) + case reflect.Map: + return c.mapCode(typ) + case reflect.Struct: + return c.structCode(typ, isPtr) + case reflect.Interface: + return c.interfaceCode(typ, false) + case reflect.Int: + return c.intCode(typ, false) + case reflect.Int8: + return c.int8Code(typ, false) + case reflect.Int16: + return c.int16Code(typ, false) + case reflect.Int32: + return c.int32Code(typ, false) + case reflect.Int64: + return c.int64Code(typ, false) + case reflect.Uint: + return c.uintCode(typ, false) + case reflect.Uint8: + return c.uint8Code(typ, false) + case reflect.Uint16: + return c.uint16Code(typ, false) + case reflect.Uint32: + return c.uint32Code(typ, false) + case reflect.Uint64: + return c.uint64Code(typ, false) + case reflect.Uintptr: + return c.uintCode(typ, false) + case reflect.Float32: + return c.float32Code(typ, false) + case reflect.Float64: + return c.float64Code(typ, false) + case reflect.String: + return c.stringCode(typ, false) + case reflect.Bool: + return c.boolCode(typ, false) + } + return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)} +} + +const intSize = 32 << (^uint(0) >> 63) + +//nolint:unparam +func (c *Compiler) intCode(typ *runtime.Type, isPtr bool) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: intSize, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) int8Code(typ *runtime.Type, isPtr bool) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: 8, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) int16Code(typ *runtime.Type, isPtr bool) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: 16, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) int32Code(typ *runtime.Type, isPtr bool) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: 32, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) int64Code(typ *runtime.Type, isPtr bool) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: 64, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) uintCode(typ *runtime.Type, isPtr bool) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: intSize, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) uint8Code(typ *runtime.Type, isPtr bool) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: 8, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) uint16Code(typ *runtime.Type, isPtr bool) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: 16, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) uint32Code(typ *runtime.Type, isPtr bool) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: 32, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) uint64Code(typ *runtime.Type, isPtr bool) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: 64, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) float32Code(typ *runtime.Type, isPtr bool) (*FloatCode, error) { + return &FloatCode{typ: typ, bitSize: 32, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) float64Code(typ *runtime.Type, isPtr bool) (*FloatCode, error) { + return &FloatCode{typ: typ, bitSize: 64, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) stringCode(typ *runtime.Type, isPtr bool) (*StringCode, error) { + return &StringCode{typ: typ, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) boolCode(typ *runtime.Type, isPtr bool) (*BoolCode, error) { + return &BoolCode{typ: typ, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) intStringCode(typ *runtime.Type) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: intSize, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) int8StringCode(typ *runtime.Type) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: 8, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) int16StringCode(typ *runtime.Type) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: 16, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) int32StringCode(typ *runtime.Type) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: 32, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) int64StringCode(typ *runtime.Type) (*IntCode, error) { + return &IntCode{typ: typ, bitSize: 64, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) uintStringCode(typ *runtime.Type) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: intSize, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) uint8StringCode(typ *runtime.Type) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: 8, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) uint16StringCode(typ *runtime.Type) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: 16, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) uint32StringCode(typ *runtime.Type) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: 32, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) uint64StringCode(typ *runtime.Type) (*UintCode, error) { + return &UintCode{typ: typ, bitSize: 64, isString: true}, nil +} + +//nolint:unparam +func (c *Compiler) bytesCode(typ *runtime.Type, isPtr bool) (*BytesCode, error) { + return &BytesCode{typ: typ, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) interfaceCode(typ *runtime.Type, isPtr bool) (*InterfaceCode, error) { + return &InterfaceCode{typ: typ, isPtr: isPtr}, nil +} + +//nolint:unparam +func (c *Compiler) marshalJSONCode(typ *runtime.Type) (*MarshalJSONCode, error) { + return &MarshalJSONCode{ + typ: typ, + isAddrForMarshaler: c.isPtrMarshalJSONType(typ), + isNilableType: c.isNilableType(typ), + isMarshalerContext: typ.Implements(marshalJSONContextType) || runtime.PtrTo(typ).Implements(marshalJSONContextType), + }, nil +} + +//nolint:unparam +func (c *Compiler) marshalTextCode(typ *runtime.Type) (*MarshalTextCode, error) { + return &MarshalTextCode{ + typ: typ, + isAddrForMarshaler: c.isPtrMarshalTextType(typ), + isNilableType: c.isNilableType(typ), + }, nil +} + +func (c *Compiler) ptrCode(typ *runtime.Type) (*PtrCode, error) { + code, err := c.typeToCodeWithPtr(typ.Elem(), true) + if err != nil { + return nil, err + } + ptr, ok := code.(*PtrCode) + if ok { + return &PtrCode{typ: typ, value: ptr.value, ptrNum: ptr.ptrNum + 1}, nil + } + return &PtrCode{typ: typ, value: code, ptrNum: 1}, nil +} + +func (c *Compiler) sliceCode(typ *runtime.Type) (*SliceCode, error) { + elem := typ.Elem() + code, err := c.listElemCode(elem) + if err != nil { + return nil, err + } + if code.Kind() == CodeKindStruct { + structCode := code.(*StructCode) + structCode.enableIndirect() + } + return &SliceCode{typ: typ, value: code}, nil +} + +func (c *Compiler) arrayCode(typ *runtime.Type) (*ArrayCode, error) { + elem := typ.Elem() + code, err := c.listElemCode(elem) + if err != nil { + return nil, err + } + if code.Kind() == CodeKindStruct { + structCode := code.(*StructCode) + structCode.enableIndirect() + } + return &ArrayCode{typ: typ, value: code}, nil +} + +func (c *Compiler) mapCode(typ *runtime.Type) (*MapCode, error) { + keyCode, err := c.mapKeyCode(typ.Key()) + if err != nil { + return nil, err + } + valueCode, err := c.mapValueCode(typ.Elem()) + if err != nil { + return nil, err + } + if valueCode.Kind() == CodeKindStruct { + structCode := valueCode.(*StructCode) + structCode.enableIndirect() + } + return &MapCode{typ: typ, key: keyCode, value: valueCode}, nil +} + +func (c *Compiler) listElemCode(typ *runtime.Type) (Code, error) { + switch { + case c.implementsMarshalJSONType(typ) || c.implementsMarshalJSONType(runtime.PtrTo(typ)): + return c.marshalJSONCode(typ) + case !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType): + return c.marshalTextCode(typ) + case typ.Kind() == reflect.Map: + return c.ptrCode(runtime.PtrTo(typ)) + default: + // isPtr was originally used to indicate whether the type of top level is pointer. + // However, since the slice/array element is a specification that can get the pointer address, explicitly set isPtr to true. + // See here for related issues: https://github.com/goccy/go-json/issues/370 + code, err := c.typeToCodeWithPtr(typ, true) + if err != nil { + return nil, err + } + ptr, ok := code.(*PtrCode) + if ok { + if ptr.value.Kind() == CodeKindMap { + ptr.ptrNum++ + } + } + return code, nil + } +} + +func (c *Compiler) mapKeyCode(typ *runtime.Type) (Code, error) { + switch { + case c.implementsMarshalText(typ): + return c.marshalTextCode(typ) + } + switch typ.Kind() { + case reflect.Ptr: + return c.ptrCode(typ) + case reflect.String: + return c.stringCode(typ, false) + case reflect.Int: + return c.intStringCode(typ) + case reflect.Int8: + return c.int8StringCode(typ) + case reflect.Int16: + return c.int16StringCode(typ) + case reflect.Int32: + return c.int32StringCode(typ) + case reflect.Int64: + return c.int64StringCode(typ) + case reflect.Uint: + return c.uintStringCode(typ) + case reflect.Uint8: + return c.uint8StringCode(typ) + case reflect.Uint16: + return c.uint16StringCode(typ) + case reflect.Uint32: + return c.uint32StringCode(typ) + case reflect.Uint64: + return c.uint64StringCode(typ) + case reflect.Uintptr: + return c.uintStringCode(typ) + } + return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)} +} + +func (c *Compiler) mapValueCode(typ *runtime.Type) (Code, error) { + switch typ.Kind() { + case reflect.Map: + return c.ptrCode(runtime.PtrTo(typ)) + default: + code, err := c.typeToCodeWithPtr(typ, false) + if err != nil { + return nil, err + } + ptr, ok := code.(*PtrCode) + if ok { + if ptr.value.Kind() == CodeKindMap { + ptr.ptrNum++ + } + } + return code, nil + } +} + +func (c *Compiler) structCode(typ *runtime.Type, isPtr bool) (*StructCode, error) { + typeptr := uintptr(unsafe.Pointer(typ)) + if code, exists := c.structTypeToCode[typeptr]; exists { + derefCode := *code + derefCode.isRecursive = true + return &derefCode, nil + } + indirect := runtime.IfaceIndir(typ) + code := &StructCode{typ: typ, isPtr: isPtr, isIndirect: indirect} + c.structTypeToCode[typeptr] = code + + fieldNum := typ.NumField() + tags := c.typeToStructTags(typ) + fields := []*StructFieldCode{} + for i, tag := range tags { + isOnlyOneFirstField := i == 0 && fieldNum == 1 + field, err := c.structFieldCode(code, tag, isPtr, isOnlyOneFirstField) + if err != nil { + return nil, err + } + if field.isAnonymous { + structCode := field.getAnonymousStruct() + if structCode != nil { + structCode.removeFieldsByTags(tags) + if c.isAssignableIndirect(field, isPtr) { + if indirect { + structCode.isIndirect = true + } else { + structCode.isIndirect = false + } + } + } + } else { + structCode := field.getStruct() + if structCode != nil { + if indirect { + // if parent is indirect type, set child indirect property to true + structCode.isIndirect = true + } 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. + structCode.isIndirect = false + } + } + } + fields = append(fields, field) + } + fieldMap := c.getFieldMap(fields) + duplicatedFieldMap := c.getDuplicatedFieldMap(fieldMap) + code.fields = c.filteredDuplicatedFields(fields, duplicatedFieldMap) + if !code.disableIndirectConversion && !indirect && isPtr { + code.enableIndirect() + } + delete(c.structTypeToCode, typeptr) + return code, nil +} + +func toElemType(t *runtime.Type) *runtime.Type { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + return t +} + +func (c *Compiler) structFieldCode(structCode *StructCode, tag *runtime.StructTag, isPtr, isOnlyOneFirstField bool) (*StructFieldCode, error) { + field := tag.Field + fieldType := runtime.Type2RType(field.Type) + isIndirectSpecialCase := isPtr && isOnlyOneFirstField + fieldCode := &StructFieldCode{ + typ: fieldType, + key: tag.Key, + tag: tag, + offset: field.Offset, + isAnonymous: field.Anonymous && !tag.IsTaggedKey && toElemType(fieldType).Kind() == reflect.Struct, + isTaggedKey: tag.IsTaggedKey, + isNilableType: c.isNilableType(fieldType), + isNilCheck: true, + } + switch { + case c.isMovePointerPositionFromHeadToFirstMarshalJSONFieldCase(fieldType, isIndirectSpecialCase): + code, err := c.marshalJSONCode(fieldType) + if err != nil { + return nil, err + } + fieldCode.value = code + fieldCode.isAddrForMarshaler = true + fieldCode.isNilCheck = false + structCode.isIndirect = false + structCode.disableIndirectConversion = true + case c.isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(fieldType, isIndirectSpecialCase): + code, err := c.marshalTextCode(fieldType) + if err != nil { + return nil, err + } + fieldCode.value = code + fieldCode.isAddrForMarshaler = true + fieldCode.isNilCheck = false + structCode.isIndirect = false + structCode.disableIndirectConversion = true + case isPtr && c.isPtrMarshalJSONType(fieldType): + // *struct{ field T } + // func (*T) MarshalJSON() ([]byte, error) + code, err := c.marshalJSONCode(fieldType) + if err != nil { + return nil, err + } + fieldCode.value = code + fieldCode.isAddrForMarshaler = true + fieldCode.isNilCheck = false + case isPtr && c.isPtrMarshalTextType(fieldType): + // *struct{ field T } + // func (*T) MarshalText() ([]byte, error) + code, err := c.marshalTextCode(fieldType) + if err != nil { + return nil, err + } + fieldCode.value = code + fieldCode.isAddrForMarshaler = true + fieldCode.isNilCheck = false + default: + code, err := c.typeToCodeWithPtr(fieldType, isPtr) + if err != nil { + return nil, err + } + switch code.Kind() { + case CodeKindPtr, CodeKindInterface: + fieldCode.isNextOpPtrType = true + } + fieldCode.value = code + } + return fieldCode, nil +} + +func (c *Compiler) isAssignableIndirect(fieldCode *StructFieldCode, isPtr bool) bool { + if isPtr { + return false + } + codeType := fieldCode.value.Kind() + if codeType == CodeKindMarshalJSON { + return false + } + if codeType == CodeKindMarshalText { + return false + } + return true +} + +func (c *Compiler) getFieldMap(fields []*StructFieldCode) map[string][]*StructFieldCode { + fieldMap := map[string][]*StructFieldCode{} + for _, field := range fields { + if field.isAnonymous { + for k, v := range c.getAnonymousFieldMap(field) { + fieldMap[k] = append(fieldMap[k], v...) + } + continue + } + fieldMap[field.key] = append(fieldMap[field.key], field) + } + return fieldMap +} + +func (c *Compiler) getAnonymousFieldMap(field *StructFieldCode) map[string][]*StructFieldCode { + fieldMap := map[string][]*StructFieldCode{} + structCode := field.getAnonymousStruct() + if structCode == nil || structCode.isRecursive { + fieldMap[field.key] = append(fieldMap[field.key], field) + return fieldMap + } + for k, v := range c.getFieldMapFromAnonymousParent(structCode.fields) { + fieldMap[k] = append(fieldMap[k], v...) + } + return fieldMap +} + +func (c *Compiler) getFieldMapFromAnonymousParent(fields []*StructFieldCode) map[string][]*StructFieldCode { + fieldMap := map[string][]*StructFieldCode{} + for _, field := range fields { + if field.isAnonymous { + for k, v := range c.getAnonymousFieldMap(field) { + // Do not handle tagged key when embedding more than once + for _, vv := range v { + vv.isTaggedKey = false + } + fieldMap[k] = append(fieldMap[k], v...) + } + continue + } + fieldMap[field.key] = append(fieldMap[field.key], field) + } + return fieldMap +} + +func (c *Compiler) getDuplicatedFieldMap(fieldMap map[string][]*StructFieldCode) map[*StructFieldCode]struct{} { + duplicatedFieldMap := map[*StructFieldCode]struct{}{} + for _, fields := range fieldMap { + if len(fields) == 1 { + continue + } + if c.isTaggedKeyOnly(fields) { + for _, field := range fields { + if field.isTaggedKey { + continue + } + duplicatedFieldMap[field] = struct{}{} + } + } else { + for _, field := range fields { + duplicatedFieldMap[field] = struct{}{} + } + } + } + return duplicatedFieldMap +} + +func (c *Compiler) filteredDuplicatedFields(fields []*StructFieldCode, duplicatedFieldMap map[*StructFieldCode]struct{}) []*StructFieldCode { + filteredFields := make([]*StructFieldCode, 0, len(fields)) + for _, field := range fields { + if field.isAnonymous { + structCode := field.getAnonymousStruct() + if structCode != nil && !structCode.isRecursive { + structCode.fields = c.filteredDuplicatedFields(structCode.fields, duplicatedFieldMap) + if len(structCode.fields) > 0 { + filteredFields = append(filteredFields, field) + } + continue + } + } + if _, exists := duplicatedFieldMap[field]; exists { + continue + } + filteredFields = append(filteredFields, field) + } + return filteredFields +} + +func (c *Compiler) isTaggedKeyOnly(fields []*StructFieldCode) bool { + var taggedKeyFieldCount int + for _, field := range fields { + if field.isTaggedKey { + taggedKeyFieldCount++ + } + } + return taggedKeyFieldCount == 1 +} + +func (c *Compiler) typeToStructTags(typ *runtime.Type) runtime.StructTags { + tags := runtime.StructTags{} + fieldNum := typ.NumField() + for i := 0; i < fieldNum; i++ { + field := typ.Field(i) + if runtime.IsIgnoredStructField(field) { + continue + } + tags = append(tags, runtime.StructTagFromField(field)) + } + return tags +} + +// *struct{ field T } => struct { field *T } +// func (*T) MarshalJSON() ([]byte, error) +func (c *Compiler) isMovePointerPositionFromHeadToFirstMarshalJSONFieldCase(typ *runtime.Type, isIndirectSpecialCase bool) bool { + return isIndirectSpecialCase && !c.isNilableType(typ) && c.isPtrMarshalJSONType(typ) +} + +// *struct{ field T } => struct { field *T } +// func (*T) MarshalText() ([]byte, error) +func (c *Compiler) isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(typ *runtime.Type, isIndirectSpecialCase bool) bool { + return isIndirectSpecialCase && !c.isNilableType(typ) && c.isPtrMarshalTextType(typ) +} + +func (c *Compiler) implementsMarshalJSON(typ *runtime.Type) bool { + if !c.implementsMarshalJSONType(typ) { + return false + } + if typ.Kind() != reflect.Ptr { + return true + } + // type kind is reflect.Ptr + if !c.implementsMarshalJSONType(typ.Elem()) { + return true + } + // needs to dereference + return false +} + +func (c *Compiler) 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 (c *Compiler) isNilableType(typ *runtime.Type) bool { + if !runtime.IfaceIndir(typ) { + return true + } + switch typ.Kind() { + case reflect.Ptr: + return true + case reflect.Map: + return true + case reflect.Func: + return true + default: + return false + } +} + +func (c *Compiler) implementsMarshalJSONType(typ *runtime.Type) bool { + return typ.Implements(marshalJSONType) || typ.Implements(marshalJSONContextType) +} + +func (c *Compiler) isPtrMarshalJSONType(typ *runtime.Type) bool { + return !c.implementsMarshalJSONType(typ) && c.implementsMarshalJSONType(runtime.PtrTo(typ)) +} + +func (c *Compiler) isPtrMarshalTextType(typ *runtime.Type) bool { + return !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType) +} + +func (c *Compiler) codeToOpcode(ctx *compileContext, typ *runtime.Type, code Code) *Opcode { + codes := code.ToOpcode(ctx) + codes.Last().Next = newEndOp(ctx, typ) + c.linkRecursiveCode(ctx) + return codes.First() +} + +func (c *Compiler) linkRecursiveCode(ctx *compileContext) { + recursiveCodes := map[uintptr]*CompiledCode{} + for _, recursive := range *ctx.recursiveCodes { + typeptr := uintptr(unsafe.Pointer(recursive.Type)) + codes := ctx.structTypeToCodes[typeptr] + if recursiveCode, ok := recursiveCodes[typeptr]; ok { + *recursive.Jmp = *recursiveCode + continue + } + + code := copyOpcode(codes.First()) + code.Op = code.Op.PtrHeadToHead() + lastCode := newEndOp(&compileContext{}, recursive.Type) + lastCode.Op = OpRecursiveEnd + + // OpRecursiveEnd must set before call TotalLength + code.End.Next = lastCode + + totalLength := code.TotalLength() + + // Idx, ElemIdx, Length must set after call TotalLength + lastCode.Idx = uint32((totalLength + 1) * uintptrSize) + lastCode.ElemIdx = lastCode.Idx + uintptrSize + lastCode.Length = lastCode.Idx + 2*uintptrSize + + // extend length to alloc slot for elemIdx + length + curTotalLength := uintptr(recursive.TotalLength()) + 3 + nextTotalLength := uintptr(totalLength) + 3 + + compiled := recursive.Jmp + compiled.Code = code + compiled.CurLen = curTotalLength + compiled.NextLen = nextTotalLength + compiled.Linked = true + + recursiveCodes[typeptr] = compiled + } +} 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 0000000..b6f45a4 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/compiler_norace.go @@ -0,0 +1,33 @@ +//go:build !race +// +build !race + +package encoder + +func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) { + initEncoder() + if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr { + codeSet, err := compileToGetCodeSetSlowPath(typeptr) + if err != nil { + return nil, err + } + return getFilteredCodeSetIfNeeded(ctx, codeSet) + } + index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift + if codeSet := cachedOpcodeSets[index]; codeSet != nil { + filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet) + if err != nil { + return nil, err + } + return filtered, nil + } + codeSet, err := newCompiler().compile(typeptr) + if err != nil { + return nil, err + } + filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet) + if err != nil { + return nil, err + } + cachedOpcodeSets[index] = codeSet + return filtered, 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 0000000..47b482f --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/compiler_race.go @@ -0,0 +1,46 @@ +//go:build race +// +build race + +package encoder + +import ( + "sync" +) + +var setsMu sync.RWMutex + +func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) { + initEncoder() + if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr { + codeSet, err := compileToGetCodeSetSlowPath(typeptr) + if err != nil { + return nil, err + } + return getFilteredCodeSetIfNeeded(ctx, codeSet) + } + index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift + setsMu.RLock() + if codeSet := cachedOpcodeSets[index]; codeSet != nil { + filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet) + if err != nil { + setsMu.RUnlock() + return nil, err + } + setsMu.RUnlock() + return filtered, nil + } + setsMu.RUnlock() + + codeSet, err := newCompiler().compile(typeptr) + if err != nil { + return nil, err + } + filtered, err := getFilteredCodeSetIfNeeded(ctx, codeSet) + if err != nil { + return nil, err + } + setsMu.Lock() + cachedOpcodeSets[index] = codeSet + setsMu.Unlock() + return filtered, 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 0000000..3833d0c --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/context.go @@ -0,0 +1,105 @@ +package encoder + +import ( + "context" + "sync" + "unsafe" + + "github.com/goccy/go-json/internal/runtime" +) + +type compileContext struct { + opcodeIndex uint32 + ptrIndex int + indent uint32 + escapeKey bool + structTypeToCodes map[uintptr]Opcodes + recursiveCodes *Opcodes +} + +func (c *compileContext) incIndent() { + c.indent++ +} + +func (c *compileContext) decIndent() { + c.indent-- +} + +func (c *compileContext) incIndex() { + c.incOpcodeIndex() + c.incPtrIndex() +} + +func (c *compileContext) decIndex() { + c.decOpcodeIndex() + c.decPtrIndex() +} + +func (c *compileContext) incOpcodeIndex() { + c.opcodeIndex++ +} + +func (c *compileContext) decOpcodeIndex() { + c.opcodeIndex-- +} + +func (c *compileContext) incPtrIndex() { + c.ptrIndex++ +} + +func (c *compileContext) decPtrIndex() { + c.ptrIndex-- +} + +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/decode_rune.go b/vendor/github.com/goccy/go-json/internal/encoder/decode_rune.go new file mode 100644 index 0000000..35c959d --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/decode_rune.go @@ -0,0 +1,126 @@ +package encoder + +import "unicode/utf8" + +const ( + // The default lowest and highest continuation byte. + locb = 128 //0b10000000 + hicb = 191 //0b10111111 + + // These names of these constants are chosen to give nice alignment in the + // table below. The first nibble is an index into acceptRanges or F for + // special one-byte cases. The second nibble is the Rune length or the + // Status for the special one-byte case. + xx = 0xF1 // invalid: size 1 + as = 0xF0 // ASCII: size 1 + s1 = 0x02 // accept 0, size 2 + s2 = 0x13 // accept 1, size 3 + s3 = 0x03 // accept 0, size 3 + s4 = 0x23 // accept 2, size 3 + s5 = 0x34 // accept 3, size 4 + s6 = 0x04 // accept 0, size 4 + s7 = 0x44 // accept 4, size 4 +) + +// first is information about the first byte in a UTF-8 sequence. +var first = [256]uint8{ + // 1 2 3 4 5 6 7 8 9 A B C D E F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F + as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F + // 1 2 3 4 5 6 7 8 9 A B C D E F + xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F + xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F + xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF + xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF + xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF + s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF + s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF + s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF +} + +const ( + lineSep = byte(168) //'\u2028' + paragraphSep = byte(169) //'\u2029' +) + +type decodeRuneState int + +const ( + validUTF8State decodeRuneState = iota + runeErrorState + lineSepState + paragraphSepState +) + +func decodeRuneInString(s string) (decodeRuneState, int) { + n := len(s) + s0 := s[0] + x := first[s0] + if x >= as { + // The following code simulates an additional check for x == xx and + // handling the ASCII and invalid cases accordingly. This mask-and-or + // approach prevents an additional branch. + mask := rune(x) << 31 >> 31 // Create 0x0000 or 0xFFFF. + if rune(s[0])&^mask|utf8.RuneError&mask == utf8.RuneError { + return runeErrorState, 1 + } + return validUTF8State, 1 + } + sz := int(x & 7) + if n < sz { + return runeErrorState, 1 + } + s1 := s[1] + switch x >> 4 { + case 0: + if s1 < locb || hicb < s1 { + return runeErrorState, 1 + } + case 1: + if s1 < 0xA0 || hicb < s1 { + return runeErrorState, 1 + } + case 2: + if s1 < locb || 0x9F < s1 { + return runeErrorState, 1 + } + case 3: + if s1 < 0x90 || hicb < s1 { + return runeErrorState, 1 + } + case 4: + if s1 < locb || 0x8F < s1 { + return runeErrorState, 1 + } + } + if sz <= 2 { + return validUTF8State, 2 + } + s2 := s[2] + if s2 < locb || hicb < s2 { + return runeErrorState, 1 + } + if sz <= 3 { + // separator character prefixes: [2]byte{226, 128} + if s0 == 226 && s1 == 128 { + switch s2 { + case lineSep: + return lineSepState, 3 + case paragraphSep: + return paragraphSepState, 3 + } + } + return validUTF8State, 3 + } + s3 := s[3] + if s3 < locb || hicb < s3 { + return runeErrorState, 1 + } + return validUTF8State, 4 +} 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 0000000..b436f5b --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/encoder.go @@ -0,0 +1,601 @@ +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 + Code Code + QueryCache map[string]*OpcodeSet + cacheMu sync.RWMutex +} + +func (s *OpcodeSet) getQueryCache(hash string) *OpcodeSet { + s.cacheMu.RLock() + codeSet := s.QueryCache[hash] + s.cacheMu.RUnlock() + return codeSet +} + +func (s *OpcodeSet) setQueryCache(hash string, codeSet *OpcodeSet) { + s.cacheMu.Lock() + s.QueryCache[hash] = codeSet + s.cacheMu.Unlock() +} + +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] +} + +//nolint:structcheck,unused +type mapIter struct { + key unsafe.Pointer + elem unsafe.Pointer + t unsafe.Pointer + h unsafe.Pointer + buckets unsafe.Pointer + bptr unsafe.Pointer + overflow unsafe.Pointer + oldoverflow unsafe.Pointer + startBucket uintptr + offset uint8 + wrapped bool + B uint8 + i uint8 + bucket uintptr + checkBucket uintptr +} + +type MapContext struct { + Start int + First int + Idx int + Slice *Mapslice + Buf []byte + Len int + Iter mapIter +} + +var mapContextPool = sync.Pool{ + New: func() interface{} { + return &MapContext{ + Slice: &Mapslice{}, + } + }, +} + +func NewMapContext(mapLen int, unorderedMap bool) *MapContext { + ctx := mapContextPool.Get().(*MapContext) + if !unorderedMap { + if len(ctx.Slice.Items) < mapLen { + ctx.Slice.Items = make([]MapItem, mapLen) + } else { + ctx.Slice.Items = ctx.Slice.Items[:mapLen] + } + } + ctx.Buf = ctx.Buf[:0] + ctx.Iter = mapIter{} + ctx.Idx = 0 + ctx.Len = mapLen + return ctx +} + +func ReleaseMapContext(c *MapContext) { + mapContextPool.Put(c) +} + +//go:linkname MapIterInit runtime.mapiterinit +//go:noescape +func MapIterInit(mapType *runtime.Type, m unsafe.Pointer, it *mapIter) + +//go:linkname MapIterKey reflect.mapiterkey +//go:noescape +func MapIterKey(it *mapIter) unsafe.Pointer + +//go:linkname MapIterNext reflect.mapiternext +//go:noescape +func MapIterNext(it *mapIter) + +//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 + } + } + + if rv.Kind() == reflect.Ptr && rv.IsNil() { + return AppendNull(ctx, b), nil + } + + v = rv.Interface() + var bb []byte + if (code.Flags & MarshalerContextFlags) != 0 { + marshaler, ok := v.(marshalerContext) + if !ok { + return AppendNull(ctx, b), nil + } + stdctx := ctx.Option.Context + if ctx.Option.Flag&FieldQueryOption != 0 { + stdctx = SetFieldQueryToContext(stdctx, code.FieldQuery) + } + b, err := marshaler.MarshalJSON(stdctx) + 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 + case reflect.String: + return 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 0000000..dfe04b5 --- /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 0000000..8b5febe --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/int.go @@ -0,0 +1,176 @@ +// This files's processing codes are inspired by https://github.com/segmentio/encoding. +// The license notation is as follows. +// +// # MIT License +// +// Copyright (c) 2019 Segment.io, Inc. +// +// 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 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, p uintptr, code *Opcode) []byte { + var u64 uint64 + switch code.NumBitSize { + case 8: + u64 = (uint64)(**(**uint8)(unsafe.Pointer(&p))) + case 16: + u64 = (uint64)(**(**uint16)(unsafe.Pointer(&p))) + case 32: + u64 = (uint64)(**(**uint32)(unsafe.Pointer(&p))) + case 64: + u64 = **(**uint64)(unsafe.Pointer(&p)) + } + 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 0000000..e96ffad --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/map112.go @@ -0,0 +1,9 @@ +//go:build !go1.13 +// +build !go1.13 + +package encoder + +import "unsafe" + +//go:linkname MapIterValue reflect.mapitervalue +func MapIterValue(it *mapIter) 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 0000000..9b69dcc --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/map113.go @@ -0,0 +1,9 @@ +//go:build go1.13 +// +build go1.13 + +package encoder + +import "unsafe" + +//go:linkname MapIterValue reflect.mapiterelem +func MapIterValue(it *mapIter) 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 0000000..df22f55 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/opcode.go @@ -0,0 +1,752 @@ +package encoder + +import ( + "bytes" + "fmt" + "sort" + "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 + NonEmptyInterfaceFlags OpFlags = 1 << 9 +) + +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 + Jmp *CompiledCode // for recursive call + FieldQuery *FieldQuery // field query for Interface / MarshalJSON / MarshalText + ElemIdx uint32 // offset to access array/slice elem + Length uint32 // offset to access slice length or array length + Indent uint32 // indent number + Size uint32 // array/slice elem size + DisplayIdx uint32 // opcode index + DisplayKey string // key text to display +} + +func (c *Opcode) Validate() error { + var prevIdx uint32 + for code := c; !code.IsEnd(); { + if prevIdx != 0 { + if code.DisplayIdx != prevIdx+1 { + return fmt.Errorf( + "invalid index. previous display index is %d but next is %d. dump = %s", + prevIdx, code.DisplayIdx, c.Dump(), + ) + } + } + prevIdx = code.DisplayIdx + code = code.IterNext() + } + return nil +} + +func (c *Opcode) IterNext() *Opcode { + if c == nil { + return nil + } + switch c.Op.CodeType() { + case CodeArrayElem, CodeSliceElem, CodeMapKey: + return c.End + default: + return c.Next + } +} + +func (c *Opcode) IsEnd() bool { + if c == nil { + return true + } + return c.Op == OpEnd || c.Op == OpInterfaceEnd || c.Op == OpRecursiveEnd +} + +func (c *Opcode) MaxIdx() uint32 { + max := uint32(0) + for _, value := range []uint32{ + c.Idx, + c.ElemIdx, + c.Length, + 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, typ *runtime.Type, op OpType) *Opcode { + return newOpCodeWithNext(ctx, typ, op, newEndOp(ctx, typ)) +} + +func opcodeOffset(idx int) uint32 { + return uint32(idx) * uintptrSize +} + +func getCodeAddrByIdx(head *Opcode, idx uint32) *Opcode { + addr := uintptr(unsafe.Pointer(head)) + uintptr(idx)*unsafe.Sizeof(Opcode{}) + return *(**Opcode)(unsafe.Pointer(&addr)) +} + +func copyOpcode(code *Opcode) *Opcode { + codeNum := ToEndCode(code).DisplayIdx + 1 + codeSlice := make([]Opcode, codeNum) + head := (*Opcode)((*runtime.SliceHeader)(unsafe.Pointer(&codeSlice)).Data) + ptr := head + c := code + for { + *ptr = 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, + FieldQuery: c.FieldQuery, + DisplayIdx: c.DisplayIdx, + DisplayKey: c.DisplayKey, + ElemIdx: c.ElemIdx, + Length: c.Length, + Size: c.Size, + Indent: c.Indent, + Jmp: c.Jmp, + } + if c.End != nil { + ptr.End = getCodeAddrByIdx(head, c.End.DisplayIdx) + } + if c.NextField != nil { + ptr.NextField = getCodeAddrByIdx(head, c.NextField.DisplayIdx) + } + if c.Next != nil { + ptr.Next = getCodeAddrByIdx(head, c.Next.DisplayIdx) + } + if c.IsEnd() { + break + } + ptr = getCodeAddrByIdx(head, c.DisplayIdx+1) + c = c.IterNext() + } + return head +} + +func setTotalLengthToInterfaceOp(code *Opcode) { + for c := code; !c.IsEnd(); { + if c.Op == OpInterface || c.Op == OpInterfacePtr { + c.Length = uint32(code.TotalLength()) + } + c = c.IterNext() + } +} + +func ToEndCode(code *Opcode) *Opcode { + c := code + for !c.IsEnd() { + c = c.IterNext() + } + 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, typ *runtime.Type, op OpType, next *Opcode) *Opcode { + return &Opcode{ + Op: op, + Idx: opcodeOffset(ctx.ptrIndex), + Next: next, + Type: typ, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } +} + +func newEndOp(ctx *compileContext, typ *runtime.Type) *Opcode { + return newOpCodeWithNext(ctx, typ, OpEnd, nil) +} + +func (c *Opcode) TotalLength() int { + var idx int + code := c + for !code.IsEnd() { + maxIdx := int(code.MaxIdx() / uintptrSize) + if idx < maxIdx { + idx = maxIdx + } + if code.Op == OpRecursiveEnd { + break + } + code = code.IterNext() + } + maxIdx := int(code.MaxIdx() / uintptrSize) + if idx < maxIdx { + idx = maxIdx + } + return idx + 1 +} + +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( + `[%03d]%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( + `[%03d]%s%s ([idx:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + ) +} + +func (c *Opcode) dumpMapEnd(code *Opcode) string { + return fmt.Sprintf( + `[%03d]%s%s ([idx:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/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( + `[%03d]%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( + `[%03d]%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( + `[%03d]%s%s ([idx:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + ) +} + +func (c *Opcode) dumpValue(code *Opcode) string { + return fmt.Sprintf( + `[%03d]%s%s ([idx:%d])`, + code.DisplayIdx, + strings.Repeat("-", int(code.Indent)), + code.Op, + code.Idx/uintptrSize, + ) +} + +func (c *Opcode) Dump() string { + codes := []string{} + for code := c; !code.IsEnd(); { + 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( + "[%03d]%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 (c *Opcode) DumpDOT() string { + type edge struct { + from, to *Opcode + label string + weight int + } + var edges []edge + + b := &bytes.Buffer{} + fmt.Fprintf(b, "digraph \"%p\" {\n", c.Type) + fmt.Fprintln(b, "mclimit=1.5;\nrankdir=TD;\nordering=out;\nnode[shape=box];") + for code := c; !code.IsEnd(); { + label := code.Op.String() + fmt.Fprintf(b, "\"%p\" [label=%q];\n", code, label) + if p := code.Next; p != nil { + edges = append(edges, edge{ + from: code, + to: p, + label: "Next", + weight: 10, + }) + } + if p := code.NextField; p != nil { + edges = append(edges, edge{ + from: code, + to: p, + label: "NextField", + weight: 2, + }) + } + if p := code.End; p != nil { + edges = append(edges, edge{ + from: code, + to: p, + label: "End", + weight: 1, + }) + } + if p := code.Jmp; p != nil { + edges = append(edges, edge{ + from: code, + to: p.Code, + label: "Jmp", + weight: 1, + }) + } + + switch code.Op.CodeType() { + case CodeSliceHead: + code = code.Next + case CodeMapHead: + code = code.Next + case CodeArrayElem, CodeSliceElem: + code = code.End + case CodeMapKey: + code = code.End + case CodeMapValue: + code = code.Next + case CodeMapEnd: + code = code.Next + case CodeStructField: + code = code.Next + case CodeStructEnd: + code = code.Next + default: + code = code.Next + } + if code.IsEnd() { + fmt.Fprintf(b, "\"%p\" [label=%q];\n", code, code.Op.String()) + } + } + sort.Slice(edges, func(i, j int) bool { + return edges[i].to.DisplayIdx < edges[j].to.DisplayIdx + }) + for _, e := range edges { + fmt.Fprintf(b, "\"%p\" -> \"%p\" [label=%q][weight=%d];\n", e.from, e.to, e.label, e.weight) + } + fmt.Fprint(b, "}") + return b.String() +} + +func newSliceHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode { + idx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + elemIdx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + length := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpSlice, + Type: typ, + Idx: idx, + DisplayIdx: ctx.opcodeIndex, + ElemIdx: elemIdx, + Length: length, + Indent: ctx.indent, + } +} + +func newSliceElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, size uintptr) *Opcode { + return &Opcode{ + Op: OpSliceElem, + Type: typ, + Idx: head.Idx, + DisplayIdx: ctx.opcodeIndex, + ElemIdx: head.ElemIdx, + Length: head.Length, + Indent: ctx.indent, + Size: uint32(size), + } +} + +func newArrayHeaderCode(ctx *compileContext, typ *runtime.Type, alen int) *Opcode { + idx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + elemIdx := opcodeOffset(ctx.ptrIndex) + return &Opcode{ + Op: OpArray, + Type: typ, + Idx: idx, + DisplayIdx: ctx.opcodeIndex, + ElemIdx: elemIdx, + Indent: ctx.indent, + Length: uint32(alen), + } +} + +func newArrayElemCode(ctx *compileContext, typ *runtime.Type, head *Opcode, length int, size uintptr) *Opcode { + return &Opcode{ + Op: OpArrayElem, + Type: typ, + Idx: head.Idx, + DisplayIdx: ctx.opcodeIndex, + ElemIdx: head.ElemIdx, + Length: uint32(length), + Indent: ctx.indent, + Size: uint32(size), + } +} + +func newMapHeaderCode(ctx *compileContext, typ *runtime.Type) *Opcode { + idx := opcodeOffset(ctx.ptrIndex) + ctx.incPtrIndex() + return &Opcode{ + Op: OpMap, + Type: typ, + Idx: idx, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } +} + +func newMapKeyCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode { + return &Opcode{ + Op: OpMapKey, + Type: typ, + Idx: head.Idx, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } +} + +func newMapValueCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode { + return &Opcode{ + Op: OpMapValue, + Type: typ, + Idx: head.Idx, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + } +} + +func newMapEndCode(ctx *compileContext, typ *runtime.Type, head *Opcode) *Opcode { + return &Opcode{ + Op: OpMapEnd, + Type: typ, + Idx: head.Idx, + DisplayIdx: ctx.opcodeIndex, + Indent: ctx.indent, + Next: newEndOp(ctx, typ), + } +} + +func newRecursiveCode(ctx *compileContext, typ *runtime.Type, jmp *CompiledCode) *Opcode { + return &Opcode{ + Op: OpRecursive, + Type: typ, + Idx: opcodeOffset(ctx.ptrIndex), + Next: newEndOp(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 0000000..12c58e4 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/option.go @@ -0,0 +1,48 @@ +package encoder + +import ( + "context" + "io" +) + +type OptionFlag uint8 + +const ( + HTMLEscapeOption OptionFlag = 1 << iota + IndentOption + UnorderedMapOption + DebugOption + ColorizeOption + ContextOption + NormalizeUTF8Option + FieldQueryOption +) + +type Option struct { + Flag OptionFlag + ColorScheme *ColorScheme + Context context.Context + DebugOut io.Writer + DebugDOTOut io.WriteCloser +} + +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 0000000..5c1241b --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/optype.go @@ -0,0 +1,932 @@ +// 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 = [400]string{ + "End", + "Interface", + "Ptr", + "SliceElem", + "SliceEnd", + "ArrayElem", + "ArrayEnd", + "MapKey", + "MapValue", + "MapEnd", + "Recursive", + "RecursivePtr", + "RecursiveEnd", + "InterfaceEnd", + "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 + OpInt OpType = 14 + OpUint OpType = 15 + OpFloat32 OpType = 16 + OpFloat64 OpType = 17 + OpBool OpType = 18 + OpString OpType = 19 + OpBytes OpType = 20 + OpNumber OpType = 21 + OpArray OpType = 22 + OpMap OpType = 23 + OpSlice OpType = 24 + OpStruct OpType = 25 + OpMarshalJSON OpType = 26 + OpMarshalText OpType = 27 + OpIntString OpType = 28 + OpUintString OpType = 29 + OpFloat32String OpType = 30 + OpFloat64String OpType = 31 + OpBoolString OpType = 32 + OpStringString OpType = 33 + OpNumberString OpType = 34 + OpIntPtr OpType = 35 + OpUintPtr OpType = 36 + OpFloat32Ptr OpType = 37 + OpFloat64Ptr OpType = 38 + OpBoolPtr OpType = 39 + OpStringPtr OpType = 40 + OpBytesPtr OpType = 41 + OpNumberPtr OpType = 42 + OpArrayPtr OpType = 43 + OpMapPtr OpType = 44 + OpSlicePtr OpType = 45 + OpMarshalJSONPtr OpType = 46 + OpMarshalTextPtr OpType = 47 + OpInterfacePtr OpType = 48 + OpIntPtrString OpType = 49 + OpUintPtrString OpType = 50 + OpFloat32PtrString OpType = 51 + OpFloat64PtrString OpType = 52 + OpBoolPtrString OpType = 53 + OpStringPtrString OpType = 54 + OpNumberPtrString OpType = 55 + OpStructHeadInt OpType = 56 + OpStructHeadOmitEmptyInt OpType = 57 + OpStructPtrHeadInt OpType = 58 + OpStructPtrHeadOmitEmptyInt OpType = 59 + OpStructHeadUint OpType = 60 + OpStructHeadOmitEmptyUint OpType = 61 + OpStructPtrHeadUint OpType = 62 + OpStructPtrHeadOmitEmptyUint OpType = 63 + OpStructHeadFloat32 OpType = 64 + OpStructHeadOmitEmptyFloat32 OpType = 65 + OpStructPtrHeadFloat32 OpType = 66 + OpStructPtrHeadOmitEmptyFloat32 OpType = 67 + OpStructHeadFloat64 OpType = 68 + OpStructHeadOmitEmptyFloat64 OpType = 69 + OpStructPtrHeadFloat64 OpType = 70 + OpStructPtrHeadOmitEmptyFloat64 OpType = 71 + OpStructHeadBool OpType = 72 + OpStructHeadOmitEmptyBool OpType = 73 + OpStructPtrHeadBool OpType = 74 + OpStructPtrHeadOmitEmptyBool OpType = 75 + OpStructHeadString OpType = 76 + OpStructHeadOmitEmptyString OpType = 77 + OpStructPtrHeadString OpType = 78 + OpStructPtrHeadOmitEmptyString OpType = 79 + OpStructHeadBytes OpType = 80 + OpStructHeadOmitEmptyBytes OpType = 81 + OpStructPtrHeadBytes OpType = 82 + OpStructPtrHeadOmitEmptyBytes OpType = 83 + OpStructHeadNumber OpType = 84 + OpStructHeadOmitEmptyNumber OpType = 85 + OpStructPtrHeadNumber OpType = 86 + OpStructPtrHeadOmitEmptyNumber OpType = 87 + OpStructHeadArray OpType = 88 + OpStructHeadOmitEmptyArray OpType = 89 + OpStructPtrHeadArray OpType = 90 + OpStructPtrHeadOmitEmptyArray OpType = 91 + OpStructHeadMap OpType = 92 + OpStructHeadOmitEmptyMap OpType = 93 + OpStructPtrHeadMap OpType = 94 + OpStructPtrHeadOmitEmptyMap OpType = 95 + OpStructHeadSlice OpType = 96 + OpStructHeadOmitEmptySlice OpType = 97 + OpStructPtrHeadSlice OpType = 98 + OpStructPtrHeadOmitEmptySlice OpType = 99 + OpStructHeadStruct OpType = 100 + OpStructHeadOmitEmptyStruct OpType = 101 + OpStructPtrHeadStruct OpType = 102 + OpStructPtrHeadOmitEmptyStruct OpType = 103 + OpStructHeadMarshalJSON OpType = 104 + OpStructHeadOmitEmptyMarshalJSON OpType = 105 + OpStructPtrHeadMarshalJSON OpType = 106 + OpStructPtrHeadOmitEmptyMarshalJSON OpType = 107 + OpStructHeadMarshalText OpType = 108 + OpStructHeadOmitEmptyMarshalText OpType = 109 + OpStructPtrHeadMarshalText OpType = 110 + OpStructPtrHeadOmitEmptyMarshalText OpType = 111 + OpStructHeadIntString OpType = 112 + OpStructHeadOmitEmptyIntString OpType = 113 + OpStructPtrHeadIntString OpType = 114 + OpStructPtrHeadOmitEmptyIntString OpType = 115 + OpStructHeadUintString OpType = 116 + OpStructHeadOmitEmptyUintString OpType = 117 + OpStructPtrHeadUintString OpType = 118 + OpStructPtrHeadOmitEmptyUintString OpType = 119 + OpStructHeadFloat32String OpType = 120 + OpStructHeadOmitEmptyFloat32String OpType = 121 + OpStructPtrHeadFloat32String OpType = 122 + OpStructPtrHeadOmitEmptyFloat32String OpType = 123 + OpStructHeadFloat64String OpType = 124 + OpStructHeadOmitEmptyFloat64String OpType = 125 + OpStructPtrHeadFloat64String OpType = 126 + OpStructPtrHeadOmitEmptyFloat64String OpType = 127 + OpStructHeadBoolString OpType = 128 + OpStructHeadOmitEmptyBoolString OpType = 129 + OpStructPtrHeadBoolString OpType = 130 + OpStructPtrHeadOmitEmptyBoolString OpType = 131 + OpStructHeadStringString OpType = 132 + OpStructHeadOmitEmptyStringString OpType = 133 + OpStructPtrHeadStringString OpType = 134 + OpStructPtrHeadOmitEmptyStringString OpType = 135 + OpStructHeadNumberString OpType = 136 + OpStructHeadOmitEmptyNumberString OpType = 137 + OpStructPtrHeadNumberString OpType = 138 + OpStructPtrHeadOmitEmptyNumberString OpType = 139 + OpStructHeadIntPtr OpType = 140 + OpStructHeadOmitEmptyIntPtr OpType = 141 + OpStructPtrHeadIntPtr OpType = 142 + OpStructPtrHeadOmitEmptyIntPtr OpType = 143 + OpStructHeadUintPtr OpType = 144 + OpStructHeadOmitEmptyUintPtr OpType = 145 + OpStructPtrHeadUintPtr OpType = 146 + OpStructPtrHeadOmitEmptyUintPtr OpType = 147 + OpStructHeadFloat32Ptr OpType = 148 + OpStructHeadOmitEmptyFloat32Ptr OpType = 149 + OpStructPtrHeadFloat32Ptr OpType = 150 + OpStructPtrHeadOmitEmptyFloat32Ptr OpType = 151 + OpStructHeadFloat64Ptr OpType = 152 + OpStructHeadOmitEmptyFloat64Ptr OpType = 153 + OpStructPtrHeadFloat64Ptr OpType = 154 + OpStructPtrHeadOmitEmptyFloat64Ptr OpType = 155 + OpStructHeadBoolPtr OpType = 156 + OpStructHeadOmitEmptyBoolPtr OpType = 157 + OpStructPtrHeadBoolPtr OpType = 158 + OpStructPtrHeadOmitEmptyBoolPtr OpType = 159 + OpStructHeadStringPtr OpType = 160 + OpStructHeadOmitEmptyStringPtr OpType = 161 + OpStructPtrHeadStringPtr OpType = 162 + OpStructPtrHeadOmitEmptyStringPtr OpType = 163 + OpStructHeadBytesPtr OpType = 164 + OpStructHeadOmitEmptyBytesPtr OpType = 165 + OpStructPtrHeadBytesPtr OpType = 166 + OpStructPtrHeadOmitEmptyBytesPtr OpType = 167 + OpStructHeadNumberPtr OpType = 168 + OpStructHeadOmitEmptyNumberPtr OpType = 169 + OpStructPtrHeadNumberPtr OpType = 170 + OpStructPtrHeadOmitEmptyNumberPtr OpType = 171 + OpStructHeadArrayPtr OpType = 172 + OpStructHeadOmitEmptyArrayPtr OpType = 173 + OpStructPtrHeadArrayPtr OpType = 174 + OpStructPtrHeadOmitEmptyArrayPtr OpType = 175 + OpStructHeadMapPtr OpType = 176 + OpStructHeadOmitEmptyMapPtr OpType = 177 + OpStructPtrHeadMapPtr OpType = 178 + OpStructPtrHeadOmitEmptyMapPtr OpType = 179 + OpStructHeadSlicePtr OpType = 180 + OpStructHeadOmitEmptySlicePtr OpType = 181 + OpStructPtrHeadSlicePtr OpType = 182 + OpStructPtrHeadOmitEmptySlicePtr OpType = 183 + OpStructHeadMarshalJSONPtr OpType = 184 + OpStructHeadOmitEmptyMarshalJSONPtr OpType = 185 + OpStructPtrHeadMarshalJSONPtr OpType = 186 + OpStructPtrHeadOmitEmptyMarshalJSONPtr OpType = 187 + OpStructHeadMarshalTextPtr OpType = 188 + OpStructHeadOmitEmptyMarshalTextPtr OpType = 189 + OpStructPtrHeadMarshalTextPtr OpType = 190 + OpStructPtrHeadOmitEmptyMarshalTextPtr OpType = 191 + OpStructHeadInterfacePtr OpType = 192 + OpStructHeadOmitEmptyInterfacePtr OpType = 193 + OpStructPtrHeadInterfacePtr OpType = 194 + OpStructPtrHeadOmitEmptyInterfacePtr OpType = 195 + OpStructHeadIntPtrString OpType = 196 + OpStructHeadOmitEmptyIntPtrString OpType = 197 + OpStructPtrHeadIntPtrString OpType = 198 + OpStructPtrHeadOmitEmptyIntPtrString OpType = 199 + OpStructHeadUintPtrString OpType = 200 + OpStructHeadOmitEmptyUintPtrString OpType = 201 + OpStructPtrHeadUintPtrString OpType = 202 + OpStructPtrHeadOmitEmptyUintPtrString OpType = 203 + OpStructHeadFloat32PtrString OpType = 204 + OpStructHeadOmitEmptyFloat32PtrString OpType = 205 + OpStructPtrHeadFloat32PtrString OpType = 206 + OpStructPtrHeadOmitEmptyFloat32PtrString OpType = 207 + OpStructHeadFloat64PtrString OpType = 208 + OpStructHeadOmitEmptyFloat64PtrString OpType = 209 + OpStructPtrHeadFloat64PtrString OpType = 210 + OpStructPtrHeadOmitEmptyFloat64PtrString OpType = 211 + OpStructHeadBoolPtrString OpType = 212 + OpStructHeadOmitEmptyBoolPtrString OpType = 213 + OpStructPtrHeadBoolPtrString OpType = 214 + OpStructPtrHeadOmitEmptyBoolPtrString OpType = 215 + OpStructHeadStringPtrString OpType = 216 + OpStructHeadOmitEmptyStringPtrString OpType = 217 + OpStructPtrHeadStringPtrString OpType = 218 + OpStructPtrHeadOmitEmptyStringPtrString OpType = 219 + OpStructHeadNumberPtrString OpType = 220 + OpStructHeadOmitEmptyNumberPtrString OpType = 221 + OpStructPtrHeadNumberPtrString OpType = 222 + OpStructPtrHeadOmitEmptyNumberPtrString OpType = 223 + OpStructHead OpType = 224 + OpStructHeadOmitEmpty OpType = 225 + OpStructPtrHead OpType = 226 + OpStructPtrHeadOmitEmpty OpType = 227 + OpStructFieldInt OpType = 228 + OpStructFieldOmitEmptyInt OpType = 229 + OpStructEndInt OpType = 230 + OpStructEndOmitEmptyInt OpType = 231 + OpStructFieldUint OpType = 232 + OpStructFieldOmitEmptyUint OpType = 233 + OpStructEndUint OpType = 234 + OpStructEndOmitEmptyUint OpType = 235 + OpStructFieldFloat32 OpType = 236 + OpStructFieldOmitEmptyFloat32 OpType = 237 + OpStructEndFloat32 OpType = 238 + OpStructEndOmitEmptyFloat32 OpType = 239 + OpStructFieldFloat64 OpType = 240 + OpStructFieldOmitEmptyFloat64 OpType = 241 + OpStructEndFloat64 OpType = 242 + OpStructEndOmitEmptyFloat64 OpType = 243 + OpStructFieldBool OpType = 244 + OpStructFieldOmitEmptyBool OpType = 245 + OpStructEndBool OpType = 246 + OpStructEndOmitEmptyBool OpType = 247 + OpStructFieldString OpType = 248 + OpStructFieldOmitEmptyString OpType = 249 + OpStructEndString OpType = 250 + OpStructEndOmitEmptyString OpType = 251 + OpStructFieldBytes OpType = 252 + OpStructFieldOmitEmptyBytes OpType = 253 + OpStructEndBytes OpType = 254 + OpStructEndOmitEmptyBytes OpType = 255 + OpStructFieldNumber OpType = 256 + OpStructFieldOmitEmptyNumber OpType = 257 + OpStructEndNumber OpType = 258 + OpStructEndOmitEmptyNumber OpType = 259 + OpStructFieldArray OpType = 260 + OpStructFieldOmitEmptyArray OpType = 261 + OpStructEndArray OpType = 262 + OpStructEndOmitEmptyArray OpType = 263 + OpStructFieldMap OpType = 264 + OpStructFieldOmitEmptyMap OpType = 265 + OpStructEndMap OpType = 266 + OpStructEndOmitEmptyMap OpType = 267 + OpStructFieldSlice OpType = 268 + OpStructFieldOmitEmptySlice OpType = 269 + OpStructEndSlice OpType = 270 + OpStructEndOmitEmptySlice OpType = 271 + OpStructFieldStruct OpType = 272 + OpStructFieldOmitEmptyStruct OpType = 273 + OpStructEndStruct OpType = 274 + OpStructEndOmitEmptyStruct OpType = 275 + OpStructFieldMarshalJSON OpType = 276 + OpStructFieldOmitEmptyMarshalJSON OpType = 277 + OpStructEndMarshalJSON OpType = 278 + OpStructEndOmitEmptyMarshalJSON OpType = 279 + OpStructFieldMarshalText OpType = 280 + OpStructFieldOmitEmptyMarshalText OpType = 281 + OpStructEndMarshalText OpType = 282 + OpStructEndOmitEmptyMarshalText OpType = 283 + OpStructFieldIntString OpType = 284 + OpStructFieldOmitEmptyIntString OpType = 285 + OpStructEndIntString OpType = 286 + OpStructEndOmitEmptyIntString OpType = 287 + OpStructFieldUintString OpType = 288 + OpStructFieldOmitEmptyUintString OpType = 289 + OpStructEndUintString OpType = 290 + OpStructEndOmitEmptyUintString OpType = 291 + OpStructFieldFloat32String OpType = 292 + OpStructFieldOmitEmptyFloat32String OpType = 293 + OpStructEndFloat32String OpType = 294 + OpStructEndOmitEmptyFloat32String OpType = 295 + OpStructFieldFloat64String OpType = 296 + OpStructFieldOmitEmptyFloat64String OpType = 297 + OpStructEndFloat64String OpType = 298 + OpStructEndOmitEmptyFloat64String OpType = 299 + OpStructFieldBoolString OpType = 300 + OpStructFieldOmitEmptyBoolString OpType = 301 + OpStructEndBoolString OpType = 302 + OpStructEndOmitEmptyBoolString OpType = 303 + OpStructFieldStringString OpType = 304 + OpStructFieldOmitEmptyStringString OpType = 305 + OpStructEndStringString OpType = 306 + OpStructEndOmitEmptyStringString OpType = 307 + OpStructFieldNumberString OpType = 308 + OpStructFieldOmitEmptyNumberString OpType = 309 + OpStructEndNumberString OpType = 310 + OpStructEndOmitEmptyNumberString OpType = 311 + OpStructFieldIntPtr OpType = 312 + OpStructFieldOmitEmptyIntPtr OpType = 313 + OpStructEndIntPtr OpType = 314 + OpStructEndOmitEmptyIntPtr OpType = 315 + OpStructFieldUintPtr OpType = 316 + OpStructFieldOmitEmptyUintPtr OpType = 317 + OpStructEndUintPtr OpType = 318 + OpStructEndOmitEmptyUintPtr OpType = 319 + OpStructFieldFloat32Ptr OpType = 320 + OpStructFieldOmitEmptyFloat32Ptr OpType = 321 + OpStructEndFloat32Ptr OpType = 322 + OpStructEndOmitEmptyFloat32Ptr OpType = 323 + OpStructFieldFloat64Ptr OpType = 324 + OpStructFieldOmitEmptyFloat64Ptr OpType = 325 + OpStructEndFloat64Ptr OpType = 326 + OpStructEndOmitEmptyFloat64Ptr OpType = 327 + OpStructFieldBoolPtr OpType = 328 + OpStructFieldOmitEmptyBoolPtr OpType = 329 + OpStructEndBoolPtr OpType = 330 + OpStructEndOmitEmptyBoolPtr OpType = 331 + OpStructFieldStringPtr OpType = 332 + OpStructFieldOmitEmptyStringPtr OpType = 333 + OpStructEndStringPtr OpType = 334 + OpStructEndOmitEmptyStringPtr OpType = 335 + OpStructFieldBytesPtr OpType = 336 + OpStructFieldOmitEmptyBytesPtr OpType = 337 + OpStructEndBytesPtr OpType = 338 + OpStructEndOmitEmptyBytesPtr OpType = 339 + OpStructFieldNumberPtr OpType = 340 + OpStructFieldOmitEmptyNumberPtr OpType = 341 + OpStructEndNumberPtr OpType = 342 + OpStructEndOmitEmptyNumberPtr OpType = 343 + OpStructFieldArrayPtr OpType = 344 + OpStructFieldOmitEmptyArrayPtr OpType = 345 + OpStructEndArrayPtr OpType = 346 + OpStructEndOmitEmptyArrayPtr OpType = 347 + OpStructFieldMapPtr OpType = 348 + OpStructFieldOmitEmptyMapPtr OpType = 349 + OpStructEndMapPtr OpType = 350 + OpStructEndOmitEmptyMapPtr OpType = 351 + OpStructFieldSlicePtr OpType = 352 + OpStructFieldOmitEmptySlicePtr OpType = 353 + OpStructEndSlicePtr OpType = 354 + OpStructEndOmitEmptySlicePtr OpType = 355 + OpStructFieldMarshalJSONPtr OpType = 356 + OpStructFieldOmitEmptyMarshalJSONPtr OpType = 357 + OpStructEndMarshalJSONPtr OpType = 358 + OpStructEndOmitEmptyMarshalJSONPtr OpType = 359 + OpStructFieldMarshalTextPtr OpType = 360 + OpStructFieldOmitEmptyMarshalTextPtr OpType = 361 + OpStructEndMarshalTextPtr OpType = 362 + OpStructEndOmitEmptyMarshalTextPtr OpType = 363 + OpStructFieldInterfacePtr OpType = 364 + OpStructFieldOmitEmptyInterfacePtr OpType = 365 + OpStructEndInterfacePtr OpType = 366 + OpStructEndOmitEmptyInterfacePtr OpType = 367 + OpStructFieldIntPtrString OpType = 368 + OpStructFieldOmitEmptyIntPtrString OpType = 369 + OpStructEndIntPtrString OpType = 370 + OpStructEndOmitEmptyIntPtrString OpType = 371 + OpStructFieldUintPtrString OpType = 372 + OpStructFieldOmitEmptyUintPtrString OpType = 373 + OpStructEndUintPtrString OpType = 374 + OpStructEndOmitEmptyUintPtrString OpType = 375 + OpStructFieldFloat32PtrString OpType = 376 + OpStructFieldOmitEmptyFloat32PtrString OpType = 377 + OpStructEndFloat32PtrString OpType = 378 + OpStructEndOmitEmptyFloat32PtrString OpType = 379 + OpStructFieldFloat64PtrString OpType = 380 + OpStructFieldOmitEmptyFloat64PtrString OpType = 381 + OpStructEndFloat64PtrString OpType = 382 + OpStructEndOmitEmptyFloat64PtrString OpType = 383 + OpStructFieldBoolPtrString OpType = 384 + OpStructFieldOmitEmptyBoolPtrString OpType = 385 + OpStructEndBoolPtrString OpType = 386 + OpStructEndOmitEmptyBoolPtrString OpType = 387 + OpStructFieldStringPtrString OpType = 388 + OpStructFieldOmitEmptyStringPtrString OpType = 389 + OpStructEndStringPtrString OpType = 390 + OpStructEndOmitEmptyStringPtrString OpType = 391 + OpStructFieldNumberPtrString OpType = 392 + OpStructFieldOmitEmptyNumberPtrString OpType = 393 + OpStructEndNumberPtrString OpType = 394 + OpStructEndOmitEmptyNumberPtrString OpType = 395 + OpStructField OpType = 396 + OpStructFieldOmitEmpty OpType = 397 + OpStructEnd OpType = 398 + OpStructEndOmitEmpty OpType = 399 +) + +func (t OpType) String() string { + if int(t) >= 400 { + 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(), "PtrHead") + 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/query.go b/vendor/github.com/goccy/go-json/internal/encoder/query.go new file mode 100644 index 0000000..1e1850c --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/query.go @@ -0,0 +1,135 @@ +package encoder + +import ( + "context" + "fmt" + "reflect" +) + +var ( + Marshal func(interface{}) ([]byte, error) + Unmarshal func([]byte, interface{}) error +) + +type FieldQuery struct { + Name string + Fields []*FieldQuery + hash string +} + +func (q *FieldQuery) Hash() string { + if q.hash != "" { + return q.hash + } + b, _ := Marshal(q) + q.hash = string(b) + return q.hash +} + +func (q *FieldQuery) MarshalJSON() ([]byte, error) { + if q.Name != "" { + if len(q.Fields) > 0 { + return Marshal(map[string][]*FieldQuery{q.Name: q.Fields}) + } + return Marshal(q.Name) + } + return Marshal(q.Fields) +} + +func (q *FieldQuery) QueryString() (FieldQueryString, error) { + b, err := Marshal(q) + if err != nil { + return "", err + } + return FieldQueryString(b), nil +} + +type FieldQueryString string + +func (s FieldQueryString) Build() (*FieldQuery, error) { + var query interface{} + if err := Unmarshal([]byte(s), &query); err != nil { + return nil, err + } + return s.build(reflect.ValueOf(query)) +} + +func (s FieldQueryString) build(v reflect.Value) (*FieldQuery, error) { + switch v.Type().Kind() { + case reflect.String: + return s.buildString(v) + case reflect.Map: + return s.buildMap(v) + case reflect.Slice: + return s.buildSlice(v) + case reflect.Interface: + return s.build(reflect.ValueOf(v.Interface())) + } + return nil, fmt.Errorf("failed to build field query") +} + +func (s FieldQueryString) buildString(v reflect.Value) (*FieldQuery, error) { + b := []byte(v.String()) + switch b[0] { + case '[', '{': + var query interface{} + if err := Unmarshal(b, &query); err != nil { + return nil, err + } + if str, ok := query.(string); ok { + return &FieldQuery{Name: str}, nil + } + return s.build(reflect.ValueOf(query)) + } + return &FieldQuery{Name: string(b)}, nil +} + +func (s FieldQueryString) buildSlice(v reflect.Value) (*FieldQuery, error) { + fields := make([]*FieldQuery, 0, v.Len()) + for i := 0; i < v.Len(); i++ { + def, err := s.build(v.Index(i)) + if err != nil { + return nil, err + } + fields = append(fields, def) + } + return &FieldQuery{Fields: fields}, nil +} + +func (s FieldQueryString) buildMap(v reflect.Value) (*FieldQuery, error) { + keys := v.MapKeys() + if len(keys) != 1 { + return nil, fmt.Errorf("failed to build field query object") + } + key := keys[0] + if key.Type().Kind() != reflect.String { + return nil, fmt.Errorf("failed to build field query. invalid object key type") + } + name := key.String() + def, err := s.build(v.MapIndex(key)) + if err != nil { + return nil, err + } + return &FieldQuery{ + Name: name, + Fields: def.Fields, + }, nil +} + +type queryKey struct{} + +func FieldQueryFromContext(ctx context.Context) *FieldQuery { + query := ctx.Value(queryKey{}) + if query == nil { + return nil + } + q, ok := query.(*FieldQuery) + if !ok { + return nil + } + return q +} + +func SetFieldQueryToContext(ctx context.Context, query *FieldQuery) context.Context { + return context.WithValue(ctx, queryKey{}, query) +} 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 0000000..4abb841 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/string.go @@ -0,0 +1,483 @@ +// This files's string processing codes are inspired by https://github.com/segmentio/encoding. +// The license notation is as follows. +// +// # MIT License +// +// Copyright (c) 2019 Segment.io, Inc. +// +// 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 encoder + +import ( + "math/bits" + "reflect" + "unsafe" +) + +const ( + lsb = 0x0101010101010101 + msb = 0x8080808080808080 +) + +var hex = "0123456789abcdef" + +//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 { + if ctx.Option.Flag&NormalizeUTF8Option != 0 { + return appendNormalizedHTMLString(buf, s) + } + return appendHTMLString(buf, s) + } + if ctx.Option.Flag&NormalizeUTF8Option != 0 { + return appendNormalizedString(buf, s) + } + return appendString(buf, s) +} + +func appendNormalizedHTMLString(buf []byte, s string) []byte { + 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 needEscapeHTMLNormalizeUTF8[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 !needEscapeHTMLNormalizeUTF8[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 + + case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F + 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 + } + state, size := decodeRuneInString(s[j:]) + switch state { + case runeErrorState: + buf = append(buf, s[i:j]...) + buf = append(buf, `\ufffd`...) + i = j + 1 + j = j + 1 + continue + // 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. + case lineSepState: + buf = append(buf, s[i:j]...) + buf = append(buf, `\u2028`...) + i = j + 3 + j = j + 3 + continue + case paragraphSepState: + buf = append(buf, s[i:j]...) + buf = append(buf, `\u2029`...) + i = j + 3 + j = j + 3 + continue + } + j += size + } + + return append(append(buf, s[i:]...), '"') +} + +func appendHTMLString(buf []byte, s string) []byte { + 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 needEscapeHTML[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 !needEscapeHTML[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 + + case 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F + 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 + } + j++ + } + + return append(append(buf, s[i:]...), '"') +} + +func appendNormalizedString(buf []byte, s string) []byte { + 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) + if (mask & msb) != 0 { + j = bits.TrailingZeros64(mask&msb) / 8 + goto ESCAPE_END + } + } + valLen := len(s) + for i := len(chunks) * 8; i < valLen; i++ { + if needEscapeNormalizeUTF8[s[i]] { + j = i + goto ESCAPE_END + } + } + return append(append(buf, s...), '"') + } +ESCAPE_END: + for j < valLen { + c := s[j] + + if !needEscapeNormalizeUTF8[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 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F + 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 + } + + state, size := decodeRuneInString(s[j:]) + switch state { + case runeErrorState: + buf = append(buf, s[i:j]...) + buf = append(buf, `\ufffd`...) + i = j + 1 + j = j + 1 + continue + // 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. + case lineSepState: + buf = append(buf, s[i:j]...) + buf = append(buf, `\u2028`...) + i = j + 3 + j = j + 3 + continue + case paragraphSepState: + buf = append(buf, s[i:j]...) + buf = append(buf, `\u2029`...) + i = j + 3 + j = j + 3 + 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 ( + 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) + if (mask & msb) != 0 { + j = bits.TrailingZeros64(mask&msb) / 8 + goto ESCAPE_END + } + } + valLen := len(s) + for i := len(chunks) * 8; i < valLen; i++ { + if needEscape[s[i]] { + j = i + goto ESCAPE_END + } + } + return append(append(buf, s...), '"') + } +ESCAPE_END: + for j < valLen { + c := s[j] + + if !needEscape[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 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0B, 0x0C, 0x0E, 0x0F, // 0x00-0x0F + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F: // 0x10-0x1F + 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 + } + j++ + } + + return append(append(buf, s[i:]...), '"') +} diff --git a/vendor/github.com/goccy/go-json/internal/encoder/string_table.go b/vendor/github.com/goccy/go-json/internal/encoder/string_table.go new file mode 100644 index 0000000..ebe42c9 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/string_table.go @@ -0,0 +1,415 @@ +package encoder + +var needEscapeHTMLNormalizeUTF8 = [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 needEscapeNormalizeUTF8 = [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 needEscapeHTML = [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 - 0xff */ +} + +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 - 0xff */ +} 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 0000000..82b6dd4 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/debug_vm.go @@ -0,0 +1,41 @@ +package vm + +import ( + "fmt" + "io" + + "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 wc := ctx.Option.DebugDOTOut; wc != nil { + _, _ = io.WriteString(wc, code.DumpDOT()) + wc.Close() + ctx.Option.DebugDOTOut = nil + } + + if err := recover(); err != nil { + w := ctx.Option.DebugOut + fmt.Fprintln(w, "=============[DEBUG]===============") + fmt.Fprintln(w, "* [TYPE]") + fmt.Fprintln(w, codeSet.Type) + fmt.Fprintf(w, "\n") + fmt.Fprintln(w, "* [ALL OPCODE]") + fmt.Fprintln(w, code.Dump()) + fmt.Fprintf(w, "\n") + fmt.Fprintln(w, "* [CONTEXT]") + fmt.Fprintf(w, "%+v\n", ctx) + fmt.Fprintln(w, "===================================") + 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 0000000..65252b4 --- /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 0000000..86291d7 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/util.go @@ -0,0 +1,207 @@ +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 +} + +type nonEmptyInterface struct { + itab *struct { + ityp *runtime.Type // static interface type + typ *runtime.Type // dynamic concrete type + // unused fields... + } + 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, bitSize uint8) uint64 { + switch bitSize { + case 8: + return (uint64)(**(**uint8)(unsafe.Pointer(&p))) + case 16: + return (uint64)(**(**uint16)(unsafe.Pointer(&p))) + case 32: + return (uint64)(**(**uint32)(unsafe.Pointer(&p))) + case 64: + return **(**uint64)(unsafe.Pointer(&p)) + } + return 0 +} +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 appendNullComma(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, "null,"...) +} + +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 0000000..645d20f --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm/vm.go @@ -0,0 +1,4859 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package vm + +import ( + "math" + "reflect" + "sort" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(ctx, b, 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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(ctx, b, load(ctxptr, code.Idx), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(ctx, b, 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, 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNullComma(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) + var ( + typ *runtime.Type + ifacePtr unsafe.Pointer + ) + up := ptrToUnsafePtr(p) + if code.Flags&encoder.NonEmptyInterfaceFlags != 0 { + iface := (*nonEmptyInterface)(up) + ifacePtr = iface.ptr + if iface.itab != nil { + typ = iface.itab.typ + } + } else { + iface := (*emptyInterface)(up) + ifacePtr = iface.ptr + typ = iface.typ + } + if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if !isDirectedNil { + b = appendNullComma(ctx, b) + code = code.Next + break + } + } + ctx.KeepRefs = append(ctx.KeepRefs, up) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(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 + ctx.BaseIndent += code.Indent + + 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(ifacePtr)) + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + unorderedMap := (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 + mapCtx := encoder.NewMapContext(mlen, unorderedMap) + mapiterinit(code.Type, uptr, &mapCtx.Iter) + store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx))) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + if unorderedMap { + b = appendMapKeyIndent(ctx, code.Next, b) + } else { + mapCtx.Start = len(b) + mapCtx.First = len(b) + } + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + idx := mapCtx.Idx + idx++ + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + if idx < mapCtx.Len { + b = appendMapKeyIndent(ctx, code, b) + mapCtx.Idx = int(idx) + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + b = appendObjectEnd(ctx, code, b) + encoder.ReleaseMapContext(mapCtx) + code = code.End.Next + } + } else { + mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)] + if idx < mapCtx.Len { + mapCtx.Idx = int(idx) + mapCtx.Start = len(b) + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendColon(ctx, b) + } else { + mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)] + mapCtx.Start = len(b) + } + value := mapitervalue(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(&mapCtx.Iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + 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[:mapCtx.First] + 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + u64 := ptrToUint64(p, code.NumBitSize) + 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, p, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + 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, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(ctx, b) + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + b = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalJSON { + 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.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p) + } + } + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalText { + 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.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p) + } + } + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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.IsTaggedKeyFlags != 0 || 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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 = appendNullComma(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.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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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 0000000..925f61e --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/debug_vm.go @@ -0,0 +1,35 @@ +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 { + w := ctx.Option.DebugOut + fmt.Fprintln(w, "=============[DEBUG]===============") + fmt.Fprintln(w, "* [TYPE]") + fmt.Fprintln(w, codeSet.Type) + fmt.Fprintf(w, "\n") + fmt.Fprintln(w, "* [ALL OPCODE]") + fmt.Fprintln(w, code.Dump()) + fmt.Fprintf(w, "\n") + fmt.Fprintln(w, "* [CONTEXT]") + fmt.Fprintf(w, "%+v\n", ctx) + fmt.Fprintln(w, "===================================") + 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 0000000..12ec56c --- /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 0000000..33f29ae --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/util.go @@ -0,0 +1,274 @@ +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 +} + +type nonEmptyInterface struct { + itab *struct { + ityp *runtime.Type // static interface type + typ *runtime.Type // dynamic concrete type + // unused fields... + } + 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, bitSize uint8) uint64 { + switch bitSize { + case 8: + return (uint64)(**(**uint8)(unsafe.Pointer(&p))) + case 16: + return (uint64)(**(**uint16)(unsafe.Pointer(&p))) + case 32: + return (uint64)(**(**uint32)(unsafe.Pointer(&p))) + case 64: + return **(**uint64)(unsafe.Pointer(&p)) + } + return 0 +} +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, p uintptr, code *encoder.Opcode) []byte { + format := ctx.Option.ColorScheme.Int + b = append(b, format.Header...) + b = encoder.AppendInt(ctx, b, p, code) + return append(b, format.Footer...) +} + +func appendUint(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte { + format := ctx.Option.ColorScheme.Uint + b = append(b, format.Header...) + b = encoder.AppendUint(ctx, b, p, 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 appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte { + format := ctx.Option.ColorScheme.Null + b = append(b, format.Header...) + b = append(b, "null"...) + return append(append(b, format.Footer...), ',') +} + +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 0000000..a63e83e --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color/vm.go @@ -0,0 +1,4859 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package vm_color + +import ( + "math" + "reflect" + "sort" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(ctx, b, 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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(ctx, b, load(ctxptr, code.Idx), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(ctx, b, 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, 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNullComma(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) + var ( + typ *runtime.Type + ifacePtr unsafe.Pointer + ) + up := ptrToUnsafePtr(p) + if code.Flags&encoder.NonEmptyInterfaceFlags != 0 { + iface := (*nonEmptyInterface)(up) + ifacePtr = iface.ptr + if iface.itab != nil { + typ = iface.itab.typ + } + } else { + iface := (*emptyInterface)(up) + ifacePtr = iface.ptr + typ = iface.typ + } + if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if !isDirectedNil { + b = appendNullComma(ctx, b) + code = code.Next + break + } + } + ctx.KeepRefs = append(ctx.KeepRefs, up) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(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 + ctx.BaseIndent += code.Indent + + 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(ifacePtr)) + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + unorderedMap := (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 + mapCtx := encoder.NewMapContext(mlen, unorderedMap) + mapiterinit(code.Type, uptr, &mapCtx.Iter) + store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx))) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + if unorderedMap { + b = appendMapKeyIndent(ctx, code.Next, b) + } else { + mapCtx.Start = len(b) + mapCtx.First = len(b) + } + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + idx := mapCtx.Idx + idx++ + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + if idx < mapCtx.Len { + b = appendMapKeyIndent(ctx, code, b) + mapCtx.Idx = int(idx) + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + b = appendObjectEnd(ctx, code, b) + encoder.ReleaseMapContext(mapCtx) + code = code.End.Next + } + } else { + mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)] + if idx < mapCtx.Len { + mapCtx.Idx = int(idx) + mapCtx.Start = len(b) + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendColon(ctx, b) + } else { + mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)] + mapCtx.Start = len(b) + } + value := mapitervalue(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(&mapCtx.Iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + 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[:mapCtx.First] + 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + u64 := ptrToUint64(p, code.NumBitSize) + 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, p, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + 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, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(ctx, b) + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + b = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalJSON { + 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.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p) + } + } + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalText { + 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.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p) + } + } + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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.IsTaggedKeyFlags != 0 || 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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 = appendNullComma(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.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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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 0000000..dd4cd48 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/debug_vm.go @@ -0,0 +1,35 @@ +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 { + w := ctx.Option.DebugOut + fmt.Fprintln(w, "=============[DEBUG]===============") + fmt.Fprintln(w, "* [TYPE]") + fmt.Fprintln(w, codeSet.Type) + fmt.Fprintf(w, "\n") + fmt.Fprintln(w, "* [ALL OPCODE]") + fmt.Fprintln(w, code.Dump()) + fmt.Fprintf(w, "\n") + fmt.Fprintln(w, "* [CONTEXT]") + fmt.Fprintf(w, "%+v\n", ctx) + fmt.Fprintln(w, "===================================") + 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 0000000..2395abe --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/util.go @@ -0,0 +1,297 @@ +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 +} + +type nonEmptyInterface struct { + itab *struct { + ityp *runtime.Type // static interface type + typ *runtime.Type // dynamic concrete type + // unused fields... + } + 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, bitSize uint8) uint64 { + switch bitSize { + case 8: + return (uint64)(**(**uint8)(unsafe.Pointer(&p))) + case 16: + return (uint64)(**(**uint16)(unsafe.Pointer(&p))) + case 32: + return (uint64)(**(**uint32)(unsafe.Pointer(&p))) + case 64: + return **(**uint64)(unsafe.Pointer(&p)) + } + return 0 +} + +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, p uintptr, code *encoder.Opcode) []byte { + format := ctx.Option.ColorScheme.Int + b = append(b, format.Header...) + b = encoder.AppendInt(ctx, b, p, code) + return append(b, format.Footer...) +} + +func appendUint(ctx *encoder.RuntimeContext, b []byte, p uintptr, code *encoder.Opcode) []byte { + format := ctx.Option.ColorScheme.Uint + b = append(b, format.Header...) + b = encoder.AppendUint(ctx, b, p, 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 appendNullComma(ctx *encoder.RuntimeContext, b []byte) []byte { + format := ctx.Option.ColorScheme.Null + b = append(b, format.Header...) + b = append(b, "null"...) + return append(append(b, format.Footer...), ',', '\n') +} + +func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b[:len(b)-2], ':', ' ') +} + +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 + // replace comma to newline + b[last-1] = '\n' + b = appendIndent(ctx, b[:last], code.Indent) + 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 0000000..3b4e22e --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_color_indent/vm.go @@ -0,0 +1,4859 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package vm_color_indent + +import ( + "math" + "reflect" + "sort" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(ctx, b, 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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(ctx, b, load(ctxptr, code.Idx), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(ctx, b, 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, 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNullComma(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) + var ( + typ *runtime.Type + ifacePtr unsafe.Pointer + ) + up := ptrToUnsafePtr(p) + if code.Flags&encoder.NonEmptyInterfaceFlags != 0 { + iface := (*nonEmptyInterface)(up) + ifacePtr = iface.ptr + if iface.itab != nil { + typ = iface.itab.typ + } + } else { + iface := (*emptyInterface)(up) + ifacePtr = iface.ptr + typ = iface.typ + } + if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if !isDirectedNil { + b = appendNullComma(ctx, b) + code = code.Next + break + } + } + ctx.KeepRefs = append(ctx.KeepRefs, up) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(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 + ctx.BaseIndent += code.Indent + + 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(ifacePtr)) + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + unorderedMap := (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 + mapCtx := encoder.NewMapContext(mlen, unorderedMap) + mapiterinit(code.Type, uptr, &mapCtx.Iter) + store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx))) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + if unorderedMap { + b = appendMapKeyIndent(ctx, code.Next, b) + } else { + mapCtx.Start = len(b) + mapCtx.First = len(b) + } + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + idx := mapCtx.Idx + idx++ + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + if idx < mapCtx.Len { + b = appendMapKeyIndent(ctx, code, b) + mapCtx.Idx = int(idx) + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + b = appendObjectEnd(ctx, code, b) + encoder.ReleaseMapContext(mapCtx) + code = code.End.Next + } + } else { + mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)] + if idx < mapCtx.Len { + mapCtx.Idx = int(idx) + mapCtx.Start = len(b) + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendColon(ctx, b) + } else { + mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)] + mapCtx.Start = len(b) + } + value := mapitervalue(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(&mapCtx.Iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + 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[:mapCtx.First] + 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + u64 := ptrToUint64(p, code.NumBitSize) + 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, p, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + 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, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(ctx, b) + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + b = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalJSON { + 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.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p) + } + } + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalText { + 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.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p) + } + } + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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.IsTaggedKeyFlags != 0 || 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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 = appendNullComma(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.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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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 0000000..9939538 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/debug_vm.go @@ -0,0 +1,35 @@ +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 { + w := ctx.Option.DebugOut + fmt.Fprintln(w, "=============[DEBUG]===============") + fmt.Fprintln(w, "* [TYPE]") + fmt.Fprintln(w, codeSet.Type) + fmt.Fprintf(w, "\n") + fmt.Fprintln(w, "* [ALL OPCODE]") + fmt.Fprintln(w, code.Dump()) + fmt.Fprintf(w, "\n") + fmt.Fprintln(w, "* [CONTEXT]") + fmt.Fprintf(w, "%+v\n", ctx) + fmt.Fprintln(w, "===================================") + 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 0000000..9e245bf --- /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 0000000..6cb745e --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/util.go @@ -0,0 +1,230 @@ +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 +} + +type nonEmptyInterface struct { + itab *struct { + ityp *runtime.Type // static interface type + typ *runtime.Type // dynamic concrete type + // unused fields... + } + 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, bitSize uint8) uint64 { + switch bitSize { + case 8: + return (uint64)(**(**uint8)(unsafe.Pointer(&p))) + case 16: + return (uint64)(**(**uint16)(unsafe.Pointer(&p))) + case 32: + return (uint64)(**(**uint32)(unsafe.Pointer(&p))) + case 64: + return **(**uint64)(unsafe.Pointer(&p)) + } + return 0 +} +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 appendNullComma(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b, "null,\n"...) +} + +func appendColon(_ *encoder.RuntimeContext, b []byte) []byte { + return append(b[:len(b)-2], ':', ' ') +} + +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 + // replace comma to newline + b[last-1] = '\n' + b = appendIndent(ctx, b[:last], code.Indent) + 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 0000000..836c5c8 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/encoder/vm_indent/vm.go @@ -0,0 +1,4859 @@ +// Code generated by internal/cmd/generator. DO NOT EDIT! +package vm_indent + +import ( + "math" + "reflect" + "sort" + "unsafe" + + "github.com/goccy/go-json/internal/encoder" + "github.com/goccy/go-json/internal/runtime" +) + +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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInt: + b = appendInt(ctx, b, 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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpUint: + b = appendUint(ctx, b, load(ctxptr, code.Idx), code) + b = appendComma(ctx, b) + code = code.Next + case encoder.OpIntString: + b = append(b, '"') + b = appendInt(ctx, b, 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, 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(ctx, b) + code = code.Next + break + } + store(ctxptr, code.Idx, p) + fallthrough + case encoder.OpInterface: + p := load(ctxptr, code.Idx) + if p == 0 { + b = appendNullComma(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) + var ( + typ *runtime.Type + ifacePtr unsafe.Pointer + ) + up := ptrToUnsafePtr(p) + if code.Flags&encoder.NonEmptyInterfaceFlags != 0 { + iface := (*nonEmptyInterface)(up) + ifacePtr = iface.ptr + if iface.itab != nil { + typ = iface.itab.typ + } + } else { + iface := (*emptyInterface)(up) + ifacePtr = iface.ptr + typ = iface.typ + } + if ifacePtr == nil { + isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ) + if !isDirectedNil { + b = appendNullComma(ctx, b) + code = code.Next + break + } + } + ctx.KeepRefs = append(ctx.KeepRefs, up) + ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(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 + ctx.BaseIndent += code.Indent + + 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(ifacePtr)) + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + unorderedMap := (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 + mapCtx := encoder.NewMapContext(mlen, unorderedMap) + mapiterinit(code.Type, uptr, &mapCtx.Iter) + store(ctxptr, code.Idx, uintptr(unsafe.Pointer(mapCtx))) + ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx)) + if unorderedMap { + b = appendMapKeyIndent(ctx, code.Next, b) + } else { + mapCtx.Start = len(b) + mapCtx.First = len(b) + } + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + case encoder.OpMapKey: + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + idx := mapCtx.Idx + idx++ + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + if idx < mapCtx.Len { + b = appendMapKeyIndent(ctx, code, b) + mapCtx.Idx = int(idx) + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + b = appendObjectEnd(ctx, code, b) + encoder.ReleaseMapContext(mapCtx) + code = code.End.Next + } + } else { + mapCtx.Slice.Items[mapCtx.Idx].Value = b[mapCtx.Start:len(b)] + if idx < mapCtx.Len { + mapCtx.Idx = int(idx) + mapCtx.Start = len(b) + key := mapiterkey(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(key)) + code = code.Next + } else { + code = code.End + } + } + case encoder.OpMapValue: + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + if (ctx.Option.Flag & encoder.UnorderedMapOption) != 0 { + b = appendColon(ctx, b) + } else { + mapCtx.Slice.Items[mapCtx.Idx].Key = b[mapCtx.Start:len(b)] + mapCtx.Start = len(b) + } + value := mapitervalue(&mapCtx.Iter) + store(ctxptr, code.Next.Idx, uintptr(value)) + mapiternext(&mapCtx.Iter) + code = code.Next + case encoder.OpMapEnd: + // this operation only used by sorted map. + mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(load(ctxptr, code.Idx))) + 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[:mapCtx.First] + 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + if len(code.Key) > 0 { + if (code.Flags&encoder.IsTaggedKeyFlags) != 0 || code.Flags&encoder.AnonymousKeyFlags == 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + u64 := ptrToUint64(p, code.NumBitSize) + 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, p, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v == 0 { + code = code.NextField + } else { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + u64 := ptrToUint64(p+uintptr(code.Offset), code.NumBitSize) + 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, p+uintptr(code.Offset), 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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, 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(ctx, b) + code = code.NextField + break + } + p = ptrToPtr(p + uintptr(code.Offset)) + if p == 0 { + b = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalJSON { + 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.OpStructPtrHeadOmitEmptyMarshalJSON: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { + p = ptrToPtr(p) + } + } + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadMarshalText { + 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.OpStructPtrHeadOmitEmptyMarshalText: + p := load(ctxptr, code.Idx) + if p == 0 { + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendNullComma(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 = appendNullComma(ctx, b) + } + code = code.End.Next + break + } + if code.Flags&encoder.AnonymousHeadFlags == 0 { + b = appendStructHead(ctx, b) + } + p += uintptr(code.Offset) + if (code.Flags & encoder.IsNilableTypeFlags) != 0 { + if (code.Flags&encoder.IndirectFlags) != 0 || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { + p = ptrToPtr(p) + } + } + 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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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 = appendNullComma(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.IsTaggedKeyFlags != 0 || 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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 = appendNullComma(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.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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendInt(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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), code.NumBitSize) + v := u64 & ((1 << code.NumBitSize) - 1) + if v != 0 { + b = appendStructKey(ctx, code, b) + b = append(b, '"') + b = appendUint(ctx, b, p+uintptr(code.Offset), 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, 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, 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, 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, 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 0000000..9207d0f --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/errors/error.go @@ -0,0 +1,183 @@ +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, + } +} + +func ErrInvalidBeginningOfValue(c byte, cursor int64) *SyntaxError { + return &SyntaxError{ + msg: fmt.Sprintf("invalid character '%c' looking for beginning of value", c), + Offset: cursor, + } +} + +type PathError struct { + msg string +} + +func (e *PathError) Error() string { + return fmt.Sprintf("json: invalid path format: %s", e.msg) +} + +func ErrInvalidPath(msg string, args ...interface{}) *PathError { + if len(args) != 0 { + return &PathError{msg: fmt.Sprintf(msg, args...)} + } + return &PathError{msg: msg} +} + +func ErrEmptyPath() *PathError { + return &PathError{msg: "path is empty"} +} 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 0000000..37cfe35 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/runtime/rtype.go @@ -0,0 +1,262 @@ +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 + +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 0000000..baab0c5 --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/runtime/struct_field.go @@ -0,0 +1,91 @@ +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 { + t := field.Type + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.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 0000000..4b693cb --- /dev/null +++ b/vendor/github.com/goccy/go-json/internal/runtime/type.go @@ -0,0 +1,98 @@ +package runtime + +import ( + "reflect" + "sync" + "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 + once sync.Once +) + +//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 { + once.Do(func() { + sections, offsets := typelinks() + if len(sections) != 1 { + return + } + if len(offsets) != 1 { + return + } + 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 + } + var addrShift uintptr + if isAligned64 { + addrShift = 6 + } else if isAligned32 { + addrShift = 5 + } + cacheSize := addrRange >> addrShift + if cacheSize > maxAcceptableTypeAddrRange { + return + } + 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 0000000..fb18065 --- /dev/null +++ b/vendor/github.com/goccy/go-json/json.go @@ -0,0 +1,368 @@ +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

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ϊ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