commit ceca244eaf56ed1eef23a0ca82ec77f8eed84d5f Author: yangyudong <916291030@qq.com> Date: Sat Apr 19 22:56:37 2025 +0800 init diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100755 index 0000000..88d0aea --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,51 @@ +# This workflow will build a golang project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go + +name: Go + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + + build: + runs-on: ubuntu-latest + strategy: + matrix: + go-version: ['1.14', 'stable'] + name: Build with Go ${{ matrix.go-version }} + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go-version }} + + - name: Install goveralls + if: ${{ matrix.go-version == 'stable' && github.ref == 'refs/heads/master' }} + run: go install github.com/mattn/goveralls@latest + + - name: Build + run: go build -v ./... + + - name: Test + run: go test -v -covermode atomic -coverprofile=covprofile ./... + + - name: Gofmt + # Run gofmt, print the output and exit with status code 1 if it isn't empty. + run: | + OUTPUT=$(gofmt -d ./) + echo "$OUTPUT" + test -z "$OUTPUT" + + - name: Send coverage + if: ${{ matrix.go-version == 'stable' && github.ref == 'refs/heads/master' }} + env: + COVERALLS_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + run: goveralls -coverprofile=covprofile -service=github diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..939f6a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.flac +*.wav +_resources_ diff --git a/.gitmodules b/.gitmodules new file mode 100755 index 0000000..aa52eb0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "flac-test-files"] + path = testdata/flac-test-files + url = https://github.com/ietf-wg-cellar/flac-test-files diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..68a49da --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to diff --git a/README.md b/README.md new file mode 100755 index 0000000..dc09430 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# flac + +[![Go build status](https://github.com/mewkiz/flac/actions/workflows/go.yml/badge.svg?branch=master)](https://github.com/mewkiz/flac/actions/workflows/go.yml) +[![Coverage Status](https://coveralls.io/repos/github/mewkiz/flac/badge.svg?branch=master)](https://coveralls.io/github/mewkiz/flac?branch=master) +[![GoDoc](https://pkg.go.dev/badge/github.com/mewkiz/flac)](https://pkg.go.dev/github.com/mewkiz/flac) + +This package provides access to [FLAC][1] (Free Lossless Audio Codec) streams. + +[1]: http://flac.sourceforge.net/format.html + +## Documentation + +Documentation provided by GoDoc. + +- [flac]: provides access to FLAC (Free Lossless Audio Codec) streams. + - [frame][flac/frame]: implements access to FLAC audio frames. + - [meta][flac/meta]: implements access to FLAC metadata blocks. + +[flac]: http://pkg.go.dev/github.com/mewkiz/flac +[flac/frame]: http://pkg.go.dev/github.com/mewkiz/flac/frame +[flac/meta]: http://pkg.go.dev/github.com/mewkiz/flac/meta + +## Changes + +* Version 1.0.12 (2024-08-11) + - Improve performance of flac.NewSeek() by using a buffered reader (see [#72](https://github.com/mewkiz/flac/pull/72)). + - Fix off-by-one error in Seek end of stream check (see [#73](https://github.com/mewkiz/flac/pull/73)). + +* Version 1.0.11 (2024-08-04) + - Move example tools to dedicated [mewkiz/flac-tools](https://github.com/mewkiz/flac-tools) repository to reduce external dependencies (see [#62](https://github.com/mewkiz/flac/pull/62)). + - Fix seek to frame start (see [#71](https://github.com/mewkiz/flac/pull/71)). Thanks to [Mark Kremer](https://github.com/MarkKremer). + - Simplify internal handling of io.Closer element in flac.Stream and flac.Encoder types (see [#70](https://github.com/mewkiz/flac/pull/70)). Thanks to [Mario Salgado](https://github.com/zalgonoise). + +* Version 1.0.10 (2023-11-11) + - Add support for LPC audio sample encoding (see [#66](https://github.com/mewkiz/flac/pull/66)). Thanks to [Mark Kremer](https://github.com/MarkKremer) for bug fixes and [Mattias Wadman](https://github.com/wader) for the invaluable [fq](https://github.com/wader/fq) tool used to investigate FLAC encoding issues. + - Replace Travis CI with GitHub actions for CI build status, test status and code coverage [#64](https://github.com/mewkiz/flac/pull/64)). Thanks to [Mark Kremer](https://github.com/MarkKremer). + +* Version 1.0.9 (2023-10-24) + - Fix integer overflow during unfolding of rice residual (see [#61](https://github.com/mewkiz/flac/pull/61)). Thanks to [Mark Kremer](https://github.com/MarkKremer). + - Fix decoding of escaped partition audio samples (see [#60](https://github.com/mewkiz/flac/issues/60)). Thanks to [Mark Kremer](https://github.com/MarkKremer). + - Handle frame hashing of audio samples with bits-per-sample not evenly divisible by 8 (see [9d50c9e](https://github.com/mewkiz/flac/commit/9d50c9ee99ba322f487ed60442dc16f22b2affb8)). + +* Version 1.0.8 (2023-04-09) + - Fix race condition when reading meta data (see [#56](https://github.com/mewkiz/flac/pull/56)). Thanks to [Zach Orosz](https://github.com/zachorosz). + - Fix encoding of 8-bps WAV audio samples (see [#52](https://github.com/mewkiz/flac/pull/52)). Thanks to [Martijn van Beurden](https://github.com/ktmf01). + - Fix StreamInfo block type error message (see [#49](https://github.com/mewkiz/flac/pull/49)). + +* Version 1.0.7 (2021-01-28) + - Add seek API (see [#44](https://github.com/mewkiz/flac/pull/44) and [#46](https://github.com/mewkiz/flac/pull/46)). Thanks to [Craig Swank](https://github.com/cswank). + +* Version 1.0.6 (2019-12-20) + - Add experimental Encoder API to encode audio samples and metadata blocks (see [#32](https://github.com/mewkiz/flac/pull/32)). + - Use go.mod. + - Skip ID3v2 data prepended to flac files when parsing (see [36cc17e](https://github.com/mewkiz/flac/commit/36cc17efed51a9bae283d6a3a7a10997492945e7)). + - Remove dependency on encodebytes. Thanks to [Mikey Dickerson](https://github.com/mdickers47). + - Add 16kHz test case. Thanks to [Chewxy](https://github.com/chewxy). + - Fix lint issues (see [#25](https://github.com/mewkiz/flac/issues/25)). + +* Version 1.0.5 (2016-05-06) + - Simplify import paths. Drop use of gopkg.in, and rely on vendoring instead (see [azul3d/engine#1](https://github.com/azul3d/engine/issues/1)). + - Add FLAC decoding benchmark (see [d675e0a](https://github.com/mewkiz/flac/blob/d675e0aaccf2e43055f56b9b3feeddfdeed402e2/frame/frame_test.go#L60)). + +* Version 1.0.4 (2016-02-11) + - Add API examples to documentation (see [#11](https://github.com/mewkiz/flac/issues/11)). + - Extend test cases (see [aadf80a](https://github.com/mewkiz/flac/commit/aadf80aa28c463a94b8d5c49757e5a0948613ce2)). + +* Version 1.0.3 (2016-02-02) + - Implement decoding of FLAC files with wasted bits-per-sample (see [#12](https://github.com/mewkiz/flac/issues/12)). + - Stress test the library using [go-fuzz](https://github.com/dvyukov/go-fuzz) (see [#10](https://github.com/mewkiz/flac/pull/10)). Thanks to [Patrick Mézard](https://github.com/pmezard). + +* Version 1.0.2 (2015-06-05) + - Fix decoding of blocking strategy (see [#9](https://github.com/mewkiz/flac/pull/9)). Thanks to [Sergey Didyk](https://github.com/sdidyk). + +* Version 1.0.1 (2015-02-25) + - Fix two subframe decoding bugs (see [#7](https://github.com/mewkiz/flac/pull/7)). Thanks to [Jonathan MacMillan](https://github.com/perotinus). + - Add frame decoding test cases. + +* Version 1.0.0 (2014-09-30) + - Initial release. + - Implement decoding of FLAC files. diff --git a/enc_test.go b/enc_test.go new file mode 100755 index 0000000..de1acb6 --- /dev/null +++ b/enc_test.go @@ -0,0 +1,230 @@ +package flac_test + +import ( + "bytes" + "io" + "io/ioutil" + "testing" + + "github.com/mewkiz/flac" + "github.com/mewkiz/flac/meta" +) + +func TestEncode(t *testing.T) { + paths := []string{ + // metadata test cases. + "meta/testdata/input-SCPAP.flac", + "meta/testdata/input-SCVA.flac", + "meta/testdata/input-SCVPAP.flac", + "meta/testdata/input-VA.flac", + "meta/testdata/input-SCVAUP.flac", // empty metadata block (of type 0x7e) + "meta/testdata/input-SVAUP.flac", // empty metadata block (of type 0x7e) + "meta/testdata/silence.flac", + // flac test cases. + "testdata/19875.flac", // prediction method 3 (FIR) + "testdata/44127.flac", // prediction method 3 (FIR) + "testdata/59996.flac", + "testdata/80574.flac", // prediction method 3 (FIR) + "testdata/172960.flac", + "testdata/189983.flac", + "testdata/191885.flac", + "testdata/212768.flac", + "testdata/220014.flac", // prediction method 2 (Fixed) + "testdata/243749.flac", // prediction method 2 (Fixed) + "testdata/256529.flac", + "testdata/257344.flac", // prediction method 3 (FIR) + "testdata/8297-275156-0011.flac", // prediction method 3 (FIR) + "testdata/love.flac", // wasted bits + // IETF test cases. + "testdata/flac-test-files/subset/01 - blocksize 4096.flac", + "testdata/flac-test-files/subset/02 - blocksize 4608.flac", + "testdata/flac-test-files/subset/03 - blocksize 16.flac", + "testdata/flac-test-files/subset/04 - blocksize 192.flac", + "testdata/flac-test-files/subset/05 - blocksize 254.flac", + "testdata/flac-test-files/subset/06 - blocksize 512.flac", + "testdata/flac-test-files/subset/07 - blocksize 725.flac", + "testdata/flac-test-files/subset/08 - blocksize 1000.flac", + "testdata/flac-test-files/subset/09 - blocksize 1937.flac", + "testdata/flac-test-files/subset/10 - blocksize 2304.flac", + "testdata/flac-test-files/subset/11 - partition order 8.flac", + "testdata/flac-test-files/subset/12 - qlp precision 15 bit.flac", + "testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac", + "testdata/flac-test-files/subset/14 - wasted bits.flac", + "testdata/flac-test-files/subset/15 - only verbatim subframes.flac", + "testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac", + "testdata/flac-test-files/subset/17 - all fixed orders.flac", + "testdata/flac-test-files/subset/18 - precision search.flac", + "testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac", + "testdata/flac-test-files/subset/20 - samplerate 39kHz.flac", + "testdata/flac-test-files/subset/21 - samplerate 22050Hz.flac", + "testdata/flac-test-files/subset/22 - 12 bit per sample.flac", + "testdata/flac-test-files/subset/23 - 8 bit per sample.flac", + "testdata/flac-test-files/subset/24 - variable blocksize file created with flake revision 264.flac", + "testdata/flac-test-files/subset/25 - variable blocksize file created with flake revision 264, modified to create smaller blocks.flac", + // NOTE: the only diff is that "26 - ...flac" uses `block_size: 0b111 + // (end of header (16 bit))` to encode the block size at the end of the + // header, whereas mewkiz/flac encodes it directly `block_size: 4096 + // (0b1100)`. Notably, the computed md5 hash of the decoded audio samples + // is identical (MD5: 3b2939b39ae7369b80451c77865e60c1). Thus, ignore the + // test case. + //"testdata/flac-test-files/subset/26 - variable blocksize file created with CUETools.Flake 2.1.6.flac", + // NOTE: the only diff is that "27 - ...flac" uses `block_size: 0b111 + // (end of header (16 bit))` to encode the block size at the end of the + // header, whereas mewkiz/flac encodes it directly `block_size: 4608 + // (0b101)`. Notably, the computed md5 hash of the decoded audio samples + // is identical (MD5: 9fb66177d2f735d4b1f501a5af1320a3). Thus, ignore the + // test case. + //"testdata/flac-test-files/subset/27 - old format variable blocksize file created with Flake 0.11.flac", + "testdata/flac-test-files/subset/28 - high resolution audio, default settings.flac", + "testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac", + "testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac", + "testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac", + "testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac", + "testdata/flac-test-files/subset/33 - samplerate 192kHz.flac", + // NOTE: the only diff is that "34 - ...flac" uses `0b1100 (end of header + // (8 bit*1000))` to encode the sample rate at the end of the header, + // whereas mewkiz/flac encodes it directly `192000 (0b11)`. Notably, the + // computed md5 hash of the decoded audio samples is identical + // (MD5: 942f56e503437dfd4c269c331774b2e3). Thus, ignore the test case. + //"testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac", + "testdata/flac-test-files/subset/35 - samplerate 134560Hz.flac", + "testdata/flac-test-files/subset/36 - samplerate 384kHz.flac", + "testdata/flac-test-files/subset/37 - 20 bit per sample.flac", + "testdata/flac-test-files/subset/38 - 3 channels (3.0).flac", + "testdata/flac-test-files/subset/39 - 4 channels (4.0).flac", + "testdata/flac-test-files/subset/40 - 5 channels (5.0).flac", + "testdata/flac-test-files/subset/41 - 6 channels (5.1).flac", + "testdata/flac-test-files/subset/42 - 7 channels (6.1).flac", + "testdata/flac-test-files/subset/43 - 8 channels (7.1).flac", + // NOTE: the only diff is that "44 - ...flac" uses `0b1100 (end of header + // (8 bit*1000))` to encode the sample rate at the end of the header, + // whereas mewkiz/flac encodes it directly `192000 (0b11)`. Notably, the + // computed md5 hash of the decoded audio samples is identical + // (MD5: cdf531d4d4b95233986bc499518a89db). Thus, ignore the test case. + //"testdata/flac-test-files/subset/44 - 8-channel surround, 192kHz, 24 bit, using only 32nd order predictors.flac", + "testdata/flac-test-files/subset/45 - no total number of samples set.flac", + "testdata/flac-test-files/subset/46 - no min-max framesize set.flac", + "testdata/flac-test-files/subset/47 - only STREAMINFO.flac", + "testdata/flac-test-files/subset/48 - Extremely large SEEKTABLE.flac", + "testdata/flac-test-files/subset/49 - Extremely large PADDING.flac", + "testdata/flac-test-files/subset/50 - Extremely large PICTURE.flac", + "testdata/flac-test-files/subset/51 - Extremely large VORBISCOMMENT.flac", + "testdata/flac-test-files/subset/52 - Extremely large APPLICATION.flac", + "testdata/flac-test-files/subset/53 - CUESHEET with very many indexes.flac", + "testdata/flac-test-files/subset/54 - 1000x repeating VORBISCOMMENT.flac", + "testdata/flac-test-files/subset/55 - file 48-53 combined.flac", + "testdata/flac-test-files/subset/56 - JPG PICTURE.flac", + "testdata/flac-test-files/subset/57 - PNG PICTURE.flac", + "testdata/flac-test-files/subset/58 - GIF PICTURE.flac", + "testdata/flac-test-files/subset/59 - AVIF PICTURE.flac", + "testdata/flac-test-files/subset/60 - mono audio.flac", + "testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac", + "testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac", + "testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac", + "testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac", + } + for _, path := range paths { + t.Run(path, func(t *testing.T) { + // Decode source file. + stream, err := flac.ParseFile(path) + if err != nil { + t.Fatalf("%q: unable to parse FLAC file; %v", path, err) + } + defer stream.Close() + + // Open encoder for FLAC stream. + out := new(bytes.Buffer) + enc, err := flac.NewEncoder(out, stream.Info, stream.Blocks...) + if err != nil { + t.Fatalf("%q: unable to create encoder for FLAC stream; %v", path, err) + } + // Encode audio samples. + for { + frame, err := stream.ParseNext() + if err != nil { + if err == io.EOF { + break + } + t.Fatalf("%q: unable to parse audio frame of FLAC stream; %v", path, err) + } + if err := enc.WriteFrame(frame); err != nil { + t.Fatalf("%q: unable to encode audio frame of FLAC stream; %v", path, err) + } + } + // Close encoder and flush pending writes. + if err := enc.Close(); err != nil { + t.Fatalf("%q: unable to close encoder for FLAC stream; %v", path, err) + } + + // Compare source and destination FLAC streams. + want, err := ioutil.ReadFile(path) + if err != nil { + t.Fatalf("%q: unable to read file; %v", path, err) + } + got := out.Bytes() + if !bytes.Equal(got, want) { + t.Fatalf("%q: content mismatch; expected % X, got % X", path, want, got) + } + }) + } +} + +func TestEncodeComment(t *testing.T) { + // Decode FLAC file. + const path = "meta/testdata/input-VA.flac" + src, err := flac.ParseFile(path) + if err != nil { + t.Fatalf("unable to parse input FLAC file; %v", err) + } + defer src.Close() + + // Add custom vorbis comment. + const want = "FLAC encoding test case" + for _, block := range src.Blocks { + if comment, ok := block.Body.(*meta.VorbisComment); ok { + comment.Vendor = want + } + } + + // Open encoder for FLAC stream. + out := new(bytes.Buffer) + enc, err := flac.NewEncoder(out, src.Info, src.Blocks...) + if err != nil { + t.Fatalf("%q: unable to create encoder for FLAC stream; %v", path, err) + } + // Encode audio samples. + for { + frame, err := src.ParseNext() + if err != nil { + if err == io.EOF { + break + } + t.Fatalf("%q: unable to parse audio frame of FLAC stream; %v", path, err) + } + if err := enc.WriteFrame(frame); err != nil { + t.Fatalf("%q: unable to encode audio frame of FLAC stream; %v", path, err) + } + } + // Close encoder and flush pending writes. + if err := enc.Close(); err != nil { + t.Fatalf("%q: unable to close encoder for FLAC stream; %v", path, err) + } + + // Parse encoded FLAC file. + stream, err := flac.Parse(out) + if err != nil { + t.Fatalf("unable to parse output FLAC file; %v", err) + } + defer stream.Close() + + // Add custom vorbis comment. + for _, block := range stream.Blocks { + if comment, ok := block.Body.(*meta.VorbisComment); ok { + got := comment.Vendor + if got != want { + t.Errorf("Vorbis comment mismatch; expected %q, got %q", want, got) + continue + } + } + } +} diff --git a/encode.go b/encode.go new file mode 100755 index 0000000..892d7a7 --- /dev/null +++ b/encode.go @@ -0,0 +1,105 @@ +package flac + +import ( + "crypto/md5" + "hash" + "io" + + "github.com/icza/bitio" + "github.com/mewkiz/flac/meta" + "github.com/mewkiz/pkg/errutil" +) + +// An Encoder represents a FLAC encoder. +type Encoder struct { + // FLAC stream of encoder. + *Stream + // Underlying io.Writer or io.WriteCloser to the output stream. + w io.Writer + // Minimum and maximum block size (in samples) of frames written by encoder. + blockSizeMin, blockSizeMax uint16 + // Minimum and maximum frame size (in bytes) of frames written by encoder. + frameSizeMin, frameSizeMax uint32 + // MD5 running hash of unencoded audio samples. + md5sum hash.Hash + // Total number of samples (per channel) written by encoder. + nsamples uint64 + // Current frame number if block size is fixed, and the first sample number + // of the current frame otherwise. + curNum uint64 +} + +// NewEncoder returns a new FLAC encoder for the given metadata StreamInfo block +// and optional metadata blocks. +func NewEncoder(w io.Writer, info *meta.StreamInfo, blocks ...*meta.Block) (*Encoder, error) { + // Store FLAC signature. + enc := &Encoder{ + Stream: &Stream{ + Info: info, + Blocks: blocks, + }, + w: w, + md5sum: md5.New(), + } + + bw := bitio.NewWriter(w) + if _, err := bw.Write(flacSignature); err != nil { + return nil, errutil.Err(err) + } + // Encode metadata blocks. + // TODO: consider using bufio.NewWriter. + if err := encodeStreamInfo(bw, info, len(blocks) == 0); err != nil { + return nil, errutil.Err(err) + } + for i, block := range blocks { + if err := encodeBlock(bw, block, i == len(blocks)-1); err != nil { + return nil, errutil.Err(err) + } + } + // Flush pending writes of metadata blocks. + if _, err := bw.Align(); err != nil { + return nil, errutil.Err(err) + } + // Return encoder to be used for encoding audio samples. + return enc, nil +} + +// Close closes the underlying io.Writer of the encoder and flushes any pending +// writes. If the io.Writer implements io.Seeker, the encoder will update the +// StreamInfo metadata block with the MD5 checksum of the unencoded audio +// samples, the number of samples, and the minimum and maximum frame size and +// block size. +func (enc *Encoder) Close() error { + // TODO: check if bit writer should be flushed before seeking on enc.w. + // Update StreamInfo metadata block. + if ws, ok := enc.w.(io.WriteSeeker); ok { + if _, err := ws.Seek(int64(len(flacSignature)), io.SeekStart); err != nil { + return errutil.Err(err) + } + // Update minimum and maximum block size (in samples) of FLAC stream. + enc.Info.BlockSizeMin = enc.blockSizeMin + enc.Info.BlockSizeMax = enc.blockSizeMax + // Update minimum and maximum frame size (in bytes) of FLAC stream. + enc.Info.FrameSizeMin = enc.frameSizeMin + enc.Info.FrameSizeMax = enc.frameSizeMax + // Update total number of samples (per channel) of FLAC stream. + enc.Info.NSamples = enc.nsamples + // Update MD5 checksum of the unencoded audio samples. + sum := enc.md5sum.Sum(nil) + for i := range sum { + enc.Info.MD5sum[i] = sum[i] + } + bw := bitio.NewWriter(ws) + // Write updated StreamInfo metadata block to output stream. + if err := encodeStreamInfo(bw, enc.Info, len(enc.Blocks) == 0); err != nil { + return errutil.Err(err) + } + if _, err := bw.Align(); err != nil { + return errutil.Err(err) + } + } + if closer, ok := enc.w.(io.Closer); ok { + return closer.Close() + } + return nil +} diff --git a/encode_frame.go b/encode_frame.go new file mode 100755 index 0000000..8822af1 --- /dev/null +++ b/encode_frame.go @@ -0,0 +1,427 @@ +package flac + +import ( + "encoding/binary" + "io" + "math" + + "github.com/icza/bitio" + "github.com/mewkiz/flac/frame" + "github.com/mewkiz/flac/internal/hashutil/crc16" + "github.com/mewkiz/flac/internal/hashutil/crc8" + "github.com/mewkiz/flac/internal/utf8" + "github.com/mewkiz/pkg/errutil" +) + +// --- [ Frame ] --------------------------------------------------------------- + +// WriteFrame encodes the given audio frame to the output stream. The Num field +// of the frame header is automatically calculated by the encoder. +func (enc *Encoder) WriteFrame(f *frame.Frame) error { + // Sanity checks. + nchannels := int(enc.Info.NChannels) + if nchannels != len(f.Subframes) { + return errutil.Newf("subframe and channel count mismatch; expected %d, got %d", nchannels, len(f.Subframes)) + } + nsamplesPerChannel := f.Subframes[0].NSamples + for i, subframe := range f.Subframes { + if nsamplesPerChannel != len(subframe.Samples) { + return errutil.Newf("invalid number of samples in channel %d; expected %d, got %d", i, nsamplesPerChannel, len(subframe.Samples)) + } + } + if nchannels != f.Channels.Count() { + return errutil.Newf("channel count mismatch; expected %d, got %d", nchannels, f.Channels.Count()) + } + + // Create a new CRC-16 hash writer which adds the data from all write + // operations to a running hash. + h := crc16.NewIBM() + hw := io.MultiWriter(h, enc.w) + + // Encode frame header. + f.Num = enc.curNum + if f.HasFixedBlockSize { + enc.curNum++ + } else { + enc.curNum += uint64(nsamplesPerChannel) + } + enc.nsamples += uint64(nsamplesPerChannel) + blockSize := uint16(nsamplesPerChannel) + if enc.blockSizeMin == 0 || blockSize < enc.blockSizeMin { + enc.blockSizeMin = blockSize + } + if enc.blockSizeMax == 0 || blockSize > enc.blockSizeMax { + enc.blockSizeMax = blockSize + } + // TODO: track number of bytes written to hw, to update values of + // frameSizeMin and frameSizeMax. + // Add unencoded audio samples to running MD5 hash. + f.Hash(enc.md5sum) + if err := enc.encodeFrameHeader(hw, f.Header); err != nil { + return errutil.Err(err) + } + + // Inter-channel decorrelation of subframe samples. + f.Decorrelate() + defer f.Correlate() // NOTE: revert decorrelation of audio samples after encoding is done (to make encode non-destructive). + + // Encode subframes. + bw := bitio.NewWriter(hw) + for channel, subframe := range f.Subframes { + // The side channel requires an extra bit per sample when using + // inter-channel decorrelation. + bps := uint(f.BitsPerSample) + switch f.Channels { + case frame.ChannelsSideRight: + // channel 0 is the side channel. + if channel == 0 { + bps++ + } + case frame.ChannelsLeftSide, frame.ChannelsMidSide: + // channel 1 is the side channel. + if channel == 1 { + bps++ + } + } + + if err := encodeSubframe(bw, f.Header, subframe, bps); err != nil { + return errutil.Err(err) + } + } + + // Zero-padding to byte alignment. + // Flush pending writes to subframe. + if _, err := bw.Align(); err != nil { + return errutil.Err(err) + } + + // CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with 0) of + // everything before the crc, back to and including the frame header sync + // code. + crc := h.Sum16() + if err := binary.Write(enc.w, binary.BigEndian, crc); err != nil { + return errutil.Err(err) + } + + return nil +} + +// --- [ Frame header ] -------------------------------------------------------- + +// encodeFrameHeader encodes the given frame header, writing to w. +func (enc *Encoder) encodeFrameHeader(w io.Writer, hdr frame.Header) error { + // Create a new CRC-8 hash writer which adds the data from all write + // operations to a running hash. + h := crc8.NewATM() + hw := io.MultiWriter(h, w) + bw := bitio.NewWriter(hw) + + // Closing the *bitio.Writer will not close the underlying writer + defer bw.Close() + + // Sync code: 11111111111110 + if err := bw.WriteBits(0x3FFE, 14); err != nil { + return errutil.Err(err) + } + + // Reserved: 0 + if err := bw.WriteBits(0x0, 1); err != nil { + return errutil.Err(err) + } + + // Blocking strategy: + // 0 : fixed-blocksize stream; frame header encodes the frame number + // 1 : variable-blocksize stream; frame header encodes the sample number + if err := bw.WriteBool(!hdr.HasFixedBlockSize); err != nil { + return errutil.Err(err) + } + + // Encode block size. + nblockSizeSuffixBits, err := encodeFrameHeaderBlockSize(bw, hdr.BlockSize) + if err != nil { + return errutil.Err(err) + } + + // Encode sample rate. + sampleRateSuffixBits, nsampleRateSuffixBits, err := encodeFrameHeaderSampleRate(bw, hdr.SampleRate) + if err != nil { + return errutil.Err(err) + } + + // Encode channels assignment. + if err := encodeFrameHeaderChannels(bw, hdr.Channels); err != nil { + return errutil.Err(err) + } + + // Encode bits-per-sample. + if err := encodeFrameHeaderBitsPerSample(bw, hdr.BitsPerSample); err != nil { + return errutil.Err(err) + } + + // Reserved: 0 + if err := bw.WriteBits(0x0, 1); err != nil { + return errutil.Err(err) + } + + // if (variable blocksize) + // <8-56>:"UTF-8" coded sample number (decoded number is 36 bits) + // else + // <8-48>:"UTF-8" coded frame number (decoded number is 31 bits) + if err := utf8.Encode(bw, hdr.Num); err != nil { + return errutil.Err(err) + } + + // Write block size after the frame header (used for uncommon block sizes). + if nblockSizeSuffixBits > 0 { + // 0110 : get 8 bit (blocksize-1) from end of header + // 0111 : get 16 bit (blocksize-1) from end of header + if err := bw.WriteBits(uint64(hdr.BlockSize-1), nblockSizeSuffixBits); err != nil { + return errutil.Err(err) + } + } + + // Write sample rate after the frame header (used for uncommon sample rates). + if nsampleRateSuffixBits > 0 { + if err := bw.WriteBits(sampleRateSuffixBits, nsampleRateSuffixBits); err != nil { + return errutil.Err(err) + } + } + + // Flush pending writes to frame header. + if _, err := bw.Align(); err != nil { + return errutil.Err(err) + } + + // CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) of + // everything before the crc, including the sync code. + crc := h.Sum8() + if err := binary.Write(w, binary.BigEndian, crc); err != nil { + return errutil.Err(err) + } + + return nil +} + +// ~~~ [ Block size ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// encodeFrameHeaderBlockSize encodes the block size of the frame header, +// writing to bw. It returns the number of bits used to store block size after +// the frame header. +func encodeFrameHeaderBlockSize(bw *bitio.Writer, blockSize uint16) (nblockSizeSuffixBits byte, err error) { + // Block size in inter-channel samples: + // 0000 : reserved + // 0001 : 192 samples + // 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608 + // 0110 : get 8 bit (blocksize-1) from end of header + // 0111 : get 16 bit (blocksize-1) from end of header + // 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768 + var bits uint64 + switch blockSize { + case 192: + // 0001 + bits = 0x1 + case 576, 1152, 2304, 4608: + // 0010-0101 : 576 * (2^(n-2)) samples, i.e. 576/1152/2304/4608 + bits = 0x2 + uint64(math.Log2(float64(blockSize/576))) + case 256, 512, 1024, 2048, 4096, 8192, 16384, 32768: + // 1000-1111 : 256 * (2^(n-8)) samples, i.e. 256/512/1024/2048/4096/8192/16384/32768 + bits = 0x8 + uint64(math.Log2(float64(blockSize/256))) + default: + if blockSize <= 256 { + // 0110 : get 8 bit (blocksize-1) from end of header + bits = 0x6 + nblockSizeSuffixBits = 8 + } else { + // 0111 : get 16 bit (blocksize-1) from end of header + bits = 0x7 + nblockSizeSuffixBits = 16 + } + } + if err := bw.WriteBits(bits, 4); err != nil { + return 0, errutil.Err(err) + } + return nblockSizeSuffixBits, nil +} + +// ~~~ [ Sample rate ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// encodeFrameHeaderSampleRate encodes the sample rate of the frame header, +// writing to bw. It returns the bits and the number of bits used to store +// sample rate after the frame header. +func encodeFrameHeaderSampleRate(bw *bitio.Writer, sampleRate uint32) (sampleRateSuffixBits uint64, nsampleRateSuffixBits byte, err error) { + // Sample rate: + // 0000 : get from STREAMINFO metadata block + // 0001 : 88.2kHz + // 0010 : 176.4kHz + // 0011 : 192kHz + // 0100 : 8kHz + // 0101 : 16kHz + // 0110 : 22.05kHz + // 0111 : 24kHz + // 1000 : 32kHz + // 1001 : 44.1kHz + // 1010 : 48kHz + // 1011 : 96kHz + // 1100 : get 8 bit sample rate (in kHz) from end of header + // 1101 : get 16 bit sample rate (in Hz) from end of header + // 1110 : get 16 bit sample rate (in tens of Hz) from end of header + // 1111 : invalid, to prevent sync-fooling string of 1s + var bits uint64 + switch sampleRate { + case 0: + // 0000 : get from STREAMINFO metadata block + bits = 0 + case 88200: + // 0001 : 88.2kHz + bits = 0x1 + case 176400: + // 0010 : 176.4kHz + bits = 0x2 + case 192000: + // 0011 : 192kHz + bits = 0x3 + case 8000: + // 0100 : 8kHz + bits = 0x4 + case 16000: + // 0101 : 16kHz + bits = 0x5 + case 22050: + // 0110 : 22.05kHz + bits = 0x6 + case 24000: + // 0111 : 24kHz + bits = 0x7 + case 32000: + // 1000 : 32kHz + bits = 0x8 + case 44100: + // 1001 : 44.1kHz + bits = 0x9 + case 48000: + // 1010 : 48kHz + bits = 0xA + case 96000: + // 1011 : 96kHz + bits = 0xB + default: + switch { + case sampleRate <= 255000 && sampleRate%1000 == 0: + // 1100 : get 8 bit sample rate (in kHz) from end of header + bits = 0xC + sampleRateSuffixBits = uint64(sampleRate / 1000) + nsampleRateSuffixBits = 8 + case sampleRate <= 65535: + // 1101 : get 16 bit sample rate (in Hz) from end of header + bits = 0xD + sampleRateSuffixBits = uint64(sampleRate) + nsampleRateSuffixBits = 16 + case sampleRate <= 655350 && sampleRate%10 == 0: + // 1110 : get 16 bit sample rate (in tens of Hz) from end of header + bits = 0xE + sampleRateSuffixBits = uint64(sampleRate / 10) + nsampleRateSuffixBits = 16 + default: + return 0, 0, errutil.Newf("unable to encode sample rate %v", sampleRate) + } + } + if err := bw.WriteBits(bits, 4); err != nil { + return 0, 0, errutil.Err(err) + } + return sampleRateSuffixBits, nsampleRateSuffixBits, nil +} + +// ~~~ [ Channels assignment ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// encodeFrameHeaderChannels encodes the channels assignment of the frame +// header, writing to bw. +func encodeFrameHeaderChannels(bw *bitio.Writer, channels frame.Channels) error { + // Channel assignment. + // 0000-0111 : (number of independent channels)-1. Where defined, the channel order follows SMPTE/ITU-R recommendations. The assignments are as follows: + // 1 channel: mono + // 2 channels: left, right + // 3 channels: left, right, center + // 4 channels: front left, front right, back left, back right + // 5 channels: front left, front right, front center, back/surround left, back/surround right + // 6 channels: front left, front right, front center, LFE, back/surround left, back/surround right + // 7 channels: front left, front right, front center, LFE, back center, side left, side right + // 8 channels: front left, front right, front center, LFE, back left, back right, side left, side right + // 1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel + // 1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel + // 1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel + // 1011-1111 : reserved + var bits uint64 + switch channels { + case frame.ChannelsMono, frame.ChannelsLR, frame.ChannelsLRC, frame.ChannelsLRLsRs, frame.ChannelsLRCLsRs, frame.ChannelsLRCLfeLsRs, frame.ChannelsLRCLfeCsSlSr, frame.ChannelsLRCLfeLsRsSlSr: + // 1 channel: mono. + // 2 channels: left, right. + // 3 channels: left, right, center. + // 4 channels: left, right, left surround, right surround. + // 5 channels: left, right, center, left surround, right surround. + // 6 channels: left, right, center, LFE, left surround, right surround. + // 7 channels: left, right, center, LFE, center surround, side left, side right. + // 8 channels: left, right, center, LFE, left surround, right surround, side left, side right. + bits = uint64(channels.Count() - 1) + case frame.ChannelsLeftSide: + // 2 channels: left, side; using inter-channel decorrelation. + // 1000 : left/side stereo: channel 0 is the left channel, channel 1 is the side(difference) channel + bits = 0x8 + case frame.ChannelsSideRight: + // 2 channels: side, right; using inter-channel decorrelation. + // 1001 : right/side stereo: channel 0 is the side(difference) channel, channel 1 is the right channel + bits = 0x9 + case frame.ChannelsMidSide: + // 2 channels: mid, side; using inter-channel decorrelation. + // 1010 : mid/side stereo: channel 0 is the mid(average) channel, channel 1 is the side(difference) channel + bits = 0xA + default: + return errutil.Newf("support for channel assignment %v not yet implemented", channels) + } + if err := bw.WriteBits(bits, 4); err != nil { + return errutil.Err(err) + } + return nil +} + +// ~~~ [ Bits-per-sample ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// encodeFrameHeaderBitsPerSample encodes the bits-per-sample of the frame +// header, writing to bw. +func encodeFrameHeaderBitsPerSample(bw *bitio.Writer, bps uint8) error { + // Sample size in bits: + // 000 : get from STREAMINFO metadata block + // 001 : 8 bits per sample + // 010 : 12 bits per sample + // 011 : reserved + // 100 : 16 bits per sample + // 101 : 20 bits per sample + // 110 : 24 bits per sample + // 111 : reserved + var bits uint64 + switch bps { + case 0: + // 000 : get from STREAMINFO metadata block + bits = 0x0 + case 8: + // 001 : 8 bits per sample + bits = 0x1 + case 12: + // 010 : 12 bits per sample + bits = 0x2 + case 16: + // 100 : 16 bits per sample + bits = 0x4 + case 20: + // 101 : 20 bits per sample + bits = 0x5 + case 24: + // 110 : 24 bits per sample + bits = 0x6 + default: + return errutil.Newf("support for sample size %v not yet implemented", bps) + } + if err := bw.WriteBits(bits, 3); err != nil { + return errutil.Err(err) + } + return nil +} diff --git a/encode_meta.go b/encode_meta.go new file mode 100755 index 0000000..2a7edfe --- /dev/null +++ b/encode_meta.go @@ -0,0 +1,419 @@ +package flac + +import ( + "encoding/binary" + "fmt" + "io" + + "github.com/icza/bitio" + "github.com/mewkiz/flac/internal/ioutilx" + "github.com/mewkiz/flac/meta" + "github.com/mewkiz/pkg/errutil" +) + +// --- [ Metadata block ] ------------------------------------------------------ + +// encodeBlock encodes the metadata block, writing to bw. +func encodeBlock(bw *bitio.Writer, block *meta.Block, last bool) error { + if block.Type == meta.TypePadding { + return encodePadding(bw, block.Length, last) + } + if block.Length == 0 { + return encodeEmptyBlock(bw, block.Type, last) + } + switch body := block.Body.(type) { + case *meta.StreamInfo: + return encodeStreamInfo(bw, body, last) + case *meta.Application: + return encodeApplication(bw, body, last) + case *meta.SeekTable: + return encodeSeekTable(bw, body, last) + case *meta.VorbisComment: + return encodeVorbisComment(bw, body, last) + case *meta.CueSheet: + return encodeCueSheet(bw, body, last) + case *meta.Picture: + return encodePicture(bw, body, last) + default: + panic(fmt.Errorf("support for metadata block body type %T not yet implemented", body)) + } +} + +// --- [ Metadata block header ] ----------------------------------------------- + +// encodeEmptyBlock encodes the metadata block header of an empty metadata +// block with the specified type, writing to bw. +func encodeEmptyBlock(bw *bitio.Writer, typ meta.Type, last bool) error { + // Store metadata block header. + hdr := &meta.Header{ + IsLast: last, + Type: typ, + Length: 0, + } + if err := encodeBlockHeader(bw, hdr); err != nil { + return errutil.Err(err) + } + return nil +} + +// --- [ Metadata block header ] ----------------------------------------------- + +// encodeBlockHeader encodes the metadata block header, writing to bw. +func encodeBlockHeader(bw *bitio.Writer, hdr *meta.Header) error { + // 1 bit: IsLast. + if err := bw.WriteBool(hdr.IsLast); err != nil { + return errutil.Err(err) + } + // 7 bits: Type. + if err := bw.WriteBits(uint64(hdr.Type), 7); err != nil { + return errutil.Err(err) + } + // 24 bits: Length. + if err := bw.WriteBits(uint64(hdr.Length), 24); err != nil { + return errutil.Err(err) + } + return nil +} + +// --- [ StreamInfo ] ---------------------------------------------------------- + +// encodeStreamInfo encodes the StreamInfo metadata block, writing to bw. +func encodeStreamInfo(bw *bitio.Writer, info *meta.StreamInfo, last bool) error { + // Store metadata block header. + const nbits = 16 + 16 + 24 + 24 + 20 + 3 + 5 + 36 + 8*16 + hdr := &meta.Header{ + IsLast: last, + Type: meta.TypeStreamInfo, + Length: nbits / 8, + } + if err := encodeBlockHeader(bw, hdr); err != nil { + return errutil.Err(err) + } + + // Store metadata block body. + // 16 bits: BlockSizeMin. + if err := bw.WriteBits(uint64(info.BlockSizeMin), 16); err != nil { + return errutil.Err(err) + } + // 16 bits: BlockSizeMax. + if err := bw.WriteBits(uint64(info.BlockSizeMax), 16); err != nil { + return errutil.Err(err) + } + // 24 bits: FrameSizeMin. + if err := bw.WriteBits(uint64(info.FrameSizeMin), 24); err != nil { + return errutil.Err(err) + } + // 24 bits: FrameSizeMax. + if err := bw.WriteBits(uint64(info.FrameSizeMax), 24); err != nil { + return errutil.Err(err) + } + // 20 bits: SampleRate. + if err := bw.WriteBits(uint64(info.SampleRate), 20); err != nil { + return errutil.Err(err) + } + // 3 bits: NChannels; stored as (number of channels) - 1. + if err := bw.WriteBits(uint64(info.NChannels-1), 3); err != nil { + return errutil.Err(err) + } + // 5 bits: BitsPerSample; stored as (bits-per-sample) - 1. + if err := bw.WriteBits(uint64(info.BitsPerSample-1), 5); err != nil { + return errutil.Err(err) + } + // 36 bits: NSamples. + if err := bw.WriteBits(info.NSamples, 36); err != nil { + return errutil.Err(err) + } + // 16 bytes: MD5sum. + if _, err := bw.Write(info.MD5sum[:]); err != nil { + return errutil.Err(err) + } + return nil +} + +// --- [ Padding ] ---------------------------------------------------------- + +// encodePadding encodes the Padding metadata block, writing to bw. +func encodePadding(bw *bitio.Writer, length int64, last bool) error { + // Store metadata block header. + hdr := &meta.Header{ + IsLast: last, + Type: meta.TypePadding, + Length: length, + } + if err := encodeBlockHeader(bw, hdr); err != nil { + return errutil.Err(err) + } + // Store metadata block body. + if _, err := io.CopyN(bw, ioutilx.Zero, length); err != nil { + return errutil.Err(err) + } + return nil +} + +// --- [ Application ] --------------------------------------------------------- + +// encodeApplication encodes the Application metadata block, writing to bw. +func encodeApplication(bw *bitio.Writer, app *meta.Application, last bool) error { + // Store metadata block header. + nbits := int64(32 + 8*len(app.Data)) + hdr := &meta.Header{ + IsLast: last, + Type: meta.TypeApplication, + Length: nbits / 8, + } + if err := encodeBlockHeader(bw, hdr); err != nil { + return errutil.Err(err) + } + + // Store metadata block body. + // 32 bits: ID. + if err := bw.WriteBits(uint64(app.ID), 32); err != nil { + return errutil.Err(err) + } + // TODO: check if the Application block may contain only an ID. + if _, err := bw.Write(app.Data); err != nil { + return errutil.Err(err) + } + return nil +} + +// --- [ SeekTable ] ----------------------------------------------------------- + +// encodeSeekTable encodes the SeekTable metadata block, writing to bw. +func encodeSeekTable(bw *bitio.Writer, table *meta.SeekTable, last bool) error { + // Store metadata block header. + nbits := int64((64 + 64 + 16) * len(table.Points)) + hdr := &meta.Header{ + IsLast: last, + Type: meta.TypeSeekTable, + Length: nbits / 8, + } + if err := encodeBlockHeader(bw, hdr); err != nil { + return errutil.Err(err) + } + + // Store metadata block body. + for _, point := range table.Points { + if err := binary.Write(bw, binary.BigEndian, point); err != nil { + return errutil.Err(err) + } + } + return nil +} + +// --- [ VorbisComment ] ------------------------------------------------------- + +// encodeVorbisComment encodes the VorbisComment metadata block, writing to bw. +func encodeVorbisComment(bw *bitio.Writer, comment *meta.VorbisComment, last bool) error { + // Store metadata block header. + nbits := int64(32 + 8*len(comment.Vendor) + 32) + for _, tag := range comment.Tags { + nbits += int64(32 + 8*(len(tag[0])+1+len(tag[1]))) + } + hdr := &meta.Header{ + IsLast: last, + Type: meta.TypeVorbisComment, + Length: nbits / 8, + } + if err := encodeBlockHeader(bw, hdr); err != nil { + return errutil.Err(err) + } + + // Store metadata block body. + // 32 bits: vendor length. + // TODO: verify that little-endian encoding is used; otherwise, switch to + // using bw.WriteBits. + if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Vendor))); err != nil { + return errutil.Err(err) + } + // (vendor length) bits: Vendor. + if _, err := bw.Write([]byte(comment.Vendor)); err != nil { + return errutil.Err(err) + } + // Store tags. + // 32 bits: number of tags. + if err := binary.Write(bw, binary.LittleEndian, uint32(len(comment.Tags))); err != nil { + return errutil.Err(err) + } + for _, tag := range comment.Tags { + // Store tag, which has the following format: + // NAME=VALUE + buf := []byte(fmt.Sprintf("%s=%s", tag[0], tag[1])) + // 32 bits: vector length + if err := binary.Write(bw, binary.LittleEndian, uint32(len(buf))); err != nil { + return errutil.Err(err) + } + // (vector length): vector. + if _, err := bw.Write(buf); err != nil { + return errutil.Err(err) + } + } + return nil +} + +// --- [ CueSheet ] ------------------------------------------------------------ + +// encodeCueSheet encodes the CueSheet metadata block, writing to bw. +func encodeCueSheet(bw *bitio.Writer, cs *meta.CueSheet, last bool) error { + // Store metadata block header. + nbits := int64(8*128 + 64 + 1 + 7 + 8*258 + 8) + for _, track := range cs.Tracks { + nbits += 64 + 8 + 8*12 + 1 + 1 + 6 + 8*13 + 8 + for range track.Indicies { + nbits += 64 + 8 + 8*3 + } + } + hdr := &meta.Header{ + IsLast: last, + Type: meta.TypeCueSheet, + Length: nbits / 8, + } + if err := encodeBlockHeader(bw, hdr); err != nil { + return errutil.Err(err) + } + + // Store metadata block body. + // Store cue sheet. + // 128 bytes: MCN. + var mcn [128]byte + copy(mcn[:], cs.MCN) + if _, err := bw.Write(mcn[:]); err != nil { + return errutil.Err(err) + } + // 64 bits: NLeadInSamples. + if err := bw.WriteBits(cs.NLeadInSamples, 64); err != nil { + return errutil.Err(err) + } + // 1 bit: IsCompactDisc. + if err := bw.WriteBool(cs.IsCompactDisc); err != nil { + return errutil.Err(err) + } + // 7 bits and 258 bytes: reserved. + if err := bw.WriteBits(0, 7); err != nil { + return errutil.Err(err) + } + if _, err := io.CopyN(bw, ioutilx.Zero, 258); err != nil { + return errutil.Err(err) + } + // Store cue sheet tracks. + // 8 bits: (number of tracks) + if err := bw.WriteBits(uint64(len(cs.Tracks)), 8); err != nil { + return errutil.Err(err) + } + for _, track := range cs.Tracks { + // 64 bits: Offset. + if err := bw.WriteBits(track.Offset, 64); err != nil { + return errutil.Err(err) + } + // 8 bits: Num. + if err := bw.WriteBits(uint64(track.Num), 8); err != nil { + return errutil.Err(err) + } + // 12 bytes: ISRC. + var isrc [12]byte + copy(isrc[:], track.ISRC) + if _, err := bw.Write(isrc[:]); err != nil { + return errutil.Err(err) + } + // 1 bit: IsAudio. + if err := bw.WriteBool(!track.IsAudio); err != nil { + return errutil.Err(err) + } + // 1 bit: HasPreEmphasis. + // mask = 01000000 + if err := bw.WriteBool(track.HasPreEmphasis); err != nil { + return errutil.Err(err) + } + // 6 bits and 13 bytes: reserved. + // mask = 00111111 + if err := bw.WriteBits(0, 6); err != nil { + return errutil.Err(err) + } + if _, err := io.CopyN(bw, ioutilx.Zero, 13); err != nil { + return errutil.Err(err) + } + // Store indicies. + // 8 bits: (number of indicies) + if err := bw.WriteBits(uint64(len(track.Indicies)), 8); err != nil { + return errutil.Err(err) + } + for _, index := range track.Indicies { + // 64 bits: Offset. + if err := bw.WriteBits(index.Offset, 64); err != nil { + return errutil.Err(err) + } + // 8 bits: Num. + if err := bw.WriteBits(uint64(index.Num), 8); err != nil { + return errutil.Err(err) + } + // 3 bytes: reserved. + if _, err := io.CopyN(bw, ioutilx.Zero, 3); err != nil { + return errutil.Err(err) + } + } + } + return nil +} + +// --- [ Picture ] ------------------------------------------------------------- + +// encodePicture encodes the Picture metadata block, writing to bw. +func encodePicture(bw *bitio.Writer, pic *meta.Picture, last bool) error { + // Store metadata block header. + nbits := int64(32 + 32 + 8*len(pic.MIME) + 32 + 8*len(pic.Desc) + 32 + 32 + 32 + 32 + 32 + 8*len(pic.Data)) + hdr := &meta.Header{ + IsLast: last, + Type: meta.TypePicture, + Length: nbits / 8, + } + if err := encodeBlockHeader(bw, hdr); err != nil { + return errutil.Err(err) + } + + // Store metadata block body. + // 32 bits: Type. + if err := bw.WriteBits(uint64(pic.Type), 32); err != nil { + return errutil.Err(err) + } + // 32 bits: (MIME type length). + if err := bw.WriteBits(uint64(len(pic.MIME)), 32); err != nil { + return errutil.Err(err) + } + // (MIME type length) bytes: MIME. + if _, err := bw.Write([]byte(pic.MIME)); err != nil { + return errutil.Err(err) + } + // 32 bits: (description length). + if err := bw.WriteBits(uint64(len(pic.Desc)), 32); err != nil { + return errutil.Err(err) + } + // (description length) bytes: Desc. + if _, err := bw.Write([]byte(pic.Desc)); err != nil { + return errutil.Err(err) + } + // 32 bits: Width. + if err := bw.WriteBits(uint64(pic.Width), 32); err != nil { + return errutil.Err(err) + } + // 32 bits: Height. + if err := bw.WriteBits(uint64(pic.Height), 32); err != nil { + return errutil.Err(err) + } + // 32 bits: Depth. + if err := bw.WriteBits(uint64(pic.Depth), 32); err != nil { + return errutil.Err(err) + } + // 32 bits: NPalColors. + if err := bw.WriteBits(uint64(pic.NPalColors), 32); err != nil { + return errutil.Err(err) + } + // 32 bits: (data length). + if err := bw.WriteBits(uint64(len(pic.Data)), 32); err != nil { + return errutil.Err(err) + } + // (data length) bytes: Data. + if _, err := bw.Write(pic.Data); err != nil { + return errutil.Err(err) + } + return nil +} diff --git a/encode_subframe.go b/encode_subframe.go new file mode 100755 index 0000000..f74b0d4 --- /dev/null +++ b/encode_subframe.go @@ -0,0 +1,369 @@ +package flac + +import ( + "fmt" + + "github.com/icza/bitio" + "github.com/mewkiz/flac/frame" + iobits "github.com/mewkiz/flac/internal/bits" + "github.com/mewkiz/pkg/errutil" +) + +// --- [ Subframe ] ------------------------------------------------------------ + +// encodeSubframe encodes the given subframe, writing to bw. +func encodeSubframe(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error { + // Encode subframe header. + if err := encodeSubframeHeader(bw, subframe.SubHeader); err != nil { + return errutil.Err(err) + } + + // Adjust bps of subframe for wasted bits-per-sample. + bps -= subframe.Wasted + + // Right shift to account for wasted bits-per-sample. + if subframe.Wasted > 0 { + for i, sample := range subframe.Samples { + subframe.Samples[i] = sample >> subframe.Wasted + } + // NOTE: use defer to restore original samples after encode. + defer func() { + for i, sample := range subframe.Samples { + subframe.Samples[i] = sample << subframe.Wasted + } + }() + } + + // Encode audio samples. + switch subframe.Pred { + case frame.PredConstant: + if err := encodeConstantSamples(bw, hdr, subframe, bps); err != nil { + return errutil.Err(err) + } + case frame.PredVerbatim: + if err := encodeVerbatimSamples(bw, hdr, subframe, bps); err != nil { + return errutil.Err(err) + } + case frame.PredFixed: + if err := encodeFixedSamples(bw, hdr, subframe, bps); err != nil { + return errutil.Err(err) + } + case frame.PredFIR: + if err := encodeFIRSamples(bw, hdr, subframe, bps); err != nil { + return errutil.Err(err) + } + default: + return errutil.Newf("support for prediction method %v not yet implemented", subframe.Pred) + } + return nil +} + +// --- [ Subframe header ] ----------------------------------------------------- + +// encodeSubframeHeader encodes the given subframe header, writing to bw. +func encodeSubframeHeader(bw *bitio.Writer, subHdr frame.SubHeader) error { + // Zero bit padding, to prevent sync-fooling string of 1s. + if err := bw.WriteBits(0x0, 1); err != nil { + return errutil.Err(err) + } + + // Subframe type: + // 000000 : SUBFRAME_CONSTANT + // 000001 : SUBFRAME_VERBATIM + // 00001x : reserved + // 0001xx : reserved + // 001xxx : if(xxx <= 4) SUBFRAME_FIXED, xxx=order ; else reserved + // 01xxxx : reserved + // 1xxxxx : SUBFRAME_LPC, xxxxx=order-1 + var bits uint64 + switch subHdr.Pred { + case frame.PredConstant: + // 000000 : SUBFRAME_CONSTANT + bits = 0x00 + case frame.PredVerbatim: + // 000001 : SUBFRAME_VERBATIM + bits = 0x01 + case frame.PredFixed: + // 001xxx : if(xxx <= 4) SUBFRAME_FIXED, xxx=order ; else reserved + bits = 0x08 | uint64(subHdr.Order) + case frame.PredFIR: + // 1xxxxx : SUBFRAME_LPC, xxxxx=order-1 + bits = 0x20 | uint64(subHdr.Order-1) + } + if err := bw.WriteBits(bits, 6); err != nil { + return errutil.Err(err) + } + + // <1+k> 'Wasted bits-per-sample' flag: + // + // 0 : no wasted bits-per-sample in source subblock, k=0 + // 1 : k wasted bits-per-sample in source subblock, k-1 follows, unary coded; e.g. k=3 => 001 follows, k=7 => 0000001 follows. + hasWastedBits := subHdr.Wasted > 0 + if err := bw.WriteBool(hasWastedBits); err != nil { + return errutil.Err(err) + } + if hasWastedBits { + if err := iobits.WriteUnary(bw, uint64(subHdr.Wasted-1)); err != nil { + return errutil.Err(err) + } + } + return nil +} + +// --- [ Constant samples ] ---------------------------------------------------- + +// encodeConstantSamples stores the given constant sample, writing to bw. +func encodeConstantSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error { + samples := subframe.Samples + sample := samples[0] + for _, s := range samples[1:] { + if sample != s { + return errutil.Newf("constant sample mismatch; expected %v, got %v", sample, s) + } + } + // Unencoded constant value of the subblock, n = frame's bits-per-sample. + if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil { + return errutil.Err(err) + } + return nil +} + +// --- [ Verbatim samples ] ---------------------------------------------------- + +// encodeVerbatimSamples stores the given samples verbatim (uncompressed), +// writing to bw. +func encodeVerbatimSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error { + // Unencoded subblock; n = frame's bits-per-sample, i = frame's blocksize. + samples := subframe.Samples + if int(hdr.BlockSize) != len(samples) { + return errutil.Newf("block size and sample count mismatch; expected %d, got %d", hdr.BlockSize, len(samples)) + } + for _, sample := range samples { + if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil { + return errutil.Err(err) + } + } + return nil +} + +// --- [ Fixed samples ] ------------------------------------------------------- + +// encodeFixedSamples stores the given samples using linear prediction coding +// with a fixed set of predefined polynomial coefficients, writing to bw. +func encodeFixedSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error { + // Encode unencoded warm-up samples. + samples := subframe.Samples + for i := 0; i < subframe.Order; i++ { + sample := samples[i] + if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil { + return errutil.Err(err) + } + } + + // Compute residuals (signal errors of the prediction) between audio + // samples and LPC predicted audio samples. + const shift = 0 + residuals, err := getLPCResiduals(subframe, frame.FixedCoeffs[subframe.Order], shift) + if err != nil { + return errutil.Err(err) + } + + // Encode subframe residuals. + if err := encodeResiduals(bw, subframe, residuals); err != nil { + return errutil.Err(err) + } + return nil +} + +// --- [ FIR samples ] ------------------------------------------------------- + +// encodeFIRSamples stores the given samples using linear prediction coding +// with a custom set of predefined polynomial coefficients, writing to bw. +func encodeFIRSamples(bw *bitio.Writer, hdr frame.Header, subframe *frame.Subframe, bps uint) error { + // Encode unencoded warm-up samples. + samples := subframe.Samples + for i := 0; i < subframe.Order; i++ { + sample := samples[i] + if err := bw.WriteBits(uint64(sample), uint8(bps)); err != nil { + return errutil.Err(err) + } + } + + // 4 bits: (coefficients' precision in bits) - 1. + if err := bw.WriteBits(uint64(subframe.CoeffPrec-1), 4); err != nil { + return errutil.Err(err) + } + + // 5 bits: predictor coefficient shift needed in bits. + if err := bw.WriteBits(uint64(subframe.CoeffShift), 5); err != nil { + return errutil.Err(err) + } + + // Encode coefficients. + for _, coeff := range subframe.Coeffs { + // (prec) bits: Predictor coefficient. + if err := bw.WriteBits(uint64(coeff), uint8(subframe.CoeffPrec)); err != nil { + return errutil.Err(err) + } + } + + // Compute residuals (signal errors of the prediction) between audio + // samples and LPC predicted audio samples. + residuals, err := getLPCResiduals(subframe, subframe.Coeffs, subframe.CoeffShift) + if err != nil { + return errutil.Err(err) + } + + // Encode subframe residuals. + if err := encodeResiduals(bw, subframe, residuals); err != nil { + return errutil.Err(err) + } + return nil +} + +// encodeResiduals encodes the residuals (prediction method error signals) of the +// subframe. +// +// ref: https://www.xiph.org/flac/format.html#residual +func encodeResiduals(bw *bitio.Writer, subframe *frame.Subframe, residuals []int32) error { + // 2 bits: Residual coding method. + if err := bw.WriteBits(uint64(subframe.ResidualCodingMethod), 2); err != nil { + return errutil.Err(err) + } + // The 2 bits are used to specify the residual coding method as follows: + // 00: Rice coding with a 4-bit Rice parameter. + // 01: Rice coding with a 5-bit Rice parameter. + // 10: reserved. + // 11: reserved. + switch subframe.ResidualCodingMethod { + case frame.ResidualCodingMethodRice1: + return encodeRicePart(bw, subframe, 4, residuals) + case frame.ResidualCodingMethodRice2: + return encodeRicePart(bw, subframe, 5, residuals) + default: + return fmt.Errorf("encodeResiduals: reserved residual coding method bit pattern (%02b)", uint8(subframe.ResidualCodingMethod)) + } +} + +// encodeRicePart encodes a Rice partition of residuals from the subframe, using +// a Rice parameter of the specified size in bits. +// +// ref: https://www.xiph.org/flac/format.html#partitioned_rice +// ref: https://www.xiph.org/flac/format.html#partitioned_rice2 +func encodeRicePart(bw *bitio.Writer, subframe *frame.Subframe, paramSize uint, residuals []int32) error { + // 4 bits: Partition order. + riceSubframe := subframe.RiceSubframe + if err := bw.WriteBits(uint64(riceSubframe.PartOrder), 4); err != nil { + return errutil.Err(err) + } + + // Parse Rice partitions; in total 2^partOrder partitions. + // + // ref: https://www.xiph.org/flac/format.html#rice_partition + // ref: https://www.xiph.org/flac/format.html#rice2_partition + partOrder := riceSubframe.PartOrder + nparts := 1 << partOrder + curResidualIndex := 0 + for i := range riceSubframe.Partitions { + partition := &riceSubframe.Partitions[i] + // (4 or 5) bits: Rice parameter. + param := partition.Param + if err := bw.WriteBits(uint64(param), uint8(paramSize)); err != nil { + return errutil.Err(err) + } + + // Determine the number of Rice encoded samples in the partition. + var nsamples int + if partOrder == 0 { + nsamples = subframe.NSamples - subframe.Order + } else if i != 0 { + nsamples = subframe.NSamples / nparts + } else { + nsamples = subframe.NSamples/nparts - subframe.Order + } + + if paramSize == 4 && param == 0xF || paramSize == 5 && param == 0x1F { + // 1111 or 11111: Escape code, meaning the partition is in unencoded + // binary form using n bits per sample; n follows as a 5-bit number. + if err := bw.WriteBits(uint64(partition.EscapedBitsPerSample), 5); err != nil { + return errutil.Err(err) + } + for j := 0; j < nsamples; j++ { + // ref: https://datatracker.ietf.org/doc/draft-ietf-cellar-flac/ + // + // From section 9.2.7.1. Escaped partition: + // + // The residual samples themselves are stored signed two's + // complement. For example, when a partition is escaped and each + // residual sample is stored with 3 bits, the number -1 is + // represented as 0b111. + residual := residuals[curResidualIndex] + curResidualIndex++ + if err := bw.WriteBits(uint64(residual), uint8(partition.EscapedBitsPerSample)); err != nil { + return errutil.Err(err) + } + } + continue + } + + // Encode the Rice residuals of the partition. + for j := 0; j < nsamples; j++ { + residual := residuals[curResidualIndex] + curResidualIndex++ + if err := encodeRiceResidual(bw, param, residual); err != nil { + return errutil.Err(err) + } + } + } + + return nil +} + +// encodeRiceResidual encodes a Rice residual (error signal). +func encodeRiceResidual(bw *bitio.Writer, k uint, residual int32) error { + // ZigZag encode. + folded := iobits.EncodeZigZag(residual) + + // unfold into low- and high. + lowMask := ^uint32(0) >> (32 - k) // lower k bits. + highMask := ^uint32(0) << k // upper bits. + high := (folded & highMask) >> k + low := folded & lowMask + + // Write unary encoded most significant bits. + if err := iobits.WriteUnary(bw, uint64(high)); err != nil { + return errutil.Err(err) + } + + // Write binary encoded least significant bits. + if err := bw.WriteBits(uint64(low), uint8(k)); err != nil { + return errutil.Err(err) + } + return nil +} + +// getLPCResiduals returns the residuals (signal errors of the prediction) +// between the given audio samples and the LPC predicted audio samples, using +// the coefficients of a given polynomial, and a couple (order of polynomial; +// i.e. len(coeffs)) of unencoded warm-up samples. +func getLPCResiduals(subframe *frame.Subframe, coeffs []int32, shift int32) ([]int32, error) { + if len(coeffs) != subframe.Order { + return nil, fmt.Errorf("getLPCResiduals: prediction order (%d) differs from number of coefficients (%d)", subframe.Order, len(coeffs)) + } + if shift < 0 { + return nil, fmt.Errorf("getLPCResiduals: invalid negative shift") + } + if subframe.NSamples != len(subframe.Samples) { + return nil, fmt.Errorf("getLPCResiduals: subframe sample count mismatch; expected %d, got %d", subframe.NSamples, len(subframe.Samples)) + } + var residuals []int32 + for i := subframe.Order; i < subframe.NSamples; i++ { + var sample int64 + for j, c := range coeffs { + sample += int64(c) * int64(subframe.Samples[i-j-1]) + } + residual := subframe.Samples[i] - int32(sample>>uint(shift)) + residuals = append(residuals, residual) + } + return residuals, nil +} diff --git a/example_test.go b/example_test.go new file mode 100755 index 0000000..55142c8 --- /dev/null +++ b/example_test.go @@ -0,0 +1,121 @@ +package flac_test + +import ( + "bytes" + "crypto/md5" + "fmt" + "io" + "log" + + "github.com/mewkiz/flac" +) + +func ExampleParseFile() { + // Parse metadata of love.flac + stream, err := flac.ParseFile("testdata/love.flac") + if err != nil { + log.Fatal(err) + } + defer stream.Close() + + fmt.Printf("unencoded audio md5sum: %032x\n", stream.Info.MD5sum[:]) + for i, block := range stream.Blocks { + fmt.Printf("block %d: %v\n", i, block.Type) + } + // Output: + // unencoded audio md5sum: bdf6f7d31f77cb696a02b2192d192a89 + // block 0: seek table + // block 1: vorbis comment + // block 2: padding +} + +func ExampleOpen() { + // Open love.flac for audio streaming without parsing metadata. + stream, err := flac.Open("testdata/love.flac") + if err != nil { + log.Fatal(err) + } + defer stream.Close() + + // Parse audio samples and verify the MD5 signature of the decoded audio + // samples. + md5sum := md5.New() + for { + // Parse one frame of audio samples at the time, each frame containing one + // subframe per audio channel. + frame, err := stream.ParseNext() + if err != nil { + if err == io.EOF { + break + } + log.Fatal(err) + } + frame.Hash(md5sum) + + // Print first three samples from each channel of the first five frames. + if frame.Num < 5 { + fmt.Printf("frame %d\n", frame.Num) + for i, subframe := range frame.Subframes { + fmt.Printf(" subframe %d\n", i) + for j, sample := range subframe.Samples { + if j >= 3 { + break + } + fmt.Printf(" sample %d: %v\n", j, sample) + } + } + } + } + fmt.Println() + + got, want := md5sum.Sum(nil), stream.Info.MD5sum[:] + fmt.Println("decoded audio md5sum valid:", bytes.Equal(got, want)) + // Output: + // frame 0 + // subframe 0 + // sample 0: 126 + // sample 1: 126 + // sample 2: 126 + // subframe 1 + // sample 0: 126 + // sample 1: 126 + // sample 2: 126 + // frame 1 + // subframe 0 + // sample 0: 126 + // sample 1: 126 + // sample 2: 126 + // subframe 1 + // sample 0: 126 + // sample 1: 126 + // sample 2: 126 + // frame 2 + // subframe 0 + // sample 0: 121 + // sample 1: 130 + // sample 2: 137 + // subframe 1 + // sample 0: 121 + // sample 1: 130 + // sample 2: 137 + // frame 3 + // subframe 0 + // sample 0: -9501 + // sample 1: -6912 + // sample 2: -3916 + // subframe 1 + // sample 0: -9501 + // sample 1: -6912 + // sample 2: -3916 + // frame 4 + // subframe 0 + // sample 0: 513 + // sample 1: 206 + // sample 2: 152 + // subframe 1 + // sample 0: 513 + // sample 1: 206 + // sample 2: 152 + // + // decoded audio md5sum valid: true +} diff --git a/flac.go b/flac.go new file mode 100755 index 0000000..d96f53e --- /dev/null +++ b/flac.go @@ -0,0 +1,426 @@ +// TODO(u): Evaluate storing the samples (and residuals) during frame audio +// decoding in a buffer allocated for the stream. This buffer would be allocated +// using BlockSize and NChannels from the StreamInfo block, and it could be +// reused in between calls to Next and ParseNext. This should reduce GC +// pressure. + +// TODO: Remove note about encoder API. + +// Package flac provides access to FLAC (Free Lossless Audio Codec) streams. +// +// A brief introduction of the FLAC stream format [1] follows. Each FLAC stream +// starts with a 32-bit signature ("fLaC"), followed by one or more metadata +// blocks, and then one or more audio frames. The first metadata block +// (StreamInfo) describes the basic properties of the audio stream and it is the +// only mandatory metadata block. Subsequent metadata blocks may appear in an +// arbitrary order. +// +// Please refer to the documentation of the meta [2] and the frame [3] packages +// for a brief introduction of their respective formats. +// +// [1]: https://www.xiph.org/flac/format.html#stream +// [2]: https://godoc.org/github.com/mewkiz/flac/meta +// [3]: https://godoc.org/github.com/mewkiz/flac/frame +// +// Note: the Encoder API is experimental until the 1.1.x release. As such, it's +// API is expected to change. +package flac + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "os" + + "github.com/mewkiz/flac/frame" + "github.com/mewkiz/flac/internal/bufseekio" + "github.com/mewkiz/flac/meta" +) + +// A Stream contains the metadata blocks and provides access to the audio frames +// of a FLAC stream. +// +// ref: https://www.xiph.org/flac/format.html#stream +type Stream struct { + // The StreamInfo metadata block describes the basic properties of the FLAC + // audio stream. + Info *meta.StreamInfo + // Zero or more metadata blocks. + Blocks []*meta.Block + + // seekTable contains one or more pre-calculated audio frame seek points of + // the stream; nil if uninitialized. + seekTable *meta.SeekTable + // seekTableSize determines how many seek points the seekTable should have if + // the flac file does not include one in the metadata. + seekTableSize int + // dataStart is the offset of the first frame header since SeekPoint.Offset + // is relative to this position. + dataStart int64 + + // Underlying io.Reader, or io.ReadCloser. + r io.Reader +} + +// New creates a new Stream for accessing the audio samples of r. It reads and +// parses the FLAC signature and the StreamInfo metadata block, but skips all +// other metadata blocks. +// +// Call Stream.Next to parse the frame header of the next audio frame, and call +// Stream.ParseNext to parse the entire next frame including audio samples. +func New(r io.Reader) (stream *Stream, err error) { + // Verify FLAC signature and parse the StreamInfo metadata block. + br := bufio.NewReader(r) + stream = &Stream{r: br} + block, err := stream.parseStreamInfo() + if err != nil { + return nil, err + } + + // Skip the remaining metadata blocks. + for !block.IsLast { + block, err = meta.New(br) + if err != nil && err != meta.ErrReservedType { + return stream, err + } + if err = block.Skip(); err != nil { + return stream, err + } + } + + return stream, nil +} + +// NewSeek returns a Stream that has seeking enabled. The incoming io.ReadSeeker +// will not be buffered, which might result in performance issues. Using an +// in-memory buffer like *bytes.Reader should work well. +func NewSeek(rs io.ReadSeeker) (stream *Stream, err error) { + br := bufseekio.NewReadSeeker(rs) + stream = &Stream{r: br, seekTableSize: defaultSeekTableSize} + + // Verify FLAC signature and parse the StreamInfo metadata block. + block, err := stream.parseStreamInfo() + if err != nil { + return stream, err + } + + for !block.IsLast { + block, err = meta.Parse(stream.r) + if err != nil { + if err != meta.ErrReservedType { + return stream, err + } + if err = block.Skip(); err != nil { + return stream, err + } + } + + if block.Header.Type == meta.TypeSeekTable { + stream.seekTable = block.Body.(*meta.SeekTable) + } + } + + // Record file offset of the first frame header. + stream.dataStart, err = br.Seek(0, io.SeekCurrent) + return stream, err +} + +var ( + // flacSignature marks the beginning of a FLAC stream. + flacSignature = []byte("fLaC") + + // id3Signature marks the beginning of an ID3 stream, used to skip over ID3 + // data. + id3Signature = []byte("ID3") + + // ErrNoSeeker reports that flac.NewSeek was called with an io.Reader not + // implementing io.Seeker, and thus does not allow for seeking. + ErrNoSeeker = errors.New("stream.Seek: reader does not implement io.Seeker") + + // ErrNoSeektable reports that no seektable has been generated. Therefore, + // it is not possible to seek in the stream. + ErrNoSeektable = errors.New("stream.searchFromStart: no seektable exists") +) + +const ( + defaultSeekTableSize = 100 +) + +// parseStreamInfo verifies the signature which marks the beginning of a FLAC +// stream, and parses the StreamInfo metadata block. It returns a boolean value +// which specifies if the StreamInfo block was the last metadata block of the +// FLAC stream. +func (stream *Stream) parseStreamInfo() (block *meta.Block, err error) { + // Verify FLAC signature. + r := stream.r + var buf [4]byte + if _, err = io.ReadFull(r, buf[:]); err != nil { + return block, err + } + + // Skip prepended ID3v2 data. + if bytes.Equal(buf[:3], id3Signature) { + if err := stream.skipID3v2(); err != nil { + return block, err + } + + // Second attempt at verifying signature. + if _, err = io.ReadFull(r, buf[:]); err != nil { + return block, err + } + } + + if !bytes.Equal(buf[:], flacSignature) { + return block, fmt.Errorf("flac.parseStreamInfo: invalid FLAC signature; expected %q, got %q", flacSignature, buf) + } + + // Parse StreamInfo metadata block. + block, err = meta.Parse(r) + if err != nil { + return block, err + } + si, ok := block.Body.(*meta.StreamInfo) + if !ok { + return block, fmt.Errorf("flac.parseStreamInfo: incorrect type of first metadata block; expected *meta.StreamInfo, got %T", block.Body) + } + stream.Info = si + return block, nil +} + +// skipID3v2 skips ID3v2 data prepended to flac files. +func (stream *Stream) skipID3v2() error { + r := bufio.NewReader(stream.r) + + // Discard unnecessary data from the ID3v2 header. + if _, err := r.Discard(2); err != nil { + return err + } + + // Read the size from the ID3v2 header. + var sizeBuf [4]byte + if _, err := r.Read(sizeBuf[:]); err != nil { + return err + } + // The size is encoded as a synchsafe integer. + size := int(sizeBuf[0])<<21 | int(sizeBuf[1])<<14 | int(sizeBuf[2])<<7 | int(sizeBuf[3]) + + _, err := r.Discard(size) + return err +} + +// Parse creates a new Stream for accessing the metadata blocks and audio +// samples of r. It reads and parses the FLAC signature and all metadata blocks. +// +// Call Stream.Next to parse the frame header of the next audio frame, and call +// Stream.ParseNext to parse the entire next frame including audio samples. +func Parse(r io.Reader) (stream *Stream, err error) { + // Verify FLAC signature and parse the StreamInfo metadata block. + br := bufio.NewReader(r) + stream = &Stream{r: br} + block, err := stream.parseStreamInfo() + if err != nil { + return nil, err + } + + // Parse the remaining metadata blocks. + for !block.IsLast { + block, err = meta.Parse(br) + if err != nil { + if err != meta.ErrReservedType { + return stream, err + } + // Skip the body of unknown (reserved) metadata blocks, as stated by + // the specification. + // + // ref: https://www.xiph.org/flac/format.html#format_overview + if err = block.Skip(); err != nil { + return stream, err + } + } + stream.Blocks = append(stream.Blocks, block) + } + + return stream, nil +} + +// Open creates a new Stream for accessing the audio samples of path. It reads +// and parses the FLAC signature and the StreamInfo metadata block, but skips +// all other metadata blocks. +// +// Call Stream.Next to parse the frame header of the next audio frame, and call +// Stream.ParseNext to parse the entire next frame including audio samples. +// +// Note: The Close method of the stream must be called when finished using it. +func Open(path string) (stream *Stream, err error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + + stream, err = New(f) + if err != nil { + return nil, err + } + + return stream, err +} + +// ParseFile creates a new Stream for accessing the metadata blocks and audio +// samples of path. It reads and parses the FLAC signature and all metadata +// blocks. +// +// Call Stream.Next to parse the frame header of the next audio frame, and call +// Stream.ParseNext to parse the entire next frame including audio samples. +// +// Note: The Close method of the stream must be called when finished using it. +func ParseFile(path string) (stream *Stream, err error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + stream, err = Parse(f) + if err != nil { + return nil, err + } + + return stream, err +} + +// Close closes the stream gracefully if the underlying io.Reader also implements the io.Closer interface. +func (stream *Stream) Close() error { + if closer, ok := stream.r.(io.Closer); ok { + return closer.Close() + } + + return nil +} + +// Next parses the frame header of the next audio frame. It returns io.EOF to +// signal a graceful end of FLAC stream. +// +// Call Frame.Parse to parse the audio samples of its subframes. +func (stream *Stream) Next() (f *frame.Frame, err error) { + return frame.New(stream.r) +} + +// ParseNext parses the entire next frame including audio samples. It returns +// io.EOF to signal a graceful end of FLAC stream. +func (stream *Stream) ParseNext() (f *frame.Frame, err error) { + return frame.Parse(stream.r) +} + +// Seek seeks to the frame containing the given absolute sample number. The +// return value specifies the first sample number of the frame containing +// sampleNum. +func (stream *Stream) Seek(sampleNum uint64) (uint64, error) { + if stream.seekTable == nil && stream.seekTableSize > 0 { + if err := stream.makeSeekTable(); err != nil { + return 0, err + } + } + + rs := stream.r.(io.ReadSeeker) + + isBiggerThanStream := stream.Info.NSamples != 0 && sampleNum >= stream.Info.NSamples + if isBiggerThanStream || sampleNum < 0 { + return 0, fmt.Errorf("unable to seek to sample number %d", sampleNum) + } + point, err := stream.searchFromStart(sampleNum) + if err != nil { + return 0, err + } + + if _, err := rs.Seek(stream.dataStart+int64(point.Offset), io.SeekStart); err != nil { + return 0, err + } + for { + // Record seek offset to start of frame. + offset, err := rs.Seek(0, io.SeekCurrent) + if err != nil { + return 0, err + } + frame, err := stream.ParseNext() + if err != nil { + return 0, err + } + if frame.SampleNumber()+uint64(frame.BlockSize) > sampleNum { + // Restore seek offset to the start of the frame containing the + // specified sample number. + _, err := rs.Seek(offset, io.SeekStart) + return frame.SampleNumber(), err + } + } +} + +// TODO(_): Utilize binary search in searchFromStart. + +// searchFromStart searches for the given sample number from the start of the +// seek table and returns the last seek point containing the sample number. If +// no seek point contains the sample number, the last seek point preceding the +// sample number is returned. If the sample number is lower than the first seek +// point, the first seek point is returned. +func (stream *Stream) searchFromStart(sampleNum uint64) (meta.SeekPoint, error) { + if len(stream.seekTable.Points) == 0 { + return meta.SeekPoint{}, ErrNoSeektable + } + prev := stream.seekTable.Points[0] + for _, p := range stream.seekTable.Points { + if p.SampleNum+uint64(p.NSamples) >= sampleNum { + return prev, nil + } + prev = p + } + return prev, nil +} + +// makeSeekTable creates a seek table with seek points to each frame of the FLAC +// stream. +func (stream *Stream) makeSeekTable() (err error) { + rs, ok := stream.r.(io.ReadSeeker) + if !ok { + return ErrNoSeeker + } + + pos, err := rs.Seek(0, io.SeekCurrent) + if err != nil { + return err + } + + _, err = rs.Seek(stream.dataStart, io.SeekStart) + if err != nil { + return err + } + + var i int + var sampleNum uint64 + var points []meta.SeekPoint + for { + // Record seek offset to start of frame. + off, err := rs.Seek(0, io.SeekCurrent) + if err != nil { + return err + } + f, err := stream.ParseNext() + if err != nil { + if err == io.EOF { + break + } + return err + } + points = append(points, meta.SeekPoint{ + SampleNum: sampleNum, + Offset: uint64(off - stream.dataStart), + NSamples: f.BlockSize, + }) + + sampleNum += uint64(f.BlockSize) + i++ + } + + stream.seekTable = &meta.SeekTable{Points: points} + + _, err = rs.Seek(pos, io.SeekStart) + return err +} diff --git a/flac_test.go b/flac_test.go new file mode 100755 index 0000000..0783caf --- /dev/null +++ b/flac_test.go @@ -0,0 +1,202 @@ +package flac_test + +import ( + "fmt" + "io" + "os" + "testing" + + "github.com/mewkiz/flac" +) + +func TestSkipID3v2(t *testing.T) { + if _, err := flac.ParseFile("testdata/id3.flac"); err != nil { + t.Fatal(err) + } +} + +func TestSeek(t *testing.T) { + f, err := os.Open("testdata/172960.flac") + if err != nil { + t.Fatal(err) + } + + defer f.Close() + + //Seek Table: + // {SampleNum:0 Offset:8283 NSamples:4096} + // {SampleNum:4096 Offset:17777 NSamples:4096} + // {SampleNum:8192 Offset:27141 NSamples:4096} + // {SampleNum:12288 Offset:36665 NSamples:4096} + // {SampleNum:16384 Offset:46179 NSamples:4096} + // {SampleNum:20480 Offset:55341 NSamples:4096} + // {SampleNum:24576 Offset:64690 NSamples:4096} + // {SampleNum:28672 Offset:74269 NSamples:4096} + // {SampleNum:32768 Offset:81984 NSamples:4096} + // {SampleNum:36864 Offset:86656 NSamples:4096} + // {SampleNum:40960 Offset:89596 NSamples:2723} + + testPos := []struct { + seek uint64 + expected uint64 + err string + }{ + {seek: 0, expected: 0}, + {seek: 9000, expected: 8192}, + {seek: 0, expected: 0}, + {seek: 8000, expected: 4096}, + {seek: 0, expected: 0}, + {seek: 50000, expected: 0, err: "unable to seek to sample number 50000"}, + {seek: 100, expected: 0}, + {seek: 8192, expected: 8192}, + {seek: 8191, expected: 4096}, + //{seek: 40960 + 2723 - 1, expected: 40960}, // last sample // TODO: re-enable when it works. See https://github.com/mewkiz/flac/pull/73 + {seek: 40960 + 2723, expected: 0, err: "unable to seek to sample number 43683"}, // one after last sample + } + + stream, err := flac.NewSeek(f) + if err != nil { + t.Fatal(err) + } + + for i, pos := range testPos { + t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) { + p, err := stream.Seek(pos.seek) + if err != nil { + if err.Error() != pos.err { + t.Fatal(err) + } + } + + if p != pos.expected { + t.Fatalf("pos %d does not equal %d", p, pos.expected) + } + + _, err = stream.ParseNext() + if err != nil && err != io.EOF { + t.Fatal(err) + } + }) + + } +} + +func TestDecode(t *testing.T) { + paths := []string{ + "meta/testdata/input-SCPAP.flac", + "meta/testdata/input-SCVA.flac", + "meta/testdata/input-SCVPAP.flac", + "meta/testdata/input-VA.flac", + "meta/testdata/silence.flac", + "testdata/19875.flac", + "testdata/44127.flac", + "testdata/59996.flac", + "testdata/80574.flac", + "testdata/172960.flac", + "testdata/189983.flac", + "testdata/191885.flac", + "testdata/212768.flac", + "testdata/220014.flac", + "testdata/243749.flac", + "testdata/256529.flac", + "testdata/257344.flac", + "testdata/8297-275156-0011.flac", + "testdata/love.flac", + // IETF test cases. + // + // ref: https://github.com/ietf-wg-cellar/flac-test-files/tree/main/subset + "testdata/flac-test-files/subset/01 - blocksize 4096.flac", + "testdata/flac-test-files/subset/02 - blocksize 4608.flac", + "testdata/flac-test-files/subset/03 - blocksize 16.flac", + "testdata/flac-test-files/subset/04 - blocksize 192.flac", + "testdata/flac-test-files/subset/05 - blocksize 254.flac", + "testdata/flac-test-files/subset/06 - blocksize 512.flac", + "testdata/flac-test-files/subset/07 - blocksize 725.flac", + "testdata/flac-test-files/subset/08 - blocksize 1000.flac", + "testdata/flac-test-files/subset/09 - blocksize 1937.flac", + "testdata/flac-test-files/subset/10 - blocksize 2304.flac", + "testdata/flac-test-files/subset/11 - partition order 8.flac", + "testdata/flac-test-files/subset/12 - qlp precision 15 bit.flac", + "testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac", + "testdata/flac-test-files/subset/14 - wasted bits.flac", + "testdata/flac-test-files/subset/15 - only verbatim subframes.flac", + "testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac", + "testdata/flac-test-files/subset/17 - all fixed orders.flac", + "testdata/flac-test-files/subset/18 - precision search.flac", + "testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac", + "testdata/flac-test-files/subset/20 - samplerate 39kHz.flac", + "testdata/flac-test-files/subset/21 - samplerate 22050Hz.flac", + "testdata/flac-test-files/subset/22 - 12 bit per sample.flac", + "testdata/flac-test-files/subset/23 - 8 bit per sample.flac", + "testdata/flac-test-files/subset/24 - variable blocksize file created with flake revision 264.flac", + "testdata/flac-test-files/subset/25 - variable blocksize file created with flake revision 264, modified to create smaller blocks.flac", + "testdata/flac-test-files/subset/26 - variable blocksize file created with CUETools.Flake 2.1.6.flac", + "testdata/flac-test-files/subset/27 - old format variable blocksize file created with Flake 0.11.flac", + "testdata/flac-test-files/subset/28 - high resolution audio, default settings.flac", + "testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac", + "testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac", + "testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac", + "testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac", + "testdata/flac-test-files/subset/33 - samplerate 192kHz.flac", + "testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac", + "testdata/flac-test-files/subset/35 - samplerate 134560Hz.flac", + "testdata/flac-test-files/subset/36 - samplerate 384kHz.flac", + "testdata/flac-test-files/subset/37 - 20 bit per sample.flac", + "testdata/flac-test-files/subset/38 - 3 channels (3.0).flac", + "testdata/flac-test-files/subset/39 - 4 channels (4.0).flac", + "testdata/flac-test-files/subset/40 - 5 channels (5.0).flac", + "testdata/flac-test-files/subset/41 - 6 channels (5.1).flac", + "testdata/flac-test-files/subset/42 - 7 channels (6.1).flac", + "testdata/flac-test-files/subset/43 - 8 channels (7.1).flac", + "testdata/flac-test-files/subset/44 - 8-channel surround, 192kHz, 24 bit, using only 32nd order predictors.flac", + "testdata/flac-test-files/subset/45 - no total number of samples set.flac", + "testdata/flac-test-files/subset/46 - no min-max framesize set.flac", + "testdata/flac-test-files/subset/47 - only STREAMINFO.flac", + "testdata/flac-test-files/subset/48 - Extremely large SEEKTABLE.flac", + "testdata/flac-test-files/subset/49 - Extremely large PADDING.flac", + "testdata/flac-test-files/subset/50 - Extremely large PICTURE.flac", + "testdata/flac-test-files/subset/51 - Extremely large VORBISCOMMENT.flac", + "testdata/flac-test-files/subset/52 - Extremely large APPLICATION.flac", + "testdata/flac-test-files/subset/53 - CUESHEET with very many indexes.flac", + "testdata/flac-test-files/subset/54 - 1000x repeating VORBISCOMMENT.flac", + "testdata/flac-test-files/subset/55 - file 48-53 combined.flac", + "testdata/flac-test-files/subset/56 - JPG PICTURE.flac", + "testdata/flac-test-files/subset/57 - PNG PICTURE.flac", + "testdata/flac-test-files/subset/58 - GIF PICTURE.flac", + "testdata/flac-test-files/subset/59 - AVIF PICTURE.flac", + "testdata/flac-test-files/subset/60 - mono audio.flac", + "testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac", + "testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac", + "testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac", + "testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac", + } + + funcs := map[string]func(io.Reader) (*flac.Stream, error){ + "new": flac.New, + "newSeek": func(r io.Reader) (*flac.Stream, error) { return flac.NewSeek(r.(io.ReadSeeker)) }, + "parse": flac.Parse, + } + + for _, path := range paths { + for k, f := range funcs { + t.Run(fmt.Sprintf("%s/%s", k, path), func(t *testing.T) { + file, err := os.Open(path) + if err != nil { + t.Fatal(err) + } + + stream, err := f(file) + if err != nil { + t.Fatal(err) + } + + _, err = stream.ParseNext() + if err != nil { + t.Fatal(err) + } + + file.Close() + }) + } + } +} diff --git a/frame/frame.go b/frame/frame.go new file mode 100755 index 0000000..877569a --- /dev/null +++ b/frame/frame.go @@ -0,0 +1,687 @@ +// Package frame implements access to FLAC audio frames. +// +// A brief introduction of the FLAC audio format [1] follows. FLAC encoders +// divide the audio stream into blocks through a process called blocking [2]. A +// block contains the unencoded audio samples from all channels during a short +// period of time. Each audio block is divided into subblocks, one per channel. +// +// There is often a correlation between the left and right channel of stereo +// audio. Using inter-channel decorrelation [3] it is possible to store only one +// of the channels and the difference between the channels, or store the average +// of the channels and their difference. An encoder decorrelates audio samples +// as follows: +// +// mid = (left + right)/2 // average of the channels +// side = left - right // difference between the channels +// +// The blocks are encoded using a variety of prediction methods [4][5] and +// stored in frames. Blocks and subblocks contains unencoded audio samples while +// frames and subframes contain encoded audio samples. A FLAC stream contains +// one or more audio frames. +// +// [1]: https://www.xiph.org/flac/format.html#architecture +// [2]: https://www.xiph.org/flac/format.html#blocking +// [3]: https://www.xiph.org/flac/format.html#interchannel +// [4]: https://www.xiph.org/flac/format.html#prediction +// [5]: https://godoc.org/github.com/mewkiz/flac/frame#Pred +package frame + +import ( + "encoding/binary" + "errors" + "fmt" + "hash" + "io" + "log" + + "github.com/mewkiz/flac/internal/bits" + "github.com/mewkiz/flac/internal/hashutil" + "github.com/mewkiz/flac/internal/hashutil/crc16" + "github.com/mewkiz/flac/internal/hashutil/crc8" + "github.com/mewkiz/flac/internal/utf8" +) + +// A Frame contains the header and subframes of an audio frame. It holds the +// encoded samples from a block (a part) of the audio stream. Each subframe +// holding the samples from one of its channel. +// +// ref: https://www.xiph.org/flac/format.html#frame +type Frame struct { + // Audio frame header. + Header + // One subframe per channel, containing encoded audio samples. + Subframes []*Subframe + // CRC-16 hash sum, calculated by read operations on hr. + crc hashutil.Hash16 + // A bit reader, wrapping read operations to hr. + br *bits.Reader + // A CRC-16 hash reader, wrapping read operations to r. + hr io.Reader + // Underlying io.Reader. + r io.Reader +} + +// New creates a new Frame for accessing the audio samples of r. It reads and +// parses an audio frame header. It returns io.EOF to signal a graceful end of +// FLAC stream. +// +// Call Frame.Parse to parse the audio samples of its subframes. +func New(r io.Reader) (frame *Frame, err error) { + // Create a new CRC-16 hash reader which adds the data from all read + // operations to a running hash. + crc := crc16.NewIBM() + hr := io.TeeReader(r, crc) + + // Parse frame header. + frame = &Frame{crc: crc, hr: hr, r: r} + err = frame.parseHeader() + return frame, err +} + +// Parse reads and parses the header, and the audio samples from each subframe +// of a frame. If the samples are inter-channel decorrelated between the +// subframes, it correlates them. It returns io.EOF to signal a graceful end of +// FLAC stream. +// +// ref: https://www.xiph.org/flac/format.html#interchannel +func Parse(r io.Reader) (frame *Frame, err error) { + // Parse frame header. + frame, err = New(r) + if err != nil { + return frame, err + } + + // Parse subframes. + err = frame.Parse() + return frame, err +} + +// Parse reads and parses the audio samples from each subframe of the frame. If +// the samples are inter-channel decorrelated between the subframes, it +// correlates them. +// +// ref: https://www.xiph.org/flac/format.html#interchannel +func (frame *Frame) Parse() error { + // Parse subframes. + frame.Subframes = make([]*Subframe, frame.Channels.Count()) + var err error + for channel := range frame.Subframes { + // The side channel requires an extra bit per sample when using + // inter-channel decorrelation. + bps := uint(frame.BitsPerSample) + switch frame.Channels { + case ChannelsSideRight: + // channel 0 is the side channel. + if channel == 0 { + bps++ + } + case ChannelsLeftSide, ChannelsMidSide: + // channel 1 is the side channel. + if channel == 1 { + bps++ + } + } + + // Parse subframe. + frame.Subframes[channel], err = frame.parseSubframe(frame.br, bps) + if err != nil { + return err + } + } + + // Inter-channel correlation of subframe samples. + frame.Correlate() + + // 2 bytes: CRC-16 checksum. + var want uint16 + if err = binary.Read(frame.r, binary.BigEndian, &want); err != nil { + return unexpected(err) + } + got := frame.crc.Sum16() + if got != want { + return fmt.Errorf("frame.Frame.Parse: CRC-16 checksum mismatch; expected 0x%04X, got 0x%04X", want, got) + } + + return nil +} + +// Hash adds the decoded audio samples of the frame to a running MD5 hash. It +// can be used in conjunction with StreamInfo.MD5sum to verify the integrity of +// the decoded audio samples. +// +// Note: The audio samples of the frame must be decoded before calling Hash. +func (frame *Frame) Hash(md5sum hash.Hash) { + // Write decoded samples to a running MD5 hash. + bps := frame.BitsPerSample + var buf [3]byte + for i := 0; i < int(frame.BlockSize); i++ { + for _, subframe := range frame.Subframes { + sample := subframe.Samples[i] + switch { + case 1 <= bps && bps <= 8: + buf[0] = uint8(sample) + md5sum.Write(buf[:1]) + case 9 <= bps && bps <= 16: + buf[0] = uint8(sample) + buf[1] = uint8(sample >> 8) + md5sum.Write(buf[:2]) + case 17 <= bps && bps <= 24: + buf[0] = uint8(sample) + buf[1] = uint8(sample >> 8) + buf[2] = uint8(sample >> 16) + md5sum.Write(buf[:]) + default: + log.Printf("frame.Frame.Hash: support for %d-bit sample size not yet implemented", bps) + } + } + } +} + +// A Header contains the basic properties of an audio frame, such as its sample +// rate and channel count. To facilitate random access decoding each frame +// header starts with a sync-code. This allows the decoder to synchronize and +// locate the start of a frame header. +// +// ref: https://www.xiph.org/flac/format.html#frame_header +type Header struct { + // Specifies if the block size is fixed or variable. + HasFixedBlockSize bool + // Block size in inter-channel samples, i.e. the number of audio samples in + // each subframe. + BlockSize uint16 + // Sample rate in Hz; a 0 value implies unknown, get sample rate from + // StreamInfo. + SampleRate uint32 + // Specifies the number of channels (subframes) that exist in the frame, + // their order and possible inter-channel decorrelation. + Channels Channels + // Sample size in bits-per-sample; a 0 value implies unknown, get sample size + // from StreamInfo. + BitsPerSample uint8 + // Specifies the frame number if the block size is fixed, and the first + // sample number in the frame otherwise. When using fixed block size, the + // first sample number in the frame can be derived by multiplying the frame + // number with the block size (in samples). + Num uint64 +} + +// Errors returned by Frame.parseHeader. +var ( + ErrInvalidSync = errors.New("frame.Frame.parseHeader: invalid sync-code") +) + +// parseHeader reads and parses the header of an audio frame. +func (frame *Frame) parseHeader() error { + // Create a new CRC-8 hash reader which adds the data from all read + // operations to a running hash. + h := crc8.NewATM() + hr := io.TeeReader(frame.hr, h) + + // Create bit reader. + br := bits.NewReader(hr) + frame.br = br + + // 14 bits: sync-code (11111111111110) + x, err := br.Read(14) + if err != nil { + // This is the only place an audio frame may return io.EOF, which signals + // a graceful end of a FLAC stream. + return err + } + if x != 0x3FFE { + return ErrInvalidSync + } + + // 1 bit: reserved. + x, err = br.Read(1) + if err != nil { + return unexpected(err) + } + if x != 0 { + return errors.New("frame.Frame.parseHeader: non-zero reserved value") + } + + // 1 bit: HasFixedBlockSize. + x, err = br.Read(1) + if err != nil { + return unexpected(err) + } + if x == 0 { + frame.HasFixedBlockSize = true + } + + // 4 bits: BlockSize. The block size parsing is simplified by deferring it to + // the end of the header. + blockSize, err := br.Read(4) + if err != nil { + return unexpected(err) + } + + // 4 bits: SampleRate. The sample rate parsing is simplified by deferring it + // to the end of the header. + sampleRate, err := br.Read(4) + if err != nil { + return unexpected(err) + } + + // Parse channels. + if err := frame.parseChannels(br); err != nil { + return err + } + + // Parse bits per sample. + if err := frame.parseBitsPerSample(br); err != nil { + return err + } + + // 1 bit: reserved. + x, err = br.Read(1) + if err != nil { + return unexpected(err) + } + if x != 0 { + return errors.New("frame.Frame.parseHeader: non-zero reserved value") + } + + // if (fixed block size) + // 1-6 bytes: UTF-8 encoded frame number. + // else + // 1-7 bytes: UTF-8 encoded sample number. + frame.Num, err = utf8.Decode(hr) + if err != nil { + return unexpected(err) + } + + // Parse block size. + if err := frame.parseBlockSize(br, blockSize); err != nil { + return err + } + + // Parse sample rate. + if err := frame.parseSampleRate(br, sampleRate); err != nil { + return err + } + + // 1 byte: CRC-8 checksum. + var want uint8 + if err = binary.Read(frame.hr, binary.BigEndian, &want); err != nil { + return unexpected(err) + } + got := h.Sum8() + if want != got { + return fmt.Errorf("frame.Frame.parseHeader: CRC-8 checksum mismatch; expected 0x%02X, got 0x%02X", want, got) + } + + return nil +} + +// parseBitsPerSample parses the bits per sample of the header. +func (frame *Frame) parseBitsPerSample(br *bits.Reader) error { + // 3 bits: BitsPerSample. + x, err := br.Read(3) + if err != nil { + return unexpected(err) + } + + // The 3 bits are used to specify the sample size as follows: + // 000: unknown sample size; get from StreamInfo. + // 001: 8 bits-per-sample. + // 010: 12 bits-per-sample. + // 011: reserved. + // 100: 16 bits-per-sample. + // 101: 20 bits-per-sample. + // 110: 24 bits-per-sample. + // 111: reserved. + switch x { + case 0x0: + // 000: unknown bits-per-sample; get from StreamInfo. + case 0x1: + // 001: 8 bits-per-sample. + frame.BitsPerSample = 8 + case 0x2: + // 010: 12 bits-per-sample. + frame.BitsPerSample = 12 + case 0x4: + // 100: 16 bits-per-sample. + frame.BitsPerSample = 16 + case 0x5: + // 101: 20 bits-per-sample. + frame.BitsPerSample = 20 + case 0x6: + // 110: 24 bits-per-sample. + frame.BitsPerSample = 24 + default: + // 011: reserved. + // 111: reserved. + return fmt.Errorf("frame.Frame.parseHeader: reserved sample size bit pattern (%03b)", x) + } + return nil +} + +// parseChannels parses the channels of the header. +func (frame *Frame) parseChannels(br *bits.Reader) error { + // 4 bits: Channels. + // + // The 4 bits are used to specify the channels as follows: + // 0000: (1 channel) mono. + // 0001: (2 channels) left, right. + // 0010: (3 channels) left, right, center. + // 0011: (4 channels) left, right, left surround, right surround. + // 0100: (5 channels) left, right, center, left surround, right surround. + // 0101: (6 channels) left, right, center, LFE, left surround, right surround. + // 0110: (7 channels) left, right, center, LFE, center surround, side left, side right. + // 0111: (8 channels) left, right, center, LFE, left surround, right surround, side left, side right. + // 1000: (2 channels) left, side; using inter-channel decorrelation. + // 1001: (2 channels) side, right; using inter-channel decorrelation. + // 1010: (2 channels) mid, side; using inter-channel decorrelation. + // 1011: reserved. + // 1100: reserved. + // 1101: reserved. + // 1111: reserved. + x, err := br.Read(4) + if err != nil { + return unexpected(err) + } + if x >= 0xB { + return fmt.Errorf("frame.Frame.parseHeader: reserved channels bit pattern (%04b)", x) + } + frame.Channels = Channels(x) + return nil +} + +// parseBlockSize parses the block size of the header. +func (frame *Frame) parseBlockSize(br *bits.Reader, blockSize uint64) error { + // The 4 bits of n are used to specify the block size as follows: + // 0000: reserved. + // 0001: 192 samples. + // 0010-0101: 576 * 2^(n-2) samples. + // 0110: get 8 bit (block size)-1 from the end of the header. + // 0111: get 16 bit (block size)-1 from the end of the header. + // 1000-1111: 256 * 2^(n-8) samples. + n := blockSize + switch { + case n == 0x0: + // 0000: reserved. + return errors.New("frame.Frame.parseHeader: reserved block size bit pattern (0000)") + case n == 0x1: + // 0001: 192 samples. + frame.BlockSize = 192 + case n >= 0x2 && n <= 0x5: + // 0010-0101: 576 * 2^(n-2) samples. + frame.BlockSize = 576 * (1 << (n - 2)) + case n == 0x6: + // 0110: get 8 bit (block size)-1 from the end of the header. + x, err := br.Read(8) + if err != nil { + return unexpected(err) + } + frame.BlockSize = uint16(x + 1) + case n == 0x7: + // 0111: get 16 bit (block size)-1 from the end of the header. + x, err := br.Read(16) + if err != nil { + return unexpected(err) + } + frame.BlockSize = uint16(x + 1) + default: + // 1000-1111: 256 * 2^(n-8) samples. + frame.BlockSize = 256 * (1 << (n - 8)) + } + return nil +} + +// parseSampleRate parses the sample rate of the header. +func (frame *Frame) parseSampleRate(br *bits.Reader, sampleRate uint64) error { + // The 4 bits are used to specify the sample rate as follows: + // 0000: unknown sample rate; get from StreamInfo. + // 0001: 88.2 kHz. + // 0010: 176.4 kHz. + // 0011: 192 kHz. + // 0100: 8 kHz. + // 0101: 16 kHz. + // 0110: 22.05 kHz. + // 0111: 24 kHz. + // 1000: 32 kHz. + // 1001: 44.1 kHz. + // 1010: 48 kHz. + // 1011: 96 kHz. + // 1100: get 8 bit sample rate (in kHz) from the end of the header. + // 1101: get 16 bit sample rate (in Hz) from the end of the header. + // 1110: get 16 bit sample rate (in daHz) from the end of the header. + // 1111: invalid. + switch sampleRate { + case 0x0: + // 0000: unknown sample rate; get from StreamInfo. + case 0x1: + // 0001: 88.2 kHz. + frame.SampleRate = 88200 + case 0x2: + // 0010: 176.4 kHz. + frame.SampleRate = 176400 + // TODO(u): Remove log message when the test cases have been extended. + log.Printf("frame.Frame.parseHeader: The flac library test cases do not yet include any audio files with sample rate %d. If possible please consider contributing this audio sample to improve the reliability of the test cases.", frame.SampleRate) + case 0x3: + // 0011: 192 kHz. + frame.SampleRate = 192000 + case 0x4: + // 0100: 8 kHz. + frame.SampleRate = 8000 + case 0x5: + // 0101: 16 kHz. + frame.SampleRate = 16000 + case 0x6: + // 0110: 22.05 kHz. + frame.SampleRate = 22050 + case 0x7: + // 0111: 24 kHz. + frame.SampleRate = 24000 + // TODO(u): Remove log message when the test cases have been extended. + log.Printf("frame.Frame.parseHeader: The flac library test cases do not yet include any audio files with sample rate %d. If possible please consider contributing this audio sample to improve the reliability of the test cases.", frame.SampleRate) + case 0x8: + // 1000: 32 kHz. + frame.SampleRate = 32000 + case 0x9: + // 1001: 44.1 kHz. + frame.SampleRate = 44100 + case 0xA: + // 1010: 48 kHz. + frame.SampleRate = 48000 + case 0xB: + // 1011: 96 kHz. + frame.SampleRate = 96000 + case 0xC: + // 1100: get 8 bit sample rate (in kHz) from the end of the header. + x, err := br.Read(8) + if err != nil { + return unexpected(err) + } + frame.SampleRate = uint32(x * 1000) + case 0xD: + // 1101: get 16 bit sample rate (in Hz) from the end of the header. + x, err := br.Read(16) + if err != nil { + return unexpected(err) + } + frame.SampleRate = uint32(x) + case 0xE: + // 1110: get 16 bit sample rate (in daHz) from the end of the header. + x, err := br.Read(16) + if err != nil { + return unexpected(err) + } + frame.SampleRate = uint32(x * 10) + default: + // 1111: invalid. + return errors.New("frame.Frame.parseHeader: invalid sample rate bit pattern (1111)") + } + return nil +} + +// Channels specifies the number of channels (subframes) that exist in a frame, +// their order and possible inter-channel decorrelation. +type Channels uint8 + +// Channel assignments. The following abbreviations are used: +// +// C: center (directly in front) +// R: right (standard stereo) +// Sr: side right (directly to the right) +// Rs: right surround (back right) +// Cs: center surround (rear center) +// Ls: left surround (back left) +// Sl: side left (directly to the left) +// L: left (standard stereo) +// Lfe: low-frequency effect (placed according to room acoustics) +// +// The first 6 channel constants follow the SMPTE/ITU-R channel order: +// +// L R C Lfe Ls Rs +const ( + ChannelsMono Channels = iota // 1 channel: mono. + ChannelsLR // 2 channels: left, right. + ChannelsLRC // 3 channels: left, right, center. + ChannelsLRLsRs // 4 channels: left, right, left surround, right surround. + ChannelsLRCLsRs // 5 channels: left, right, center, left surround, right surround. + ChannelsLRCLfeLsRs // 6 channels: left, right, center, LFE, left surround, right surround. + ChannelsLRCLfeCsSlSr // 7 channels: left, right, center, LFE, center surround, side left, side right. + ChannelsLRCLfeLsRsSlSr // 8 channels: left, right, center, LFE, left surround, right surround, side left, side right. + ChannelsLeftSide // 2 channels: left, side; using inter-channel decorrelation. + ChannelsSideRight // 2 channels: side, right; using inter-channel decorrelation. + ChannelsMidSide // 2 channels: mid, side; using inter-channel decorrelation. +) + +// nChannels specifies the number of channels used by each channel assignment. +var nChannels = [...]int{ + ChannelsMono: 1, + ChannelsLR: 2, + ChannelsLRC: 3, + ChannelsLRLsRs: 4, + ChannelsLRCLsRs: 5, + ChannelsLRCLfeLsRs: 6, + ChannelsLRCLfeCsSlSr: 7, + ChannelsLRCLfeLsRsSlSr: 8, + ChannelsLeftSide: 2, + ChannelsSideRight: 2, + ChannelsMidSide: 2, +} + +// Count returns the number of channels (subframes) used by the provided channel +// assignment. +func (channels Channels) Count() int { + return nChannels[channels] +} + +// Correlate reverts any inter-channel decorrelation between the samples of the +// subframes. +// +// An encoder decorrelates audio samples as follows: +// +// mid = (left + right)/2 +// side = left - right +func (frame *Frame) Correlate() { + switch frame.Channels { + case ChannelsLeftSide: + // 2 channels: left, side; using inter-channel decorrelation. + left := frame.Subframes[0].Samples + side := frame.Subframes[1].Samples + for i := range side { + // right = left - side + side[i] = left[i] - side[i] + } + case ChannelsSideRight: + // 2 channels: side, right; using inter-channel decorrelation. + side := frame.Subframes[0].Samples + right := frame.Subframes[1].Samples + for i := range side { + // left = right + side + side[i] = right[i] + side[i] + } + case ChannelsMidSide: + // 2 channels: mid, side; using inter-channel decorrelation. + mid := frame.Subframes[0].Samples + side := frame.Subframes[1].Samples + for i := range side { + // left = (2*mid + side)/2 + // right = (2*mid - side)/2 + m := mid[i] + s := side[i] + m *= 2 + // Notice that the integer division in mid = (left + right)/2 discards + // the least significant bit. It can be reconstructed however, since a + // sum A+B and a difference A-B has the same least significant bit. + // + // ref: Data Compression: The Complete Reference (ch. 7, Decorrelation) + m |= s & 1 + mid[i] = (m + s) / 2 + side[i] = (m - s) / 2 + } + } +} + +// Decorrelate performs inter-channel decorrelation between the samples of the +// subframes. +// +// An encoder decorrelates audio samples as follows: +// +// mid = (left + right)/2 +// side = left - right +func (frame *Frame) Decorrelate() { + switch frame.Channels { + case ChannelsLeftSide: + // 2 channels: left, side; using inter-channel decorrelation. + left := frame.Subframes[0].Samples // already left; no change after inter-channel decorrelation. + right := frame.Subframes[1].Samples // set to side after inter-channel decorrelation. + for i := range left { + l := left[i] + r := right[i] + // inter-channel decorrelation: + // side = left - right + side := l - r + right[i] = side + } + case ChannelsSideRight: + // 2 channels: side, right; using inter-channel decorrelation. + left := frame.Subframes[0].Samples // set to side after inter-channel decorrelation. + right := frame.Subframes[1].Samples // already right; no change after inter-channel decorrelation. + for i := range left { + l := left[i] + r := right[i] + // inter-channel decorrelation: + // side = left - right + side := l - r + left[i] = side + } + case ChannelsMidSide: + // 2 channels: mid, side; using inter-channel decorrelation. + left := frame.Subframes[0].Samples // set to mid after inter-channel decorrelation. + right := frame.Subframes[1].Samples // set to side after inter-channel decorrelation. + for i := range left { + // inter-channel decorrelation: + // mid = (left + right)/2 + // side = left - right + l := left[i] + r := right[i] + mid := int32((int64(l) + int64(r)) >> 1) // NOTE: using `(left + right) >> 1`, not the same as `(left + right) / 2`. + side := l - r + left[i] = mid + right[i] = side + } + } +} + +// SampleNumber returns the first sample number contained within the frame. +func (frame *Frame) SampleNumber() uint64 { + if frame.HasFixedBlockSize { + return frame.Num * uint64(frame.BlockSize) + } + return frame.Num +} + +// unexpected returns io.ErrUnexpectedEOF if err is io.EOF, and returns err +// otherwise. +func unexpected(err error) error { + if err == io.EOF { + return io.ErrUnexpectedEOF + } + return err +} diff --git a/frame/frame_test.go b/frame/frame_test.go new file mode 100755 index 0000000..cf66425 --- /dev/null +++ b/frame/frame_test.go @@ -0,0 +1,193 @@ +package frame_test + +import ( + "bytes" + "crypto/md5" + "io" + "testing" + + "github.com/mewkiz/flac" +) + +var golden = []struct { + path string +}{ + {path: "../testdata/love.flac"}, + {path: "../testdata/19875.flac"}, + {path: "../testdata/44127.flac"}, + {path: "../testdata/59996.flac"}, + {path: "../testdata/80574.flac"}, + {path: "../testdata/172960.flac"}, + {path: "../testdata/189983.flac"}, + {path: "../testdata/191885.flac"}, + {path: "../testdata/212768.flac"}, + {path: "../testdata/220014.flac"}, + {path: "../testdata/243749.flac"}, + {path: "../testdata/256529.flac"}, + {path: "../testdata/257344.flac"}, + + // IETF test cases. + {path: "../testdata/flac-test-files/subset/01 - blocksize 4096.flac"}, + {path: "../testdata/flac-test-files/subset/02 - blocksize 4608.flac"}, + {path: "../testdata/flac-test-files/subset/03 - blocksize 16.flac"}, + {path: "../testdata/flac-test-files/subset/04 - blocksize 192.flac"}, + {path: "../testdata/flac-test-files/subset/05 - blocksize 254.flac"}, + {path: "../testdata/flac-test-files/subset/06 - blocksize 512.flac"}, + {path: "../testdata/flac-test-files/subset/07 - blocksize 725.flac"}, + {path: "../testdata/flac-test-files/subset/08 - blocksize 1000.flac"}, + {path: "../testdata/flac-test-files/subset/09 - blocksize 1937.flac"}, + {path: "../testdata/flac-test-files/subset/10 - blocksize 2304.flac"}, + {path: "../testdata/flac-test-files/subset/11 - partition order 8.flac"}, + {path: "../testdata/flac-test-files/subset/12 - qlp precision 15 bit.flac"}, + {path: "../testdata/flac-test-files/subset/13 - qlp precision 2 bit.flac"}, + {path: "../testdata/flac-test-files/subset/14 - wasted bits.flac"}, + {path: "../testdata/flac-test-files/subset/15 - only verbatim subframes.flac"}, + {path: "../testdata/flac-test-files/subset/16 - partition order 8 containing escaped partitions.flac"}, + {path: "../testdata/flac-test-files/subset/17 - all fixed orders.flac"}, + {path: "../testdata/flac-test-files/subset/18 - precision search.flac"}, + {path: "../testdata/flac-test-files/subset/19 - samplerate 35467Hz.flac"}, + {path: "../testdata/flac-test-files/subset/20 - samplerate 39kHz.flac"}, + {path: "../testdata/flac-test-files/subset/21 - samplerate 22050Hz.flac"}, + {path: "../testdata/flac-test-files/subset/22 - 12 bit per sample.flac"}, + {path: "../testdata/flac-test-files/subset/23 - 8 bit per sample.flac"}, + {path: "../testdata/flac-test-files/subset/24 - variable blocksize file created with flake revision 264.flac"}, + {path: "../testdata/flac-test-files/subset/25 - variable blocksize file created with flake revision 264, modified to create smaller blocks.flac"}, + {path: "../testdata/flac-test-files/subset/26 - variable blocksize file created with CUETools.Flake 2.1.6.flac"}, + {path: "../testdata/flac-test-files/subset/27 - old format variable blocksize file created with Flake 0.11.flac"}, + {path: "../testdata/flac-test-files/subset/28 - high resolution audio, default settings.flac"}, + {path: "../testdata/flac-test-files/subset/29 - high resolution audio, blocksize 16384.flac"}, + {path: "../testdata/flac-test-files/subset/30 - high resolution audio, blocksize 13456.flac"}, + {path: "../testdata/flac-test-files/subset/31 - high resolution audio, using only 32nd order predictors.flac"}, + {path: "../testdata/flac-test-files/subset/32 - high resolution audio, partition order 8 containing escaped partitions.flac"}, + {path: "../testdata/flac-test-files/subset/33 - samplerate 192kHz.flac"}, + {path: "../testdata/flac-test-files/subset/34 - samplerate 192kHz, using only 32nd order predictors.flac"}, + {path: "../testdata/flac-test-files/subset/35 - samplerate 134560Hz.flac"}, + {path: "../testdata/flac-test-files/subset/36 - samplerate 384kHz.flac"}, + {path: "../testdata/flac-test-files/subset/37 - 20 bit per sample.flac"}, + {path: "../testdata/flac-test-files/subset/38 - 3 channels (3.0).flac"}, + {path: "../testdata/flac-test-files/subset/39 - 4 channels (4.0).flac"}, + {path: "../testdata/flac-test-files/subset/40 - 5 channels (5.0).flac"}, + {path: "../testdata/flac-test-files/subset/41 - 6 channels (5.1).flac"}, + {path: "../testdata/flac-test-files/subset/42 - 7 channels (6.1).flac"}, + {path: "../testdata/flac-test-files/subset/43 - 8 channels (7.1).flac"}, + {path: "../testdata/flac-test-files/subset/44 - 8-channel surround, 192kHz, 24 bit, using only 32nd order predictors.flac"}, + {path: "../testdata/flac-test-files/subset/45 - no total number of samples set.flac"}, + {path: "../testdata/flac-test-files/subset/46 - no min-max framesize set.flac"}, + {path: "../testdata/flac-test-files/subset/47 - only STREAMINFO.flac"}, + {path: "../testdata/flac-test-files/subset/48 - Extremely large SEEKTABLE.flac"}, + {path: "../testdata/flac-test-files/subset/49 - Extremely large PADDING.flac"}, + {path: "../testdata/flac-test-files/subset/50 - Extremely large PICTURE.flac"}, + {path: "../testdata/flac-test-files/subset/51 - Extremely large VORBISCOMMENT.flac"}, + {path: "../testdata/flac-test-files/subset/52 - Extremely large APPLICATION.flac"}, + {path: "../testdata/flac-test-files/subset/53 - CUESHEET with very many indexes.flac"}, + {path: "../testdata/flac-test-files/subset/54 - 1000x repeating VORBISCOMMENT.flac"}, + {path: "../testdata/flac-test-files/subset/55 - file 48-53 combined.flac"}, + {path: "../testdata/flac-test-files/subset/56 - JPG PICTURE.flac"}, + {path: "../testdata/flac-test-files/subset/57 - PNG PICTURE.flac"}, + {path: "../testdata/flac-test-files/subset/58 - GIF PICTURE.flac"}, + {path: "../testdata/flac-test-files/subset/59 - AVIF PICTURE.flac"}, + {path: "../testdata/flac-test-files/subset/60 - mono audio.flac"}, + {path: "../testdata/flac-test-files/subset/61 - predictor overflow check, 16-bit.flac"}, + {path: "../testdata/flac-test-files/subset/62 - predictor overflow check, 20-bit.flac"}, + // TODO: fix decoding of "subset/63 - ...flac": MD5 checksum mismatch for decoded audio samples; expected e4e4a6b3a672a849a3e2157c11ad23c6, got a0343afaaaa6229266d78ccf3175eb8d + {path: "../testdata/flac-test-files/subset/63 - predictor overflow check, 24-bit.flac"}, + {path: "../testdata/flac-test-files/subset/64 - rice partitions with escape code zero.flac"}, +} + +func TestFrameHash(t *testing.T) { + var zeroHash [md5.Size]byte + for _, g := range golden { + t.Run(g.path, func(t *testing.T) { + stream, err := flac.Open(g.path) + if err != nil { + t.Fatal(err) + } + defer stream.Close() + + // Skip frame hash test if no MD5 hash was set in StreamInfo. + want := stream.Info.MD5sum[:] + if bytes.Equal(want, zeroHash[:]) { + t.Skipf("path=%q, skipping frame hash test as no MD5 hash was set in StreamInfo", g.path) + return + } + + md5sum := md5.New() + for frameNum := 0; ; frameNum++ { + frame, err := stream.ParseNext() + if err != nil { + if err == io.EOF { + break + } + t.Errorf("path=%q, frameNum=%d: error while parsing frame; %v", g.path, frameNum, err) + continue + } + frame.Hash(md5sum) + } + got := md5sum.Sum(nil) + // Verify the decoded audio samples by comparing the MD5 checksum that is + // stored in StreamInfo with the computed one. + if !bytes.Equal(got, want) { + t.Errorf("path=%q: MD5 checksum mismatch for decoded audio samples; expected %32x, got %32x", g.path, want, got) + } + }) + } +} + +func BenchmarkFrameParse(b *testing.B) { + // The file 151185.flac is a 119.5 MB public domain FLAC file used to + // benchmark the flac library. Because of its size, it has not been included + // in the repository, but is available for download at + // + // http://freesound.org/people/jarfil/sounds/151185/ + for i := 0; i < b.N; i++ { + stream, err := flac.Open("../testdata/benchmark/151185.flac") + if err != nil { + b.Fatal(err) + } + for { + _, err := stream.ParseNext() + if err != nil { + if err == io.EOF { + break + } + stream.Close() + b.Fatal(err) + } + } + stream.Close() + } +} + +func BenchmarkFrameHash(b *testing.B) { + // The file 151185.flac is a 119.5 MB public domain FLAC file used to + // benchmark the flac library. Because of its size, it has not been included + // in the repository, but is available for download at + // + // http://freesound.org/people/jarfil/sounds/151185/ + for i := 0; i < b.N; i++ { + stream, err := flac.Open("../testdata/benchmark/151185.flac") + if err != nil { + b.Fatal(err) + } + md5sum := md5.New() + for { + frame, err := stream.ParseNext() + if err != nil { + if err == io.EOF { + break + } + stream.Close() + b.Fatal(err) + } + frame.Hash(md5sum) + } + stream.Close() + want := stream.Info.MD5sum[:] + got := md5sum.Sum(nil) + // Verify the decoded audio samples by comparing the MD5 checksum that is + // stored in StreamInfo with the computed one. + if !bytes.Equal(got, want) { + b.Fatalf("MD5 checksum mismatch for decoded audio samples; expected %32x, got %32x", want, got) + } + } +} diff --git a/frame/subframe.go b/frame/subframe.go new file mode 100755 index 0000000..b906609 --- /dev/null +++ b/frame/subframe.go @@ -0,0 +1,534 @@ +package frame + +import ( + "errors" + "fmt" + + "github.com/mewkiz/flac/internal/bits" +) + +// A Subframe contains the encoded audio samples from one channel of an audio +// block (a part of the audio stream). +// +// ref: https://www.xiph.org/flac/format.html#subframe +type Subframe struct { + // Subframe header. + SubHeader + // Unencoded audio samples. Samples is initially nil, and gets populated by a + // call to Frame.Parse. + // + // Samples is used by decodeFixed and decodeFIR to temporarily store + // residuals. Before returning they call decodeLPC which decodes the audio + // samples. + Samples []int32 + // Number of audio samples in the subframe. + NSamples int +} + +// parseSubframe reads and parses the header, and the audio samples of a +// subframe. +func (frame *Frame) parseSubframe(br *bits.Reader, bps uint) (subframe *Subframe, err error) { + // Parse subframe header. + subframe = new(Subframe) + if err = subframe.parseHeader(br); err != nil { + return subframe, err + } + // Adjust bps of subframe for wasted bits-per-sample. + bps -= subframe.Wasted + + // Decode subframe audio samples. + subframe.NSamples = int(frame.BlockSize) + subframe.Samples = make([]int32, 0, subframe.NSamples) + switch subframe.Pred { + case PredConstant: + err = subframe.decodeConstant(br, bps) + case PredVerbatim: + err = subframe.decodeVerbatim(br, bps) + case PredFixed: + err = subframe.decodeFixed(br, bps) + case PredFIR: + err = subframe.decodeFIR(br, bps) + } + + // Left shift to account for wasted bits-per-sample. + for i, sample := range subframe.Samples { + subframe.Samples[i] = sample << subframe.Wasted + } + return subframe, err +} + +// A SubHeader specifies the prediction method and order of a subframe. +// +// ref: https://www.xiph.org/flac/format.html#subframe_header +type SubHeader struct { + // Specifies the prediction method used to encode the audio sample of the + // subframe. + Pred Pred + // Prediction order used by fixed and FIR linear prediction decoding. + Order int + // Wasted bits-per-sample. + Wasted uint + // Residual coding method used by fixed and FIR linear prediction decoding. + ResidualCodingMethod ResidualCodingMethod + // Coefficients' precision in bits used by FIR linear prediction decoding. + CoeffPrec uint + // Predictor coefficient shift needed in bits used by FIR linear prediction + // decoding. + CoeffShift int32 + // Predictor coefficients used by FIR linear prediction decoding. + Coeffs []int32 + // Rice-coding subframe fields used by residual coding methods rice1 and + // rice2; nil if unused. + RiceSubframe *RiceSubframe +} + +// RiceSubframe holds rice-coding subframe fields used by residual coding +// methods rice1 and rice2. +type RiceSubframe struct { + // Partition order used by fixed and FIR linear prediction decoding + // (for residual coding methods, rice1 and rice2). + PartOrder int // TODO: remove PartOrder and infer from int(math.Log2(float64(len(Partitions))))? + // Rice partitions. + Partitions []RicePartition +} + +// RicePartition is a partition containing a subset of the residuals of a +// subframe. +type RicePartition struct { + // Rice parameter. + Param uint + // Residual sample size in bits-per-sample used by escaped partitions. + EscapedBitsPerSample uint +} + +// parseHeader reads and parses the header of a subframe. +func (subframe *Subframe) parseHeader(br *bits.Reader) error { + // 1 bit: zero-padding. + x, err := br.Read(1) + if err != nil { + return unexpected(err) + } + if x != 0 { + return errors.New("frame.Subframe.parseHeader: non-zero padding") + } + + // 6 bits: Pred. + x, err = br.Read(6) + if err != nil { + return unexpected(err) + } + // The 6 bits are used to specify the prediction method and order as follows: + // 000000: Constant prediction method. + // 000001: Verbatim prediction method. + // 00001x: reserved. + // 0001xx: reserved. + // 001xxx: + // if (xxx <= 4) + // Fixed prediction method; xxx=order + // else + // reserved. + // 01xxxx: reserved. + // 1xxxxx: FIR prediction method; xxxxx=order-1 + switch { + case x < 1: + // 000000: Constant prediction method. + subframe.Pred = PredConstant + case x < 2: + // 000001: Verbatim prediction method. + subframe.Pred = PredVerbatim + case x < 8: + // 00001x: reserved. + // 0001xx: reserved. + return fmt.Errorf("frame.Subframe.parseHeader: reserved prediction method bit pattern (%06b)", x) + case x < 16: + // 001xxx: + // if (xxx <= 4) + // Fixed prediction method; xxx=order + // else + // reserved. + order := int(x & 0x07) + if order > 4 { + return fmt.Errorf("frame.Subframe.parseHeader: reserved prediction method bit pattern (%06b)", x) + } + subframe.Pred = PredFixed + subframe.Order = order + case x < 32: + // 01xxxx: reserved. + return fmt.Errorf("frame.Subframe.parseHeader: reserved prediction method bit pattern (%06b)", x) + default: + // 1xxxxx: FIR prediction method; xxxxx=order-1 + subframe.Pred = PredFIR + subframe.Order = int(x&0x1F) + 1 + } + + // 1 bit: hasWastedBits. + x, err = br.Read(1) + if err != nil { + return unexpected(err) + } + if x != 0 { + // k wasted bits-per-sample in source subblock, k-1 follows, unary coded; + // e.g. k=3 => 001 follows, k=7 => 0000001 follows. + x, err = br.ReadUnary() + if err != nil { + return unexpected(err) + } + subframe.Wasted = uint(x) + 1 + } + + return nil +} + +// Pred specifies the prediction method used to encode the audio samples of a +// subframe. +type Pred uint8 + +// Prediction methods. +const ( + // PredConstant specifies that the subframe contains a constant sound. The + // audio samples are encoded using run-length encoding. Since every audio + // sample has the same constant value, a single unencoded audio sample is + // stored in practice. It is replicated a number of times, as specified by + // BlockSize in the frame header. + PredConstant Pred = iota + // PredVerbatim specifies that the subframe contains unencoded audio samples. + // Random sound is often stored verbatim, since no prediction method can + // compress it sufficiently. + PredVerbatim + // PredFixed specifies that the subframe contains linear prediction coded + // audio samples. The coefficients of the prediction polynomial are selected + // from a fixed set, and can represent 0th through fourth-order polynomials. + // The prediction order (0 through 4) is stored within the subframe along + // with the same number of unencoded warm-up samples, which are used to kick + // start the prediction polynomial. The remainder of the subframe stores + // encoded residuals (signal errors) which specify the difference between the + // predicted and the original audio samples. + PredFixed + // PredFIR specifies that the subframe contains linear prediction coded audio + // samples. The coefficients of the prediction polynomial are stored in the + // subframe, and can represent 0th through 32nd-order polynomials. The + // prediction order (0 through 32) is stored within the subframe along with + // the same number of unencoded warm-up samples, which are used to kick start + // the prediction polynomial. The remainder of the subframe stores encoded + // residuals (signal errors) which specify the difference between the + // predicted and the original audio samples. + PredFIR +) + +// signExtend interprets x as a signed n-bit integer value and sign extends it +// to 32 bits. +func signExtend(x uint64, n uint) int32 { + // x is signed if its most significant bit is set. + if x&(1<<(n-1)) != 0 { + // Sign extend x. + return int32(x | ^uint64(0)<> uint(shift)) + } + return nil +} diff --git a/go.mod b/go.mod new file mode 100755 index 0000000..2986412 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/mewkiz/flac + +go 1.14 + +require ( + github.com/icza/bitio v1.1.0 + github.com/mewkiz/pkg v0.0.0-20230226050401-4010bf0fec14 +) diff --git a/go.sum b/go.sum new file mode 100755 index 0000000..3653f5a --- /dev/null +++ b/go.sum @@ -0,0 +1,37 @@ +github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= +github.com/icza/bitio v1.1.0 h1:ysX4vtldjdi3Ygai5m1cWy4oLkhWTAi+SyO6HC8L9T0= +github.com/icza/bitio v1.1.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A= +github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k= +github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA= +github.com/jszwec/csvutil v1.5.1/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg= +github.com/mewkiz/pkg v0.0.0-20230226050401-4010bf0fec14 h1:tnAPMExbRERsyEYkmR1YjhTgDM0iqyiBYf8ojRXxdbA= +github.com/mewkiz/pkg v0.0.0-20230226050401-4010bf0fec14/go.mod h1:QYCFBiH5q6XTHEbWhR0uhR3M9qNPoD2CSQzr0g75kE4= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/bits/reader.go b/internal/bits/reader.go new file mode 100755 index 0000000..85027bc --- /dev/null +++ b/internal/bits/reader.go @@ -0,0 +1,84 @@ +// Package bits provides bit access operations and binary decoding algorithms. +package bits + +import ( + "fmt" + "io" +) + +// A Reader handles bit reading operations. It buffers bits up to the next byte +// boundary. +type Reader struct { + // Underlying reader. + r io.Reader + // Temporary read buffer. + buf [8]uint8 + // Between 0 and 7 buffered bits since previous read operations. + x uint8 + // The number of buffered bits in x. + n uint +} + +// NewReader returns a new Reader that reads bits from r. +func NewReader(r io.Reader) *Reader { + return &Reader{r: r} +} + +// Read reads and returns the next n bits, at most 64. It buffers bits up to the +// next byte boundary. +func (br *Reader) Read(n uint) (x uint64, err error) { + if n == 0 { + return 0, nil + } + if n > 64 { + return 0, fmt.Errorf("bit.Reader.Read: invalid number of bits; n (%d) exceeds 64", n) + } + + // Read buffered bits. + if br.n > 0 { + switch { + case br.n == n: + br.n = 0 + return uint64(br.x), nil + case br.n > n: + br.n -= n + mask := ^uint8(0) << br.n + x = uint64(br.x&mask) >> br.n + br.x &^= mask + return x, nil + } + n -= br.n + x = uint64(br.x) + br.n = 0 + } + + // Fill the temporary buffer. + bytes := n / 8 + bits := n % 8 + if bits > 0 { + bytes++ + } + _, err = io.ReadFull(br.r, br.buf[:bytes]) + if err != nil { + return 0, err + } + + // Read bits from the temporary buffer. + for _, b := range br.buf[:bytes-1] { + x <<= 8 + x |= uint64(b) + } + b := br.buf[bytes-1] + if bits > 0 { + x <<= bits + br.n = 8 - bits + mask := ^uint8(0) << br.n + x |= uint64(b&mask) >> br.n + br.x = b & ^mask + } else { + x <<= 8 + x |= uint64(b) + } + + return x, nil +} diff --git a/internal/bits/reader_test.go b/internal/bits/reader_test.go new file mode 100755 index 0000000..5acaede --- /dev/null +++ b/internal/bits/reader_test.go @@ -0,0 +1,688 @@ +// © 2013 the Bits Authors under the MIT license. See AUTHORS for the list of authors. +// +// Some benchmark functions in this file were adapted from github.com/bamiaux/iobit +// which came with the following copyright notice: +// Copyright 2013 Benoît Amiaux. All rights reserved. + +package bits + +import ( + "bytes" + "io" + "math/rand" + "testing" +) + +func TestRead(t *testing.T) { + tests := []struct { + data []byte + ns []uint + vals []uint64 + }{ + // 11111111 + {[]byte{0xFF}, []uint{1, 1, 1, 1, 1, 1, 1, 1}, []uint64{1, 1, 1, 1, 1, 1, 1, 1}}, + {[]byte{0xFF}, []uint{2, 2, 2, 2}, []uint64{0x3, 0x3, 0x3, 0x3}}, + {[]byte{0xFF}, []uint{3, 3, 2}, []uint64{0x7, 0x7, 0x3}}, + {[]byte{0xFF}, []uint{4, 4}, []uint64{0xF, 0xF}}, + {[]byte{0xFF}, []uint{5, 3}, []uint64{0x1F, 0x7}}, + {[]byte{0xFF}, []uint{6, 2}, []uint64{0x3F, 0x3}}, + {[]byte{0xFF}, []uint{7, 1}, []uint64{0x7F, 0x1}}, + {[]byte{0xFF}, []uint{8}, []uint64{0xFF}}, + + // 10101010 + {[]byte{0xAA}, []uint{1, 1, 1, 1, 1, 1, 1, 1}, []uint64{1, 0, 1, 0, 1, 0, 1, 0}}, + {[]byte{0xAA}, []uint{2, 2, 2, 2}, []uint64{0x2, 0x2, 0x2, 0x2}}, + {[]byte{0xAA}, []uint{3, 3, 2}, []uint64{0x5, 0x2, 0x2}}, + {[]byte{0xAA}, []uint{4, 4}, []uint64{0xA, 0xA}}, + {[]byte{0xAA}, []uint{5, 3}, []uint64{0x15, 0x2}}, + {[]byte{0xAA}, []uint{6, 2}, []uint64{0x2A, 0x2}}, + {[]byte{0xAA}, []uint{7, 1}, []uint64{0x55, 0x0}}, + {[]byte{0xAA}, []uint{8}, []uint64{0xAA}}, + + {[]byte{0xAA}, []uint{0}, []uint64{0}}, + + // orig: 101010101010101010101010101010101010101010101010101010101010101010101010 + // 6 bits: 101010 (0x2A) + // 64 bits: 1010101010101010101010101010101010101010101010101010101010101010 (0xAAAAAAAAAAAAAAAA) + // 2 bit: 10 (0x2) + {[]byte{0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}, []uint{6, 64, 2}, []uint64{0x2A, 0xAAAAAAAAAAAAAAAA, 0x2}}, + + // 01 1011011 011011 0 + {[]byte{0x6D, 0xB6}, []uint{2, 7, 6, 1}, []uint64{0x1, 0x5B, 0x1B, 0x0}}, + + { + []byte{0x21, 0x0F, 0xC7, 0xBB, 0x81, 0x86, 0x39, 0xAC, 0x48, 0xA4, 0xC6, 0xAF, 0xA2, 0xF1, 0x58, 0x1A, 0x8B, 0x95, 0x25, 0xE2, 0x0F, 0xDA, 0x68, 0x92, 0x7F, 0x2B, 0x2F, 0xF8, 0x36, 0xF7, 0x35, 0x78, 0xDB, 0x0F, 0xA5, 0x4C, 0x29, 0xF7, 0xFD, 0x92, 0x8D, 0x92, 0xCA, 0x43, 0xF1, 0x93, 0xDE, 0xE4, 0x7F, 0x59, 0x15, 0x49, 0xF5, 0x97, 0xA8, 0x11, 0xC8, 0xFA, 0x67, 0xAB, 0x03, 0x1E, 0xBD, 0x9C, 0x6A, 0xA4, 0xE9, 0x82, 0x9F, 0x22, 0x4B, 0xE8, 0xEA, 0xF6, 0x67, 0x26, 0xC9, 0x07, 0x7C, 0xB4, 0x1F, 0x79, 0x01, 0x9D, 0x89, 0x2B, 0xE9, 0x93, 0x03, 0xB2, 0xBE, 0x58, 0x82, 0xF3, 0x24, 0x07, 0x58, 0xA3, 0x8D, 0x7E}, + []uint{2, 40, 28, 62, 8, 59, 51, 54, 63, 49, 11, 42, 64, 7, 41, 2, 4, 58, 24, 55, 63, 13}, + []uint64{0x00, 0x843F1EEE06, 0x18E6B12, 0xA4C6AFA2F1581A8, 0xB9, 0x292F107ED34493F, 0x4ACBFE0DBDCD5, 0x38DB0FA54C29F7, 0x7EC946C96521F8C9, 0x1DEE47F591549, 0x7AC, 0x2F502391F4C, 0xF56063D7B38D549D, 0x18, 0x53E4497D1D, 0x01, 0x07, 0x2CCE4D920EF9683, 0xEF2033, 0x5892BE99303B2B, 0x72C41799203AC51C, 0xD7E}, + }, + { + []byte{0x0D, 0xAF, 0x62, 0xD6, 0x5D, 0xCE, 0x5B, 0xA5, 0x24, 0xF7, 0x35, 0x8E, 0xFB, 0xB5, 0xB8, 0x32, 0x20, 0xCF, 0x58, 0x63, 0x6C, 0xBC, 0x40, 0xCF, 0xAC, 0x9A, 0xEB, 0x3C, 0xC8, 0x47, 0xBC, 0xDC, 0xF1, 0x0F, 0x71, 0x7A, 0xA2, 0x62, 0x77, 0xFF, 0x0A, 0x3A, 0x0E, 0xC7, 0x3E, 0x10, 0xFF, 0x40, 0x8E, 0xCE, 0x87, 0x28, 0xF8, 0x4A, 0xE1, 0xAF, 0x7B, 0xBF, 0x86, 0xE9, 0x94, 0x6F, 0xB0, 0x8F, 0xB6, 0x58, 0x97, 0x5A, 0xB5, 0x52, 0x9D, 0x70, 0x40, 0x74, 0xAF, 0x4A, 0xC8, 0xC0, 0xF5, 0xA4, 0x6F, 0x09, 0x6E, 0xE8, 0x47, 0x7A, 0x77, 0x54, 0x30, 0x03, 0x8F, 0xC0, 0x0E, 0xAC, 0x03, 0xAF, 0x4D, 0xDC, 0xD3, 0x25}, + []uint{62, 44, 50, 50, 7, 53, 11, 9, 57, 37, 35, 54, 30, 45, 5, 8, 59, 9, 13, 48, 62, 46, 6}, + []uint64{0x36BD8B5977396E9, 0x493DCD63BEE, 0x35B83220CF586, 0xDB2F1033EB26, 0x5D, 0xCF3211EF373C4, 0x1EE, 0x5E, 0x151313BFF851D07, 0xC73E10FF4, 0x47674394, 0x1F095C35EF77F0, 0x374CA37D, 0x108FB658975A, 0x16, 0xAA, 0x29D704074AF4AC8, 0x181, 0x1D69, 0x1BC25BBA11DE, 0x2775430038FC00EA, 0x300EBD37734C, 0x25}, + }, + { + []byte{0x08, 0x0F, 0x1D, 0xFD, 0xC9, 0xC4, 0xAD, 0x25, 0x6F, 0x47, 0x56, 0x20, 0x46, 0xFC, 0x40, 0x54, 0xF5, 0x9B, 0x5B, 0xE5, 0x46, 0x5E, 0x75, 0xE6, 0xE0, 0xAA, 0x60, 0xC8, 0xEB, 0x2E, 0xE5, 0xD4, 0xCD, 0x26, 0x50, 0xA8, 0x1C, 0xCE, 0xE3, 0x55, 0x07, 0xA1, 0x1A, 0x37, 0x90, 0x71, 0xC7, 0x51, 0xF7, 0x1F, 0xDF, 0x0D, 0xFE, 0xB3, 0xFB, 0xC8, 0xF0, 0x08, 0x25, 0xE6, 0x4C, 0x27, 0x62, 0xFA, 0xC9, 0xFE, 0x63, 0xE2, 0x42, 0x03, 0x7A, 0x8B, 0xC4, 0x03, 0x69, 0x6E, 0x07, 0x33, 0x42, 0x37, 0x10, 0x4C, 0x5E, 0xC5, 0x64, 0x2C, 0xA3, 0xC1, 0xC2, 0x55, 0x0A, 0x87, 0x16, 0xA9, 0x28, 0xE7, 0xCD, 0xBA, 0xEA, 0xC9}, + []uint{64, 38, 1, 25, 10, 6, 13, 38, 27, 13, 48, 53, 3, 30, 60, 39, 32, 34, 5, 1, 56, 26, 47, 21, 43, 32, 35}, + []uint64{0x80F1DFDC9C4AD25, 0x1BD1D58811, 0x01, 0xFC4054, 0x3D6, 0x1B, 0xB7C, 0x2A32F3AF37, 0x2A9832, 0x759, 0x772EA6693285, 0x81CCEE35507A1, 0x00, 0x346F20E3, 0x8EA3EE3FBE1BFD6, 0x3FBC8F0082, 0x5E64C276, 0xBEB27F98, 0x1F, 0x00, 0x242037A8BC4036, 0x25B81CC, 0x6846E2098BD8, 0x1590B2, 0x478384AA150, 0xE2D5251C, 0x7CDBAEAC9}, + }, + { + []byte{0x49, 0x2C, 0x95, 0x56, 0xD7, 0x40, 0x88, 0xA9, 0x13, 0x2E, 0x4A, 0x5C, 0x13, 0xCC, 0x15, 0x9A, 0xA6, 0xEB, 0x4A, 0x0E, 0x9B, 0x96, 0x3C, 0xAD, 0xD1, 0x6E, 0x9C, 0x2D, 0xBA, 0xFD, 0xCE, 0x26, 0xC7, 0x18, 0xBC, 0xDC, 0x0F, 0xA7, 0xD4, 0xAD, 0x15, 0x5E, 0xEB, 0xCC, 0xB9, 0x46, 0x71, 0xE3, 0xDD, 0xFB, 0x4B, 0x99, 0x7D, 0x5B, 0x3F, 0xE4, 0xA4, 0x8B, 0x59, 0x8E, 0x7D, 0x89, 0xDF, 0xFF, 0x84, 0x0D, 0xAE, 0xCA, 0xA8, 0x9B, 0x8E, 0xF2, 0x31, 0xF6, 0xF2, 0x7E, 0x13, 0xDA, 0xEB, 0xE2, 0xED, 0xCD, 0xED, 0x9F, 0x38, 0xC6, 0x9E, 0x7F, 0x7A, 0xA1, 0x83, 0x4E, 0xDA, 0x01, 0xE3, 0x35, 0x41, 0x20, 0x10, 0xA6}, + []uint{18, 61, 54, 29, 43, 60, 15, 25, 42, 47, 8, 6, 7, 2, 37, 8, 13, 24, 49, 16, 22, 19, 36, 17, 43, 27, 9, 5, 36, 22}, + []uint64{0x124B2, 0xAAB6BA044548997, 0x94B827982B354, 0x1BAD283A, 0x372C795BA2D, 0xD385B75FB9C4D8E, 0x18BC, 0x1B81F4F, 0x2A568AAF75E, 0x32E519C78F77, 0xED, 0x0B, 0x4C, 0x02, 0x1F56CFF929, 0x22, 0x1ACC, 0x73EC4E, 0x1FFF840DAECAA, 0x89B8, 0x3BC8C7, 0x6DE4F, 0xC27B5D7C5, 0x1B737, 0x5B3E718D3CF, 0x77AA183, 0x9D, 0x16, 0x8078CD504, 0x2010A6}, + }, + { + []byte{0x7B, 0x22, 0xD1, 0x15, 0x7D, 0x2A, 0x8F, 0x5E, 0x35, 0x8E, 0xFD, 0x26, 0x3D, 0x98, 0xF0, 0x10, 0x18, 0xD7, 0x1E, 0xDC, 0x1D, 0x54, 0x3A, 0x4D, 0xF3, 0xED, 0xDB, 0x19, 0x46, 0xF8, 0x5B, 0xF3, 0xE5, 0x2C, 0x4B, 0xB6, 0x80, 0x08, 0x4D, 0x27, 0x71, 0x58, 0xAA, 0x81, 0x28, 0x1C, 0x8A, 0xB5, 0x47, 0x6A, 0x84, 0x1B, 0xF2, 0x23, 0xC1, 0xC0, 0x6E, 0x51, 0xF9, 0xB5, 0x19, 0x80, 0xCD, 0xF8, 0x06, 0x6B, 0x31, 0xF6, 0x23, 0x84, 0x1C, 0xB6, 0xBF, 0xEA, 0x59, 0x9B, 0xD8, 0x4F, 0x84, 0x04, 0xDB, 0x4B, 0x71, 0xE4, 0xAE, 0xF2, 0xD6, 0xE9, 0x2A, 0x16, 0x42, 0x9E, 0x0C, 0xFC, 0xA6, 0x84, 0x79, 0xC8, 0x2A, 0x23}, + []uint{52, 58, 42, 30, 54, 55, 26, 15, 18, 43, 47, 34, 58, 3, 15, 17, 48, 8, 50, 49, 37, 18, 23}, + []uint64{0x7B22D1157D2A8, 0x3D78D63BF498F66, 0xF01018D71E, 0x3707550E, 0x24DF3EDDB1946F, 0x42DF9F29625DB4, 0x109A4, 0x7715, 0x22AA0, 0x25039156A8E, 0x6A841BF223C1, 0x301B947E6, 0x351980CDF8066B3, 0x00, 0x7D88, 0x1C20E, 0x5B5FF52CCDEC, 0x27, 0x30809B696E3C9, 0xBBCB5BA4A859, 0x14F067E53, 0x108F3, 0x482A23}, + }, + { + []byte{0x0B, 0xBD, 0x5B, 0x49, 0x1C, 0x14, 0x1C, 0xE6, 0x96, 0x97, 0x97, 0x3C, 0x76, 0x70, 0xF4, 0x3E, 0xBA, 0x37, 0x88, 0xB2, 0x46, 0xBF, 0x22, 0xE9, 0xA2, 0x84, 0x7A, 0x3D, 0xF2, 0x12, 0xC9, 0xB5, 0x28, 0x15, 0x0A, 0x31, 0x4E, 0xFC, 0x13, 0x09, 0x02, 0x41, 0x3F, 0xCC, 0x8E, 0x0B, 0x06, 0xD1, 0xA3, 0x80, 0x6E, 0x48, 0x12, 0x00, 0xA7, 0xD2, 0x77, 0xCD, 0x9D, 0xB5, 0x91, 0x13, 0x0A, 0x45, 0xBB, 0xE3, 0xFA, 0x0F, 0xC7, 0x8F, 0x4F, 0x4C, 0x3C, 0xB3, 0xC1, 0xD7, 0xC8, 0x92, 0xB1, 0x32, 0x0B, 0x07, 0x21, 0x27, 0x60, 0x0A, 0xF5, 0x44, 0xDB, 0x90, 0x8C, 0x62, 0xBB, 0x20, 0xB1, 0x84, 0x3B, 0xDB, 0xAF, 0xDB}, + []uint{5, 4, 44, 10, 7, 54, 2, 22, 24, 49, 32, 52, 63, 57, 25, 5, 61, 22, 9, 25, 51, 12, 14, 1, 23, 57, 16, 40, 14}, + []uint64{0x01, 0x07, 0x7AB69238283, 0x273, 0x25, 0x297973C7670F43, 0x03, 0x2BA378, 0x8B246B, 0x1E45D34508F47, 0xBE425936, 0xA502A14629DF8, 0x130902413FCC8E0B, 0xDA34700DC9024, 0x29F49, 0x1B, 0x1CD9DB591130A45B, 0x2F8FE8, 0x7E, 0x78F4F4, 0x61E59E0EBE449, 0x589, 0x2416, 0x00, 0xE424E, 0x1802BD5136E4231, 0x8AEC, 0x82C610EF6E, 0x2FDB}, + }, + { + []byte{0x48, 0xB3, 0x01, 0xCE, 0x08, 0x20, 0xE4, 0xBD, 0x27, 0x21, 0x0A, 0x77, 0x34, 0x5A, 0x50, 0x74, 0xD5, 0x56, 0xCB, 0xE2, 0xCB, 0x7A, 0x63, 0x5F, 0xE3, 0x04, 0x52, 0x87, 0xA8, 0x16, 0x3D, 0x78, 0xE5, 0xC3, 0x82, 0x84, 0x80, 0xC9, 0x67, 0xD4, 0x34, 0xB4, 0xAF, 0xEF, 0x9F, 0x91, 0x5E, 0x1B, 0x8D, 0xF5, 0x43, 0x24, 0xB4, 0xDA, 0xD0, 0xBA, 0xC0, 0xEE, 0xF1, 0x94, 0xA1, 0xE8, 0xAC, 0xDB, 0x84, 0xB8, 0xDC, 0x99, 0x62, 0x4B, 0x19, 0xD1, 0xF8, 0xC5, 0x48, 0x7E, 0xEB, 0x9F, 0x82, 0xFF, 0xE9, 0xA4, 0x88, 0x86, 0x5C, 0x28, 0x60, 0x0F, 0xA3, 0xA7, 0x0B, 0x97, 0xFE, 0x4C, 0x99, 0x17, 0x08, 0xB5, 0x58, 0x94}, + []uint{34, 25, 22, 55, 18, 20, 35, 30, 1, 12, 30, 64, 32, 33, 51, 3, 32, 32, 15, 10, 25, 26, 26, 20, 62, 63, 24}, + []uint64{0x122CC0738, 0x410725, 0x3A4E42, 0xA77345A5074D5, 0x15B2F, 0x8B2DE, 0x4C6BFC608, 0x2943D40B, 0x00, 0x3D7, 0x23970E0A, 0x1203259F50D2D2BF, 0xBE7E4578, 0xDC6FAA19, 0x12D36B42EB03B, 0x05, 0xE32943D1, 0x59B70971, 0x5C99, 0x189, 0x58CE8F, 0x318A90F, 0x375CFC1, 0x7FF4D, 0x9110CB850C01F47, 0x270B97FE4C991708, 0xB55894}, + }, + { + []byte{0x48, 0x34, 0xA6, 0xF7, 0xD5, 0x71, 0x21, 0x1F, 0x5D, 0x73, 0xC4, 0xCF, 0x93, 0x0B, 0x9C, 0x62, 0xD3, 0xD2, 0x0F, 0x53, 0x68, 0xFC, 0x22, 0x1B, 0x99, 0x91, 0x60, 0x87, 0x45, 0x9C, 0x56, 0x41, 0x66, 0x1C, 0x32, 0x52, 0xB0, 0xAA, 0xA1, 0x65, 0xED, 0x1D, 0x0F, 0x3E, 0x40, 0x5B, 0x80, 0xD1, 0xE8, 0x6B, 0x4C, 0x1A, 0x7E, 0xAD, 0xC2, 0x77, 0x36, 0xA5, 0x02, 0x01, 0x21, 0x98, 0x92, 0x1C, 0x7A, 0xCB, 0x68, 0x3B, 0x03, 0xFC, 0xC9, 0x67, 0xF7, 0x77, 0x65, 0xE7, 0xFA, 0x5E, 0xF9, 0xE5, 0x92, 0x2A, 0x97, 0x7C, 0xAC, 0x82, 0xF5, 0xEE, 0xAD, 0x81, 0xF4, 0xB9, 0xF0, 0xF7, 0xA7, 0x9C, 0x91, 0xC6, 0x51, 0x4D}, + []uint{61, 55, 35, 55, 14, 6, 37, 60, 46, 25, 52, 62, 27, 23, 3, 27, 39, 19, 31, 2, 6, 52, 7, 48, 8}, + []uint64{0x90694DEFAAE2423, 0x75D73C4CF930B9, 0x63169E907, 0x54DA3F0886E664, 0x1608, 0x1D, 0x2CE2B20B3, 0xE1929585550B2F, 0x1A3A1E7C80B7, 0x347A1, 0xAD3069FAB709D, 0x336A502012198921, 0x63D65B4, 0xEC0FF, 0x01, 0x4967F77, 0x3B2F3FD2F7, 0x67964, 0x4552EF95, 0x02, 0x10, 0x5EBDD5B03E973, 0x70, 0xF7A79C91C651, 0x4D}, + }, + { + []byte{0x04, 0x2A, 0xDC, 0xC2, 0x25, 0xBF, 0x31, 0x81, 0x18, 0xE5, 0x6F, 0xAD, 0xE0, 0x60, 0x2C, 0xAC, 0x62, 0xF2, 0xD5, 0x59, 0xB9, 0x26, 0xAE, 0x4D, 0x67, 0x86, 0x7B, 0x23, 0xA2, 0xCB, 0xAC, 0x63, 0x06, 0xB2, 0xE3, 0x2F, 0x73, 0x59, 0x64, 0x79, 0xAC, 0x74, 0x15, 0xF2, 0x51, 0x14, 0xFB, 0x45, 0x06, 0xBB, 0xF0, 0x29, 0x5A, 0xD2, 0x90, 0x6F, 0x24, 0xB9, 0x8F, 0x06, 0x54, 0xAE, 0x56, 0x33, 0x3D, 0x79, 0x92, 0x42, 0x50, 0xCF, 0x16, 0x53, 0xCB, 0xC6, 0x57, 0x45, 0x17, 0xEA, 0x69, 0x40, 0xAC, 0xCB, 0x97, 0x74, 0xA0, 0x8A, 0x79, 0x40, 0xA1, 0x2E, 0x63, 0xCA, 0x61, 0xCD, 0x98, 0x2B, 0xCF, 0x55, 0x3A, 0xCB}, + []uint{4, 14, 31, 4, 42, 46, 62, 30, 58, 51, 6, 1, 39, 61, 52, 24, 48, 57, 6, 50, 44, 1, 54, 15}, + []uint64{0x00, 0x10AB, 0x39844B7E, 0x06, 0xC08C72B7D6, 0x3C0C05958C5E, 0x16AACDC935726B3C, 0xCF64745, 0x25D63183597197B, 0x4D6591E6B1D05, 0x1F, 0x00, 0x25114FB450, 0xD77E052B5A520DE, 0x49731E0CA95CA, 0xC667AF, 0x32484A19E2CA, 0xF2F195D145FA9A, 0x14, 0x2B32E5DD2822, 0x9E50284B98F, 0x00, 0x14C39B30579EAA, 0x3ACB}, + }, + { + []byte{0x8A, 0xCC, 0x20, 0x56, 0x0B, 0x1B, 0x64, 0xA3, 0x37, 0x3A, 0x54, 0xD7, 0x6E, 0x2B, 0x16, 0x8E, 0x92, 0xE5, 0xC1, 0xCA, 0x2B, 0xE8, 0x00, 0x8A, 0x64, 0xBF, 0x5C, 0x3F, 0x3F, 0xF6, 0x3C, 0x11, 0x80, 0x34, 0x84, 0x3E, 0xE4, 0x04, 0x51, 0x7C, 0x54, 0xA0, 0x07, 0x59, 0xD3, 0x2E, 0x19, 0x3E, 0x1E, 0xAE, 0x16, 0x47, 0x2F, 0xF5, 0xF1, 0x19, 0xB6, 0xA1, 0x36, 0x2D, 0xFC, 0x1B, 0x86, 0x13, 0xE0, 0xF4, 0xF9, 0x68, 0x57, 0x9D, 0x1F, 0xDE, 0xE5, 0x12, 0xD1, 0x94, 0x47, 0xD8, 0xE5, 0x2A, 0xAF, 0xCE, 0xE0, 0xB7, 0x98, 0xB2, 0xE1, 0xEE, 0xA5, 0x7A, 0x89, 0xB4, 0x06, 0x8B, 0x59, 0xD6, 0xBF, 0x69, 0x56, 0x4B}, + []uint{13, 1, 5, 35, 47, 53, 53, 18, 10, 42, 12, 6, 6, 62, 43, 42, 38, 55, 35, 21, 27, 57, 25, 13, 32, 33, 6, 10}, + []uint64{0x1159, 0x01, 0x01, 0x1582C6D9, 0x1466E74A9AED, 0x18AC5A3A4B9707, 0x515F40045325F, 0x2B87E, 0x1FF, 0x2C782300690, 0x87D, 0x32, 0x00, 0x228BE2A5003ACE99, 0x3864F87AB85, 0x2472FF5F119, 0x2DA84D8B7F, 0x370C27C1E9F2D, 0x579D1FDE, 0x1CA25A, 0x19447D8, 0x1CA555F9DC16F31, 0xCB87BA, 0x12BD, 0x44DA0345, 0x159D6BF69, 0x15, 0x24B}, + }, + { + []byte{0x47, 0xC2, 0x96, 0xCD, 0x76, 0xCD, 0x5C, 0x93, 0xA4, 0x08, 0xD0, 0x96, 0x39, 0x5C, 0xE1, 0x02, 0x05, 0xBF, 0xD5, 0x7B, 0xF8, 0xD6, 0xCD, 0x5D, 0x30, 0x6E, 0xD2, 0x31, 0x28, 0xEB, 0x5C, 0x3C, 0x4A, 0x95, 0xF1, 0x3F, 0xB6, 0xA8, 0xAD, 0xB8, 0x53, 0xC8, 0xED, 0x3D, 0x9D, 0xB4, 0xC2, 0x2F, 0xE5, 0x79, 0x94, 0x3F, 0x15, 0x38, 0xBE, 0xEB, 0x51, 0x9B, 0xB9, 0x6F, 0x6F, 0xF1, 0x4F, 0xA6, 0x7F, 0xB4, 0xD0, 0x1B, 0xF7, 0x8A, 0xF7, 0xCC, 0xD8, 0x36, 0x17, 0xD4, 0x9A, 0xAE, 0xFF, 0x04, 0x07, 0xAA, 0x86, 0xC6, 0x12, 0x31, 0x77, 0x8A, 0x5B, 0x15, 0x0B, 0xEB, 0x1C, 0xA4, 0xF8, 0xA2, 0x12, 0xD8, 0x81, 0xA2}, + []uint{16, 21, 34, 33, 40, 35, 26, 3, 34, 6, 45, 11, 45, 44, 6, 14, 7, 32, 11, 16, 35, 16, 48, 43, 63, 14, 13, 34, 35, 13, 7}, + []uint64{0x47C2, 0x12D9AE, 0x366AE49D2, 0x8D09639, 0x5CE10205BF, 0x6ABDFC6B6, 0x1ABA60D, 0x06, 0x348C4A3AD, 0x1C, 0x78952BE27F6, 0x6A8, 0x15B70A791DA7, 0xB3B69845FCA, 0x3C, 0x3287, 0x71, 0x538BEEB5, 0xCD, 0xDCB7, 0x5BFC53E99, 0xFED3, 0x406FDE2BDF33, 0x306C2FA9355, 0x6FF0407AA86C6123, 0x5DE, 0x52D, 0x22A17D639, 0x24F8A212D, 0x1103, 0x22}, + }, + { + []byte{0xAD, 0x57, 0x64, 0x74, 0x59, 0x9A, 0x31, 0x7D, 0x46, 0x3A, 0xD3, 0x15, 0xEA, 0xE7, 0x3A, 0xBC, 0xBF, 0xE7, 0x6A, 0x36, 0xF2, 0x99, 0x7A, 0x5F, 0x09, 0xB2, 0x3E, 0xE5, 0xD6, 0x7D, 0x84, 0x7A, 0x62, 0xB3, 0xD8, 0xC3, 0x84, 0x42, 0x40, 0x59, 0xBE, 0x8A, 0x59, 0xC7, 0x35, 0xD7, 0xC9, 0xB2, 0x6F, 0xDD, 0x67, 0x04, 0x3B, 0x20, 0xDC, 0x27, 0x63, 0x82, 0x34, 0x3D, 0xBC, 0xE6, 0x29, 0x45, 0x15, 0x94, 0xC9, 0x0C, 0xFA, 0xCF, 0x0F, 0x35, 0x58, 0x06, 0x12, 0x51, 0x18, 0xE7, 0x42, 0x11, 0x39, 0xB3, 0xB4, 0xDD, 0xFE, 0x3F, 0xD7, 0x54, 0xB0, 0xF3, 0x56, 0x61, 0x7D, 0xC4, 0x09, 0xA2, 0x1E, 0x36, 0xFA, 0xFA}, + []uint{23, 21, 29, 16, 60, 23, 38, 41, 14, 27, 15, 61, 34, 40, 47, 21, 23, 51, 2, 30, 50, 53, 38, 4, 29, 10}, + []uint64{0x56ABB2, 0x74599, 0x1462FA8C, 0x75A6, 0x2BD5CE75797FCED, 0x236F29, 0x25E97C26C8, 0x1F72EB3EC23, 0x34C5, 0x33D8C38, 0x2212, 0x59BE8A59C735D7, 0x326C9BF75, 0x9C10EC8370, 0x4EC704687B79, 0x198A51, 0x22B299, 0x10CFACF0F3558, 0x00, 0x6125118, 0x39D0844E6CED3, 0xEFF1FEBAA5879, 0x2ACC2FB881, 0x03, 0x8878DBE, 0x2FA}, + }, + { + []byte{0xCD, 0x03, 0x06, 0x80, 0x27, 0x9D, 0x7E, 0x06, 0x6D, 0x29, 0x42, 0xAE, 0x44, 0x8D, 0xA3, 0xC9, 0x85, 0x03, 0xF1, 0x4D, 0x48, 0xB6, 0xC7, 0xDF, 0xBF, 0x87, 0x7E, 0x58, 0xB1, 0x92, 0x87, 0x05, 0x06, 0xE1, 0x6E, 0x0D, 0x15, 0x51, 0x99, 0xC5, 0x6C, 0x71, 0xCF, 0xFB, 0x8F, 0xE2, 0xD3, 0xA2, 0x31, 0x90, 0x4F, 0x38, 0x9C, 0x3A, 0xD7, 0x50, 0xD0, 0x75, 0x70, 0x33, 0x8B, 0x62, 0x44, 0x23, 0x9E, 0x6A, 0x8C, 0xE7, 0xB2, 0xCA, 0x84, 0x3C, 0x9F, 0x57, 0x70, 0x51, 0xA5, 0xBE, 0xD4, 0x4A, 0x3A, 0x61, 0xE8, 0x4E, 0x75, 0x25, 0xCD, 0x4E, 0x72, 0x5C, 0x69, 0xB3, 0x5B, 0x74, 0xF2, 0x4B, 0x76, 0x9C, 0x8B, 0xF0}, + []uint{47, 52, 30, 11, 13, 23, 37, 17, 13, 18, 26, 3, 64, 5, 37, 21, 37, 46, 28, 8, 23, 48, 1, 9, 30, 42, 15, 23, 26, 16, 12, 19}, + []uint64{0x6681834013CE, 0xBF033694A1572, 0x91B4793, 0x50, 0x7E2, 0x4D48B6, 0x18FBF7F0EF, 0x1962C, 0xC94, 0xE0A0, 0x370B706, 0x04, 0x55466715B1C73FEE, 0x07, 0x1E2D3A2319, 0x9E71, 0x70EB5D434, 0x7570338B624, 0x4239E6A, 0x8C, 0x73D965, 0x421E4FABB828, 0x01, 0x14B, 0x1F6A251D, 0xC3D09CEA4B, 0x4D4E, 0x392E34, 0x366B6E9, 0xE496, 0xED3, 0x48BF0}, + }, + { + []byte{0x69, 0x4F, 0x3D, 0x68, 0x86, 0x48, 0x1B, 0x9E, 0x94, 0xFF, 0xDE, 0x36, 0xDD, 0xD1, 0xBF, 0x69, 0x48, 0x8D, 0xCF, 0x2C, 0x2A, 0xA0, 0xA2, 0xFF, 0xC9, 0xD9, 0x6A, 0x99, 0x3D, 0x6D, 0xFA, 0x39, 0x79, 0xAC, 0x87, 0xC1, 0xAF, 0xCE, 0x2A, 0xCF, 0x09, 0x84, 0xFD, 0xC1, 0xE6, 0xC4, 0x27, 0x2E, 0x4A, 0x4C, 0x64, 0x0F, 0xBC, 0x81, 0xFA, 0xED, 0xED, 0x23, 0x29, 0x02, 0x6F, 0xF5, 0x81, 0xC5, 0x18, 0x33, 0x08, 0xC8, 0x7F, 0xE0, 0xD0, 0x90, 0xC0, 0x12, 0x77, 0xEE, 0xEB, 0x6A, 0x6C, 0x11, 0x08, 0xA0, 0xBB, 0xF2, 0x94, 0x80, 0xA1, 0x98, 0xBB, 0x44, 0xDC, 0xE4, 0x07, 0x99, 0x1D, 0x54, 0x18, 0x58, 0x14, 0x39}, + []uint{20, 47, 3, 29, 11, 38, 53, 36, 6, 20, 14, 8, 55, 6, 32, 23, 49, 28, 16, 50, 20, 55, 41, 3, 31, 13, 33, 39, 21}, + []uint64{0x694F3, 0x6B443240DCF4, 0x05, 0x7FEF1B6, 0x774, 0x1BF69488DC, 0x1E58554145FF93, 0xB2D5327AD, 0x2F, 0xD1CBC, 0x3590, 0xF8, 0x1AFCE2ACF0984F, 0x37, 0x79B109C, 0x5C9498, 0x1903EF207EBB7, 0xB48CA40, 0x9BFD, 0x181C5183308C8, 0x7FE0D, 0x4860093BF775B, 0xA6C1108A0B, 0x05, 0x7CA52028, 0xCC5, 0x1B44DCE40, 0x3CC8EAA0C2, 0x181439}, + }, + { + []byte{0xAA, 0xE8, 0x77, 0xB9, 0x9B, 0xB1, 0xDF, 0xCD, 0x24, 0x21, 0xCA, 0xFC, 0x15, 0x32, 0xFC, 0x71, 0x41, 0x53, 0x20, 0x3C, 0x9A, 0x26, 0x5E, 0x35, 0x58, 0x6E, 0x97, 0xC3, 0xEE, 0x5A, 0x8F, 0x6C, 0x26, 0x9C, 0xD9, 0xB0, 0x54, 0xCE, 0x57, 0x3D, 0xDC, 0x41, 0x56, 0xE6, 0xBE, 0x7A, 0x20, 0xEF, 0x04, 0xF6, 0x14, 0x4F, 0x21, 0x78, 0x5A, 0x55, 0x66, 0xA1, 0x3D, 0xF8, 0x7D, 0x5C, 0x10, 0x3C, 0x3F, 0x28, 0x4C, 0x05, 0x62, 0x3F, 0xDA, 0xBF, 0x11, 0xA7, 0x02, 0x8E, 0xC8, 0x4F, 0xC2, 0x4A, 0x86, 0xE4, 0xFD, 0xD4, 0xAC, 0x37, 0x10, 0xD7, 0x60, 0x05, 0x97, 0xE0, 0x08, 0xD8, 0xB6, 0xAA, 0x08, 0xC9, 0xD5, 0x1F}, + []uint{9, 23, 6, 21, 31, 58, 51, 34, 50, 22, 35, 63, 13, 37, 12, 29, 63, 64, 16, 46, 9, 28, 47, 33}, + []uint64{0x155, 0x6877B9, 0x26, 0x1D8EFE, 0x3490872B, 0x3C1532FC7141532, 0x1E4D132F1AAC, 0xDD2F87DC, 0x2D47B6134E6CD, 0x20A99C, 0x573DDC415, 0x3735F3D1077827B0, 0x144F, 0x42F0B4AAC, 0xD42, 0xF7E1F57, 0x20787E50980AC47, 0xFB57E234E051D909, 0xF849, 0x143727EEA561, 0x171, 0xD76005, 0x4BF0046C5B55, 0x8C9D51F}, + }, + { + []byte{0x7E, 0x3B, 0x8C, 0x41, 0x5D, 0x41, 0x24, 0xF4, 0x14, 0x8C, 0x75, 0xCB, 0x0D, 0x8E, 0x08, 0xEA, 0xD9, 0xE5, 0x84, 0x3E, 0x54, 0xA0, 0xD9, 0x22, 0xF5, 0xB8, 0x0D, 0xED, 0x3A, 0x7F, 0x93, 0x06, 0xF8, 0xC8, 0x4A, 0x60, 0x15, 0x65, 0x06, 0x43, 0xFF, 0x3A, 0x50, 0xFE, 0xCE, 0xE0, 0x15, 0x1F, 0x03, 0x7F, 0x2B, 0xB1, 0x04, 0x07, 0x9C, 0xCD, 0x9B, 0xEA, 0xCE, 0xC7, 0xAB, 0x96, 0xD5, 0x42, 0x88, 0x93, 0xBB, 0xD0, 0x2B, 0x74, 0x06, 0x68, 0x3E, 0xE2, 0x80, 0xDA, 0x78, 0x10, 0x94, 0x47, 0x3C, 0x7B, 0xA1, 0x8F, 0x27, 0x55, 0xD7, 0x37, 0xA9, 0x5F, 0xDD, 0x1D, 0xE1, 0xF4, 0x03, 0xA8, 0x99, 0xC2, 0xD0, 0x86}, + []uint{34, 59, 46, 49, 28, 60, 53, 47, 38, 45, 23, 33, 8, 1, 8, 12, 11, 50, 16, 25, 30, 33, 2, 3, 33, 35, 18}, + []uint64{0x1F8EE3105, 0x3A8249E82918EB9, 0x186C704756CF, 0x5843E54A0D92, 0x2F5B80D, 0xED3A7F9306F8C84, 0x14C02ACA0C87FE, 0x3A50FECEE015, 0x7C0DFCAEC, 0x8203CE66CDF, 0x2B3B1E, 0x15CB6AA14, 0x44, 0x01, 0x3B, 0xBD0, 0x15B, 0x280CD07DC501B, 0x4F02, 0x2511CF, 0x7BA18F2, 0xEABAE6F5, 0x00, 0x05, 0xFEE8EF0F, 0x500EA2670, 0x2D086}, + }, + { + []byte{0xDD, 0xE8, 0x87, 0xA5, 0xCA, 0xBB, 0xC8, 0x9F, 0x2F, 0xAF, 0x66, 0xE8, 0xB9, 0x48, 0x0D, 0x31, 0xB5, 0x8E, 0xAA, 0x48, 0x6A, 0x74, 0xCB, 0xC5, 0x9E, 0x1C, 0x1D, 0xE5, 0x1D, 0x89, 0x0A, 0x4B, 0x10, 0x12, 0xAA, 0xFB, 0x08, 0x6B, 0x10, 0x62, 0x55, 0x94, 0xA1, 0x38, 0xB0, 0x4D, 0x3F, 0xB1, 0xA8, 0xFC, 0xA2, 0x0E, 0x6C, 0x6B, 0x65, 0x73, 0x2D, 0x61, 0x47, 0x24, 0xB9, 0xBB, 0xA0, 0x4A, 0xF8, 0x05, 0xF4, 0x74, 0x1B, 0x06, 0x99, 0x93, 0x63, 0x4A, 0xF7, 0x9D, 0x43, 0x23, 0x00, 0x30, 0x39, 0x5A, 0x65, 0x8A, 0xA4, 0x13, 0xF1, 0x6A, 0x29, 0xB7, 0x16, 0x24, 0xDD, 0xDB, 0xF7, 0x75, 0x05, 0x94, 0x48, 0x76}, + []uint{32, 10, 14, 19, 40, 24, 28, 60, 31, 59, 43, 11, 27, 19, 22, 33, 46, 51, 41, 10, 29, 31, 34, 9, 25, 28, 24}, + []uint64{0xDDE887A5, 0x32A, 0x3BC8, 0x4F97D, 0x7B3745CA40, 0x698DAC, 0x7552435, 0x3A65E2CF0E0EF28, 0x7624292C, 0x202555F610D620C, 0x25594A138B0, 0x269, 0x7EC6A3F, 0x1441C, 0x3635B2, 0x1732D6147, 0x92E6EE812BE, 0xBE8E8360D33, 0x4D8D2BDE75, 0x32, 0x6006072, 0x5A658AA4, 0x4FC5A8A6, 0x1B8, 0x1624DDD, 0xBF77505, 0x944876}, + }, + { + []byte{0x80, 0x94, 0x8F, 0xFF, 0xAB, 0xB3, 0x58, 0x12, 0x91, 0x7D, 0xEB, 0xBA, 0x4F, 0xF2, 0x01, 0x6B, 0xCD, 0xFF, 0x44, 0xB7, 0xD7, 0xC7, 0x19, 0xAE, 0x12, 0x9A, 0x65, 0x48, 0x18, 0xD7, 0x10, 0x30, 0x2D, 0x72, 0x76, 0xC1, 0x97, 0x4E, 0xC2, 0x91, 0x40, 0x30, 0x92, 0x47, 0x5E, 0xCB, 0xC2, 0x85, 0xBA, 0xF4, 0xEF, 0x47, 0x3D, 0x70, 0x2D, 0x64, 0xD8, 0x63, 0xAD, 0xB2, 0x96, 0xC4, 0xF1, 0x1A, 0x57, 0xB2, 0xAB, 0xF4, 0x6E, 0x1E, 0x4E, 0x4E, 0x93, 0x32, 0xF1, 0x6C, 0x76, 0x1F, 0xA1, 0xAE, 0xD6, 0x5A, 0x27, 0x1D, 0x37, 0xA9, 0x2B, 0x32, 0x4A, 0xF6, 0x29, 0x47, 0xC0, 0x29, 0x69, 0xCE, 0xA9, 0x64, 0x93, 0xBC}, + []uint{37, 49, 14, 17, 29, 33, 20, 9, 52, 30, 60, 24, 18, 22, 41, 3, 11, 30, 23, 14, 38, 14, 20, 27, 6, 15, 25, 63, 42, 4, 10}, + []uint64{0x101291FFF5, 0xECD604A45F7A, 0x3BA4, 0x1FE40, 0x5AF37FD, 0x25BEBE38, 0xCD709, 0x9A, 0x654818D710302, 0x35C9DB06, 0x5D3B0A4500C2491, 0xD7B2F0, 0x285BA, 0x3D3BD1, 0x19EB816B26C, 0x01, 0x475, 0x2D94B627, 0x44695E, 0x32AB, 0x3D1B879393, 0x2933, 0x2F16C, 0x3B0FD0D, 0x1D, 0x565A, 0x4E3A6F, 0x292B324AF62947C0, 0xA5A73AA592, 0x04, 0x3BC}, + }, + { + []byte{0x00, 0xFA, 0x33, 0x12, 0xCB, 0xA1, 0x5D, 0xC3, 0x6C, 0x6A, 0x85, 0xBF, 0xA2, 0x49, 0x3C, 0x04, 0x16, 0xD2, 0xF2, 0x2E, 0xCA, 0x84, 0x20, 0x29, 0x9D, 0x54, 0x0C, 0xE2, 0x4A, 0x7D, 0x26, 0x36, 0x54, 0xC2, 0x7B, 0x72, 0x3D, 0x4A, 0xA6, 0x6E, 0xAD, 0xDE, 0xF7, 0x94, 0x78, 0xF5, 0xB5, 0x7D, 0x24, 0xB2, 0x9C, 0xC4, 0x5E, 0xA5, 0xE2, 0xF6, 0x2D, 0x5C, 0x7D, 0x8D, 0x32, 0x47, 0x4A, 0xC6, 0x51, 0xBA, 0x66, 0x80, 0xA4, 0xF9, 0x22, 0xF0, 0x3E, 0x51, 0x09, 0xAD, 0x1E, 0x26, 0x1E, 0xC5, 0x0C, 0x2A, 0xFA, 0x7A, 0xDC, 0x8A, 0x6F, 0xF2, 0x3C, 0x0A, 0xD4, 0xAB, 0x25, 0x1F, 0xFD, 0x1A, 0xC1, 0x9E, 0x35, 0x8D}, + []uint{11, 43, 6, 27, 24, 36, 9, 63, 39, 53, 11, 56, 17, 59, 57, 52, 42, 11, 45, 15, 54, 17, 21, 13, 18, 1}, + []uint64{0x07, 0x68CC4B2E857, 0x1C, 0x1B63542, 0xDFD124, 0x9E020B697, 0x122, 0x765421014CEAA067, 0x929F498D9, 0xA613DB91EA553, 0x1BA, 0xB77BDE51E3D6D5, 0x1E925, 0x4A73117A978BD8B, 0xAE3EC69923A563, 0x28DD3340527C9, 0x5E07CA2135, 0x51E, 0x4C3D8A1855F, 0x27AD, 0x3229BFC8F02B52, 0x15928, 0x1FFD1A, 0x1833, 0x31AC6, 0x01}, + }, + { + []byte{0x78, 0xF4, 0x61, 0xC2, 0x47, 0x09, 0x4B, 0x98, 0xDD, 0x2A, 0xF5, 0x9F, 0x24, 0x99, 0x71, 0x4A, 0x3E, 0x0E, 0xB0, 0xEF, 0xB0, 0xAA, 0x6C, 0x61, 0xB2, 0xF6, 0x46, 0x0F, 0xB5, 0x94, 0x3E, 0x64, 0x4A, 0x5B, 0x55, 0xF4, 0x16, 0xF0, 0x65, 0xB4, 0x74, 0xD9, 0x3F, 0x07, 0x29, 0x7E, 0x12, 0xBF, 0xF6, 0xC1, 0x39, 0x0B, 0x1E, 0x33, 0xC0, 0x65, 0xEC, 0x68, 0xA2, 0x1E, 0xBE, 0xD1, 0x5A, 0x66, 0xC2, 0xCD, 0xA6, 0xF2, 0x46, 0x39, 0x03, 0x84, 0xE1, 0xF9, 0x72, 0x46, 0xF5, 0x3E, 0xA3, 0x3B, 0x49, 0x47, 0x0D, 0xB2, 0xBA, 0x43, 0x5A, 0x6B, 0x52, 0xF2, 0x01, 0x99, 0x3F, 0xBB, 0x0F, 0xA3, 0x55, 0x95, 0xB3, 0x5E}, + []uint{22, 44, 17, 40, 32, 4, 31, 20, 14, 57, 50, 57, 3, 10, 24, 59, 58, 18, 40, 51, 19, 25, 33, 55, 17}, + []uint64{0x1E3D18, 0x7091C252E63, 0xE957, 0xACF924CB8A, 0x51F07587, 0x07, 0x6C2A9B18, 0x6CBD9, 0x60F, 0x16B287CC894B6AB, 0x3A0B7832DA3A6, 0x193F07297E12BFF, 0x03, 0x182, 0x72163C, 0x33C065EC68A21EB, 0x3B45699B0B369BC, 0x24639, 0x384E1F972, 0x237A9F519DA4A, 0x1C36C, 0x15D21AD, 0x6B52F201, 0x4C9FDD87D1AACA, 0x1B35E}, + }, + { + []byte{0x5D, 0x8E, 0x1E, 0xCA, 0x9E, 0xB2, 0x62, 0x1F, 0xC3, 0x5C, 0xD0, 0x64, 0xC8, 0x63, 0xD9, 0x53, 0x2F, 0x2E, 0x5E, 0x6D, 0x03, 0xC6, 0xB1, 0xFE, 0x3A, 0xAE, 0x99, 0x3C, 0x47, 0x91, 0x34, 0x15, 0x1C, 0x95, 0xE4, 0xD1, 0xD0, 0xC0, 0xE7, 0xFD, 0x66, 0x35, 0x33, 0xC3, 0x03, 0xAA, 0x77, 0xCC, 0x1C, 0x77, 0x92, 0xB9, 0xA2, 0xD7, 0xE4, 0xEA, 0xD1, 0x4A, 0x74, 0xF4, 0x05, 0x4C, 0xCB, 0xBF, 0xEB, 0x98, 0x20, 0x8F, 0x77, 0x4D, 0xAA, 0x13, 0xD6, 0xB1, 0xCF, 0x80, 0x9D, 0x6B, 0xDB, 0x02, 0xA9, 0xA3, 0xD2, 0x0F, 0xCA, 0x4D, 0xDC, 0xC5, 0x58, 0x10, 0x3D, 0x96, 0x82, 0xF1, 0x00, 0x32, 0x6B, 0x25, 0xFC, 0x0E}, + []uint{39, 44, 24, 38, 3, 27, 12, 58, 22, 28, 54, 20, 35, 30, 27, 46, 41, 35, 44, 19, 1, 20, 41, 8, 36, 48}, + []uint64{0x2EC70F654F, 0x59310FE1AE6, 0x832643, 0x7B2A65E5C, 0x05, 0x73681E3, 0x58F, 0x3C755D32788F226, 0x20A8E4, 0xAF268E8, 0x181CFFACC6A678, 0x60754, 0x77CC1C779, 0xAE68B5F, 0x49D5A29, 0x13A7A02A665D, 0x1FEB98208F7, 0x3A6D509EB, 0x58E7C04EB5E, 0x6C0AA, 0x00, 0xD1E90, 0xFCA4DDCC55, 0x81, 0x3D9682F1, 0x326B25FC0E}, + }, + { + []byte{0xB4, 0x6D, 0x53, 0x49, 0xB7, 0x06, 0x34, 0x33, 0x99, 0x26, 0xC8, 0x16, 0x3E, 0x5F, 0x8E, 0x87, 0x26, 0xDE, 0x13, 0xBD, 0xBA, 0xEA, 0x1A, 0x03, 0xCD, 0x2E, 0xAC, 0x7D, 0x79, 0xFA, 0x25, 0x4F, 0xAF, 0x5B, 0xC4, 0xE4, 0x6A, 0x50, 0x33, 0x83, 0xCC, 0xF5, 0x49, 0x3E, 0xCF, 0xAC, 0xAA, 0x94, 0x89, 0x33, 0xB6, 0xC4, 0x77, 0xBF, 0xAF, 0xE6, 0xFA, 0x07, 0x07, 0x5B, 0x8E, 0x6B, 0x8B, 0xFE, 0x1C, 0xE3, 0x20, 0xF3, 0x17, 0x54, 0x3F, 0x38, 0x99, 0xD4, 0xAB, 0x85, 0xE7, 0x7D, 0x47, 0xE3, 0x41, 0x98, 0xE9, 0x5B, 0xF4, 0x38, 0x18, 0xEE, 0x13, 0x64, 0x2E, 0xC3, 0x5F, 0x22, 0x42, 0x41, 0xCB, 0x62, 0x59, 0xBE}, + []uint{56, 11, 10, 52, 2, 11, 13, 21, 25, 24, 13, 2, 52, 27, 43, 10, 16, 41, 13, 46, 60, 57, 4, 62, 43, 13, 40, 28, 5}, + []uint64{0xB46D5349B70634, 0x19C, 0x324, 0xD902C7CBF1D0E, 0x01, 0x1B7, 0x109D, 0x1DBAEA, 0x34079A, 0x5D58FA, 0x1E7E, 0x02, 0x254FAF5BC4E46, 0x52819C1, 0x733D524FB3E, 0x2CA, 0xA948, 0x12676D88EF7, 0x1EBF, 0x26FA07075B8E, 0x6B8BFE1CE320F31, 0xEA87E7133A9570, 0x0B, 0x33BEA3F1A0CC74AD, 0x7D0E063B84D, 0x1217, 0x61AF912120, 0xE5B12CD, 0x1E}, + }, + { + []byte{0x23, 0xFE, 0xE6, 0xE3, 0x2F, 0x43, 0xE0, 0x65, 0xBD, 0xCA, 0xD1, 0xD8, 0x44, 0x1A, 0x37, 0x2C, 0xF8, 0xB3, 0x17, 0x83, 0x0E, 0x12, 0xDB, 0x23, 0x90, 0x83, 0x9C, 0xBF, 0x7D, 0x16, 0x5E, 0x28, 0xCA, 0x6E, 0x86, 0xE0, 0x09, 0x61, 0x71, 0xE5, 0x00, 0x4D, 0xCE, 0xE1, 0x8A, 0xA8, 0xBD, 0xB1, 0xD5, 0xC4, 0xF2, 0xEF, 0x0B, 0xEE, 0x07, 0x6A, 0x12, 0x2F, 0xB1, 0x2B, 0x5D, 0x0B, 0xC4, 0xD3, 0xE0, 0x9A, 0xC6, 0xDC, 0x25, 0x75, 0x87, 0xC8, 0xB2, 0x7B, 0xAE, 0x6A, 0xC8, 0x3C, 0xF9, 0x2A, 0xC6, 0xD7, 0xBD, 0x6D, 0x88, 0x91, 0x82, 0xAB, 0x01, 0xA0, 0x3C, 0x3E, 0xE2, 0x5B, 0x22, 0xB9, 0xF4, 0x40, 0x13, 0x27}, + []uint{46, 17, 6, 2, 47, 18, 58, 46, 1, 3, 45, 56, 64, 21, 53, 35, 1, 38, 57, 31, 7, 49, 8, 60, 31}, + []uint64{0x8FFB9B8CBD0, 0x1F032, 0x37, 0x02, 0x72B47611068D, 0x32CF8, 0x2CC5E0C384B6C8E, 0x10839CBF7D16, 0x00, 0x05, 0x1C5194DD0DC0, 0x12C2E3CA009B9D, 0xC315517B63AB89E5, 0x1BC2FB, 0x103B50917D895A, 0x742F134F8, 0x00, 0x1358DB84AE, 0x161F22C9EEB9AB2, 0x79F2558, 0x6D, 0xF7ADB1123055, 0x60, 0x340787DC4B64573, 0x74401327}, + }, + { + []byte{0xD7, 0x29, 0xE8, 0xD8, 0x9D, 0x5F, 0x04, 0x11, 0x02, 0x6B, 0xDE, 0x9E, 0x4F, 0x4B, 0xF9, 0x97, 0x75, 0x01, 0xB6, 0x49, 0xE5, 0x48, 0xFF, 0x34, 0x2A, 0xE6, 0xCF, 0x5D, 0x85, 0x6D, 0xF8, 0x35, 0x8C, 0xEA, 0x04, 0xB3, 0x10, 0x5B, 0x07, 0x80, 0x3B, 0xD5, 0x69, 0x4E, 0xD2, 0xA5, 0x9F, 0x6A, 0x38, 0x77, 0x58, 0x5C, 0x79, 0xEB, 0x03, 0x30, 0x5C, 0x5D, 0x7D, 0x47, 0xD1, 0xD3, 0xAE, 0xC2, 0xE8, 0xB5, 0x69, 0x35, 0x58, 0xD5, 0xC2, 0x91, 0x80, 0x4E, 0x1B, 0x87, 0x92, 0xB2, 0x60, 0x69, 0x02, 0x6F, 0x47, 0x1B, 0x89, 0x14, 0x7E, 0x4F, 0xE4, 0xF9, 0xF0, 0x4D, 0xBD, 0x76, 0x72, 0x36, 0xF3, 0xD8, 0xB8, 0x4D}, + []uint{43, 23, 21, 42, 26, 28, 54, 30, 49, 8, 33, 11, 25, 35, 39, 38, 21, 37, 62, 7, 60, 57, 36, 15}, + []uint64{0x6B94F46C4EA, 0x7C1044, 0x135EF, 0x13C9E97F32E, 0x3A80DB2, 0x4F2A47F, 0x26855CD9EBB0AD, 0x2FC1AC67, 0xA04B3105B078, 0x03, 0x17AAD29DA, 0x2A5, 0x13ED470, 0x77585C79E, 0x581982E2EB, 0x3A8FA3A75D, 0x10BA2D, 0xB49AAC6AE, 0x523009C370F2564, 0x60, 0x69026F471B89147, 0x1C9FC9F3E09B7AE, 0xCE46DE7B1, 0x384D}, + }, + { + []byte{0x76, 0x2E, 0x87, 0xCE, 0x9D, 0x1C, 0xF7, 0x87, 0xD8, 0x0E, 0xD4, 0x6B, 0x3D, 0x01, 0x84, 0x6C, 0xDE, 0xF7, 0x72, 0xC4, 0xCC, 0xAE, 0xC4, 0xF4, 0x35, 0xBD, 0xDC, 0xA5, 0x69, 0x4F, 0xFF, 0x98, 0x7D, 0x30, 0xBE, 0x40, 0xE7, 0x39, 0xF6, 0xFD, 0x52, 0x19, 0xD9, 0x51, 0xB4, 0x04, 0x22, 0x5C, 0x93, 0x07, 0x7D, 0xB9, 0xF0, 0x5D, 0x53, 0x67, 0x6E, 0xAA, 0xCF, 0x28, 0x16, 0x14, 0x2C, 0x28, 0x5A, 0xB9, 0x20, 0xD3, 0x8C, 0x42, 0xFC, 0x6D, 0xE5, 0x68, 0x47, 0x84, 0xBF, 0x4D, 0x9C, 0x55, 0x62, 0x56, 0x10, 0xAE, 0xFC, 0x1E, 0x91, 0x8B, 0x52, 0x52, 0x49, 0x25, 0x3C, 0x6F, 0xC0, 0x59, 0x59, 0x2D, 0x80, 0x43}, + []uint{42, 51, 40, 8, 22, 55, 9, 12, 60, 53, 35, 48, 31, 50, 34, 7, 7, 53, 55, 41, 35, 32, 2, 18}, + []uint64{0x1D8BA1F3A74, 0x39EF0FB01DA8D, 0x67A0308D9B, 0xDE, 0x3B9626, 0x32BB13D0D6F772, 0x12B, 0x4A7, 0xFFCC3E985F20739, 0x19F6FD5219D951, 0x5A02112E4, 0x983BEDCF82EA, 0x4D9DBAAB, 0xF2816142C285, 0x2AE4834E3, 0x08, 0x2F, 0x18DBCAD08F097E, 0x4D9C55625610AE, 0x1F83D2316A4, 0x5249253C6, 0xFC059592, 0x03, 0x18043}, + }, + { + []byte{0x33, 0xC2, 0xC3, 0xBC, 0x9D, 0x2A, 0x36, 0xB4, 0x92, 0x36, 0x02, 0x93, 0x54, 0xB9, 0x86, 0x32, 0xC1, 0x0C, 0x75, 0xC4, 0x3B, 0xE4, 0x0A, 0x3F, 0xDF, 0x4E, 0xF6, 0x05, 0x4F, 0x30, 0x19, 0xA6, 0xE9, 0xE6, 0x55, 0xAF, 0xE8, 0xC4, 0x3F, 0xFF, 0xE3, 0x40, 0xC1, 0xA2, 0xE1, 0x05, 0xD7, 0x77, 0x82, 0xD5, 0xF9, 0xA6, 0x0F, 0x54, 0xED, 0x96, 0xA0, 0x68, 0xEC, 0xAE, 0x57, 0xE3, 0x6A, 0xD2, 0xCE, 0x18, 0x9A, 0xC2, 0x5E, 0x10, 0x3C, 0x21, 0x5C, 0x38, 0xA9, 0xC4, 0x82, 0x76, 0xF9, 0xA9, 0x9B, 0x33, 0x43, 0x40, 0x61, 0xDD, 0x0D, 0x83, 0x9E, 0xDE, 0x08, 0x4C, 0x13, 0x33, 0x82, 0x6A, 0xF4, 0xAB, 0x61, 0x1C}, + []uint{28, 60, 58, 5, 41, 56, 29, 27, 38, 2, 28, 51, 3, 63, 33, 57, 36, 61, 22, 1, 62, 26, 13}, + []uint64{0x33C2C3B, 0xC9D2A36B4923602, 0x24D52E618CB0431, 0x1A, 0x1C43BE40A3F, 0xDF4EF6054F3019, 0x14DD3CCA, 0x5AFE8C4, 0xFFFF8D030, 0x01, 0xA2E105D, 0x3BBC16AFCD307, 0x05, 0x29DB2D40D1D95CAF, 0x18DAB4B38, 0xC4D612F081E10A, 0xE1C54E241, 0x76F9A99B3343406, 0x77436, 0x00, 0x73DBC1098266704, 0x357A55B, 0x11C}, + }, + { + []byte{0xCB, 0x0A, 0x64, 0xC1, 0xEF, 0xEC, 0x67, 0x09, 0xE1, 0x9A, 0x2A, 0xC2, 0xC5, 0xD9, 0xC7, 0x3D, 0x2A, 0x49, 0x3E, 0xF4, 0x30, 0xC9, 0x47, 0x2E, 0xEC, 0xAA, 0x46, 0xDA, 0x31, 0x62, 0x27, 0x4F, 0xAD, 0x4C, 0x50, 0xCD, 0x83, 0x51, 0x37, 0x09, 0x8B, 0xC7, 0x6D, 0x62, 0xFE, 0xC3, 0xE9, 0x91, 0xE5, 0xE8, 0x4D, 0x11, 0x1B, 0xDE, 0x03, 0x23, 0xAA, 0x1E, 0x65, 0xAD, 0x06, 0x23, 0x28, 0xD2, 0xDF, 0x59, 0x47, 0x52, 0xF2, 0x3F, 0xC7, 0x68, 0x50, 0x20, 0xF3, 0x2A, 0xC0, 0xFB, 0xBB, 0xC0, 0xAD, 0x26, 0xA6, 0x75, 0x19, 0x1B, 0xD8, 0x1F, 0xF9, 0xFD, 0x33, 0x10, 0x2C, 0x15, 0x80, 0xDC, 0xA7, 0xF6, 0xF4, 0x50}, + []uint{21, 51, 60, 7, 33, 20, 14, 36, 57, 10, 51, 3, 17, 50, 55, 3, 14, 7, 35, 45, 12, 43, 50, 51, 28, 27}, + []uint64{0x19614C, 0x4C1EFEC6709E1, 0x9A2AC2C5D9C73D2, 0x52, 0x93EF430C, 0x9472E, 0x3B2A, 0x91B68C588, 0x13A7D6A62866C1A, 0x226, 0x7098BC76D62FE, 0x06, 0x3E99, 0x797A134446F7, 0x40647543CCB5A0, 0x06, 0x8CA, 0x1A, 0x2DF594752, 0x1E47F8ED0A04, 0x1E6, 0x2AC0FBBBC0A, 0x349A99D4646F6, 0x3FF3FA662058, 0x2B01B94, 0x7F6F450}, + }, + { + []byte{0x56, 0x6B, 0xDA, 0x9E, 0xD9, 0x04, 0x9A, 0xE7, 0x5E, 0x85, 0x25, 0x0B, 0x1D, 0xEF, 0xB8, 0x65, 0x6F, 0xFF, 0xE5, 0x6F, 0x02, 0xA8, 0xE2, 0x9B, 0x18, 0xC2, 0x11, 0x8A, 0x7E, 0xB5, 0xDF, 0x72, 0x44, 0x0C, 0xC7, 0x85, 0x43, 0xC5, 0x75, 0x3A, 0x2B, 0x1F, 0xA5, 0x75, 0x66, 0x42, 0x15, 0x03, 0xB3, 0x2F, 0x90, 0xCB, 0x2B, 0x56, 0x8E, 0x2E, 0xB1, 0x98, 0xD0, 0x5D, 0x53, 0x8D, 0x7C, 0xF8, 0x0E, 0x07, 0x98, 0x60, 0x4E, 0x8D, 0x69, 0xF9, 0x2E, 0xD7, 0x9A, 0xE2, 0x4D, 0x37, 0x49, 0xB9, 0x59, 0x5D, 0x2D, 0xC2, 0x7E, 0x50, 0x7B, 0x97, 0x4F, 0x06, 0x2B, 0xBC, 0xCB, 0x10, 0x3E, 0x0E, 0xD3, 0xF8, 0x7E, 0x78}, + []uint{38, 55, 32, 34, 58, 58, 53, 8, 29, 19, 37, 46, 7, 55, 39, 44, 24, 5, 5, 22, 19, 11, 49, 40, 13}, + []uint64{0x159AF6A7B6, 0x20935CEBD0A4A1, 0x63BDF70C, 0x2B7FFF2B7, 0x20551C536318423, 0x53F5AEFB922066, 0x78543C5753A2B, 0x1F, 0x14AEACC8, 0x21503, 0x1665F21965, 0x1AB471758CC6, 0x41, 0x3AA71AF9F01C0F, 0x18604E8D69, 0xF92ED79AE24, 0xD3749B, 0x12, 0x16, 0x15D2DC, 0x13F28, 0x1EE, 0xBA78315DE658, 0x81F0769FC3, 0x1E78}, + }, + { + []byte{0x52, 0xEE, 0x85, 0xDF, 0x00, 0xC1, 0xE3, 0x65, 0x76, 0x46, 0x99, 0x52, 0xDC, 0xA5, 0x26, 0x5C, 0x31, 0x62, 0xEB, 0xC2, 0xCD, 0xC7, 0x27, 0x12, 0xE4, 0xFC, 0xC5, 0x56, 0xB5, 0xDB, 0x87, 0x39, 0x94, 0xFB, 0x3D, 0x31, 0x24, 0xB7, 0x16, 0x4D, 0x6E, 0x51, 0x8E, 0x47, 0x8E, 0xFF, 0xC0, 0x58, 0x09, 0xC3, 0xE7, 0xCC, 0x5C, 0xA8, 0x82, 0x0F, 0xE2, 0x4D, 0xD2, 0x6D, 0xBF, 0x9B, 0x3D, 0x28, 0xD6, 0x65, 0x6D, 0x0A, 0x05, 0x1B, 0xFA, 0x66, 0x9C, 0xF6, 0x15, 0xCE, 0x50, 0xE1, 0x21, 0x90, 0x9B, 0xA0, 0xDE, 0xDB, 0x76, 0x7C, 0xB6, 0x2D, 0x30, 0xEB, 0xCD, 0x74, 0xE5, 0x19, 0x18, 0xC0, 0x7D, 0x43, 0xA3, 0x61}, + []uint{33, 22, 19, 36, 45, 49, 18, 64, 5, 22, 40, 5, 2, 47, 9, 13, 9, 54, 55, 11, 32, 15, 22, 55, 41, 37, 24, 7, 9}, + []uint64{0xA5DD0BBE, 0x60F1, 0x595D9, 0x1A654B729, 0x932E18B175E, 0x2CDC72712E4F, 0x33155, 0xAD76E1CE653ECF4C, 0x09, 0x96E2C, 0x9ADCA31C8F, 0x03, 0x02, 0x7FE02C04E1F3, 0x1CC, 0xB95, 0x20, 0x20FE24DD26DBF9, 0x59E946B32B6850, 0x146, 0xFE99A73D, 0x42B9, 0x328709, 0x6426E837B6DD9, 0x1E5B169875E, 0xD74E51918, 0xC07D43, 0x51, 0x161}, + }, + { + []byte{0xB0, 0x67, 0x0E, 0x66, 0x77, 0x4D, 0x4E, 0xDB, 0xEB, 0xDC, 0x05, 0x3B, 0xAA, 0xBB, 0xE8, 0x71, 0x59, 0xD4, 0x71, 0x53, 0xBE, 0xF4, 0x78, 0x2A, 0xB8, 0x9F, 0x09, 0xBB, 0x18, 0x2D, 0x89, 0xD7, 0xDF, 0x15, 0xB9, 0xD6, 0x6D, 0x90, 0x3F, 0x2B, 0xBF, 0xF7, 0xC7, 0x41, 0x1D, 0xCA, 0xAB, 0x52, 0x41, 0x21, 0x6F, 0xB1, 0xF1, 0x2F, 0xCD, 0xC8, 0x85, 0xC3, 0xD7, 0x80, 0x82, 0xFB, 0x86, 0x14, 0x3E, 0x34, 0x95, 0x3E, 0x82, 0xE2, 0x14, 0x51, 0x93, 0xFE, 0xEE, 0x0A, 0xF2, 0xFE, 0xDE, 0x97, 0xB7, 0xEF, 0x1F, 0x95, 0x5D, 0x8F, 0xE8, 0x59, 0xC9, 0x5E, 0x9B, 0x9D, 0x35, 0x0C, 0x84, 0x54, 0x7D, 0x7D, 0x30, 0x42}, + []uint{1, 13, 4, 42, 5, 62, 28, 12, 37, 22, 51, 1, 36, 54, 18, 39, 13, 57, 64, 24, 56, 44, 24, 63, 30}, + []uint64{0x01, 0xC19, 0x0C, 0xE66774D4ED, 0x17, 0x35EE029DD55DF438, 0xACEA38A, 0x9DF, 0xF4782AB89, 0x3C26EC, 0x305B13AFBE2B7, 0x00, 0x759B640FC, 0x2BBFF7C7411DCA, 0x2AD49, 0x242DF63E2, 0xBF3, 0xE442E1EBC0417D, 0xC30A1F1A4A9F4171, 0xA28C9, 0xFF7705797F6F4B, 0xDBF78FCAAEC, 0x7F42CE, 0x257A6E74D4321151, 0x3D7D3042}, + }, + { + []byte{0xD8, 0x92, 0xDB, 0xF2, 0x33, 0xA4, 0x8B, 0x06, 0xD6, 0xC5, 0xBE, 0x2D, 0x6B, 0x2B, 0x82, 0x33, 0x75, 0xA7, 0xD4, 0x36, 0x2F, 0x46, 0x81, 0xE1, 0xC7, 0xBB, 0xDC, 0xF9, 0x1C, 0x93, 0xF8, 0xEB, 0xFA, 0x14, 0xF3, 0xD2, 0xCB, 0xD7, 0x70, 0x24, 0xAA, 0x92, 0xE5, 0xB3, 0x14, 0x5F, 0x18, 0x14, 0xEC, 0xC3, 0x5B, 0xF0, 0x33, 0xE7, 0xF6, 0xA7, 0x2D, 0x0F, 0xF7, 0x0A, 0x84, 0xD1, 0x87, 0xEF, 0xDD, 0xCD, 0xDC, 0xA8, 0xA1, 0xEF, 0x18, 0x6F, 0xDB, 0x05, 0x79, 0xD6, 0xF9, 0x33, 0x89, 0x9A, 0x57, 0xB7, 0xAC, 0xFE, 0x1C, 0x49, 0xA5, 0x6B, 0x5D, 0x15, 0x19, 0x1F, 0x74, 0x35, 0x87, 0xB3, 0xDD, 0xF6, 0x91, 0x59}, + []uint{59, 22, 40, 1, 33, 56, 30, 30, 20, 23, 23, 64, 4, 27, 7, 23, 11, 33, 13, 43, 20, 8, 21, 55, 56, 64, 14}, + []uint64{0x6C496DF919D2458, 0xDAD8B, 0x7C5AD65704, 0x00, 0x19BAD3EA1, 0xB17A340F0E3DDE, 0x39F23927, 0x3C75FD0A, 0x79E96, 0x2F5DC0, 0x495525, 0xCB6628BE3029D986, 0x0B, 0x3F033E7, 0x7B, 0x29CB43, 0x7EE, 0x2A13461F, 0x17EE, 0x73772A287BC, 0x61BF6, 0xC1, 0xBCEB7, 0x64CE26695EDEB3, 0xF8712695AD7454, 0x647DD0D61ECF77DA, 0x1159}, + }, + { + []byte{0xEE, 0xDC, 0x02, 0xB6, 0x64, 0xD5, 0x98, 0xBA, 0x54, 0x05, 0x83, 0x4E, 0xB1, 0xC6, 0x5E, 0x02, 0x6F, 0x12, 0x3A, 0xC4, 0xD4, 0x99, 0xF8, 0xF4, 0x4E, 0xC5, 0x5F, 0x69, 0xB9, 0xEE, 0xFF, 0xB0, 0x5A, 0x10, 0x69, 0xEF, 0x95, 0x82, 0xA6, 0x51, 0xAC, 0x06, 0x46, 0x6A, 0x69, 0x80, 0x07, 0x5A, 0xDB, 0x0B, 0x58, 0x49, 0xD3, 0x9B, 0xD6, 0x66, 0xFC, 0x14, 0x05, 0x58, 0x46, 0x98, 0x16, 0xC0, 0x3E, 0x50, 0xDB, 0xD7, 0x68, 0xC1, 0xFE, 0x16, 0xA8, 0xE6, 0x80, 0x21, 0xBA, 0xC1, 0x89, 0xB7, 0xD3, 0xCF, 0xDF, 0x3E, 0x5E, 0xB0, 0x76, 0x25, 0xB0, 0xB8, 0x65, 0xA1, 0x57, 0x35, 0x2B, 0x79, 0x35, 0x23, 0x70, 0x7A}, + []uint{19, 14, 28, 59, 53, 55, 20, 4, 1, 40, 36, 2, 42, 20, 60, 61, 59, 46, 62, 23, 50, 4, 42}, + []uint64{0x776E0, 0x56C, 0xC9AB317, 0x25405834EB1C65E, 0x4DE247589A93, 0x1F8F44EC55F69B, 0x9EEFF, 0x0B, 0x00, 0xB420D3DF2, 0xB054CA358, 0x00, 0xC8CD4D3000, 0xEB5B6, 0x16B093A737ACCDF, 0x105015611A605B00, 0x7CA1B7AED183FC2, 0x354734010DD6, 0x3136FA79FBE7CBD, 0x307625, 0x2C2E196855CD4, 0x0A, 0x3793523707A}, + }, + { + []byte{0x26, 0x44, 0x9D, 0xFF, 0x6D, 0x96, 0x22, 0x0A, 0xD1, 0xF2, 0xE7, 0x81, 0xD8, 0xEC, 0x90, 0xFD, 0x74, 0x52, 0x63, 0x4A, 0x3C, 0x34, 0xDB, 0x1A, 0xA8, 0xDF, 0xA5, 0x62, 0x34, 0x57, 0x32, 0x2C, 0x53, 0xEC, 0xDF, 0x03, 0xFC, 0xE0, 0x86, 0x03, 0x24, 0xCD, 0x44, 0x36, 0xDF, 0xE2, 0x2F, 0x55, 0x25, 0xD6, 0x27, 0xF3, 0x2E, 0xDB, 0x38, 0x31, 0x5D, 0xAC, 0x2C, 0x28, 0x05, 0x33, 0xA2, 0xFB, 0x0D, 0x7C, 0x02, 0x1B, 0x8A, 0xD4, 0xDF, 0xFC, 0x02, 0x69, 0xC4, 0x2C, 0x65, 0x6F, 0x8C, 0xA4, 0x2F, 0x19, 0x04, 0xBE, 0xC5, 0x0F, 0x8C, 0xF0, 0xB1, 0x8A, 0x2E, 0x58, 0x96, 0xC3, 0x87, 0x1F, 0x89, 0x4F, 0xA9, 0x44}, + []uint{37, 50, 48, 42, 39, 50, 30, 29, 11, 10, 17, 20, 29, 52, 50, 17, 27, 47, 16, 16, 25, 61, 28, 8, 29, 12}, + []uint64{0x4C893BFED, 0x2CB110568F973, 0xC0EC76487EBA, 0xA4C6947869, 0x5B1AA8DFA5, 0x188D15CC8B14F, 0x2CDF03FC, 0x1C10C064, 0x4CD, 0x110, 0x1B6FF, 0x117AA, 0x125D627F, 0x32EDB38315DAC, 0xB0A014CE8BEC, 0x6BE0, 0x86E2B5, 0x1BFF804D3885, 0x8CAD, 0xF194, 0x10BC641, 0x5F6287C67858C51, 0x72C4B61, 0xC3, 0x11F894FA, 0x944}, + }, + { + []byte{0x93, 0xC5, 0x74, 0xE2, 0x73, 0x08, 0xB2, 0xDD, 0xB8, 0xD7, 0xD5, 0xC3, 0x88, 0x2F, 0x98, 0xA2, 0xB8, 0x42, 0x98, 0xE2, 0xFD, 0xC6, 0x7F, 0x6C, 0x47, 0xE6, 0xC5, 0x9D, 0x30, 0x31, 0x40, 0x3C, 0x63, 0xE7, 0xD1, 0x20, 0x1E, 0x85, 0xF9, 0x40, 0x98, 0xE8, 0x9F, 0x31, 0xDF, 0x9E, 0x14, 0xEE, 0xB5, 0x62, 0x56, 0x7F, 0x88, 0x3F, 0xE1, 0xD1, 0xEB, 0xAC, 0x09, 0xCD, 0x71, 0xF8, 0x23, 0x07, 0xDA, 0x37, 0x32, 0x37, 0xDE, 0x65, 0x21, 0x72, 0x9B, 0x89, 0x9B, 0xEC, 0x35, 0xBC, 0x6B, 0xB8, 0x20, 0x00, 0xF6, 0xA9, 0x06, 0xDC, 0xAC, 0xE8, 0xC3, 0x52, 0x89, 0x20, 0x74, 0xC9, 0xB3, 0xCC, 0x72, 0x45, 0x0E, 0x76}, + []uint{49, 42, 47, 16, 27, 33, 16, 39, 45, 23, 47, 52, 64, 20, 17, 63, 30, 50, 23, 54, 31, 12}, + []uint64{0x1278AE9C4E611, 0x196EDC6BEAE, 0xE20BE628AE1, 0xA63, 0x45FB8CF, 0x1DB11F9B1, 0x674C, 0x628078C7C, 0x1F44807A17E5, 0x131D1, 0x1F31DF9E14EE, 0xB562567F883FE, 0x1D1EBAC09CD71F82, 0x307DA, 0x6E64, 0x37DE6521729B899B, 0x3B0D6F1A, 0x3B82000F6A906, 0x6E5674, 0x186A51240E9936, 0x3CC72450, 0xE76}, + }, + { + []byte{0xCA, 0x4E, 0x83, 0x60, 0x1A, 0xEF, 0xAC, 0x61, 0x4C, 0x22, 0x4A, 0xE3, 0xFC, 0xEF, 0x32, 0x2A, 0xDB, 0x52, 0x73, 0xC3, 0xEB, 0xA6, 0xF0, 0xAE, 0x35, 0x1D, 0x0C, 0xDE, 0x1D, 0x38, 0x41, 0x75, 0x4B, 0xF3, 0x62, 0x98, 0x73, 0x07, 0xB9, 0x58, 0x83, 0x38, 0x29, 0xE3, 0xCD, 0x38, 0xBA, 0xF0, 0x59, 0xDC, 0x74, 0xE4, 0xE4, 0x17, 0x6C, 0x83, 0xBF, 0x52, 0xDB, 0xEA, 0xF5, 0xFA, 0xBF, 0x1D, 0xBA, 0x13, 0xED, 0xDA, 0x93, 0x6E, 0xCB, 0x89, 0x1E, 0x83, 0x72, 0xC5, 0x28, 0x3A, 0x5F, 0x8D, 0xAF, 0xDB, 0xDD, 0x6E, 0xA9, 0xD2, 0x76, 0x4B, 0x7F, 0x4A, 0xD8, 0x0E, 0xBF, 0xE0, 0xC6, 0x5F, 0xA0, 0x77, 0x7A, 0x2B}, + []uint{57, 31, 47, 37, 29, 27, 49, 3, 52, 31, 34, 41, 35, 37, 47, 59, 31, 46, 10, 7, 14, 54, 22}, + []uint64{0x1949D06C035DF58, 0x614C224A, 0x71FE7799156D, 0x15273C3EBA, 0xDE15C6A, 0x1D0CDE1, 0x1A7082EA97E6C, 0x02, 0x987307B958833, 0x414F1E69, 0x3175E0B3B, 0x11D393905DB, 0x1077EA5B7, 0x1ABD7EAFC7, 0x37427DBB526D, 0x6CB891E8372C528, 0x1D2FC6D7, 0x3B7BADD53A4E, 0x325, 0x5F, 0x34AD, 0x203AFF83197E81, 0x377A2B}, + }, + { + []byte{0x2C, 0x77, 0x59, 0x98, 0x44, 0xE0, 0xD5, 0x78, 0x5F, 0xFE, 0xD1, 0x44, 0xAD, 0xCC, 0x78, 0x46, 0x69, 0x3B, 0xD5, 0xC2, 0x03, 0xE1, 0x24, 0x54, 0x8C, 0xAB, 0x06, 0x61, 0x78, 0x78, 0x89, 0x42, 0x8B, 0x1C, 0x9E, 0xA1, 0x13, 0xC8, 0x09, 0xAB, 0x7E, 0xD6, 0xC6, 0xB2, 0xAF, 0x4D, 0x1D, 0xB4, 0x85, 0xB5, 0x5D, 0x39, 0x23, 0x8E, 0x67, 0x8D, 0x48, 0xA1, 0x1B, 0x42, 0xDD, 0xBD, 0xCB, 0x53, 0xA8, 0x20, 0x50, 0xF7, 0x44, 0xE7, 0xBC, 0x7A, 0x85, 0x09, 0x71, 0x04, 0xCF, 0x81, 0xCA, 0xB4, 0x10, 0xF2, 0xBF, 0xC7, 0x7C, 0x05, 0xC3, 0x62, 0x19, 0x79, 0x04, 0x7F, 0xF8, 0x54, 0x85, 0x0E, 0x35, 0xE4, 0x64, 0x4C}, + []uint{35, 33, 39, 14, 2, 40, 63, 64, 53, 56, 47, 42, 51, 12, 9, 43, 58, 55, 32, 52}, + []uint64{0x163BACCC2, 0x4E0D5785, 0x7FF68A256E, 0x18F0, 0x02, 0x3349DEAE10, 0xF84915232AC1985, 0xE1E2250A2C727A84, 0x9E404D5BF6B63, 0x5957A68EDA42DA, 0x574E48E399E3, 0x148A11B42DD, 0x5EE5A9D410287, 0xBA2, 0xE7, 0x5E3D4284B88, 0x99F03956821E57, 0x7C77C05C362197, 0x9047FF85, 0x4850E35E4644C}, + }, + { + []byte{0x2F, 0x1E, 0xB8, 0x50, 0xC1, 0xF6, 0xD4, 0xD4, 0x33, 0xD8, 0x40, 0xC9, 0x5E, 0xB5, 0x29, 0x9E, 0x60, 0x65, 0xB4, 0xD2, 0x68, 0x4D, 0x3F, 0x7E, 0x0D, 0xCB, 0xE6, 0x9E, 0x0D, 0x2A, 0x4C, 0xF5, 0xD4, 0x0D, 0x20, 0x36, 0x17, 0xCB, 0xCD, 0x2A, 0xA4, 0xBE, 0x08, 0x48, 0x7C, 0xFE, 0x77, 0x28, 0xDA, 0xC0, 0xFF, 0xAC, 0x48, 0xF5, 0xCD, 0x34, 0xCD, 0x1D, 0x6E, 0x13, 0x19, 0xDD, 0x0D, 0xF1, 0x78, 0x41, 0x59, 0x87, 0xDB, 0x13, 0x44, 0xC1, 0xE0, 0xB7, 0x9C, 0x18, 0xF9, 0x4E, 0x09, 0x53, 0x99, 0x95, 0x9D, 0x7C, 0x0E, 0xDB, 0xF5, 0x7D, 0x55, 0x20, 0x19, 0x6A, 0x39, 0x30, 0xC8, 0x6E, 0xE7, 0x0E, 0xCA, 0x02}, + []uint{15, 11, 7, 40, 53, 47, 60, 55, 29, 8, 29, 25, 53, 33, 45, 9, 30, 17, 30, 11, 7, 37, 35, 43, 25, 19, 8, 19}, + []uint64{0x178F, 0x2E1, 0x21, 0x83EDA9A867, 0x16103257AD4A67, 0x4C0CB69A4D09, 0xA7EFC1B97CD3C1A, 0x2A4CF5D40D2036, 0x2F979A5, 0x54, 0x12F82121, 0x1E7F3B9, 0x8DAC0FFAC48F5, 0x19A699A3A, 0x1B84C677437C, 0xBC, 0x82B30FB, 0xC4D1, 0xC1E0B79, 0x60C, 0x3E, 0xA704A9CCC, 0x5675F03B6, 0x7EAFAAA4032, 0x1A8E4C3, 0x10DDC, 0xE1, 0x6CA02}, + }, + { + []byte{0x52, 0x18, 0x09, 0x9C, 0xE3, 0xF6, 0x3F, 0xA5, 0xED, 0xF7, 0x0E, 0xB9, 0x49, 0x47, 0x88, 0x47, 0x62, 0x11, 0x91, 0x9A, 0xDD, 0x33, 0x2C, 0xF9, 0x77, 0x0C, 0xFE, 0x5D, 0xBC, 0x11, 0x25, 0x0C, 0x57, 0x41, 0x2E, 0x26, 0x6A, 0x84, 0xF4, 0x6B, 0x74, 0x45, 0x74, 0x06, 0x1F, 0xAF, 0x0E, 0x4D, 0x5A, 0xBF, 0x4E, 0x02, 0x6E, 0xF5, 0x7B, 0xA4, 0xCD, 0x5F, 0xFC, 0x9B, 0xA3, 0x7D, 0x8D, 0x35, 0x11, 0xEE, 0x63, 0x6B, 0xE1, 0xC8, 0x51, 0xDB, 0x79, 0x94, 0x42, 0x4D, 0xEA, 0xAE, 0xBD, 0xC0, 0x24, 0x0C, 0x28, 0x3B, 0xCB, 0x2D, 0x67, 0x10, 0x38, 0x99, 0x8F, 0xFA, 0x9D, 0x76, 0xC5, 0xD9, 0x85, 0x0E, 0xDA, 0x45}, + []uint{33, 3, 51, 28, 16, 63, 3, 16, 33, 58, 33, 12, 64, 41, 13, 11, 52, 27, 8, 15, 1, 20, 30, 61, 34, 39, 35}, + []uint64{0xA4301339, 0x06, 0x1FB1FD2F6FB87, 0x5CA4A3C, 0x423B, 0x846466B74CCB3E5, 0x06, 0xE19F, 0x1976F0449, 0x10C57412E266A84, 0x1E8D6E88A, 0xE80, 0xC3F5E1C9AB57E9C0, 0x9BBD5EE933, 0xAFF, 0x726, 0xE8DF634D447B9, 0x46D7C39, 0x0A, 0x1DB7, 0x01, 0x32884, 0x26F5575E, 0x1C0240C283BCB2D6, 0x1C40E2663, 0x7F53AED8BB, 0x1850EDA45}, + }, + { + []byte{0xD6, 0x66, 0x64, 0xE0, 0x81, 0x98, 0x56, 0xB5, 0xF4, 0xA8, 0x1E, 0x12, 0x6F, 0xB0, 0x17, 0xE7, 0x91, 0xF9, 0x6C, 0x82, 0x9F, 0x22, 0xE2, 0x15, 0x5A, 0xCE, 0x73, 0x71, 0x29, 0x69, 0x8F, 0x94, 0xC7, 0xB3, 0x4F, 0x1B, 0x16, 0x28, 0xE7, 0xD6, 0x7E, 0x5F, 0xDE, 0xB6, 0x93, 0xA8, 0xDB, 0x9B, 0x44, 0x19, 0xDC, 0xE7, 0x57, 0x69, 0x4F, 0xA9, 0x33, 0x4C, 0x16, 0x5A, 0x91, 0xE4, 0x69, 0x33, 0x34, 0x93, 0x92, 0xE0, 0x00, 0xA2, 0xF2, 0xFB, 0xA9, 0xE0, 0xB5, 0xE0, 0xC0, 0x9D, 0x39, 0x52, 0xD6, 0xA4, 0x45, 0xB3, 0x9E, 0x96, 0x51, 0x44, 0xAD, 0xF0, 0x70, 0x51, 0x7D, 0xA7, 0x9F, 0xBB, 0x20, 0x41, 0x0C, 0x94}, + []uint{49, 14, 13, 57, 39, 20, 12, 63, 47, 53, 9, 52, 41, 9, 24, 60, 44, 16, 50, 21, 42, 36, 29}, + []uint64{0x1ACCCC9C10330, 0x2B5A, 0x1F4A, 0x103C24DF602FCF2, 0x1F96C829F2, 0x2E215, 0x5AC, 0x739B894B4C7CA63D, 0x4D3C6C58A39F, 0xB3F2FEF5B49D4, 0xDB, 0x9B4419DCE7576, 0x129F5266982, 0x196, 0xA4791A, 0x4CCD24E4B80028B, 0xCBEEA782D78, 0x3027, 0x13952D6A445B3, 0x13D2CA, 0xA256F83828, 0xBED3CFDD9, 0x410C94}, + }, + { + []byte{0xA1, 0xA6, 0x11, 0xEE, 0xBB, 0x60, 0x43, 0x9A, 0x10, 0xDA, 0x7D, 0xBB, 0x9D, 0xFC, 0x67, 0x7E, 0xE5, 0x57, 0x36, 0x8C, 0xB4, 0x20, 0x6D, 0x5A, 0xD1, 0x61, 0x1F, 0x1B, 0x1F, 0x23, 0x72, 0x26, 0xB1, 0xFF, 0x12, 0x26, 0xBB, 0x6D, 0x2B, 0x7A, 0x7E, 0x15, 0x5A, 0x2F, 0x0E, 0x17, 0xEF, 0x71, 0xCB, 0x1C, 0x18, 0xD0, 0xFE, 0x00, 0x9F, 0xC6, 0x0C, 0xB7, 0x45, 0xED, 0xF7, 0xB9, 0x93, 0xAF, 0xA5, 0x02, 0xB6, 0xFA, 0x8D, 0x7C, 0xF6, 0x2C, 0x36, 0x9A, 0x81, 0xB8, 0xCE, 0x89, 0x63, 0xAD, 0x26, 0x5C, 0x3B, 0x1B, 0xF7, 0xB8, 0xAE, 0xAF, 0x5C, 0x07, 0x47, 0x3C, 0x79, 0x14, 0x0F, 0x18, 0x35, 0xAA, 0x30, 0xCE}, + []uint{30, 56, 32, 18, 22, 48, 9, 2, 41, 20, 9, 18, 51, 20, 28, 52, 47, 37, 24, 24, 20, 8, 19, 25, 9, 29, 24, 37, 2, 6, 33}, + []uint64{0x2869847B, 0xAED810E684369F, 0x6EE77F19, 0x37EE5, 0x15CDA3, 0x2D081B56B458, 0x8F, 0x02, 0x6C7C8DC89A, 0xC7FC4, 0x113, 0x176DA, 0x2B7A7E155A2F0, 0xE17EF, 0x71CB1C1, 0x8D0FE009FC60C, 0x5BA2F6FBDCC9, 0x1AFA502B6F, 0xA8D7CF, 0x62C369, 0xA81B8, 0xCE, 0x44B1D, 0xD265C3, 0x163, 0xFDEE2BA, 0xBD701D, 0x39E3C8A07, 0x02, 0x0C, 0x35AA30CE}, + }, + { + []byte{0x44, 0x4D, 0xAD, 0xF6, 0xC5, 0x49, 0x84, 0x42, 0x7C, 0x1C, 0x52, 0xAB, 0x5E, 0xB4, 0xB1, 0x05, 0x2A, 0x91, 0xE7, 0xAD, 0x2C, 0x17, 0x8F, 0xCE, 0xB5, 0x0A, 0x3A, 0xAA, 0x05, 0x57, 0x36, 0xFD, 0x18, 0xA4, 0x2F, 0x32, 0x14, 0xAE, 0x60, 0x5D, 0xEE, 0x36, 0xBD, 0x7B, 0x1F, 0x6A, 0xB5, 0x10, 0x26, 0x0A, 0x19, 0xD1, 0x25, 0x53, 0xEA, 0x97, 0xF3, 0x9C, 0xE6, 0x71, 0x1E, 0xA6, 0x33, 0x98, 0x6C, 0x3E, 0xB4, 0xBD, 0x1D, 0x5B, 0xDF, 0xAB, 0xEF, 0x5D, 0xDE, 0x17, 0xB0, 0x62, 0x7D, 0x71, 0x8A, 0x36, 0xF5, 0x5B, 0xD2, 0x92, 0x54, 0xB7, 0xD0, 0x1B, 0xAD, 0x75, 0x69, 0xA0, 0x5A, 0x77, 0xFD, 0xF2, 0x81, 0xF5}, + []uint{29, 23, 54, 22, 44, 39, 56, 7, 49, 58, 48, 51, 17, 63, 28, 7, 55, 32, 62, 56}, + []uint64{0x889B5BE, 0x6C5498, 0x1109F0714AAD7A, 0x34B105, 0x2A91E7AD2C1, 0x3C7E75A851, 0xD5502AB9B7E8C5, 0x10, 0x17990A57302EF, 0x1C6D7AF63ED56A2, 0x4C1433A24AA, 0x3EA97F39CE671, 0x3D4C, 0x33986C3EB4BD1D5B, 0xDFABEF5, 0x6E, 0x785EC189F5C628, 0xDBD56F4A, 0x1254B7D01BAD7569, 0xA05A77FDF281F5}, + }, + { + []byte{0x0C, 0x0A, 0x46, 0x32, 0x3A, 0x2A, 0x4C, 0xD8, 0x81, 0x7D, 0x88, 0x36, 0xA9, 0x0D, 0xD2, 0xF7, 0x1C, 0x9C, 0xB9, 0xE8, 0x6B, 0x6D, 0x1D, 0xA5, 0x89, 0x16, 0x95, 0x20, 0x42, 0x46, 0x59, 0xD0, 0x4B, 0xEF, 0x6A, 0x1A, 0xD6, 0x92, 0xFF, 0x34, 0x44, 0x7D, 0x2D, 0x61, 0xC6, 0xE1, 0xAD, 0x75, 0x64, 0xDD, 0x00, 0xDA, 0x0F, 0x3E, 0xAB, 0x4D, 0x1B, 0x79, 0x55, 0x02, 0xC8, 0xF6, 0x8C, 0xF0, 0x4F, 0xAD, 0x64, 0x37, 0x08, 0xDC, 0x05, 0x4C, 0xE0, 0x3F, 0xE6, 0x0E, 0x6A, 0xC9, 0x5B, 0x82, 0x8B, 0x54, 0x2B, 0x28, 0x0F, 0xE5, 0x41, 0x4A, 0x53, 0x53, 0x81, 0x9C, 0x22, 0x75, 0xD4, 0x2A, 0x9F, 0x03, 0x14, 0x2D}, + []uint{7, 25, 64, 47, 3, 22, 11, 18, 56, 12, 64, 63, 8, 35, 40, 12, 31, 18, 64, 51, 58, 22, 64, 5}, + []uint64{0x06, 0xA4632, 0x3A2A4CD8817D8836, 0x5486E97B8E4E, 0x02, 0x39E86B, 0x368, 0x3B4B1, 0x22D2A40848CB3A, 0x97, 0xDED435AD25FE6888, 0x7D2D61C6E1AD7564, 0xDD, 0x6D079F5, 0x5A68DBCAA8, 0x164, 0x3DA33C13, 0x3AD64, 0x3708DC054CE03FE6, 0x73564ADC145A, 0x2856501FCA8294A, 0x1A9C0C, 0xE113AEA154F818A1, 0x0D}, + }, + { + []byte{0xB0, 0x2B, 0x72, 0xA2, 0xB5, 0xBA, 0x1F, 0xA0, 0x87, 0xEF, 0xEE, 0xE5, 0x01, 0x7F, 0x46, 0x66, 0x05, 0x7E, 0xBD, 0x0B, 0x06, 0x43, 0x3D, 0xA2, 0xCC, 0x6B, 0xA1, 0xB5, 0xBF, 0x91, 0xA7, 0x6C, 0x44, 0xC7, 0xB7, 0x7A, 0xBE, 0x20, 0xE9, 0xB1, 0xA7, 0xF9, 0x58, 0x2E, 0x92, 0x5F, 0xA2, 0xD5, 0x10, 0x98, 0xF9, 0x58, 0x1F, 0x91, 0x84, 0xCE, 0xEC, 0x53, 0x42, 0xE5, 0xBA, 0xD8, 0xC9, 0x3C, 0x5B, 0x4F, 0x7A, 0x8D, 0xC4, 0xFE, 0x6E, 0x56, 0x0A, 0x1A, 0x08, 0x2B, 0xD5, 0xFF, 0x8F, 0x28, 0xAB, 0x6A, 0xB3, 0x6C, 0x8A, 0x0F, 0x2B, 0xA5, 0x73, 0xED, 0xC7, 0x2C, 0xB9, 0xB7, 0xFD, 0x9C, 0xCA, 0xE7, 0x4E, 0xBA}, + []uint{51, 62, 30, 50, 54, 45, 5, 36, 27, 34, 30, 27, 60, 20, 44, 43, 45, 5, 5, 12, 9, 25, 18, 50, 13}, + []uint64{0x5815B9515ADD0, 0x3F410FDFDDCA02FE, 0x233302BF, 0x17A160C867B45, 0x2635D0DADFC8D3, 0x16C44C7B77AB, 0x1C, 0x41D3634FF, 0x1582E92, 0x17E8B5442, 0x18F9581F, 0x48C2677, 0x629A172DD6C649E, 0x2DA7B, 0xD46E27F372B, 0x286820AF57, 0x1FC79455B559, 0x16, 0x19, 0x141, 0x1CA, 0x1D2B9F6, 0x38E59, 0x1CDBFECE6573A, 0xEBA}, + }, + { + []byte{0x8E, 0xEB, 0xED, 0x77, 0xFC, 0xB9, 0x57, 0xAA, 0xC6, 0xF4, 0xEA, 0xF7, 0x59, 0xA3, 0x3F, 0xC7, 0x98, 0xF2, 0x6A, 0xA1, 0x0C, 0x08, 0xE5, 0x54, 0x8A, 0x69, 0x24, 0xE8, 0xCD, 0xD2, 0x27, 0x74, 0xC6, 0x96, 0x64, 0x1D, 0x00, 0x76, 0x21, 0xA1, 0x4F, 0xE8, 0xCF, 0x42, 0xFD, 0x51, 0x86, 0xD8, 0xBD, 0xA9, 0x28, 0x00, 0x42, 0xE9, 0x4B, 0xCB, 0xF5, 0xCF, 0x20, 0xFA, 0x96, 0x2F, 0x39, 0x86, 0x1B, 0x22, 0x73, 0x15, 0x65, 0x78, 0xFE, 0xB9, 0x12, 0xCD, 0x70, 0x2C, 0x8D, 0xE6, 0x4B, 0x08, 0x3C, 0xBB, 0x62, 0x96, 0xF9, 0xC3, 0x18, 0x29, 0xB6, 0x01, 0xEF, 0x76, 0xB6, 0x10, 0x8D, 0x00, 0x09, 0xC8, 0xBD, 0xC9}, + []uint{23, 25, 14, 24, 54, 57, 17, 10, 55, 55, 48, 6, 52, 23, 29, 46, 62, 52, 16, 9, 28, 44, 19, 20, 12}, + []uint64{0x4775F6, 0x177FCB9, 0x15EA, 0xB1BD3A, 0x2F759A33FC798F, 0x4D5421811CAA91, 0x9A49, 0xE8, 0x66E913BA634B32, 0x7401D886853FA, 0x33D0BF5461B6, 0x0B, 0xDA9280042E94B, 0x65FAE7, 0x120FA962, 0x3CE6186C89CC, 0x156578FEB912CD70, 0x2C8DE64B083CB, 0xB629, 0xDF, 0x3863053, 0x6C03DEED6C2, 0x8D00, 0x9C8B, 0xDC9}, + }, + { + []byte{0xCF, 0x4B, 0x63, 0xE2, 0x82, 0xA4, 0xA3, 0x18, 0x6B, 0x5B, 0x1E, 0xAA, 0x55, 0x8D, 0xBD, 0x1D, 0xE3, 0xA5, 0xAE, 0x26, 0x41, 0xBA, 0x07, 0xC5, 0x85, 0xA2, 0xB0, 0xCC, 0xA9, 0x90, 0x6B, 0xA4, 0x07, 0xBF, 0xE3, 0x01, 0x1F, 0x0D, 0x73, 0xBD, 0xC4, 0xAB, 0x03, 0xC0, 0xD7, 0xEC, 0x47, 0xCE, 0x21, 0x9C, 0x43, 0x3B, 0x88, 0xD4, 0xA3, 0xDE, 0x49, 0x70, 0x48, 0x47, 0x84, 0x97, 0xD8, 0x03, 0x34, 0x74, 0x26, 0x4B, 0x0E, 0x52, 0x32, 0x18, 0xDF, 0x36, 0xD2, 0x34, 0xA1, 0x9C, 0x04, 0x97, 0x83, 0x10, 0xC2, 0x32, 0xF8, 0x5A, 0xD2, 0xCB, 0xD8, 0x3B, 0x35, 0x58, 0x86, 0x00, 0x89, 0xDE, 0xF5, 0x7C, 0x1A, 0xFA}, + []uint{23, 40, 60, 52, 61, 12, 53, 39, 40, 17, 40, 58, 31, 13, 58, 39, 47, 4, 38, 16, 43, 12, 4}, + []uint64{0x67A5B1, 0xF14152518C, 0x35AD8F552AC6DE8, 0xEF1D2D71320DD, 0x7C585A2B0CCA99, 0x6B, 0x1480F7FC6023E1, 0x573BDC4AB0, 0x3C0D7EC47C, 0x1C433, 0x8867711A94, 0x1EF24B82423C24B, 0x7600CD1D, 0x132, 0x161CA46431BE6DA, 0x234A19C049, 0x3C18861197C2, 0x0D, 0x1A597B0766, 0xAB10, 0x60089DEF57C, 0x1AF, 0x0A}, + }, + { + []byte{0xC5, 0x28, 0x7C, 0xA6, 0x66, 0xF1, 0xAE, 0xF5, 0xC2, 0x0E, 0xCA, 0x71, 0xCB, 0x22, 0xE0, 0xB5, 0xA6, 0x6E, 0xC9, 0x23, 0xBE, 0xD6, 0x6A, 0x16, 0x8E, 0xC1, 0x00, 0x9B, 0xD7, 0x59, 0xA7, 0x8E, 0x68, 0x41, 0x13, 0x55, 0xAD, 0x6A, 0xC9, 0x49, 0xE1, 0x6A, 0x17, 0xBE, 0x8B, 0xA3, 0xFC, 0x81, 0x3B, 0xFB, 0x88, 0xCB, 0x1C, 0x66, 0x3F, 0x66, 0x28, 0x84, 0xB4, 0xBF, 0xFD, 0xAC, 0x65, 0x7F, 0x80, 0x67, 0x98, 0x32, 0xBF, 0x6E, 0xDC, 0xBD, 0xCD, 0x18, 0x7C, 0xBB, 0x54, 0xF9, 0xBA, 0x66, 0x79, 0x6A, 0x39, 0xC1, 0x55, 0x0E, 0x2C, 0x2B, 0x08, 0x10, 0x7F, 0x0A, 0x8A, 0xFA, 0xE3, 0x24, 0x31, 0x99, 0xFE, 0xAA}, + []uint{29, 64, 55, 11, 37, 3, 50, 2, 21, 56, 17, 35, 48, 42, 61, 26, 3, 16, 19, 11, 9, 64, 50, 11, 29, 14, 17}, + []uint64{0x18A50F94, 0xCCDE35DEB841D94E, 0x1CB22E0B5A66EC, 0x491, 0x1BED66A168, 0x07, 0x1820137AEB34F, 0x00, 0xE6841, 0x1355AD6AC949E1, 0xD42F, 0x3E8BA3FC8, 0x13BFB88CB1C6, 0x18FD98A212D, 0x5FFED632BFC033C, 0x30657ED, 0x06, 0xDCBD, 0x668C3, 0x72E, 0x1AA, 0x7CDD333CB51CE0AA, 0x21C58561020FE, 0xA8, 0x15F5C648, 0x18CC, 0x1FEAA}, + }, + { + []byte{0x69, 0x50, 0x9D, 0x23, 0xBD, 0xE7, 0x5B, 0x7F, 0x45, 0x9A, 0xD4, 0xD8, 0x62, 0x06, 0xCD, 0x3E, 0x7F, 0x32, 0xB5, 0x41, 0x25, 0x12, 0xD2, 0x13, 0xC9, 0x91, 0x44, 0x49, 0x86, 0x50, 0x8E, 0xCF, 0x38, 0x1E, 0x85, 0x65, 0xCB, 0x68, 0x6A, 0xFF, 0x1E, 0x03, 0x28, 0x0A, 0xB0, 0x93, 0xB6, 0xD5, 0x50, 0x15, 0x04, 0xB1, 0x6C, 0x71, 0xF1, 0xE7, 0xFE, 0xC9, 0x10, 0x89, 0xD6, 0xCE, 0x3F, 0x4F, 0xFF, 0x2F, 0xE8, 0xE7, 0xD1, 0x88, 0x19, 0x74, 0xEF, 0xC4, 0xD8, 0xAA, 0x49, 0x77, 0x09, 0xE9, 0x73, 0x5C, 0x75, 0xCB, 0x2F, 0x97, 0xB2, 0xF7, 0x8A, 0x71, 0x1C, 0xC5, 0x9D, 0x72, 0x16, 0x66, 0x18, 0x39, 0x3F, 0xBF}, + []uint{47, 4, 10, 61, 39, 3, 60, 41, 7, 5, 46, 14, 54, 21, 57, 14, 48, 57, 4, 56, 60, 34, 33, 25}, + []uint64{0x34A84E91DEF3, 0x0A, 0x36F, 0x1D166B5361881B34, 0x7CFE656A82, 0x02, 0x512D213C9914449, 0x10CA11D9E70, 0x1E, 0x10, 0x2B2E5B4357F8, 0x3C06, 0x14055849DB6AA8, 0x1504B, 0x2D8E3E3CFFD922, 0x44E, 0xB671FA7FF97F, 0x8E7D1881974EFC, 0x04, 0xD8AA497709E973, 0x5C75CB2F97B2F78, 0x29C473167, 0xB90B330C, 0x393FBF}, + }, + { + []byte{0x66, 0x39, 0x3F, 0x83, 0xCF, 0x72, 0x88, 0x33, 0xFB, 0xC8, 0x2F, 0x5D, 0x9E, 0x20, 0xD3, 0xF3, 0x8B, 0x9D, 0xC9, 0xE8, 0xEC, 0xC1, 0x77, 0xD0, 0x76, 0xFF, 0x95, 0x84, 0x0E, 0x97, 0x97, 0x1F, 0x62, 0x6B, 0x24, 0x42, 0x72, 0x39, 0x75, 0x5B, 0x1C, 0x65, 0xA4, 0x91, 0x43, 0xDF, 0xCA, 0x1D, 0x4F, 0x15, 0x64, 0x1E, 0xA5, 0xFC, 0xBF, 0x4B, 0x2D, 0x5D, 0xD9, 0x3F, 0xC8, 0xD9, 0x09, 0x15, 0x81, 0x71, 0xF7, 0x2D, 0x0C, 0xAD, 0xE1, 0x6F, 0x76, 0x92, 0x48, 0x1F, 0xF7, 0x63, 0xC5, 0x4E, 0x9B, 0x0E, 0xB7, 0x1F, 0xE3, 0x9C, 0x71, 0x1D, 0x85, 0xB6, 0x23, 0x48, 0x3D, 0x5B, 0x27, 0x54, 0xD0, 0xE6, 0xFF, 0x66}, + []uint{63, 43, 6, 51, 18, 20, 8, 45, 60, 24, 54, 8, 60, 4, 35, 38, 42, 26, 28, 18, 25, 15, 28, 8, 16, 57}, + []uint64{0x331C9FC1E7B94419, 0x7EF20BD7678, 0x20, 0x69F9C5CEE4F47, 0x1982E, 0xFA0ED, 0xFF, 0x56103A5E5C7, 0xD89AC9109C8E5D5, 0x6C7196, 0x249143DFCA1D4F, 0x15, 0x641EA5FCBF4B2D5, 0x0D, 0x6C9FE46C8, 0x122B02E3EE, 0x168656F0B7B, 0x2D24903, 0xFEEC78A, 0x274D8, 0xEB71FE, 0x1CE3, 0x88EC2DB, 0x11, 0xA41E, 0x15B2754D0E6FF66}, + }, + { + []byte{0x8F, 0x63, 0xBD, 0x4A, 0x79, 0xCC, 0x5B, 0x8B, 0x94, 0xD1, 0x09, 0xEC, 0xEA, 0x03, 0x58, 0xA1, 0xED, 0x5C, 0x72, 0x41, 0xBE, 0x2E, 0x84, 0x52, 0x1F, 0xE0, 0x20, 0x0F, 0x6E, 0x34, 0x3C, 0xEF, 0xC2, 0xD4, 0x1B, 0x4C, 0x52, 0x99, 0x33, 0x4F, 0x53, 0xB0, 0xD7, 0x54, 0x4B, 0x59, 0x2E, 0xEB, 0x04, 0x59, 0xAE, 0xFF, 0x4E, 0x47, 0xE1, 0x06, 0x8F, 0xB2, 0xF2, 0xB2, 0xB4, 0x73, 0x3B, 0xDA, 0x65, 0xBF, 0x04, 0x74, 0xAB, 0xE0, 0x8C, 0x51, 0x04, 0x7A, 0x68, 0x7D, 0xFE, 0xF1, 0xF1, 0xC6, 0x87, 0xD9, 0x20, 0xEE, 0x9C, 0xD7, 0x05, 0xB7, 0x7F, 0xB2, 0x9E, 0xC7, 0xB7, 0x1E, 0x28, 0x85, 0xE0, 0x86, 0xA8, 0x3C}, + []uint{7, 18, 6, 31, 48, 10, 41, 63, 35, 22, 27, 13, 22, 64, 30, 9, 14, 53, 18, 47, 8, 62, 30, 18, 41, 56, 7}, + []uint64{0x47, 0x2C77A, 0x25, 0x1E7316E2, 0xE534427B3A80, 0x358, 0x143DAB8E483, 0x3E2E84521FE0200F, 0x371A1E77E, 0x5A836, 0x4C52993, 0x69E, 0x29D86B, 0xAA25AC9775822CD7, 0x1FE9C8FC, 0x41, 0x28FB, 0x5E56568E677B4, 0x32DF8, 0x11D2AF823144, 0x11, 0x3A687DFEF1F1C687, 0x36483BA7, 0xD705, 0x16EFF653D8F, 0x6E3C510BC10D50, 0x3C}, + }, + { + []byte{0x68, 0xBC, 0xC2, 0x6E, 0x0B, 0xE7, 0x1E, 0x5A, 0x9E, 0xE4, 0x64, 0xB1, 0xF7, 0x37, 0xA7, 0xF8, 0x1B, 0x6E, 0xD3, 0x99, 0x2A, 0xE4, 0x42, 0x43, 0xA7, 0x5E, 0xD0, 0x02, 0x1D, 0x64, 0x72, 0x99, 0x26, 0xF5, 0x76, 0xD1, 0xD5, 0x0D, 0x11, 0x30, 0x71, 0x58, 0x4F, 0xD3, 0xAB, 0x73, 0xBB, 0xD0, 0x1C, 0xE9, 0xCA, 0x37, 0x41, 0xA1, 0xF6, 0x76, 0x13, 0xD6, 0x7A, 0xF2, 0xA0, 0x76, 0x66, 0xC3, 0x3B, 0x3A, 0x9C, 0xE8, 0x28, 0x50, 0x9A, 0x76, 0x2C, 0xFC, 0x48, 0x2A, 0x23, 0xD9, 0xF4, 0x39, 0x9F, 0xC1, 0x85, 0x49, 0xFE, 0xFD, 0x2C, 0x14, 0x73, 0x3D, 0x08, 0xE9, 0x15, 0x9E, 0xC1, 0x86, 0xA5, 0x27, 0xAB, 0x9D}, + []uint{7, 27, 15, 37, 13, 26, 25, 4, 56, 38, 25, 11, 13, 38, 26, 32, 51, 7, 53, 13, 46, 53, 41, 50, 41, 52}, + []uint64{0x34, 0x2F309B8, 0x17CE, 0x796A7B919, 0x58F, 0x2E6F4FF, 0x6DBB4, 0x0E, 0x64AB91090E9D7B, 0x10021D6472, 0x1324DEA, 0x76D, 0x3AA, 0x6889838AC, 0x9FA756, 0xE777A039, 0x69CA3741A1F67, 0x30, 0x13D67AF2A07666, 0x1867, 0x19D4E7414284, 0x1A762CFC482A23, 0x1B3E8733F83, 0x2A4FF7E960A3, 0x133D08E9159, 0xEC186A527AB9D}, + }, + { + []byte{0xDE, 0xFA, 0x7D, 0x18, 0x91, 0x5F, 0xD5, 0x6A, 0x70, 0x0D, 0xEA, 0x2C, 0x70, 0x3E, 0xC2, 0x17, 0x65, 0x69, 0xB9, 0x94, 0x4D, 0xEF, 0x61, 0x47, 0xFB, 0x07, 0x57, 0x14, 0x60, 0xEE, 0x6F, 0x2C, 0x50, 0x2C, 0xDC, 0x56, 0xAC, 0x5A, 0x1E, 0xA6, 0x3D, 0xAE, 0xEB, 0xEB, 0x52, 0xA0, 0x8F, 0xEB, 0x2C, 0x01, 0x55, 0x6B, 0x7D, 0x29, 0x15, 0x06, 0xB9, 0x12, 0x9E, 0x88, 0x15, 0x06, 0xE5, 0x81, 0x77, 0x61, 0x3E, 0x6A, 0x0E, 0xE4, 0xA9, 0xE2, 0x73, 0x78, 0x7A, 0x04, 0x3A, 0x8E, 0xB2, 0x68, 0x3E, 0x97, 0xFE, 0x8B, 0xA7, 0x54, 0x7C, 0x44, 0xCD, 0x50, 0x75, 0x8D, 0x1E, 0x3C, 0xF8, 0x0F, 0x09, 0x7A, 0x30, 0x38}, + []uint{18, 55, 46, 36, 6, 40, 36, 28, 62, 26, 58, 8, 62, 57, 61, 31, 4, 14, 55, 59, 6, 5, 27}, + []uint64{0x37BE9, 0x7A3122BFAAD4E0, 0x6F516381F61, 0xBB2B4DCC, 0x28, 0x9BDEC28FF6, 0xEAE28C1D, 0xCDE58A0, 0x166E2B562D0F531E, 0x35DD7D6, 0x295047F59600AAB, 0x5B, 0x3A522A0D72253D10, 0x541B9605DD84F9, 0x15077254F139BC3D, 0x10EA3AC, 0x09, 0x283E, 0x4BFF45D3AA3E22, 0x33541D63478F3E0, 0x0F, 0x01, 0x17A3038}, + }, + { + []byte{0x1F, 0x14, 0x9C, 0x3B, 0x12, 0xAB, 0xA7, 0x1E, 0x56, 0x9C, 0x0F, 0x6B, 0xD7, 0x06, 0x53, 0x96, 0xD3, 0x93, 0x66, 0x48, 0x51, 0x47, 0x3B, 0x8B, 0x73, 0x6D, 0x56, 0x25, 0xE1, 0x37, 0x33, 0x5E, 0x50, 0x51, 0xD5, 0xA2, 0xDF, 0x36, 0x71, 0x08, 0xA4, 0x45, 0xA2, 0xD8, 0x7A, 0xE4, 0x71, 0x2C, 0x8F, 0x2F, 0x58, 0x1C, 0x92, 0x53, 0x36, 0x72, 0xD1, 0x3E, 0xED, 0xDB, 0xBE, 0x81, 0x6E, 0xA5, 0x3C, 0x88, 0xE6, 0x86, 0xA2, 0xFD, 0x2C, 0xEC, 0xE2, 0x87, 0x3C, 0x4E, 0xA8, 0xB9, 0x30, 0xB6, 0xD2, 0x44, 0xFD, 0x7C, 0xDD, 0x9D, 0x68, 0x7E, 0xE3, 0xC0, 0xE1, 0x55, 0xB5, 0x46, 0xEE, 0x6E, 0x3A, 0xEC, 0xC0, 0xEE}, + []uint{27, 22, 22, 27, 60, 40, 63, 9, 2, 14, 31, 30, 40, 57, 18, 25, 52, 61, 35, 27, 25, 51, 9, 40, 13}, + []uint64{0xF8A4E1, 0x362557, 0x138F2B, 0x2703DAF, 0x5C194E5B4E4D992, 0x1451CEE2DC, 0x6DAAC4BC26E66BCA, 0x14, 0x01, 0x3568, 0x5BE6CE21, 0x5222D16, 0xC3D7238964, 0xF2F581C9253367, 0xB44F, 0x176EDDF, 0x40B7529E44734, 0x6A2FD2CECE2873C, 0x27545C985, 0x5B4913F, 0xBE6ECE, 0x5A1FB8F038556, 0x1AA, 0x377371D766, 0xEE}, + }, + { + []byte{0xC6, 0x50, 0x5B, 0xDC, 0x8F, 0x17, 0x18, 0xFC, 0x74, 0xB0, 0xA2, 0x6B, 0x88, 0x04, 0x43, 0x34, 0x39, 0xEE, 0x82, 0x49, 0x11, 0xCE, 0x55, 0x79, 0xC0, 0xBE, 0xC5, 0x9A, 0x68, 0xA7, 0xC3, 0xF3, 0x10, 0x6D, 0xCC, 0x36, 0x5A, 0xCE, 0x18, 0x02, 0xE0, 0x3F, 0x72, 0xCF, 0x15, 0xBF, 0xE6, 0x8E, 0x53, 0xA8, 0xE8, 0xC7, 0x8A, 0xF2, 0x36, 0x8F, 0x23, 0xB4, 0xF1, 0x2A, 0xF2, 0xBB, 0x12, 0x3E, 0x89, 0xDA, 0x20, 0x08, 0x70, 0x08, 0xC3, 0xD7, 0x29, 0x87, 0x29, 0xA9, 0x3C, 0x63, 0x28, 0x7B, 0x85, 0xE4, 0x58, 0x91, 0x9A, 0x28, 0xCD, 0x52, 0x3D, 0x8F, 0x57, 0xC6, 0xE6, 0xD2, 0xC7, 0x4E, 0x8C, 0x8C, 0x94, 0x0B}, + []uint{30, 9, 43, 58, 57, 60, 39, 34, 10, 51, 14, 9, 33, 26, 38, 8, 24, 11, 40, 60, 41, 44, 40, 14, 7}, + []uint64{0x319416F7, 0x47, 0x45C63F1D2C2, 0x226B8804433439E, 0x1D0492239CAAF38, 0x17D8B34D14F87E6, 0x106DCC365A, 0x338600B80, 0x3F7, 0x1678ADFF34729, 0x351D, 0x31, 0x1C5791B47, 0x24769E2, 0x15795D891F, 0x44, 0xED1004, 0x1C0, 0x230F5CA61C, 0xA6A4F18CA1EE179, 0x2C48CD1466, 0xA91EC7ABE37, 0x36963A7464, 0x1928, 0x0B}, + }, + { + []byte{0x92, 0x34, 0xDC, 0xA7, 0x57, 0x47, 0x83, 0xFB, 0x4C, 0x08, 0x2D, 0x84, 0xED, 0x7A, 0xD1, 0x7A, 0x8F, 0xDF, 0x10, 0xAE, 0xD4, 0x58, 0xEB, 0xF7, 0x69, 0xE8, 0x94, 0x41, 0x97, 0xAC, 0x78, 0x04, 0x9C, 0x5E, 0xB3, 0xB9, 0x0C, 0xE3, 0x48, 0xC5, 0x45, 0x1A, 0xBB, 0x8D, 0x21, 0xA0, 0x4B, 0x77, 0xE1, 0x01, 0x06, 0x6D, 0x89, 0x37, 0xD8, 0xB9, 0xCF, 0xD3, 0x94, 0xD0, 0xFD, 0xF8, 0xE2, 0xC5, 0x33, 0x3E, 0xAF, 0x7F, 0x9B, 0xF1, 0xDE, 0x2D, 0xF7, 0x10, 0x3A, 0xBA, 0xD9, 0x17, 0xF8, 0x79, 0x7A, 0xF4, 0xAC, 0x44, 0x60, 0x5E, 0x2E, 0xA5, 0x87, 0xC9, 0x9C, 0x7D, 0x0A, 0x42, 0xAC, 0xBF, 0x90, 0x0A, 0x83, 0xB9}, + []uint{41, 57, 52, 49, 23, 39, 53, 1, 6, 37, 2, 19, 13, 10, 52, 17, 38, 20, 20, 45, 36, 56, 22, 20, 49, 5, 18}, + []uint64{0x12469B94EAE, 0x11E0FED3020B613, 0xB5EB45EA3F7C4, 0x576A2C75FBB4, 0x7A2510, 0x32F58F0093, 0x117ACEE4338D23, 0x00, 0x0A, 0x1146AEE348, 0x01, 0x5025B, 0x17E1, 0x04, 0x19B624DF62E73, 0x1E9CA, 0x1A1FBF1C58, 0xA667D, 0x5EFF3, 0xFC778B7DC40, 0xEAEB645FE, 0x1E5EBD2B111817, 0x22EA58, 0x7C99C, 0xFA1485597F20, 0x02, 0x283B9}, + }, + { + []byte{0x14, 0x51, 0xA2, 0xCB, 0xC5, 0x75, 0xFD, 0x6D, 0xAA, 0x55, 0x35, 0x8A, 0x0C, 0x63, 0xD7, 0xD0, 0x6A, 0x88, 0x56, 0x78, 0xDE, 0x38, 0xA8, 0xAA, 0xB0, 0x3A, 0x8A, 0xD4, 0xCC, 0x91, 0x9A, 0x6D, 0xA2, 0xC9, 0xA5, 0x3A, 0xAB, 0x4C, 0xC4, 0xFC, 0x3C, 0xB2, 0x44, 0xBB, 0x3C, 0xFB, 0xF8, 0x62, 0x82, 0x90, 0xF8, 0x5E, 0x6A, 0x3C, 0x6A, 0x14, 0x61, 0x7E, 0xA8, 0x0C, 0x3B, 0x7F, 0x00, 0xF8, 0x18, 0x14, 0xBD, 0x13, 0xA3, 0xC6, 0xE6, 0xF1, 0xB0, 0x9F, 0x91, 0xF7, 0x16, 0xC9, 0xDB, 0x9D, 0xC8, 0xB8, 0x96, 0xA0, 0x22, 0x95, 0xF3, 0x39, 0x8C, 0xE8, 0x6D, 0xDC, 0xE2, 0x75, 0xAD, 0xC3, 0xC9, 0x2E, 0x2A, 0xDC}, + []uint{9, 52, 26, 1, 3, 3, 39, 45, 14, 59, 41, 42, 38, 61, 61, 57, 29, 56, 58, 6, 11, 32, 33, 17, 7}, + []uint64{0x28, 0xA345978AEBFAD, 0x2D52A9A, 0x01, 0x04, 0x02, 0x418C7AFA0D, 0xA2159E378E2, 0x28AA, 0x581D456A6648CD3, 0xDA2C9A53AA, 0x2D3313F0F2C, 0x244BB3CFBF, 0x10C50521F0BCD478, 0x1A85185FAA030EDF, 0x1807C0C0A5E89D1, 0x1C6E6F1B, 0x9F91F716C9DB9, 0x3722E25A808A57C, 0x33, 0x4C6, 0x7436EE71, 0x75ADC3C9, 0x5C55, 0x5C}, + }, + { + []byte{0x71, 0x4F, 0x73, 0x51, 0xAA, 0x39, 0xC9, 0x4F, 0xF7, 0x6E, 0x45, 0x35, 0x07, 0x37, 0x78, 0x28, 0x44, 0x01, 0x14, 0xE7, 0xCA, 0x39, 0x71, 0x8B, 0x93, 0x42, 0x99, 0x23, 0x8B, 0x38, 0x34, 0x2F, 0xD9, 0x59, 0xF7, 0xFA, 0x8F, 0x96, 0x99, 0x23, 0x4D, 0x5D, 0x6D, 0xF2, 0xDD, 0xEB, 0x60, 0xF6, 0x7F, 0x01, 0xBA, 0x5D, 0xAD, 0x7E, 0xD2, 0x2C, 0x34, 0x11, 0x1E, 0xD7, 0x77, 0xAE, 0x59, 0x52, 0x8B, 0xAC, 0x48, 0x9F, 0xF3, 0x26, 0xCF, 0x56, 0xE2, 0x16, 0x56, 0x15, 0xB1, 0xDE, 0xDC, 0x0E, 0x00, 0x35, 0x4A, 0x59, 0x72, 0x56, 0x44, 0xD7, 0x22, 0x77, 0x2E, 0x78, 0x26, 0x3E, 0x0E, 0xF2, 0xB7, 0x37, 0x5B, 0x86}, + []uint{49, 54, 59, 50, 64, 64, 51, 12, 33, 26, 54, 4, 29, 33, 32, 61, 44, 41, 18, 22}, + []uint64{0xE29EE6A35473, 0x24A7FBB7229A83, 0x4DDE0A11004539F, 0xA39718B93429, 0x9238B38342FD959F, 0x7FA8F9699234D5D6, 0x6F96EF5B07B3F, 0x80D, 0x1A5DAD7ED, 0x8B0D04, 0x11ED777AE59528, 0x0B, 0x158913FE, 0xC9B3D5B8, 0x8595856C, 0xEF6E07001AA52CB, 0x92B226B913B, 0x12E78263E0E, 0x3CADC, 0x375B86}, + }, + { + []byte{0x50, 0xFB, 0x8B, 0x19, 0xF8, 0xE7, 0x6D, 0xEF, 0xCC, 0x78, 0x91, 0x98, 0x77, 0xAD, 0x00, 0xA7, 0x6F, 0x35, 0x25, 0xA8, 0x8F, 0xC2, 0x2E, 0x07, 0x1C, 0x95, 0x09, 0x10, 0xED, 0xCC, 0x86, 0x3C, 0xF1, 0x04, 0x2C, 0xC6, 0xC6, 0xE7, 0x89, 0xC1, 0x7F, 0x34, 0x16, 0xBE, 0x45, 0x47, 0xD8, 0xE7, 0x84, 0x74, 0x30, 0x91, 0x36, 0xDD, 0x88, 0x00, 0xB9, 0x73, 0x22, 0xA9, 0xF1, 0x72, 0x5F, 0x6B, 0x61, 0x1F, 0x09, 0xFA, 0xB8, 0x8F, 0xE1, 0x24, 0xBB, 0xDF, 0xB9, 0x43, 0xD8, 0x46, 0x3E, 0x4C, 0xD9, 0x77, 0x56, 0xD5, 0x4F, 0x98, 0x7D, 0x61, 0xD6, 0xFA, 0x27, 0xB6, 0xA1, 0x95, 0x8A, 0xB2, 0x40, 0x6E, 0x1F, 0xC2}, + []uint{9, 19, 15, 27, 49, 35, 15, 38, 48, 39, 29, 49, 62, 51, 3, 17, 38, 37, 35, 13, 6, 33, 54, 8, 14, 35, 22}, + []uint64{0xA1, 0x7B8B1, 0x4FC7, 0x1DB7BF3, 0x3C48CC3BD680, 0x29DBCD496, 0x511F, 0x2117038E4A, 0x848876E6431E, 0x3C410B31B1, 0x173C4E0B, 0x1F3416BE4547D, 0x239E11D0C244DB76, 0x100172E64553E, 0x01, 0xE4BE, 0x35B08F84FD, 0xB88FE124B, 0x5EFDCA1EC, 0x463, 0x39, 0x66CBBAB6, 0x2A9F30FAC3ADF4, 0x4F, 0x1B50, 0x6562AC901, 0x2E1FC2}, + }, + { + []byte{0xCB, 0x0B, 0xBC, 0xEA, 0x8E, 0x98, 0xFC, 0x67, 0x6A, 0x13, 0x54, 0x10, 0x90, 0xE9, 0xAF, 0x4D, 0xA5, 0x28, 0xAD, 0x14, 0xD3, 0x62, 0x21, 0x81, 0x4F, 0x15, 0x40, 0x65, 0x32, 0x37, 0x39, 0x8C, 0x71, 0x38, 0xBE, 0xF8, 0x37, 0x6B, 0x96, 0x5A, 0x2C, 0x19, 0x6F, 0xF3, 0xCF, 0xF9, 0x08, 0xC3, 0x4B, 0xAB, 0x9C, 0xB3, 0xA2, 0xE7, 0x62, 0x61, 0xBC, 0x59, 0x83, 0x95, 0x5B, 0x22, 0x0B, 0x1B, 0x7D, 0x7B, 0xDE, 0xF7, 0x96, 0xC0, 0x30, 0x29, 0xEF, 0x4E, 0x46, 0xE8, 0x8D, 0x24, 0xFC, 0x0B, 0x5E, 0xC1, 0x40, 0x6E, 0xA6, 0x81, 0xB1, 0x66, 0x15, 0x78, 0xED, 0xF6, 0x3A, 0x6D, 0x3B, 0xC6, 0x29, 0x3B, 0x29, 0xAD}, + []uint{34, 62, 46, 7, 8, 55, 14, 33, 30, 14, 16, 63, 29, 31, 39, 52, 60, 2, 21, 4, 60, 45, 9, 51, 15}, + []uint64{0x32C2EF3AA, 0xE98FC676A135410, 0x243A6BD3694A, 0x15, 0xA2, 0x4D36221814F154, 0x194, 0x191B9CC63, 0x22717DF0, 0x1BB5, 0xCB2D, 0xB065BFCF3FE4230, 0x1A5D5CE5, 0x4E8B9D89, 0x4378B3072A, 0xB6441636FAF7B, 0xDEF2D806053DE9C, 0x02, 0x6E88D, 0x02, 0x4FC0B5EC1406EA6, 0x10362CC2AF1D, 0x17D, 0x474DA778C5276, 0x29AD}, + }, + { + []byte{0x65, 0x00, 0xA4, 0x4F, 0x09, 0x6B, 0x77, 0xDC, 0xB3, 0x75, 0xDA, 0x0C, 0xEF, 0x14, 0x65, 0x7B, 0x1B, 0xDF, 0x21, 0x1E, 0xBA, 0x98, 0xC0, 0xD0, 0x34, 0xB3, 0x75, 0x8F, 0x90, 0x17, 0xF0, 0x73, 0x99, 0x7D, 0x1A, 0x89, 0xDF, 0x48, 0xEE, 0xF4, 0x7C, 0x23, 0x93, 0x2B, 0xFF, 0xFE, 0x5A, 0x3C, 0x4F, 0x9D, 0x4C, 0x22, 0x2E, 0xD0, 0x31, 0x23, 0xD6, 0x00, 0xA2, 0x63, 0xD8, 0x78, 0xAD, 0x90, 0xB3, 0xF2, 0x8B, 0x38, 0x45, 0xB3, 0x1A, 0xB7, 0x5B, 0xD3, 0x5A, 0x93, 0x43, 0x65, 0x33, 0xB2, 0xB4, 0x74, 0x2C, 0x87, 0x63, 0x15, 0xCF, 0x9F, 0x20, 0x6D, 0xCF, 0xE7, 0x49, 0xFD, 0x32, 0x85, 0x0D, 0x4C, 0x56, 0x23}, + []uint{33, 45, 36, 59, 14, 38, 44, 46, 39, 5, 16, 58, 26, 45, 28, 1, 48, 46, 26, 54, 57, 19, 17}, + []uint64{0xCA01489E, 0x25ADDF72CDD, 0x76833BC51, 0x4AF637BE423D753, 0x606, 0x206966EB1F, 0x202FE0E732F, 0x28D44EFA4777, 0x51F08E4CAF, 0x1F, 0xFF2D, 0x789F3A98445DA0, 0x1891EB0, 0xA263D878AD, 0x90B3F28, 0x01, 0x6708B66356EB, 0x1E9AD49A1B29, 0x276568E, 0x21643B18AE7CF9, 0x6DCFE749FD328, 0x286A6, 0x5623}, + }, + { + []byte{0x31, 0xB1, 0x41, 0xCC, 0x16, 0x3C, 0xA8, 0x45, 0x95, 0x99, 0x28, 0x22, 0xBC, 0xDB, 0x79, 0xB1, 0x73, 0x27, 0xF2, 0x83, 0xFF, 0x6D, 0x48, 0x0D, 0xAF, 0x90, 0x08, 0xF8, 0x9C, 0xD3, 0x54, 0x39, 0x63, 0x63, 0x75, 0xD7, 0xA0, 0x88, 0x47, 0x1A, 0x8A, 0x0F, 0x3D, 0x0E, 0x92, 0x7B, 0x6E, 0x5D, 0x01, 0x4F, 0x0E, 0x59, 0x79, 0xF0, 0x4B, 0xDC, 0x53, 0x58, 0x2A, 0x6E, 0x98, 0xC9, 0x62, 0xAD, 0x24, 0x08, 0xB7, 0x37, 0xAB, 0x65, 0x9A, 0x2A, 0x59, 0x3E, 0xE4, 0x29, 0x9C, 0x10, 0xC3, 0x45, 0xD7, 0x6A, 0x1C, 0x4D, 0xC3, 0x85, 0xFF, 0x94, 0x8E, 0x56, 0x3B, 0x21, 0x7A, 0x3D, 0x6C, 0x7D, 0xE3, 0x97, 0x37, 0x6C}, + []uint{37, 10, 30, 25, 3, 25, 7, 11, 15, 8, 19, 20, 25, 37, 45, 63, 33, 52, 55, 12, 63, 24, 1, 31, 53, 25, 54, 17}, + []uint64{0x636283982, 0x31E, 0x1508B2B3, 0x4A08AF, 0x01, 0x16DE6C5, 0x66, 0x27F, 0x141F, 0xFB, 0x35203, 0x6BE40, 0x47C4E6, 0x1354396363, 0xEBAF41108E3, 0x28A0F3D0E927B6E5, 0x1A029E1CB, 0x2F3E097B8A6B0, 0x2A6E98C962AD24, 0x8B, 0x39BD5B2CD152C9F7, 0x214CE0, 0x01, 0x61A2EBB, 0xA1C4DC385FF94, 0x11CAC76, 0x10BD1EB63EF1CB, 0x1376C}, + }, + { + []byte{0x8B, 0x89, 0x8A, 0x74, 0xAA, 0x17, 0xFF, 0xDA, 0x92, 0xDF, 0xB8, 0xC9, 0xFE, 0xB4, 0xB6, 0x84, 0x9C, 0x55, 0x64, 0x82, 0x41, 0x81, 0xFE, 0x23, 0xF1, 0xAC, 0x76, 0x5D, 0x55, 0xC8, 0x13, 0x6C, 0x5A, 0x0E, 0xAA, 0x71, 0x12, 0xFA, 0xED, 0x0C, 0x56, 0x2F, 0xD9, 0x70, 0x38, 0x7F, 0x8D, 0x06, 0x00, 0x3C, 0xD8, 0xB7, 0xE4, 0x99, 0x69, 0xD4, 0xFC, 0xA0, 0x35, 0x5D, 0x9F, 0xD2, 0x59, 0x32, 0x93, 0x60, 0x4A, 0x57, 0xCD, 0x93, 0x94, 0x74, 0x6F, 0x99, 0x5C, 0x49, 0x58, 0x62, 0xE5, 0xF3, 0x59, 0x9B, 0x33, 0xFE, 0x9D, 0x86, 0x2D, 0xA3, 0x0A, 0xB8, 0xB8, 0x7E, 0xFB, 0x51, 0xD0, 0x16, 0xF6, 0xF3, 0x22, 0x22}, + []uint{31, 27, 6, 12, 61, 3, 47, 47, 8, 8, 15, 29, 29, 32, 27, 22, 42, 51, 14, 52, 6, 25, 6, 22, 51, 62, 60, 5}, + []uint64{0x45C4C53A, 0x2A85FFF, 0x1A, 0x92D, 0x1F7193FD696D0938, 0x05, 0x2B24120C0FF1, 0xFC6B1D97557, 0x20, 0x4D, 0x58B4, 0x3AA9C44, 0x17D76862, 0xB17ECB81, 0x61FE341, 0x2003CD, 0x22DF9265A75, 0x1F9406ABB3FA4, 0x2C99, 0x49B0252BE6C9C, 0x28, 0x1D1BE65, 0x1C, 0x125618, 0x5CBE6B33667FD, 0xEC316D1855C5C3F, 0x7DA8E80B7B79911, 0x02}, + }, + { + []byte{0xC8, 0x02, 0x2F, 0x55, 0xFC, 0x45, 0xDF, 0xA9, 0x4D, 0x04, 0xDC, 0x73, 0xDF, 0x5C, 0x82, 0x14, 0x9E, 0x65, 0xC8, 0xFF, 0x12, 0x5E, 0x15, 0x8F, 0xCA, 0x0A, 0xC9, 0xB9, 0x59, 0x99, 0x64, 0x7A, 0x6A, 0xE6, 0x49, 0x9C, 0x74, 0x72, 0xCD, 0xB3, 0x6F, 0xCF, 0x99, 0x02, 0xB1, 0x2C, 0xB4, 0x78, 0xF4, 0x43, 0x1C, 0xB9, 0xB0, 0xE6, 0xC6, 0x94, 0xF3, 0x01, 0x66, 0x13, 0x5E, 0x2A, 0xF9, 0xD0, 0x33, 0xFC, 0x77, 0xC4, 0xFA, 0x0F, 0x7B, 0xFD, 0x1C, 0xC2, 0x77, 0xED, 0x37, 0xAA, 0x97, 0x3D, 0x1E, 0x86, 0x96, 0x9C, 0x67, 0x12, 0xC2, 0x8B, 0xA7, 0xCB, 0xC1, 0x35, 0xCE, 0x80, 0xF2, 0x4F, 0xCB, 0xB8, 0x9F, 0xE4}, + []uint{28, 39, 42, 11, 32, 11, 2, 11, 58, 55, 37, 23, 17, 57, 41, 8, 22, 21, 23, 3, 1, 49, 45, 27, 46, 48, 9, 34}, + []uint64{0xC8022F5, 0x2FE22EFD4A, 0x1A09B8E7BEB, 0x482, 0x149E65C8, 0x7F8, 0x02, 0x25E, 0x563F282B26E566, 0x32C8F4D5CC9338, 0x1D1CB36CDB, 0x79F320, 0xAC4B, 0x5A3C7A218E5CD8, 0xE6C694F301, 0x66, 0x4D78A, 0x17CE81, 0x4FF1DF, 0x00, 0x01, 0x7D07BDFE8E61, 0x77ED37AA973, 0x68F434B, 0x138CE2585174, 0xF97826B9D01E, 0x93, 0x3CBB89FE4}, + }, + { + []byte{0x69, 0x18, 0xCA, 0x1F, 0x76, 0xD9, 0x00, 0xA8, 0xC4, 0x7C, 0x90, 0xB8, 0xC9, 0x4B, 0xF2, 0xE1, 0xEF, 0xFA, 0x7C, 0x5A, 0x6E, 0xB2, 0xDA, 0x4A, 0x86, 0x2E, 0x93, 0x5A, 0xB0, 0x61, 0x15, 0x72, 0xDD, 0x20, 0xEA, 0xBF, 0xA5, 0x4D, 0x9C, 0x7C, 0x9E, 0xD0, 0xA4, 0x0D, 0x1D, 0x85, 0xF1, 0x03, 0xBA, 0xA0, 0xF7, 0x37, 0x96, 0x0E, 0x05, 0x4C, 0xCD, 0x96, 0x9E, 0x7F, 0xF2, 0xE9, 0xE5, 0xA2, 0x7F, 0xED, 0x32, 0x13, 0x24, 0x1F, 0x60, 0x93, 0x0F, 0x25, 0x4D, 0x96, 0x9B, 0x4C, 0x19, 0xE1, 0xA8, 0x20, 0x41, 0x27, 0xE5, 0x1C, 0x92, 0x30, 0x93, 0x15, 0x0D, 0xD8, 0xCB, 0xAC, 0x25, 0xE1, 0x60, 0xE2, 0x4D, 0x1E}, + []uint{36, 31, 43, 61, 45, 54, 48, 21, 50, 49, 44, 30, 7, 12, 26, 30, 62, 63, 60, 28}, + []uint64{0x6918CA1F7, 0x36C80546, 0x11F242E3252, 0x1F970F7FD3E2D375, 0x12DA4A862E93, 0x16AC18455CB748, 0x3AAFE953671F, 0x4F685, 0x81A3B0BE2077, 0xA83DCDE58381, 0x533365A79FF, 0x32E9E5A2, 0x3F, 0xF69, 0x2426483, 0x3B049879, 0xA9B2D369833C350, 0x204127E51C923093, 0x150DD8CBAC25E16, 0xE24D1E}, + }, + { + []byte{0x06, 0x15, 0x43, 0xBF, 0x63, 0x7B, 0xFD, 0x1D, 0xED, 0xB3, 0x50, 0x4E, 0x2F, 0x27, 0x4D, 0x97, 0xD2, 0x0D, 0x47, 0x39, 0xD1, 0x16, 0x90, 0x26, 0xEC, 0xC6, 0x5D, 0x6C, 0xA5, 0x99, 0x92, 0x02, 0xD7, 0x1D, 0x35, 0x00, 0x4A, 0xE0, 0xFF, 0xE5, 0xEC, 0x16, 0x13, 0x59, 0xB3, 0x05, 0xE9, 0x4D, 0xD5, 0x7D, 0x24, 0x81, 0x14, 0x2C, 0xF4, 0xF7, 0xBD, 0xD0, 0x19, 0xFB, 0x51, 0xE9, 0x9E, 0x54, 0x17, 0x84, 0x9E, 0x39, 0x23, 0x1E, 0xFC, 0x9B, 0xC1, 0xF2, 0x75, 0xA1, 0xC6, 0xFC, 0x3D, 0xEA, 0xB4, 0xA0, 0x64, 0xA0, 0xE0, 0x43, 0xD6, 0x66, 0xF7, 0x77, 0x0B, 0xF0, 0x1E, 0x66, 0x6B, 0x7B, 0xAD, 0xCA, 0xDB, 0xEC}, + []uint{39, 11, 11, 10, 48, 32, 20, 46, 26, 16, 25, 24, 37, 16, 47, 63, 18, 9, 51, 38, 56, 63, 61, 32, 1}, + []uint64{0x30AA1DFB1, 0x5EF, 0x7A3, 0x2F6, 0xD9A8271793A6, 0xCBE906A3, 0x9CE88, 0x2D204DD98CBA, 0x3652CCC, 0x9016, 0x171D350, 0x4AE0F, 0x1FCBD82C26, 0xB366, 0x5E94DD57D24, 0x408A167A7BDEE80C, 0x3F6A3, 0x1A6, 0x3CA82F093C724, 0x18F7E4DE0F, 0x93AD0E37E1EF55, 0x52819283810F599B, 0x1BBB85F80F3335BD, 0xD6E56DF6, 0x00}, + }, + { + []byte{0xA3, 0x34, 0x99, 0x5A, 0xA7, 0x43, 0xDE, 0x9D, 0x0D, 0xB0, 0x07, 0x3A, 0x06, 0x10, 0x48, 0x4F, 0x9D, 0x6E, 0xA1, 0x12, 0xBE, 0x3E, 0xBE, 0x16, 0x5C, 0x0D, 0xC9, 0x30, 0x78, 0x71, 0x44, 0x0F, 0xC1, 0xB5, 0x54, 0x00, 0xEE, 0xEB, 0x28, 0x81, 0x2C, 0xF9, 0x16, 0xEA, 0xA6, 0x31, 0x28, 0xC0, 0x08, 0xDD, 0x33, 0x89, 0x6B, 0x58, 0x2F, 0x6A, 0x73, 0xA6, 0xED, 0xDD, 0xFA, 0x6D, 0xAE, 0x45, 0xA4, 0xE1, 0x2B, 0xD3, 0xDA, 0xF1, 0x1F, 0x4A, 0x89, 0x03, 0xD4, 0x9A, 0xF1, 0x0C, 0x9B, 0x01, 0xF3, 0x67, 0x87, 0x64, 0x93, 0x21, 0x2C, 0xC7, 0x84, 0x3D, 0xBE, 0x07, 0x6B, 0x2B, 0xD2, 0x87, 0x5B, 0xAB, 0x1E, 0x2A}, + []uint{17, 5, 3, 47, 17, 35, 37, 43, 52, 22, 45, 63, 37, 55, 37, 16, 12, 32, 12, 13, 2, 49, 3, 55, 5, 37, 15, 33, 1}, + []uint64{0x14669, 0x06, 0x02, 0x5AA743DE9D0D, 0x1600E, 0x3A0610484, 0x1F3ADD4225, 0x3E3EBE165C0, 0xDC9307871440F, 0x306D55, 0x777594409, 0x33E45BAA98C4A300, 0x46E99C4B5, 0x560BDA9CE9BB77, 0xFD36D722D, 0x2709, 0x5E9, 0xED788FA5, 0x448, 0x3D4, 0x02, 0xD78864D80F9B, 0x01, 0x70EC92642598F0, 0x10, 0x1EDF03B595, 0x74A1, 0x1ADD58F15, 0x00}, + }, + { + []byte{0xC2, 0x1C, 0x29, 0x23, 0xD2, 0x85, 0x5C, 0x44, 0xDD, 0x85, 0xEB, 0xB0, 0x7D, 0x6B, 0x97, 0x2B, 0x4A, 0x92, 0x13, 0xDF, 0x85, 0x7B, 0x3F, 0xF1, 0x81, 0xFD, 0x59, 0xC5, 0x6B, 0x34, 0xE8, 0x98, 0xFB, 0x49, 0x38, 0x07, 0x6B, 0xE7, 0x0C, 0x2B, 0x48, 0x23, 0x87, 0x36, 0x1E, 0x2A, 0x00, 0x39, 0x0E, 0x01, 0x9C, 0x34, 0x67, 0x8D, 0x62, 0x2F, 0xD3, 0x59, 0x80, 0x20, 0x14, 0xB1, 0xDF, 0xE0, 0xA9, 0xF3, 0x05, 0x8D, 0xFB, 0x1F, 0xD2, 0xE5, 0x43, 0xEA, 0xEB, 0xE0, 0xF3, 0x78, 0x15, 0x16, 0x34, 0x1A, 0xD7, 0x05, 0xB3, 0x66, 0xC1, 0xB1, 0x7A, 0x98, 0xFB, 0x9C, 0x88, 0x1F, 0xD4, 0xD4, 0xEF, 0x03, 0x43, 0xFA}, + []uint{54, 24, 30, 28, 48, 31, 42, 39, 14, 8, 55, 63, 17, 57, 64, 10, 62, 60, 10, 41, 31, 12}, + []uint64{0x30870A48F4A157, 0x113761, 0x1EBB07D6, 0xB972B4A, 0x9213DF857B3F, 0x78C0FEAC, 0x38AD669D131, 0x7B4938076B, 0x39C3, 0x0A, 0x690470E6C3C540, 0x390E019C34678D6, 0x45FA, 0xD66008052C77F8, 0x2A7CC1637EC7F4B9, 0x143, 0x3ABAF83CDE05458D, 0x6B5C16CD9B06C5, 0x3A9, 0x11F739103FA, 0x4D4EF034, 0x3FA}, + }, + { + []byte{0x2E, 0xB7, 0x5F, 0x66, 0x0C, 0xEE, 0x9F, 0x22, 0x62, 0xEE, 0x89, 0x47, 0x18, 0x75, 0xC2, 0x9C, 0x4B, 0xC0, 0x5A, 0xB1, 0x11, 0x1F, 0x57, 0xA4, 0x68, 0xF4, 0xA9, 0xF4, 0x0A, 0x52, 0x86, 0xA5, 0x4B, 0x56, 0xBF, 0xC0, 0x2F, 0x16, 0x31, 0x62, 0xA2, 0x78, 0xD1, 0x9D, 0xE9, 0x0F, 0x2D, 0x40, 0xC5, 0xA7, 0x3C, 0x6C, 0x53, 0x8A, 0xBF, 0xD2, 0x16, 0x78, 0xDB, 0x22, 0xD3, 0x19, 0x69, 0x17, 0x9D, 0x81, 0x43, 0x98, 0x3A, 0x82, 0x93, 0x84, 0xFF, 0x4B, 0xA0, 0x26, 0xB0, 0x5C, 0xC3, 0x72, 0xA5, 0x7C, 0xDE, 0xC8, 0xD5, 0x2E, 0x6F, 0x80, 0x75, 0x14, 0xA5, 0xAB, 0x96, 0xEE, 0x60, 0x94, 0x0D, 0x42, 0xB9, 0x62}, + []uint{49, 25, 55, 41, 56, 18, 46, 16, 29, 17, 38, 39, 23, 18, 12, 34, 45, 9, 4, 48, 28, 59, 9, 14, 15, 34, 19}, + []uint64{0x5D6EBECC19DD, 0x7C898B, 0x5D128E30EB8538, 0x12F016AC444, 0x7D5E91A3D2A7D0, 0xA528, 0x1A952D5AFF00, 0xBC58, 0x18B1513C, 0xD19D, 0x3A43CB5031, 0x34E78D8A71, 0x2BFD21, 0x19E36, 0xC8B, 0x131969179, 0x1B0287307505, 0x4E, 0x01, 0x3FD2E809AC17, 0x30DCA95, 0x79BD91AA5CDF00E, 0x145, 0xA5A, 0x5CB7, 0x1CC1281A8, 0x2B962}, + }, + { + []byte{0x11, 0x9E, 0xE6, 0x8D, 0x03, 0x9F, 0x19, 0x2F, 0x7C, 0x53, 0xA3, 0xA6, 0x8F, 0x6C, 0xA2, 0xF4, 0x0E, 0xE2, 0x21, 0x84, 0x09, 0xDB, 0x3C, 0xDF, 0x61, 0xEC, 0xCE, 0x30, 0xF0, 0x0B, 0x4E, 0x47, 0x97, 0x26, 0xE2, 0xE8, 0x13, 0x7A, 0x9D, 0x77, 0x17, 0x28, 0xB2, 0x5F, 0x77, 0x64, 0x25, 0x93, 0x01, 0xEB, 0x8B, 0xD9, 0x8F, 0x54, 0x49, 0x2C, 0x0B, 0x6F, 0x85, 0x9E, 0x06, 0x34, 0x26, 0x0C, 0xF1, 0x44, 0xC9, 0x5D, 0x04, 0x46, 0x92, 0x69, 0xA1, 0x16, 0xA9, 0x0D, 0x32, 0x3A, 0x88, 0x11, 0x33, 0x3B, 0xCD, 0x3F, 0x78, 0x4F, 0x0A, 0x5D, 0x55, 0x69, 0x35, 0x22, 0x2C, 0x90, 0xFD, 0xC2, 0x49, 0xF5, 0x44, 0x7D}, + []uint{50, 55, 18, 59, 59, 49, 28, 6, 23, 35, 63, 16, 40, 13, 12, 43, 56, 7, 34, 44, 3, 18, 11, 52, 6}, + []uint64{0x467B9A340E7C, 0x325EF8A7474D1E, 0x36517, 0x503B888610276CF, 0x1BEC3D99C61E016, 0x1391E5C9B8BA0, 0x4DEA75D, 0x31, 0x394592, 0x7DDD90964, 0x603D717B31EA8925, 0x816D, 0xF0B3C0C684, 0x1833, 0xC51, 0x192BA088D24, 0xD3422D521A6475, 0x08, 0x44CCEF34, 0xFDE13C29755, 0x02, 0x349A9, 0x8B, 0x243F70927D511, 0x3D}, + }, + { + []byte{0x6D, 0x2D, 0x02, 0x1B, 0x65, 0xC7, 0x93, 0x72, 0xA1, 0xC8, 0x00, 0xE7, 0xD6, 0xB5, 0x89, 0x88, 0x9B, 0x48, 0x4E, 0x8A, 0x7F, 0x41, 0x10, 0x12, 0x6B, 0xF5, 0x3C, 0x74, 0x9F, 0x86, 0x6F, 0x9E, 0x74, 0x0C, 0x6C, 0x80, 0x6D, 0x65, 0xBB, 0xAC, 0x9A, 0xAF, 0x74, 0x6E, 0x28, 0x07, 0x2D, 0xCD, 0x12, 0x07, 0xEE, 0x47, 0x97, 0xC0, 0xF8, 0x85, 0xBC, 0x6C, 0x00, 0xE6, 0x03, 0x07, 0x19, 0xB2, 0xE0, 0xC0, 0x76, 0x24, 0xB8, 0xD0, 0x98, 0x5B, 0xD3, 0xBE, 0x06, 0x6C, 0x9C, 0xF2, 0x64, 0xC2, 0xAC, 0x9D, 0xE2, 0x58, 0x76, 0xF0, 0x2F, 0x1D, 0xA8, 0x92, 0xDA, 0xB8, 0x54, 0xEE, 0xC9, 0xB2, 0x6F, 0xE2, 0xC2, 0x3A}, + []uint{49, 35, 28, 50, 45, 11, 8, 11, 41, 57, 52, 4, 57, 7, 55, 27, 27, 30, 12, 10, 64, 32, 58, 10, 20}, + []uint64{0xDA5A0436CB8F, 0x1372A1C80, 0xE7D6B5, 0x226226D213A29, 0x1FA0880935FA, 0x4F1, 0xD2, 0x3F0, 0x19BE79D031B, 0x4036B2DDD64D57, 0xBA37140396E68, 0x09, 0x7EE4797C0F885, 0x5E, 0x1B003980C1C66C, 0x5C180EC, 0x24B8D09, 0x216F4EF8, 0x19B, 0x9C, 0xF264C2AC9DE25876, 0xF02F1DA8, 0x24B6AE153BB26C9, 0x2FE, 0x2C23A}, + }, + { + []byte{0xF6, 0x50, 0x44, 0x6B, 0xE9, 0x59, 0x96, 0x1E, 0x48, 0x15, 0x9A, 0x63, 0x62, 0xDC, 0x04, 0x5E, 0x86, 0xE3, 0xCA, 0x7A, 0x47, 0x38, 0x1C, 0xB8, 0xD0, 0x0F, 0x4D, 0x0B, 0x7C, 0x4D, 0xB8, 0xE7, 0xAB, 0xD2, 0x11, 0x03, 0x13, 0x90, 0xD1, 0x08, 0x50, 0xD0, 0xC9, 0xAE, 0xBD, 0x67, 0xB2, 0x3B, 0xDE, 0xED, 0x7B, 0x79, 0x0F, 0x23, 0xE2, 0x89, 0x33, 0x7E, 0xE9, 0x07, 0xE1, 0x24, 0xDC, 0xAB, 0x49, 0xDE, 0x26, 0xFC, 0xA1, 0xE3, 0x9B, 0x6C, 0x16, 0x5E, 0x60, 0xEA, 0xFF, 0x67, 0x56, 0x9B, 0xF3, 0x88, 0xCC, 0x57, 0x56, 0xCB, 0x76, 0x25, 0xDA, 0xB5, 0x9C, 0xE8, 0x3D, 0xB7, 0x79, 0xED, 0xF5, 0xB4, 0x99, 0xB4}, + []uint{44, 12, 8, 57, 32, 29, 32, 28, 18, 40, 8, 58, 60, 59, 64, 50, 46, 4, 46, 59, 46}, + []uint64{0xF650446BE95, 0x996, 0x1E, 0x902B34C6C5B808, 0xBD0DC794, 0x1E91CE07, 0x2E3403D3, 0x42DF136, 0x38E7A, 0xBD21103139, 0x0D, 0x421434326BAF59, 0xEC8EF7BB5EDE43C, 0x47C51266FDD20FC, 0x249B95693BC4DF94, 0xF1CDB60B2F30, 0x1D5FECEAD37E, 0x07, 0x4662BAB65BB, 0x976AD673A0F6DD, 0x39EDF5B499B4}, + }, + { + []byte{0xB0, 0x15, 0x5C, 0x01, 0xE3, 0x0E, 0x1A, 0xB6, 0x97, 0x04, 0x07, 0x63, 0xBB, 0x29, 0x2D, 0xB7, 0x80, 0xD3, 0x50, 0x42, 0x6B, 0xA3, 0xCA, 0x7C, 0x71, 0x40, 0xF2, 0xB6, 0x51, 0x89, 0x52, 0x84, 0xF1, 0x93, 0xAB, 0xAF, 0xC9, 0x9D, 0x1C, 0x3D, 0x43, 0xEC, 0xB8, 0x6F, 0xA1, 0xCE, 0xAB, 0x94, 0xF2, 0xF0, 0xF3, 0x14, 0xE9, 0x41, 0x02, 0x9B, 0xA6, 0x42, 0x83, 0xB7, 0xF6, 0x58, 0x60, 0x60, 0xDD, 0xD1, 0xC3, 0xCF, 0xCA, 0x4C, 0x74, 0xDC, 0x6D, 0xEF, 0x7F, 0x8C, 0x9F, 0xE9, 0xE4, 0x1F, 0xDF, 0xCD, 0x59, 0xAC, 0x70, 0x43, 0xE0, 0xF9, 0x5E, 0xB6, 0x8D, 0x10, 0x5F, 0xE0, 0x4B, 0x85, 0xD8, 0xCF, 0x59, 0xE3}, + []uint{55, 6, 54, 27, 46, 46, 43, 11, 7, 18, 16, 23, 23, 60, 12, 9, 54, 61, 39, 31, 54, 34, 40, 31}, + []uint64{0x580AAE00F1870D, 0x16, 0x34B8203B1DD949, 0x36DE034, 0x350426BA3CA7, 0x31C503CAD946, 0x12A509E3275, 0x3AF, 0x64, 0x33A38, 0x7A87, 0x6CB86F, 0x50E755, 0xCA7978798A74A08, 0x14D, 0x1A6, 0x10A0EDFD961818, 0x6EE8E1E7E5263A6, 0x71B7BDFE32, 0x3FD3C83F, 0x2FE6ACD63821F0, 0x1F2BD6D1A, 0x20BFC0970B, 0x58CF59E3}, + }, + { + []byte{0x7F, 0x0D, 0xFB, 0x8B, 0x93, 0x2C, 0x51, 0xC3, 0xAE, 0x2F, 0xBE, 0xD2, 0xAD, 0xFE, 0x95, 0x3F, 0xEB, 0x41, 0xF1, 0x59, 0xDD, 0xBA, 0x1F, 0x31, 0xC1, 0x5C, 0x82, 0x78, 0x93, 0x3A, 0x53, 0x99, 0x29, 0x1F, 0x3E, 0x5B, 0xB5, 0x69, 0x25, 0x22, 0x34, 0xF3, 0x7C, 0x3A, 0xA8, 0xB6, 0xE4, 0xE3, 0x5E, 0xD5, 0x9D, 0xFB, 0x69, 0x49, 0xD0, 0x9F, 0x01, 0x4C, 0x03, 0x88, 0xD2, 0x82, 0x6E, 0xC7, 0x85, 0x35, 0x4D, 0xE7, 0x19, 0xA6, 0xF8, 0x1D, 0x3D, 0xDD, 0xC7, 0xE1, 0x89, 0x83, 0x69, 0xD9, 0xA3, 0x30, 0x25, 0x42, 0x95, 0x6E, 0x02, 0xFE, 0xC9, 0xDC, 0x6E, 0xD8, 0x58, 0xBB, 0xB6, 0x61, 0x48, 0xB9, 0x6D, 0xF8}, + []uint{57, 11, 41, 47, 48, 3, 18, 37, 2, 23, 46, 10, 41, 43, 30, 51, 30, 22, 54, 24, 59, 11, 30, 21, 6, 34, 1}, + []uint64{0xFE1BF7172658A3, 0x43A, 0x1C5F7DA55BF, 0x6953FEB41F15, 0x9DDBA1F31C15, 0x06, 0x104F1, 0x4CE94E64A, 0x01, 0xF9F2D, 0x36AD24A4469E, 0x1BE, 0x3AA8B6E4E3, 0x2F6ACEFDB4A, 0x13A13E02, 0x4C0388D2826EC, 0x1E14D537, 0x2719A6, 0x3E074F7771F862, 0x60DA76, 0x346604A852ADC05, 0x7EC, 0x2771BB61, 0xC5DDB, 0x0C, 0xA45CB6FC, 0x00}, + }, + { + []byte{0xA8, 0x79, 0x2E, 0x69, 0x7C, 0xA9, 0x38, 0x1C, 0xBB, 0x72, 0x13, 0x55, 0xA9, 0x2B, 0xC6, 0xCD, 0xB9, 0x05, 0xAA, 0x90, 0xE3, 0x86, 0x2A, 0xB2, 0xD4, 0x18, 0x0C, 0xC0, 0x79, 0x2E, 0xFB, 0x29, 0x9B, 0x65, 0xA7, 0xB5, 0x06, 0x46, 0xD4, 0x1C, 0x7C, 0x4D, 0xDA, 0x29, 0x68, 0x83, 0xA6, 0x66, 0xFE, 0xA8, 0x96, 0x52, 0xAF, 0x88, 0x38, 0x25, 0x15, 0x51, 0xE0, 0x46, 0x29, 0x70, 0x7D, 0x74, 0xC9, 0xA2, 0xDD, 0x9C, 0xEA, 0x0D, 0x42, 0xFA, 0x50, 0x6A, 0x52, 0x77, 0x24, 0xC8, 0x37, 0x40, 0x45, 0x01, 0xEC, 0x9C, 0xDE, 0x91, 0x94, 0x23, 0xBD, 0x0A, 0xFA, 0x68, 0x39, 0xF3, 0x4F, 0xAD, 0x4E, 0xF4, 0xEB, 0x35}, + []uint{16, 23, 38, 47, 6, 47, 2, 15, 21, 1, 13, 37, 17, 45, 6, 40, 31, 56, 59, 25, 27, 12, 14, 60, 64, 35, 10, 33}, + []uint64{0xA879, 0x1734BE, 0x152703976E, 0x21355A92BC6C, 0x36, 0x720B5521C70C, 0x01, 0x2ACB, 0xA0C06, 0x00, 0x180F, 0x4BBECA66D, 0x12D3D, 0x150646D41C7C, 0x13, 0x768A5A20E9, 0x4CDFD512, 0xCA55F10704A2AA, 0x1E04629707D74C9, 0x145BB39, 0x6A0D42F, 0xA50, 0x1A94, 0x9DC9320DD011407, 0xB2737A46508EF42B, 0x74D073E69, 0x3D6, 0x14EF4EB35}, + }, + { + []byte{0x79, 0xD5, 0x86, 0x52, 0x20, 0xE8, 0xC2, 0x30, 0x48, 0xBC, 0x55, 0xC3, 0x16, 0x7C, 0xAA, 0xED, 0x94, 0xB2, 0xEC, 0x72, 0xB6, 0x37, 0x2D, 0xDC, 0xC5, 0x32, 0xD7, 0x37, 0xEC, 0x9F, 0xBF, 0x05, 0x83, 0x87, 0x82, 0x02, 0xE9, 0xDF, 0x9A, 0x27, 0x20, 0x18, 0xC4, 0x63, 0x9B, 0x2B, 0x74, 0xFB, 0xC9, 0xBD, 0xE2, 0xF0, 0xD6, 0xB7, 0x88, 0x28, 0x2B, 0x8F, 0xD1, 0xE5, 0xE0, 0xFC, 0x54, 0x53, 0xC6, 0x3C, 0xD5, 0xC6, 0xCC, 0x18, 0x12, 0xDC, 0xAB, 0x57, 0x56, 0x3A, 0xCC, 0x3A, 0x42, 0x65, 0x30, 0x02, 0xB5, 0x17, 0x69, 0x18, 0x86, 0xB0, 0xC0, 0xE8, 0x65, 0x96, 0xBB, 0x24, 0x42, 0xCA, 0x60, 0x74, 0x3E, 0x4E}, + []uint{49, 12, 22, 14, 60, 8, 49, 19, 64, 29, 5, 37, 17, 56, 40, 3, 4, 19, 29, 45, 6, 51, 14, 10, 53, 48, 37}, + []uint64{0xF3AB0CA441D1, 0x846, 0x245E2, 0x2B86, 0x2CF955DB2965D8E, 0x56, 0x18DCB77314CB5, 0x66FD9, 0x3F7E0B070F0405D3, 0x17E689C8, 0x00, 0x18C4639B2B, 0xE9F7, 0x937BC5E1AD6F10, 0x50571FA3CB, 0x06, 0x00, 0x7E2A2, 0x13C63CD5, 0x18D983025B95, 0x1A, 0x5D58EB30E9099, 0x1300, 0xAD, 0x8BB48C4358607, 0x432CB5D92216, 0xA60743E4E}, + }, + { + []byte{0x1D, 0x25, 0xA6, 0x20, 0x3A, 0x6C, 0x00, 0xE9, 0xD1, 0x02, 0xD0, 0xA1, 0xB6, 0xEF, 0xA5, 0x89, 0x34, 0xCC, 0x79, 0x82, 0x7E, 0x3A, 0x46, 0x57, 0xF5, 0x83, 0x6E, 0xAE, 0xF2, 0x43, 0x25, 0xA5, 0xD5, 0xF0, 0x9B, 0x8E, 0xDD, 0x0F, 0xCC, 0x8E, 0x0C, 0xD7, 0xB1, 0xC3, 0x56, 0x9F, 0xA0, 0x2A, 0x9D, 0x0C, 0x37, 0xD1, 0xBD, 0x13, 0x67, 0x31, 0xD4, 0x84, 0xD3, 0xE9, 0xCE, 0xB2, 0x34, 0xDB, 0xFC, 0x31, 0x75, 0xCD, 0x70, 0x08, 0x4C, 0x71, 0x75, 0xDD, 0x8F, 0x3F, 0xD5, 0xFA, 0xC3, 0x24, 0xE8, 0xC0, 0x10, 0x9B, 0x7C, 0xF9, 0xCA, 0xE9, 0x54, 0x21, 0xD8, 0xE3, 0x8D, 0x31, 0xA3, 0x39, 0xA5, 0xC4, 0xF3, 0xFC}, + []uint{32, 13, 52, 46, 22, 7, 13, 37, 50, 64, 63, 60, 52, 42, 57, 35, 35, 54, 35, 31}, + []uint64{0x1D25A620, 0x74D, 0x801D3A205A143, 0x1B77D2C49A66, 0xF304F, 0x63, 0x148C, 0x15FD60DBAB, 0x2F24325A5D5F0, 0x9B8EDD0FCC8E0CD7, 0x58E1AB4FD0154E86, 0x1BE8DE89B398EA4, 0x269F4E7591A6D, 0x3F862EB9AE0, 0x2131C5D7763CFF, 0x2BF58649D, 0xC0109B7C, 0x3E72BA55087638, 0x71A634673, 0x25C4F3FC}, + }, + { + []byte{0x68, 0x5A, 0x69, 0x38, 0xFD, 0x40, 0x54, 0xB3, 0x83, 0x36, 0x19, 0x7E, 0x49, 0x98, 0x71, 0xA3, 0x2A, 0x61, 0xF7, 0xE7, 0x8A, 0x7E, 0x6B, 0x1A, 0xB8, 0x98, 0x47, 0x80, 0x1A, 0x45, 0x10, 0xDC, 0xD7, 0x19, 0x89, 0xBF, 0xF0, 0x6A, 0x58, 0xFF, 0x62, 0xE4, 0xEC, 0x13, 0x4C, 0x50, 0x88, 0xFA, 0xFC, 0xA6, 0x12, 0xA6, 0xB3, 0xA4, 0xDB, 0x1E, 0x4C, 0xA4, 0x6D, 0x6B, 0xA2, 0xE1, 0xB7, 0x38, 0x47, 0x98, 0x64, 0xF9, 0xBD, 0xC2, 0x52, 0xB9, 0x85, 0x5A, 0xAA, 0x08, 0x67, 0xC9, 0xA6, 0x10, 0x6C, 0x9F, 0xB1, 0x85, 0xAB, 0x93, 0x8E, 0x27, 0x9E, 0x5A, 0xD8, 0x4B, 0xAB, 0x1D, 0x07, 0x24, 0x5A, 0x92, 0xE8, 0xFE}, + []uint{53, 49, 47, 35, 53, 37, 62, 62, 2, 44, 23, 43, 10, 31, 49, 39, 56, 4, 58, 43}, + []uint64{0xD0B4D271FA80A, 0x12CE0CD865F92, 0x330E34654C3E, 0x7E78A7E6B, 0x3571308F00348, 0x1443735C66, 0x9BFF06A58FF62E4, 0x3B04D314223EBF29, 0x02, 0x12A6B3A4DB1, 0x726523, 0x35AE8B86DCE, 0x47, 0x4C327CDE, 0x1C252B9855AAA, 0x433E4D308, 0x364FD8C2D5C9C7, 0x01, 0xF3CB5B097563A0, 0x7245A92E8FE}, + }, + { + []byte{0x81, 0xB5, 0xA2, 0x65, 0x98, 0x2C, 0x6B, 0x6B, 0xC7, 0x8F, 0x17, 0x8A, 0xE9, 0x66, 0xF9, 0x70, 0x5D, 0xCE, 0x2F, 0x35, 0xC3, 0xB7, 0xEC, 0xB8, 0x3F, 0xA1, 0xB8, 0x6F, 0x08, 0x31, 0xAB, 0x93, 0x9E, 0x7C, 0xFB, 0x43, 0x1C, 0xA4, 0xB6, 0xD1, 0x89, 0xD3, 0x4F, 0xD4, 0x2A, 0x89, 0x72, 0x13, 0x50, 0xB9, 0x02, 0xC7, 0x6A, 0x98, 0xE0, 0x3F, 0x75, 0x33, 0x61, 0x36, 0x8F, 0x7B, 0xC7, 0x8F, 0x7F, 0x78, 0x21, 0xC1, 0xD1, 0x73, 0x7D, 0xCE, 0x8C, 0xD6, 0xB3, 0x20, 0x9C, 0xAF, 0x5A, 0x57, 0x8B, 0xE5, 0xC6, 0xA4, 0xCA, 0x76, 0x1E, 0x50, 0x20, 0x43, 0x87, 0xE4, 0xCE, 0x0F, 0x89, 0x21, 0x64, 0x65, 0x9B, 0xD3}, + []uint{1, 15, 30, 2, 9, 48, 40, 45, 20, 27, 29, 1, 13, 35, 47, 59, 24, 38, 50, 39, 37, 8, 54, 46, 14, 58, 11}, + []uint64{0x01, 0x1B5, 0x2899660B, 0x00, 0xD6, 0xD78F1E2F15D2, 0xCDF2E0BB9C, 0xBCD70EDFB2E, 0xFE86, 0x70DE106, 0x6AE4E79, 0x01, 0x1CFB, 0x218E525B6, 0x46274D3F50AA, 0x12E426A172058ED, 0x531C07, 0x3BA99B09B4, 0x1EF78F1EFEF04, 0x1C1D1737DC, 0x1D19AD6641, 0x39, 0x17AD2BC5F2E352, 0x194EC3CA0408, 0x1C3F, 0x99C1F1242C8CB3, 0x3D3}, + }, + { + []byte{0x71, 0xF3, 0xAA, 0x6E, 0x84, 0xDF, 0xE6, 0x77, 0xA6, 0xC2, 0xAE, 0x13, 0x8C, 0x9E, 0xDF, 0xFA, 0x68, 0x97, 0x18, 0x10, 0x2D, 0x29, 0xE9, 0x8A, 0xBF, 0xA3, 0xB6, 0x34, 0x93, 0xA0, 0x81, 0xE6, 0xBB, 0xB2, 0x2B, 0xCC, 0x6C, 0x2E, 0xD2, 0xD0, 0x97, 0xB8, 0x7B, 0x41, 0x3D, 0x11, 0xFB, 0xFC, 0xE0, 0xE3, 0x5B, 0x75, 0xE4, 0x6A, 0x28, 0x88, 0x0A, 0x2D, 0x41, 0x6B, 0x00, 0xE3, 0xB8, 0xA1, 0x98, 0x45, 0x63, 0xD1, 0x89, 0xF1, 0xDD, 0xE5, 0xAB, 0xB8, 0x07, 0xA1, 0x7A, 0xDF, 0xA6, 0xF4, 0x89, 0x6D, 0x41, 0x90, 0xA2, 0x3B, 0x79, 0x07, 0xA6, 0xFE, 0xB5, 0x19, 0x32, 0x0D, 0x7E, 0x8F, 0x37, 0x49, 0xB1, 0x1F}, + []uint{18, 39, 32, 4, 63, 43, 56, 45, 45, 5, 15, 29, 6, 33, 52, 33, 44, 44, 21, 32, 57, 45, 23, 16}, + []uint64{0x1C7CE, 0x54DD09BFCC, 0xEF4D855C, 0x02, 0x38C9EDFFA6897181, 0x1694F4C55F, 0xD1DB1A49D040F3, 0xBBB22BCC6C2, 0x1DA5A12F70F6, 0x10, 0x27A2, 0x7EFF383, 0x23, 0xB6EBC8D4, 0x5110145A82D60, 0x38EE2866, 0x1158F4627C7, 0x7796AEE01E8, 0xBD6FD, 0x37A44B6A, 0x190A23B7907A6F, 0x1D6A32641AFD, 0xF3749, 0xB11F}, + }, + { + []byte{0xAC, 0x14, 0xB0, 0x1B, 0x9B, 0xF6, 0x27, 0xD0, 0xB0, 0xB4, 0x78, 0xD8, 0x72, 0x2F, 0x7B, 0x35, 0x27, 0x93, 0xD7, 0x03, 0xBE, 0x3D, 0x08, 0x38, 0xA4, 0x4F, 0x77, 0xC6, 0x93, 0x8C, 0xDF, 0x54, 0x7B, 0x25, 0x14, 0xDB, 0xF4, 0x3A, 0x1B, 0xB0, 0x20, 0x0C, 0x7A, 0x40, 0x15, 0xE4, 0xCE, 0x72, 0x9E, 0x50, 0x05, 0x85, 0xFE, 0x5A, 0xDA, 0x51, 0xC1, 0x10, 0x35, 0xB6, 0x93, 0x7D, 0xE1, 0x29, 0x8A, 0xA1, 0x64, 0xCB, 0xD7, 0x43, 0x53, 0x6F, 0x1A, 0x31, 0x83, 0x1E, 0x90, 0xFF, 0x5D, 0x99, 0xF8, 0xF1, 0xB4, 0xBD, 0x91, 0xEF, 0xF3, 0xB7, 0x70, 0x71, 0x1D, 0x09, 0x4B, 0x8A, 0x94, 0x47, 0x86, 0xDF, 0xB9, 0x73}, + []uint{63, 40, 4, 14, 10, 41, 30, 19, 11, 22, 20, 18, 17, 26, 63, 12, 39, 8, 12, 7, 23, 64, 2, 57, 48, 5, 26, 18, 31, 29, 21}, + []uint64{0x560A580DCDFB13E8, 0x585A3C6C39, 0x01, 0x1EF6, 0x1A9, 0x793D703BE3, 0x3420E291, 0x1EEF8, 0x693, 0x2337D5, 0x1EC94, 0x14DBF, 0x8743, 0x1D81006, 0x1E900579339CA794, 0x16, 0xBFCB5B4A3, 0x82, 0x206, 0x5B, 0x349BEF, 0x94C550B265EBA1A, 0x02, 0xDBC68C60C7A43F, 0xD7667E3C6D2F, 0x0C, 0x23DFE76, 0x3B838, 0x474252E2, 0x14A23C36, 0x1FB973}, + }, + { + []byte{0xE4, 0x50, 0xCC, 0x46, 0xE5, 0x6C, 0xB4, 0x5E, 0x7D, 0x27, 0x6A, 0x12, 0x75, 0x27, 0x71, 0xB2, 0x5F, 0xCD, 0x62, 0x8E, 0x39, 0x4C, 0x93, 0xAB, 0x74, 0x84, 0x7D, 0x73, 0x72, 0x69, 0x2B, 0x3E, 0x09, 0x98, 0x75, 0xCE, 0xEA, 0xCE, 0x41, 0x90, 0x1B, 0x5E, 0x43, 0x77, 0x9F, 0x03, 0x45, 0xD5, 0x5C, 0xE2, 0xED, 0x27, 0xF9, 0x3C, 0x74, 0x7B, 0x43, 0x46, 0x74, 0x48, 0xBA, 0x17, 0x38, 0xD5, 0x20, 0xE5, 0xA0, 0xF4, 0xF6, 0xF2, 0xDD, 0x35, 0x11, 0xDC, 0x2C, 0x05, 0x24, 0xF9, 0x32, 0x87, 0xF2, 0x46, 0x5C, 0x38, 0x5F, 0x30, 0xD5, 0xE5, 0xCA, 0x7B, 0xB2, 0x84, 0x2B, 0x52, 0x79, 0x1E, 0xA2, 0xA7, 0xF2, 0xE5}, + []uint{36, 51, 25, 30, 33, 48, 1, 40, 47, 24, 52, 35, 50, 19, 46, 35, 49, 42, 43, 25, 3, 46, 20}, + []uint64{0xE450CC46E, 0x2B65A2F3E93B5, 0x127527, 0x1C6C97F3, 0xB1471CA6, 0x49D5BA423EB9, 0x01, 0x72692B3E09, 0x4C3AE7756720, 0xC80DAF, 0x21BBCF81A2EAA, 0x738BB49FE, 0x13C747B434674, 0x245D0, 0x2E71AA41CB41, 0x74F6F2DD3, 0xA23B8580A49F, 0x9943F9232E, 0xE17CC35797, 0x53DD94, 0x01, 0x2B52791EA2A, 0x7F2E5}, + }, + { + []byte{0x62, 0x1F, 0x77, 0x6B, 0x70, 0x29, 0x95, 0x1E, 0xE8, 0xF4, 0xFB, 0x70, 0x7C, 0x70, 0xB6, 0x51, 0xF6, 0xD5, 0xD8, 0x16, 0x6D, 0xB0, 0x7D, 0x7F, 0xE3, 0x3A, 0x1C, 0x01, 0x3C, 0x72, 0xD5, 0x19, 0x42, 0x22, 0xE9, 0xCB, 0x6E, 0xF5, 0x4F, 0x63, 0xAA, 0x74, 0xDA, 0x86, 0x06, 0xB0, 0x0E, 0x2B, 0xF1, 0xD8, 0x12, 0x3D, 0x78, 0xCD, 0x60, 0x4F, 0xE4, 0x24, 0x18, 0xE9, 0xB2, 0x8A, 0xAC, 0xB4, 0x95, 0x53, 0x1D, 0x31, 0xDF, 0x2C, 0x24, 0x59, 0x32, 0x26, 0xFC, 0xDE, 0x18, 0x5A, 0x10, 0x25, 0x66, 0xDF, 0x5D, 0xFB, 0x4F, 0xC6, 0x40, 0xBC, 0x81, 0x51, 0xB1, 0xC5, 0xC7, 0xED, 0x68, 0xEF, 0xEF, 0x03, 0xD1, 0x3B}, + []uint{43, 47, 64, 7, 19, 26, 16, 29, 30, 10, 17, 28, 35, 31, 49, 46, 25, 43, 18, 14, 24, 58, 17, 2, 22, 22, 18, 40}, + []uint64{0x310FBBB5B81, 0x26547BA3D3ED, 0xC1F1C2D947DB5760, 0x2C, 0x6DB07, 0x35FF8CE, 0x8700, 0x9E396A8, 0x328445D3, 0x25B, 0xEF54, 0xF63AA74, 0x6D4303580, 0x38AFC760, 0x91EBC66B027F, 0x84831D36515, 0xB2D255, 0x263A63BE584, 0x22C99, 0x4DF, 0x9BC30B, 0x10812B36FAEFDA7, 0x1C640, 0x02, 0x3C8151, 0x2C7171, 0x3ED68, 0xEFEF03D13B}, + }, + { + []byte{0xCD, 0x82, 0x19, 0x41, 0x84, 0x11, 0x69, 0x22, 0x42, 0x4E, 0xA2, 0x7B, 0xF6, 0x52, 0xC1, 0x02, 0x54, 0x2D, 0xFB, 0x27, 0x0E, 0x8C, 0x34, 0x0A, 0xCE, 0x0E, 0x4F, 0x05, 0x94, 0x9D, 0xF2, 0x5A, 0xCB, 0x48, 0x05, 0xA3, 0x38, 0x41, 0xDE, 0x45, 0x83, 0x4F, 0x0B, 0xBF, 0x11, 0x7A, 0x01, 0x5A, 0x30, 0x93, 0x0F, 0x18, 0x86, 0x95, 0x95, 0x7E, 0x3C, 0x73, 0xB4, 0x45, 0x5F, 0xE0, 0x3B, 0xA1, 0xCA, 0x5B, 0x6E, 0x12, 0xCE, 0xF7, 0xC1, 0x48, 0x89, 0xFA, 0x79, 0x8B, 0xD2, 0x7D, 0xCC, 0x75, 0x5C, 0xF4, 0x8D, 0x72, 0x54, 0xD5, 0xED, 0x47, 0x8E, 0x6E, 0x0E, 0x18, 0x0F, 0x1B, 0xB6, 0xA3, 0x62, 0x32, 0xB2, 0xB3}, + []uint{43, 57, 38, 50, 12, 62, 63, 24, 14, 12, 14, 42, 6, 17, 10, 51, 53, 7, 58, 1, 4, 20, 14, 29, 35, 30, 5, 29}, + []uint64{0x66C10CA0C20, 0x116922424EA27BF, 0x194B040950, 0x2DFB270E8C340, 0xACE, 0x393C165277C96B2, 0x6900B467083BC8B0, 0x69E177, 0x388B, 0xD00, 0x2B46, 0x49878C434A, 0x32, 0x15F8F, 0x73, 0x5A22AFF01DD0E, 0xA5B6E12CEF7C1, 0x24, 0x113F4F317A4FB98, 0x01, 0x0D, 0x573D2, 0xD72, 0xA9ABDA8, 0x78E6E0E18, 0x3C6EDA8, 0x1B, 0x232B2B3}, + }, + { + []byte{0x34, 0xFA, 0x8F, 0x98, 0x59, 0x1E, 0xE3, 0x3E, 0x39, 0xCE, 0x5F, 0x3C, 0xBB, 0xEF, 0xBB, 0xE9, 0xE2, 0xA0, 0x31, 0x73, 0x67, 0x50, 0x0C, 0xF0, 0x94, 0xCC, 0x5F, 0x23, 0xF9, 0x86, 0x9D, 0xF8, 0xBD, 0xF7, 0xB9, 0x91, 0xB7, 0x06, 0xF5, 0xE0, 0x50, 0x6C, 0x2C, 0xF9, 0xE6, 0xE8, 0x2B, 0xDC, 0xBA, 0xBC, 0x02, 0x90, 0xBF, 0xF7, 0x63, 0x91, 0xF3, 0x4D, 0xAF, 0x53, 0x8D, 0xAC, 0xAE, 0xC3, 0x44, 0x24, 0xE6, 0x90, 0xCC, 0xB0, 0x16, 0x12, 0x6E, 0x35, 0x0B, 0x77, 0x2C, 0xF1, 0xF5, 0xE3, 0xA1, 0x82, 0x58, 0x2C, 0x0E, 0x64, 0xCC, 0x98, 0x39, 0x5D, 0x92, 0x91, 0xBE, 0x50, 0xC7, 0x27, 0x0C, 0x12, 0xF4, 0x0E}, + []uint{23, 44, 62, 40, 13, 51, 6, 42, 31, 59, 29, 37, 37, 23, 23, 41, 64, 42, 44, 8, 63, 18}, + []uint64{0x1A7D47, 0xCC2C8F719F1, 0x339CBE7977DF77D3, 0xC54062E6CE, 0x1403, 0x1E12998BE47F3, 0x03, 0x13BF17BEF73, 0x11B706F5, 0x702836167CF3741, 0xBDCBABC, 0x5217FEEC, 0xE47CD36BD, 0x271B59, 0x2EC344, 0x49CD219960, 0x2C24DC6A16EE59E3, 0x3AF1D0C12C1, 0x60732664C1C, 0xAE, 0x64A46F9431C9C304, 0x2F40E}, + }, + { + []byte{0xA8, 0xC6, 0x63, 0x71, 0x15, 0xAF, 0x2F, 0x1D, 0x44, 0x45, 0xC8, 0xCC, 0x64, 0xED, 0x7E, 0xB7, 0xC5, 0x8A, 0xC1, 0x2A, 0xF9, 0xA0, 0x9E, 0x6B, 0xD2, 0x1E, 0xC7, 0x83, 0x6C, 0x44, 0x73, 0x04, 0x5F, 0xD8, 0x31, 0x89, 0xCF, 0xA2, 0x2C, 0xDE, 0xCF, 0x5F, 0xF3, 0xE6, 0xCF, 0x88, 0x7A, 0xE9, 0x3F, 0xD2, 0x23, 0x25, 0x9D, 0x4F, 0xF4, 0xC3, 0x39, 0xB9, 0x60, 0xCA, 0x31, 0xD2, 0xFC, 0xF3, 0xC1, 0x29, 0xC8, 0x5C, 0x05, 0x95, 0xA1, 0xB7, 0x72, 0xC9, 0x8B, 0x85, 0xFD, 0x18, 0xCB, 0x05, 0x9B, 0x11, 0xD8, 0xEA, 0xF6, 0x4E, 0xB2, 0xDA, 0x35, 0xEC, 0xDD, 0x75, 0x3E, 0xCC, 0xCE, 0x5F, 0x3A, 0xFB, 0xC3, 0x01}, + []uint{2, 38, 8, 59, 17, 7, 23, 38, 34, 52, 45, 60, 36, 45, 22, 55, 6, 9, 26, 11, 37, 37, 19, 56, 27, 31}, + []uint64{0x02, 0x28C6637115, 0xAF, 0x178EA222E466327, 0xD7EB, 0x3E, 0x162B04, 0x2AF9A09E6B, 0x3487B1E0D, 0xB111CC117F60C, 0xC4E7D1166F6, 0x7AFF9F367C43D74, 0x9FE91192C, 0x1D4FF4C339B9, 0x18328C, 0x3A5F9E7825390B, 0x20, 0x59, 0x1686DDC, 0x593, 0x2E17F4632, 0x182CD88EC7, 0x2BD93, 0xACB68D7B375D4F, 0x5999CBE, 0x3AFBC301}, + }, + { + []byte{0x2B, 0x17, 0x50, 0xEA, 0x8B, 0xD1, 0x09, 0x00, 0x9C, 0x2E, 0x3C, 0x07, 0x3B, 0x0D, 0xFC, 0x07, 0xAA, 0xD1, 0x55, 0x1E, 0x37, 0x40, 0xE0, 0xBB, 0xC5, 0x38, 0x40, 0x64, 0xF5, 0x3C, 0x0B, 0x0B, 0x37, 0x76, 0x43, 0xDA, 0x7F, 0x01, 0x63, 0x03, 0xA3, 0xF9, 0xD8, 0x06, 0x93, 0x4C, 0xF0, 0x01, 0xE6, 0x86, 0xAA, 0x94, 0x35, 0xD5, 0xB3, 0xA2, 0x1D, 0xB6, 0x2A, 0x40, 0x83, 0xFE, 0x63, 0x2E, 0x40, 0x81, 0x42, 0x11, 0xC4, 0x61, 0x9A, 0xAF, 0x08, 0x0D, 0x36, 0x20, 0x32, 0x67, 0xEA, 0x49, 0xF4, 0x26, 0xA5, 0x8D, 0xF4, 0xFD, 0xAC, 0x15, 0xB2, 0x5B, 0x97, 0x49, 0xC2, 0xDE, 0x1D, 0x79, 0x43, 0xD8, 0x20, 0x63}, + []uint{58, 27, 18, 25, 4, 25, 47, 9, 22, 36, 4, 53, 13, 53, 15, 15, 2, 54, 34, 62, 62, 37, 41, 34, 50}, + []uint64{0xAC5D43AA2F4424, 0x1385C7, 0x2039D, 0x10DFC07, 0x0A, 0x15A2AA3, 0x63740E0BBC53, 0x108, 0x327A9, 0xE05859BBB, 0x02, 0x3DA7F016303A3, 0x1F3B, 0x1A4D33C0079A, 0xD55, 0x1435, 0x03, 0x15B3A21DB62A40, 0x20FF98CB9, 0x814211C4619AAF, 0x2034D880C99FA92, 0xFA1352C6F, 0x14FDAC15B25, 0x2E5D270B7, 0x21D7943D82063}, + }, + { + []byte{0x93, 0x6A, 0xA0, 0xA2, 0xA9, 0x33, 0x42, 0x9C, 0x74, 0x54, 0x5E, 0x06, 0x0E, 0xE2, 0x05, 0x9E, 0x8F, 0xCC, 0x56, 0xBC, 0x59, 0xBD, 0xAF, 0x76, 0x71, 0x9C, 0x06, 0x88, 0x42, 0x5A, 0xBC, 0x12, 0x29, 0x1C, 0x48, 0x11, 0x96, 0xA0, 0x78, 0x15, 0x6D, 0xDE, 0x8F, 0xF4, 0xBC, 0x9D, 0xB1, 0x4B, 0xEB, 0xDC, 0x9F, 0x6B, 0x70, 0xE3, 0x77, 0x32, 0x42, 0xAE, 0x35, 0x82, 0x8A, 0xD9, 0x1E, 0x26, 0x33, 0xA2, 0x51, 0xD9, 0x2B, 0xAE, 0x07, 0xBF, 0x8B, 0x14, 0x8D, 0x53, 0xC5, 0xFF, 0xE4, 0x27, 0x9F, 0x10, 0xC3, 0x2B, 0x4B, 0x90, 0x9F, 0xB2, 0x99, 0x38, 0xA7, 0xB4, 0xD2, 0xA4, 0x4B, 0xF3, 0x5D, 0x52, 0x94, 0xD2}, + []uint{29, 7, 49, 40, 43, 23, 4, 17, 13, 29, 59, 63, 8, 25, 2, 28, 49, 27, 50, 14, 6, 5, 22, 20, 3, 35, 32, 19, 12, 48, 19}, + []uint64{0x126D5414, 0x2A, 0x12668538E8A8B, 0xC0C1DC40B3, 0x68FCC56BC59, 0x5ED7BB, 0x03, 0x119C0, 0xD10, 0x1096AF04, 0x4523890232D40F0, 0x156DDE8FF4BC9DB1, 0x4B, 0x1D7B93E, 0x03, 0x5B871BB, 0x13242AE35828A, 0x6C8F131, 0x2744A3B2575C0, 0x3DFC, 0x16, 0x05, 0x8D53C, 0x5FFE4, 0x01, 0x1E7C430CA, 0xD2E427EC, 0x53271, 0x4F6, 0x9A54897E6BAA, 0x294D2}, + }, + { + []byte{0x41, 0x7C, 0x00, 0xB7, 0x0A, 0x88, 0x91, 0x50, 0x11, 0x1E, 0x2D, 0xDC, 0xA6, 0xF0, 0x3D, 0xDE, 0xC4, 0x37, 0xD7, 0x61, 0x65, 0x8D, 0x2B, 0x3A, 0x94, 0xAB, 0x46, 0xC3, 0x9D, 0xD1, 0x8B, 0x38, 0x7B, 0x5F, 0x17, 0xB5, 0xFF, 0x73, 0xE1, 0xAB, 0x17, 0x34, 0x4B, 0x0F, 0x5B, 0xB7, 0x84, 0x94, 0x06, 0xB1, 0x01, 0x15, 0x57, 0x4C, 0x77, 0xBF, 0xF8, 0x31, 0x6C, 0x2D, 0xDB, 0x80, 0x94, 0x7F, 0x70, 0xF5, 0x9F, 0xB9, 0xAF, 0xEB, 0x79, 0x15, 0xD5, 0xCF, 0x69, 0x55, 0x39, 0x69, 0xF0, 0x2E, 0xEB, 0x7F, 0x98, 0x8F, 0x9D, 0x51, 0x8B, 0x5F, 0xC0, 0xD1, 0x3F, 0xAB, 0xA7, 0x6B, 0x27, 0xED, 0x5C, 0x81, 0x42, 0x87}, + []uint{43, 57, 36, 34, 17, 2, 53, 49, 40, 39, 30, 24, 9, 35, 21, 28, 19, 53, 4, 53, 57, 53, 12, 22, 10}, + []uint64{0x20BE005B854, 0x89150111E2DDCA, 0x6F03DDEC4, 0xDF5D8596, 0x6959, 0x03, 0xA52AD1B0E7746, 0x59C3DAF8BDAF, 0xFB9F0D58B9, 0x512C3D6EDE, 0x49406B1, 0x11557, 0x98, 0x77BFF8316, 0x185BB7, 0x128FEE, 0xF59F, 0x1735FD6F22BAB9, 0x0E, 0x1A554E5A7C0BBA, 0x1BFCC47CEA8C5AF, 0x1C0D13FABA76B2, 0x7ED, 0x172050, 0x287}, + }, + { + []byte{0x62, 0x94, 0x17, 0x81, 0xEB, 0x57, 0xC8, 0x95, 0x9F, 0x6D, 0x5E, 0xB5, 0xB7, 0x75, 0xE0, 0x67, 0xB5, 0x74, 0xBB, 0x0D, 0xCE, 0xA3, 0x1A, 0x2A, 0xC7, 0x51, 0x0E, 0x1B, 0x08, 0x9E, 0xA2, 0xFC, 0x01, 0x20, 0xBF, 0xA3, 0x6B, 0xAC, 0x4B, 0x5B, 0x25, 0x35, 0xE1, 0x2A, 0x6F, 0xD2, 0x27, 0x6C, 0x29, 0x3C, 0x8A, 0x7E, 0x1C, 0x0D, 0xCD, 0x6A, 0x0B, 0x51, 0x7F, 0x12, 0x4D, 0xE8, 0xAC, 0x16, 0x18, 0x83, 0x16, 0xFD, 0xFE, 0x01, 0xA1, 0xC7, 0xF9, 0x6A, 0xBB, 0x48, 0x76, 0x98, 0xF0, 0x09, 0xE3, 0x9A, 0x2F, 0x83, 0xDF, 0x55, 0x4D, 0x41, 0xDC, 0x6F, 0x39, 0xA4, 0xEA, 0x6D, 0x3E, 0x4D, 0xD3, 0xE7, 0x8F, 0xFB}, + []uint{20, 19, 52, 17, 9, 10, 40, 5, 57, 24, 46, 25, 24, 11, 18, 13, 24, 39, 8, 27, 34, 11, 53, 48, 36, 44, 36, 50}, + []uint64{0x62941, 0x3C0F5, 0xABE44ACFB6AF5, 0x15B77, 0xBC, 0x33, 0xDABA5D86E7, 0x0A, 0x634558EA21C361, 0x13D45F, 0x200905FD1B5D, 0xC4B5B2, 0x535E12, 0x537, 0x3A44E, 0x1B0A, 0x4F229F, 0x4381B9AD41, 0x6A, 0x17F124D, 0x3A2B05862, 0x62, 0x1BF7F806871FE5, 0xAAED21DA63C0, 0x278E68BE0, 0xF7D55350771, 0xBCE693A9B, 0x13E4DD3E78FFB}, + }, + { + []byte{0x6B, 0x8C, 0x0C, 0x85, 0x7A, 0x48, 0x0C, 0xBA, 0x1D, 0x28, 0x30, 0xB4, 0x23, 0xA2, 0x16, 0x85, 0x62, 0x13, 0x29, 0x59, 0x81, 0x4E, 0x23, 0xDC, 0xA7, 0xD7, 0x85, 0x14, 0x4B, 0xD8, 0x8E, 0xA7, 0xD7, 0xC2, 0x3A, 0xD2, 0x86, 0x60, 0xA0, 0xBE, 0x6A, 0x22, 0xCD, 0xF1, 0x07, 0x75, 0xD2, 0x48, 0x9A, 0xEA, 0x56, 0x3D, 0x16, 0x70, 0xEF, 0x9F, 0xF5, 0xC2, 0x94, 0x86, 0x4C, 0x21, 0x29, 0x85, 0x9A, 0x84, 0x52, 0xF4, 0x41, 0xAC, 0xC5, 0x17, 0xD9, 0x72, 0xBE, 0xBA, 0x88, 0x38, 0xC2, 0xD2, 0x7D, 0xB3, 0xC1, 0x7A, 0x93, 0x61, 0x35, 0xEF, 0x34, 0xB3, 0x92, 0xA0, 0x7A, 0x34, 0x7B, 0x4D, 0x93, 0xDE, 0x1C, 0x46}, + []uint{61, 42, 37, 33, 39, 19, 40, 14, 62, 26, 60, 57, 36, 52, 19, 64, 51, 33, 55}, + []uint64{0xD718190AF490197, 0x10E94185A11, 0x1A21685621, 0x652B3029, 0x623DCA7D78, 0x28A25, 0xEC4753EBE1, 0x75A, 0x14330505F351166F, 0x220EEBA, 0x49135D4AC7A2CE1, 0x1BE7FD70A521930, 0x84A6166A1, 0x14BD106B3145F, 0x32E57, 0xD75107185A4FB678, 0x17A936135EF34, 0x1672540F4, 0x347B4D93DE1C46}, + }, + { + []byte{0xC8, 0x0A, 0xF4, 0xE9, 0x19, 0x51, 0xA6, 0xEA, 0x2C, 0x73, 0xB2, 0x54, 0xCE, 0x8B, 0x7D, 0x94, 0xDC, 0xB5, 0x38, 0x27, 0x6E, 0xD0, 0x3A, 0x1E, 0xA2, 0x09, 0x63, 0x7B, 0x9E, 0x2B, 0x7F, 0x8C, 0x9E, 0x49, 0x42, 0x8A, 0x15, 0xDF, 0xF7, 0xF9, 0xDF, 0xCA, 0xE3, 0xB5, 0x3D, 0x4F, 0xE0, 0x67, 0x7C, 0xC5, 0x77, 0x59, 0x1C, 0x51, 0x28, 0xD0, 0x0A, 0xE7, 0x4A, 0x14, 0xE5, 0x49, 0xF9, 0xA1, 0x49, 0x08, 0x3B, 0xE7, 0x3D, 0xC2, 0xB9, 0x95, 0x06, 0x8A, 0xA3, 0x7F, 0x63, 0x9E, 0x7F, 0x87, 0x67, 0xFC, 0x63, 0x54, 0x98, 0x00, 0x15, 0x3D, 0x4F, 0x99, 0xCD, 0x0F, 0x4A, 0xCC, 0x0D, 0x03, 0x16, 0x69, 0xB6, 0x67}, + []uint{33, 50, 24, 24, 5, 53, 5, 61, 26, 56, 35, 50, 2, 22, 59, 54, 8, 7, 48, 13, 14, 27, 42, 37, 42, 3}, + []uint64{0x19015E9D2, 0xCA8D3751639D, 0x92A674, 0x5BECA6, 0x1C, 0x16A704EDDA0743, 0x1A, 0x1104B1BDCF15BFC6, 0x13C9285, 0x142BBFEFF3BF95, 0x63B53D4FE, 0x19DF315DD647, 0x00, 0x144A34, 0x15CE9429CA93F3, 0x10A4841DF39EE1, 0x5C, 0x65, 0x41A2A8DFD8E7, 0x13FC, 0xECF, 0x7C63549, 0x200054F53E6, 0xE687A5660, 0x1A062CD36CC, 0x07}, + }, + { + []byte{0x83, 0x89, 0x65, 0xAD, 0xCF, 0xD1, 0xA9, 0x1F, 0xB5, 0x29, 0x97, 0x34, 0xA0, 0x5C, 0x67, 0xEC, 0x10, 0x7C, 0xB5, 0xB9, 0xB1, 0x3F, 0x70, 0xCD, 0x54, 0x37, 0xCF, 0x1A, 0x0A, 0xF8, 0x7C, 0x68, 0xF1, 0x7A, 0x4E, 0x69, 0x53, 0xAA, 0xBA, 0x8E, 0x42, 0xC8, 0x49, 0x28, 0xB4, 0xED, 0x55, 0x08, 0x88, 0x0D, 0xAF, 0xF1, 0x34, 0x2B, 0x4A, 0x14, 0x2F, 0x00, 0x2E, 0xB7, 0x9B, 0xEE, 0x86, 0x62, 0x25, 0x12, 0x39, 0xF6, 0x12, 0xD6, 0x9F, 0x95, 0x52, 0x68, 0x2F, 0x9B, 0x2E, 0xBC, 0x32, 0xC4, 0xC6, 0x98, 0x99, 0xB6, 0xB9, 0x93, 0x61, 0xA2, 0x07, 0x20, 0x70, 0x1D, 0x1C, 0x9F, 0xC3, 0xCF, 0x72, 0xFA, 0x4A, 0x1B}, + []uint{47, 7, 1, 29, 41, 12, 14, 2, 46, 54, 62, 59, 12, 45, 62, 1, 6, 6, 50, 14, 23, 27, 45, 11, 51, 36, 20, 17}, + []uint64{0x41C4B2D6E7E8, 0x6A, 0x00, 0x11FB5299, 0xE6940B8CFD, 0x820, 0x3E5A, 0x03, 0x1CD89FB866AA, 0x6F9E3415F0F8D, 0x78BD2734A9D55D4, 0x390B2124A2D3B55, 0x422, 0x406D7F89A15, 0x294285E005D6F37D, 0x01, 0x28, 0x19, 0x22251239F612D, 0x1A7E, 0x2AA4D0, 0x2F9B2EB, 0x1865898D3133, 0x36B, 0x4C9B0D1039038, 0xE8E4FE1E, 0x7B97D, 0x4A1B}, + }, + { + []byte{0x9D, 0xCF, 0xB2, 0x8C, 0xE0, 0xE6, 0xD3, 0xD4, 0xC0, 0x77, 0x4C, 0x43, 0xDB, 0xEE, 0x32, 0xD6, 0x67, 0x9F, 0xED, 0xAA, 0xB6, 0x0C, 0x1D, 0x65, 0x61, 0x02, 0xA1, 0xB0, 0x08, 0xB9, 0x06, 0xCF, 0xA1, 0xD4, 0xE0, 0x54, 0x75, 0x30, 0x59, 0xDA, 0xFE, 0x16, 0x9F, 0x36, 0x88, 0xD4, 0x70, 0x3D, 0xE4, 0x2E, 0x78, 0x17, 0x5F, 0x18, 0x5A, 0x7F, 0x35, 0x31, 0x63, 0xD0, 0xF9, 0xCF, 0x34, 0xD6, 0xDF, 0x7E, 0xB9, 0x07, 0x24, 0x37, 0x2B, 0x5C, 0xFC, 0xD0, 0x3B, 0x32, 0xD4, 0xA7, 0x96, 0x28, 0xD1, 0x23, 0xDA, 0x6C, 0xEA, 0x4C, 0x29, 0x31, 0xB2, 0x20, 0x3C, 0x23, 0xE2, 0xEB, 0x22, 0x78, 0x79, 0xD1, 0xBC, 0xEB}, + []uint{49, 29, 9, 37, 23, 47, 33, 37, 49, 15, 60, 35, 21, 35, 36, 5, 9, 45, 31, 23, 18, 64, 13, 58, 19}, + []uint64{0x13B9F6519C1CD, 0x14F5301D, 0x1A6, 0x43DBEE32D, 0x333CFF, 0x36AAD8307595, 0x108150D80, 0x8B906CFA1, 0x1A9C0A8EA60B3, 0x5AFE, 0x169F3688D4703DE, 0x2173C0BAF, 0x1185A7, 0x79A98B1E8, 0x7CE79A6B6, 0x1F, 0xFD, 0xE41C90DCAD7, 0x1F9A0766, 0x2D4A79, 0x18A34, 0x48F69B3A930A4C6C, 0x1101, 0x3847C5D644F0F3A, 0x1BCEB}, + }, + { + []byte{0x91, 0x0B, 0x7C, 0xD2, 0x4C, 0xB9, 0x12, 0xA4, 0x56, 0x7E, 0xE5, 0x29, 0xEC, 0x0D, 0xEE, 0xD9, 0xCD, 0x10, 0x96, 0x04, 0xDE, 0xAE, 0x9A, 0x8E, 0xFA, 0x41, 0x7C, 0x47, 0x22, 0x53, 0xD3, 0xBF, 0x1E, 0x78, 0x75, 0xBA, 0x7A, 0x88, 0x06, 0x39, 0xC3, 0x8C, 0x59, 0x79, 0x6B, 0x4F, 0x52, 0x30, 0x08, 0xF6, 0x7E, 0x0A, 0xB9, 0x74, 0xB8, 0x25, 0x9C, 0x20, 0x53, 0x7E, 0x4C, 0xAC, 0xE4, 0x58, 0x38, 0xCC, 0xAA, 0x55, 0xCA, 0xE9, 0x1F, 0x2A, 0xD8, 0x15, 0xB8, 0x53, 0x7D, 0xD3, 0x16, 0x47, 0x96, 0xC2, 0x98, 0x56, 0x35, 0xDB, 0x83, 0x5E, 0xD7, 0xCF, 0xB6, 0x03, 0x6A, 0xBF, 0x7A, 0x6C, 0x7A, 0x54, 0x99, 0x0C}, + []uint{34, 58, 36, 43, 41, 55, 14, 6, 6, 12, 62, 43, 34, 27, 12, 29, 46, 25, 51, 13, 36, 42, 35, 40}, + []uint64{0x2442DF349, 0xCB912A4567EE52, 0x9EC0DEED9, 0x66884B026F5, 0xE9A8EFA417, 0x6239129E9DF8F3, 0x30EB, 0x1D, 0x0F, 0x510, 0x31CE1C62CBCB5A7, 0x548C023D9F8, 0xAB974B82, 0x2CE1029, 0xBF2, 0xCACE458, 0xE332A9572BA, 0x8F956C, 0x56E14DF74C59, 0x3CB, 0x614C2B1AE, 0x3706BDAF9F6, 0x6036ABF7A, 0x6C7A54990C}, + }, + { + []byte{0xAE, 0x2E, 0x61, 0xAB, 0x47, 0x76, 0x8C, 0x9E, 0x28, 0x13, 0x95, 0x06, 0x9A, 0x10, 0x8A, 0x5B, 0xFD, 0xB2, 0x2F, 0xC5, 0x44, 0x29, 0xB3, 0xBF, 0x5B, 0x39, 0xD5, 0x5A, 0xD2, 0xED, 0x48, 0xA6, 0x09, 0x11, 0x37, 0x9A, 0x18, 0x04, 0xA2, 0xC5, 0x07, 0x94, 0xAF, 0x3F, 0x3C, 0x59, 0x3E, 0x8E, 0xE6, 0x9C, 0x25, 0x03, 0xFC, 0xFA, 0xB3, 0x95, 0xB8, 0xAD, 0x53, 0x12, 0x2F, 0xB9, 0x91, 0x9C, 0xD0, 0x93, 0x52, 0xF8, 0x03, 0x68, 0xD2, 0x72, 0xD4, 0x63, 0x2B, 0xAA, 0xFF, 0x92, 0x8E, 0xFB, 0x82, 0xC4, 0x41, 0xEC, 0x40, 0x0C, 0x9D, 0xFB, 0x40, 0x25, 0x0B, 0x2F, 0xB1, 0x34, 0x05, 0xD7, 0xB4, 0x73, 0xAE, 0x05}, + []uint{20, 26, 55, 35, 26, 47, 15, 22, 5, 30, 16, 29, 32, 21, 47, 57, 49, 56, 32, 13, 23, 8, 54, 20, 31, 31}, + []uint64{0xAE2E6, 0x6AD1DD, 0x5193C50272A0D3, 0x2108A5BFD, 0x2C8BF15, 0x853677EB673, 0x555A, 0x34BB52, 0x05, 0xC12226F, 0x3430, 0x128B141, 0xE52BCFCF, 0x2C9F4, 0x3B9A70940FF3, 0x1D59CADC56A9891, 0xFB9919CD0935, 0x2F80368D272D46, 0x32BAAFF9, 0x51D, 0x7B82C4, 0x41, 0x3B1003277ED009, 0x42CBE, 0x62680BAF, 0x3473AE05}, + }, + { + []byte{0xC3, 0x42, 0xF8, 0x38, 0x04, 0x5F, 0x4F, 0x7A, 0x7A, 0x2F, 0x32, 0xEC, 0xE5, 0x0F, 0xDD, 0x4C, 0x16, 0x10, 0x31, 0x0A, 0xF0, 0xAE, 0x6D, 0xE1, 0xEB, 0xE3, 0x4E, 0x11, 0x30, 0x6C, 0xC1, 0xA8, 0xA6, 0xB5, 0x33, 0xD3, 0x58, 0x03, 0xBF, 0x16, 0x09, 0x37, 0x4D, 0xE7, 0xE9, 0x82, 0xCC, 0xBC, 0xFA, 0x12, 0x4D, 0xAC, 0xF6, 0x53, 0x22, 0xBD, 0xF7, 0xFD, 0x22, 0x77, 0xEC, 0x5B, 0xD1, 0xC4, 0xA2, 0x97, 0xC9, 0x04, 0x1C, 0x62, 0x7B, 0xD4, 0x03, 0x82, 0x21, 0x22, 0x2B, 0x20, 0xC6, 0x0D, 0xF8, 0xAA, 0x03, 0xC0, 0x30, 0x21, 0x31, 0xF0, 0xEE, 0x9B, 0x17, 0x60, 0x24, 0x94, 0x71, 0x5F, 0x04, 0xC5, 0x21, 0x97}, + []uint{62, 59, 50, 16, 6, 35, 61, 35, 43, 22, 8, 55, 5, 33, 27, 32, 33, 23, 21, 40, 38, 23, 2, 27, 43, 1}, + []uint64{0x30D0BE0E0117D3DE, 0x4F45E65D9CA1FBA, 0x260B081885785, 0x736F, 0x03, 0x6BE34E113, 0xD983514D6A67A6, 0x5803BF160, 0x49BA6F3F4C1, 0x19979F, 0x42, 0x24DACF65322BDF, 0x0F, 0x1F489DFB1, 0x37A3894, 0x52F92083, 0x1189EF500, 0x704424, 0x8AC83, 0x1837E2A80F, 0x302131F0, 0x774D8B, 0x02, 0x6024947, 0xAF826290CB, 0x01}, + }, + { + []byte{0xDB, 0xB6, 0x8B, 0x84, 0x54, 0x5F, 0x96, 0xF5, 0xA7, 0x0A, 0x0C, 0x86, 0x2B, 0x97, 0x6C, 0x1D, 0x06, 0xF1, 0x2B, 0x6B, 0x3C, 0xD6, 0xE2, 0x4E, 0x00, 0x50, 0xFF, 0x99, 0x4E, 0x19, 0x48, 0xC0, 0x51, 0xAE, 0x3F, 0x8A, 0x89, 0xB5, 0x4E, 0x1D, 0x4B, 0xA7, 0x4E, 0xC6, 0xF9, 0x51, 0x4C, 0xAC, 0xFA, 0x68, 0x40, 0xB1, 0xD6, 0xA5, 0x40, 0xF3, 0xCD, 0xDC, 0xCB, 0x3B, 0x5E, 0xBD, 0x4D, 0x42, 0xA1, 0xDE, 0x60, 0x5F, 0xFF, 0x04, 0xB8, 0xC4, 0xC6, 0xCC, 0x6D, 0xAE, 0xE0, 0xD4, 0x5C, 0x19, 0x12, 0x0C, 0xE1, 0x5D, 0xEA, 0x52, 0x81, 0x48, 0x36, 0x7E, 0xB4, 0x3E, 0x2F, 0x55, 0xE8, 0xF1, 0x5C, 0xCC, 0xE9, 0x69}, + []uint{40, 14, 56, 38, 64, 31, 42, 45, 46, 13, 7, 51, 4, 7, 54, 61, 37, 57, 15, 30, 56, 32}, + []uint64{0xDBB68B8454, 0x17E5, 0xBD69C283218AE5, 0x36C1D06F12, 0xB6B3CD6E24E0050F, 0x7CCA70CA, 0x1180A35C7F1, 0xA26D538752E, 0x274EC6F9514C, 0x159F, 0x26, 0x42058EB52A079, 0x0E, 0x37, 0x1CCB3B5EBD4D42, 0x143BCC0BFFE09718, 0x131B31B6BB, 0x106A2E0C890670A, 0x77A9, 0x12814836, 0x7EB43E2F55E8F1, 0x5CCCE969}, + }, + { + []byte{0xC1, 0xD6, 0x8F, 0x43, 0xE4, 0xDA, 0x73, 0x69, 0xFF, 0xD2, 0xBD, 0x90, 0x9C, 0xA7, 0x7F, 0x80, 0x19, 0x74, 0xED, 0xAA, 0xFC, 0x25, 0x6C, 0xB8, 0x2B, 0xD9, 0xE1, 0x2F, 0xC1, 0xD8, 0xCF, 0x8C, 0x5F, 0xA9, 0xA7, 0x4A, 0x4B, 0xFD, 0x69, 0x5D, 0x81, 0x47, 0x74, 0x01, 0x04, 0xC0, 0xE2, 0x44, 0xC0, 0x6A, 0x9D, 0x55, 0x36, 0x67, 0x97, 0x1D, 0xA5, 0x77, 0xF1, 0x66, 0xA7, 0xFF, 0x9A, 0xE7, 0xE7, 0x2C, 0x11, 0xBA, 0xD1, 0x35, 0xAB, 0xFE, 0x6E, 0x1B, 0x4E, 0x71, 0x8E, 0xE1, 0x76, 0x9A, 0x37, 0xC9, 0xB9, 0x0D, 0xE7, 0x48, 0xE3, 0xF5, 0x1B, 0xD0, 0x37, 0xAD, 0xB5, 0x6A, 0x5D, 0x1D, 0x68, 0xA6, 0x25, 0xA5}, + []uint{43, 24, 64, 30, 32, 57, 56, 61, 50, 3, 45, 46, 3, 60, 22, 42, 5, 60, 20, 24, 10, 43}, + []uint64{0x60EB47A1F26, 0xD39B4F, 0xFE95EC84E53BFC00, 0x32E9DB55, 0xF84AD970, 0xAF6784BF07633E, 0x317EA69D292FF5, 0x14AEC0A3BA008260, 0x1C48980D53AAA, 0x03, 0xCCF2E3B4AEF, 0x38B353FFCD73, 0x07, 0x9CB046EB44D6AFF, 0x26E1B4, 0x39C63B85DA6, 0x11, 0xBE4DC86F3A471FA, 0x8DE81, 0xBD6DAB, 0x14B, 0x51D68A625A5}, + }, + { + []byte{0xD2, 0x0F, 0x71, 0xCA, 0xCA, 0xC7, 0x54, 0x23, 0xD0, 0x56, 0x71, 0xA4, 0x96, 0x84, 0x3D, 0xA6, 0x34, 0x6E, 0x5E, 0x7F, 0x4E, 0x49, 0x22, 0xE0, 0x9E, 0xC8, 0x94, 0x2E, 0xAF, 0x34, 0x2F, 0xF6, 0xD3, 0xA7, 0x90, 0x9E, 0xEC, 0x25, 0x15, 0xC5, 0xFB, 0xE4, 0xBD, 0x08, 0x3D, 0x5A, 0x70, 0x77, 0x17, 0x20, 0x2F, 0x1B, 0x1B, 0xAB, 0xA5, 0xC9, 0x83, 0x6D, 0x44, 0x21, 0xD6, 0x0A, 0x01, 0xBD, 0x5D, 0x9F, 0xFD, 0xE4, 0xDF, 0xE4, 0xFD, 0x83, 0xA2, 0x7C, 0xAF, 0x23, 0x7B, 0xB1, 0x6B, 0xAA, 0x71, 0x50, 0x11, 0xBB, 0x48, 0x66, 0xE8, 0x6C, 0xF4, 0x42, 0x28, 0x36, 0x78, 0xEE, 0x64, 0xA5, 0xEA, 0xFC, 0x2E, 0x5A}, + []uint{32, 19, 41, 28, 7, 20, 33, 64, 3, 54, 63, 16, 12, 12, 63, 9, 64, 3, 29, 29, 18, 6, 28, 3, 2, 39, 41, 40, 22}, + []uint64{0xD20F71CA, 0x6563A, 0x1423D05671A, 0x496843D, 0x53, 0x1A372, 0x1E7F4E492, 0x2E09EC8942EAF342, 0x07, 0x3EDA74F213DD84, 0x515C5FBE4BD083D5, 0xA707, 0x717, 0x202, 0x78D8DD5D2E4C1B6A, 0x42, 0x1D60A01BD5D9FFDE, 0x02, 0xDFE4FD8, 0x744F95E, 0x11BDD, 0x22, 0xD754E2A, 0x00, 0x00, 0x237690CDD0, 0x1B3D108A0D9, 0xE3B99297AB, 0x3C2E5A}, + }, + { + []byte{0x97, 0xD2, 0x7B, 0x0E, 0xF3, 0x1D, 0x05, 0xA6, 0x82, 0x27, 0xD8, 0xE0, 0x4C, 0x2C, 0xFE, 0x8E, 0x5B, 0x92, 0x67, 0xA1, 0xDA, 0x2F, 0xC8, 0x6A, 0x3F, 0x83, 0x20, 0x33, 0xB2, 0xF7, 0xE6, 0x6E, 0xE2, 0x93, 0x98, 0xA2, 0x32, 0x15, 0xD1, 0x21, 0x41, 0xBC, 0x2B, 0xDE, 0xFE, 0x55, 0xFB, 0x6C, 0x34, 0x28, 0xC4, 0x41, 0xA1, 0xFE, 0x33, 0x0C, 0xD3, 0xF5, 0x4A, 0x90, 0xF7, 0x58, 0x04, 0x0C, 0xB6, 0xEE, 0x44, 0xCC, 0x80, 0x3F, 0x00, 0x8F, 0xA8, 0x85, 0xE8, 0x9C, 0x9D, 0xF5, 0x5A, 0xEA, 0xA0, 0x6B, 0x3B, 0x59, 0xD1, 0x89, 0x81, 0x5A, 0xE0, 0x10, 0xD5, 0xD3, 0x7B, 0x1A, 0x4E, 0xAF, 0x3D, 0xE9, 0x3E, 0x59}, + []uint{22, 40, 15, 18, 48, 34, 7, 54, 40, 57, 21, 10, 60, 13, 5, 38, 25, 14, 28, 20, 11, 53, 9, 36, 23, 46, 17, 4, 32}, + []uint64{0x25F49E, 0xC3BCC74169, 0x5044, 0x3EC70, 0x26167F472DC9, 0xCF43B45F, 0x48, 0x1A8FE0C80CECBD, 0xF99BB8A4E6, 0x51190AE890A0DE, 0x2BDEF, 0x395, 0x7EDB0D0A3110687, 0x1F19, 0x10, 0x334FD52A43, 0x1BAC020, 0x196D, 0xDC89990, 0x7E01, 0xFA, 0x110BD1393BEAB5, 0x1AA, 0x81ACED674, 0x31302B, 0x170086AE9BD8, 0x1A4EA, 0x0F, 0x3DE93E59}, + }, + { + []byte{0xAB, 0x5F, 0xA3, 0x18, 0x91, 0x10, 0x4D, 0x85, 0x95, 0xC6, 0x23, 0xBA, 0x0D, 0xBD, 0xC4, 0x2A, 0x12, 0x30, 0xE1, 0xD3, 0xFE, 0xA2, 0x0B, 0xB9, 0xD9, 0x3D, 0x61, 0x91, 0x97, 0x8B, 0x53, 0x2A, 0xC1, 0x80, 0x3C, 0x46, 0x46, 0x44, 0x57, 0x8A, 0x23, 0x66, 0xF2, 0x51, 0xCC, 0xF8, 0xFB, 0xEF, 0x0A, 0x0B, 0x72, 0xF0, 0xA8, 0x36, 0xE7, 0x26, 0x04, 0x83, 0x15, 0x36, 0x04, 0x73, 0x38, 0x48, 0x41, 0x61, 0x0B, 0x09, 0x46, 0xBC, 0x29, 0xA8, 0x02, 0xB6, 0x80, 0xDB, 0xCF, 0x22, 0x54, 0x5B, 0x5A, 0x2E, 0x34, 0x24, 0x06, 0xB9, 0x66, 0x4C, 0xD1, 0xB7, 0x1A, 0xFF, 0x92, 0x06, 0x49, 0xD1, 0x26, 0xE6, 0x23, 0xAD}, + []uint{61, 43, 8, 31, 38, 4, 45, 5, 51, 58, 5, 2, 51, 22, 38, 44, 26, 20, 52, 51, 49, 39, 50, 7}, + []uint64{0x156BF463122209B0, 0x595C623BA0D, 0xBD, 0x62150918, 0x1C3A7FD441, 0x07, 0xE764F586465, 0x1C, 0x2D4CAB0600F11, 0x24644578A2366F2, 0x0A, 0x00, 0x733E3EFBC282D, 0x32F0A8, 0xDB9C98120, 0xC54D811CCE1, 0x841610, 0xB0946, 0xBC29A802B680D, 0x5E7912A2DAD17, 0x342406B9664C, 0x68DB8D7FC9, 0xC93A24DCC47, 0x2D}, + }, + { + []byte{0xAA, 0x55}, + []uint{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + []uint64{1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1}, + }, + + { + []byte{0xAA, 0x55}, + []uint{7, 8, 1}, + []uint64{0x55, 0x2A, 0x1}, + }, + + { + []byte{0xAA, 0x55}, + []uint{3, 3, 3, 3, 3, 1}, + []uint64{0x5, 0x2, 0x4, 0x5, 0x2, 0x1}, + }, + + { + []byte{0xAA, 0x55}, + []uint{16}, + []uint64{0xAA55}, + }, + + { + []byte{0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55}, + []uint{32, 32}, + []uint64{0xAA55AA55, 0xAA55AA55}, + }, + + { + []byte{0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55}, + []uint{33, 31}, + []uint64{0x154AB54AB, 0x2A55AA55}, + }, + } + + for i, test := range tests { + r := NewReader(bytes.NewReader(test.data)) + if len(test.ns) != len(test.vals) { + panic("Number of reads does not match number of results") + } + for j, n := range test.ns { + m, err := r.Read(n) + if err != nil { + panic("Unexpected error: " + err.Error()) + } + if m != test.vals[j] { + t.Errorf("i=%d; %v with reads %v: read %d gave %x, expected %x", i, test.data, test.ns, j, m, test.vals[j]) + } + } + } +} + +func TestReadEOF(t *testing.T) { + tests := []struct { + data []byte + n uint + err error + }{ + {[]byte{0xFF}, 8, nil}, + {[]byte{0xFF}, 2, nil}, + {[]byte{0xFF}, 9, io.ErrUnexpectedEOF}, + {[]byte{}, 1, io.EOF}, + {[]byte{0xFF, 0xFF}, 16, nil}, + {[]byte{0xFF, 0xFF}, 17, io.ErrUnexpectedEOF}, + } + + for i, test := range tests { + r := NewReader(bytes.NewReader(test.data)) + if _, err := r.Read(test.n); err != test.err { + t.Errorf("i=%d; Reading %d from %v, expected err=%s, got err=%s", i, test.n, test.data, test.err, err) + } + } +} + +func BenchmarkReadAlign1(b *testing.B) { + benchmarkReads(b, 64, 1) +} + +func BenchmarkReadAlign32(b *testing.B) { + benchmarkReads(b, 64, 32) +} + +func BenchmarkReadAlign64(b *testing.B) { + benchmarkReads(b, 64, 64) +} + +func benchmarkReads(b *testing.B, chunk, align int) { + size := 1 << 12 + buf, bits, _, last := prepareBenchmark(size, chunk, align) + b.SetBytes(int64(len(buf))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + r := NewReader(bytes.NewReader(buf)) + for j := 0; j < last; j++ { + if _, err := r.Read(bits[j]); err != nil { + b.Error(err) + continue + } + } + } +} + +func prepareBenchmark(size, chunk, align int) ([]byte, []uint, []uint64, int) { + buf := make([]byte, size) + bits := make([]uint, size) + values := make([]uint64, size) + idx := 0 + last := 0 + for i := 0; i < size; i++ { + val := getNumBits(idx, size*8, chunk, align) + idx += val + if val != 0 { + last = i + 1 + } + bits[i] = uint(val) + values[i] = uint64(rand.Uint32())<<32 + uint64(rand.Uint32()) + } + return buf, bits, values, last +} + +func getNumBits(read, max, chunk, align int) int { + bits := 1 + if align != chunk { + bits += rand.Intn(chunk / align) + } + bits *= align + if read+bits > max { + bits = max - read + } + if bits > chunk { + panic("too many bits") + } + return bits +} diff --git a/internal/bits/twocomp.go b/internal/bits/twocomp.go new file mode 100755 index 0000000..45d52b4 --- /dev/null +++ b/internal/bits/twocomp.go @@ -0,0 +1,27 @@ +package bits + +// IntN returns the signed two's complement of x with the specified integer bit +// width. +// +// Examples of unsigned (n-bit width) x values on the left and decoded values on +// the right: +// +// 0b011 -> 3 +// 0b010 -> 2 +// 0b001 -> 1 +// 0b000 -> 0 +// 0b111 -> -1 +// 0b110 -> -2 +// 0b101 -> -3 +// 0b100 -> -4 +func IntN(x uint64, n uint) int64 { + signBitMask := uint64(1 << (n - 1)) + if x&signBitMask == 0 { + // positive. + return int64(x) + } + // negative. + v := int64(x ^ signBitMask) // clear sign bit. + v -= int64(signBitMask) + return v +} diff --git a/internal/bits/twocomp_test.go b/internal/bits/twocomp_test.go new file mode 100755 index 0000000..d803889 --- /dev/null +++ b/internal/bits/twocomp_test.go @@ -0,0 +1,27 @@ +package bits + +import "testing" + +func TestIntN(t *testing.T) { + golden := []struct { + x uint64 + n uint + want int64 + }{ + {x: 0b011, n: 3, want: 3}, + {x: 0b010, n: 3, want: 2}, + {x: 0b001, n: 3, want: 1}, + {x: 0b000, n: 3, want: 0}, + {x: 0b111, n: 3, want: -1}, + {x: 0b110, n: 3, want: -2}, + {x: 0b101, n: 3, want: -3}, + {x: 0b100, n: 3, want: -4}, + } + for _, g := range golden { + got := IntN(g.x, g.n) + if g.want != got { + t.Errorf("result mismatch of IntN(x=0b%03b, n=%d); expected %d, got %d", g.x, g.n, g.want, got) + continue + } + } +} diff --git a/internal/bits/unary.go b/internal/bits/unary.go new file mode 100755 index 0000000..b4a81fc --- /dev/null +++ b/internal/bits/unary.go @@ -0,0 +1,58 @@ +package bits + +import ( + "github.com/icza/bitio" +) + +// ReadUnary decodes and returns an unary coded integer, whose value is +// represented by the number of leading zeros before a one. +// +// Examples of unary coded binary on the left and decoded decimal on the right: +// +// 1 => 0 +// 01 => 1 +// 001 => 2 +// 0001 => 3 +// 00001 => 4 +// 000001 => 5 +// 0000001 => 6 +func (br *Reader) ReadUnary() (x uint64, err error) { + for { + bit, err := br.Read(1) + if err != nil { + return 0, err + } + if bit == 1 { + break + } + x++ + } + return x, nil +} + +// WriteUnary encodes x as an unary coded integer, whose value is represented by +// the number of leading zeros before a one. +// +// Examples of unary coded binary on the left and decoded decimal on the right: +// +// 0 => 1 +// 1 => 01 +// 2 => 001 +// 3 => 0001 +// 4 => 00001 +// 5 => 000001 +// 6 => 0000001 +func WriteUnary(bw *bitio.Writer, x uint64) error { + for ; x > 8; x -= 8 { + if err := bw.WriteByte(0x0); err != nil { + return err + } + } + + bits := uint64(1) + n := byte(x + 1) + if err := bw.WriteBits(bits, n); err != nil { + return err + } + return nil +} diff --git a/internal/bits/unary_test.go b/internal/bits/unary_test.go new file mode 100755 index 0000000..4db524a --- /dev/null +++ b/internal/bits/unary_test.go @@ -0,0 +1,36 @@ +package bits_test + +import ( + "bytes" + "testing" + + "github.com/icza/bitio" + "github.com/mewkiz/flac/internal/bits" +) + +func TestUnary(t *testing.T) { + buf := &bytes.Buffer{} + bw := bitio.NewWriter(buf) + + for want := uint64(0); want < 1000; want++ { + // Write unary + if err := bits.WriteUnary(bw, want); err != nil { + t.Fatalf("unable to write unary; %v", err) + } + // Flush buffer + if err := bw.Close(); err != nil { + t.Fatalf("unable to close (flush) the bit buffer; %v", err) + } + + // Read written unary + r := bits.NewReader(buf) + got, err := r.ReadUnary() + if err != nil { + t.Fatalf("unable to read unary; %v", err) + } + + if want != got { + t.Fatalf("mismatch between written and read unary value; expected: %d, got: %d", want, got) + } + } +} diff --git a/internal/bits/zigzag.go b/internal/bits/zigzag.go new file mode 100755 index 0000000..3d6ac40 --- /dev/null +++ b/internal/bits/zigzag.go @@ -0,0 +1,41 @@ +package bits + +// DecodeZigZag decodes a ZigZag encoded integer and returns it. +// +// Examples of ZigZag encoded values on the left and decoded values on the +// right: +// +// 0 => 0 +// 1 => -1 +// 2 => 1 +// 3 => -2 +// 4 => 2 +// 5 => -3 +// 6 => 3 +// +// ref: https://developers.google.com/protocol-buffers/docs/encoding +func DecodeZigZag(x uint32) int32 { + return int32(x>>1) ^ -int32(x&1) +} + +// EncodeZigZag encodes a given integer to ZigZag-encoding. +// +// Examples of integer input on the left and corresponding ZigZag encoded values +// on the right: +// +// 0 => 0 +// -1 => 1 +// 1 => 2 +// -2 => 3 +// 2 => 4 +// -3 => 5 +// 3 => 6 +// +// ref: https://developers.google.com/protocol-buffers/docs/encoding +func EncodeZigZag(x int32) uint32 { + if x < 0 { + x = -x + return uint32(x)<<1 - 1 + } + return uint32(x) << 1 +} diff --git a/internal/bits/zigzag_test.go b/internal/bits/zigzag_test.go new file mode 100755 index 0000000..2a8fdc5 --- /dev/null +++ b/internal/bits/zigzag_test.go @@ -0,0 +1,49 @@ +package bits + +import ( + "testing" +) + +func TestDecodeZigZag(t *testing.T) { + golden := []struct { + x uint32 + want int32 + }{ + {x: 0, want: 0}, + {x: 1, want: -1}, + {x: 2, want: 1}, + {x: 3, want: -2}, + {x: 4, want: 2}, + {x: 5, want: -3}, + {x: 6, want: 3}, + } + for _, g := range golden { + got := DecodeZigZag(g.x) + if g.want != got { + t.Errorf("result mismatch of DecodeZigZag(x=%d); expected %d, got %d", g.x, g.want, got) + continue + } + } +} + +func TestEncodeZigZag(t *testing.T) { + golden := []struct { + x int32 + want uint32 + }{ + {x: 0, want: 0}, + {x: -1, want: 1}, + {x: 1, want: 2}, + {x: -2, want: 3}, + {x: 2, want: 4}, + {x: -3, want: 5}, + {x: 3, want: 6}, + } + for _, g := range golden { + got := EncodeZigZag(g.x) + if g.want != got { + t.Errorf("result mismatch of EncodeZigZag(x=%d); expected %d, got %d", g.x, g.want, got) + continue + } + } +} diff --git a/internal/bufseekio/readseeker.go b/internal/bufseekio/readseeker.go new file mode 100755 index 0000000..9678eda --- /dev/null +++ b/internal/bufseekio/readseeker.go @@ -0,0 +1,152 @@ +package bufseekio + +import ( + "errors" + "io" +) + +const ( + defaultBufSize = 4096 +) + +// ReadSeeker implements buffering for an io.ReadSeeker object. +// ReadSeeker is based on bufio.Reader with Seek functionality added +// and unneeded functionality removed. +type ReadSeeker struct { + buf []byte + pos int64 // absolute start position of buf + rd io.ReadSeeker // read-seeker provided by the client + r, w int // buf read and write positions within buf + err error +} + +const minReadBufferSize = 16 + +// NewReadSeekerSize returns a new ReadSeeker whose buffer has at least the specified +// size. If the argument io.ReadSeeker is already a ReadSeeker with large enough +// size, it returns the underlying ReadSeeker. +func NewReadSeekerSize(rd io.ReadSeeker, size int) *ReadSeeker { + // Is it already a Reader? + b, ok := rd.(*ReadSeeker) + if ok && len(b.buf) >= size { + return b + } + if size < minReadBufferSize { + size = minReadBufferSize + } + r := new(ReadSeeker) + r.reset(make([]byte, size), rd) + return r +} + +// NewReadSeeker returns a new ReadSeeker whose buffer has the default size. +func NewReadSeeker(rd io.ReadSeeker) *ReadSeeker { + return NewReadSeekerSize(rd, defaultBufSize) +} + +var errNegativeRead = errors.New("bufseekio: reader returned negative count from Read") + +func (b *ReadSeeker) reset(buf []byte, r io.ReadSeeker) { + *b = ReadSeeker{ + buf: buf, + rd: r, + } +} + +func (b *ReadSeeker) readErr() error { + err := b.err + b.err = nil + return err +} + +// Read reads data into p. +// It returns the number of bytes read into p. +// The bytes are taken from at most one Read on the underlying Reader, +// hence n may be less than len(p). +// To read exactly len(p) bytes, use io.ReadFull(b, p). +// If the underlying Reader can return a non-zero count with io.EOF, +// then this Read method can do so as well; see the [io.Reader] docs. +func (b *ReadSeeker) Read(p []byte) (n int, err error) { + n = len(p) + if n == 0 { + if b.buffered() > 0 { + return 0, nil + } + return 0, b.readErr() + } + if b.r == b.w { + if b.err != nil { + return 0, b.readErr() + } + if len(p) >= len(b.buf) { + // Large read, empty buffer. + // Read directly into p to avoid copy. + n, b.err = b.rd.Read(p) + if n < 0 { + panic(errNegativeRead) + } + b.pos += int64(n) + return n, b.readErr() + } + // One read. + b.pos += int64(b.r) + b.r = 0 + b.w = 0 + n, b.err = b.rd.Read(b.buf) + if n < 0 { + panic(errNegativeRead) + } + if n == 0 { + return 0, b.readErr() + } + b.w += n + } + + // copy as much as we can + // Note: if the slice panics here, it is probably because + // the underlying reader returned a bad count. See issue 49795. + n = copy(p, b.buf[b.r:b.w]) + b.r += n + return n, nil +} + +// buffered returns the number of bytes that can be read from the current buffer. +func (b *ReadSeeker) buffered() int { return b.w - b.r } + +func (b *ReadSeeker) Seek(offset int64, whence int) (int64, error) { + // The stream.Seek() implementation makes heavy use of seeking with offset 0 + // to obtain the current position; let's optimize for it. + if offset == 0 && whence == io.SeekCurrent { + return b.position(), nil + } + // When seeking from the end, the absolute position isn't known by ReadSeeker + // so the current buffer cannot be used. Seeking cannot be avoided. + if whence == io.SeekEnd { + return b.seek(offset, whence) + } + // Calculate the absolute offset. + abs := offset + if whence == io.SeekCurrent { + abs += b.position() + } + // Check if the offset is within buf. + if abs >= b.pos && abs < b.pos+int64(b.w) { + b.r = int(abs - b.pos) + return abs, nil + } + + return b.seek(abs, io.SeekStart) +} + +func (b *ReadSeeker) seek(offset int64, whence int) (int64, error) { + b.r = 0 + b.w = 0 + var err error + b.pos, err = b.rd.Seek(offset, whence) + return b.pos, err +} + +// position returns the absolute read offset. +func (b *ReadSeeker) position() int64 { + return b.pos + int64(b.r) +} diff --git a/internal/bufseekio/readseeker_test.go b/internal/bufseekio/readseeker_test.go new file mode 100755 index 0000000..06b162d --- /dev/null +++ b/internal/bufseekio/readseeker_test.go @@ -0,0 +1,266 @@ +package bufseekio + +import ( + "bytes" + "errors" + "io" + "reflect" + "testing" +) + +func TestNewReadSeekerSize(t *testing.T) { + buf := bytes.NewReader(make([]byte, 100)) + + // Test custom buffer size. + if rs := NewReadSeekerSize(buf, 20); len(rs.buf) != 20 { + t.Fatalf("want %d got %d", 20, len(rs.buf)) + } + + // Test too small buffer size. + if rs := NewReadSeekerSize(buf, 1); len(rs.buf) != minReadBufferSize { + t.Fatalf("want %d got %d", minReadBufferSize, len(rs.buf)) + } + + // Test reuse existing ReadSeeker. + rs := NewReadSeekerSize(buf, 20) + if rs2 := NewReadSeekerSize(rs, 5); rs != rs2 { + t.Fatal("expected ReadSeeker to be reused but got a different ReadSeeker") + } +} + +func TestNewReadSeeker(t *testing.T) { + buf := bytes.NewReader(make([]byte, 100)) + if rs := NewReadSeeker(buf); len(rs.buf) != defaultBufSize { + t.Fatalf("want %d got %d", defaultBufSize, len(rs.buf)) + } +} + +func TestReadSeeker_Read(t *testing.T) { + data := make([]byte, 100) + for i := range data { + data[i] = byte(i) + } + rs := NewReadSeekerSize(bytes.NewReader(data), 20) + if len(rs.buf) != 20 { + t.Fatal("the buffer size was changed and the validity of this test has become unknown") + } + + // Test small read. + got := make([]byte, 5) + if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{0, 1, 2, 3, 4}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{0, 1, 2, 3, 4}, got, err) + } + if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 5 { + t.Fatalf("want %d got %d, err=%v", 5, p, err) + } + + // Test big read with initially filled buffer. + got = make([]byte, 25) + if n, err := rs.Read(got); err != nil || n != 15 || !reflect.DeepEqual(got, []byte{5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 15, n, []byte{5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, got, err) + } + if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 20 { + t.Fatalf("want %d got %d, err=%v", 20, p, err) + } + + // Test big read with initially empty buffer. + if n, err := rs.Read(got); err != nil || n != 25 || !reflect.DeepEqual(got, []byte{20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 25, n, []byte{20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44}, got, err) + } + if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 45 { + t.Fatalf("want %d got %d, err=%v", 45, p, err) + } + + // Test EOF. + if p, err := rs.Seek(98, io.SeekStart); err != nil || p != 98 { + t.Fatalf("want %d got %d, err=%v", 98, p, err) + } + got = make([]byte, 5) + if n, err := rs.Read(got); err != nil || n != 2 || !reflect.DeepEqual(got, []byte{98, 99, 0, 0, 0}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 2, n, []byte{98, 99, 0, 0, 0}, got, err) + } + if n, err := rs.Read(got); err != io.EOF || n != 0 { + t.Fatalf("want n read %d got %d, err=%v", 0, n, err) + } + + // Test source that returns bytes and an error at the same time. + rs = NewReadSeekerSize(&readAndError{bytes: []byte{2, 3, 5}}, 20) + if len(rs.buf) != 20 { + t.Fatal("the buffer size was changed and the validity of this test has become unknown") + } + got = make([]byte, 5) + if n, err := rs.Read(got); err != nil || n != 3 || !reflect.DeepEqual(got, []byte{2, 3, 5, 0, 0}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 3, n, []byte{2, 3, 5, 0, 0}, got, err) + } + if n, err := rs.Read(got); err != expectedErr || n != 0 { + t.Fatalf("want n read %d got %d, want error %v, got %v", 0, n, expectedErr, err) + } + + // Test read nothing with an empty buffer and a queued error. + rs = NewReadSeekerSize(&readAndError{bytes: []byte{2, 3, 5}}, 20) + if len(rs.buf) != 20 { + t.Fatal("the buffer size was changed and the validity of this test has become unknown") + } + got = make([]byte, 3) + if n, err := rs.Read(got); err != nil || n != 3 || !reflect.DeepEqual(got, []byte{2, 3, 5}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 3, n, []byte{2, 3, 5}, got, err) + } + if n, err := rs.Read(nil); err != expectedErr || n != 0 { + t.Fatalf("want n read %d got %d, want error %v, got %v", 0, n, expectedErr, err) + } + if n, err := rs.Read(nil); err != nil || n != 0 { + t.Fatalf("want n read %d got %d, err=%v", 0, n, err) + } + + // Test read nothing with a non-empty buffer and a queued error. + rs = NewReadSeekerSize(&readAndError{bytes: []byte{2, 3, 5}}, 20) + if len(rs.buf) != 20 { + t.Fatal("the buffer size was changed and the validity of this test has become unknown") + } + got = make([]byte, 1) + if n, err := rs.Read(got); err != nil || n != 1 || !reflect.DeepEqual(got, []byte{2}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 1, n, []byte{}, got, err) + } + if n, err := rs.Read(nil); err != nil || n != 0 { + t.Fatalf("want n read %d got %d, err=%v", 0, n, err) + } +} + +var expectedErr = errors.New("expected error") + +type readAndError struct { + bytes []byte +} + +func (r *readAndError) Read(p []byte) (n int, err error) { + for i, b := range r.bytes { + p[i] = b + } + return len(r.bytes), expectedErr +} + +func (r *readAndError) Seek(offset int64, whence int) (int64, error) { + panic("not implemented") +} + +func TestReadSeeker_Seek(t *testing.T) { + data := make([]byte, 100) + for i := range data { + data[i] = byte(i) + } + r := &seekRecorder{rs: bytes.NewReader(data)} + rs := NewReadSeekerSize(r, 20) + if len(rs.buf) != 20 { + t.Fatal("the buffer size was changed and the validity of this test has become unknown") + } + + got := make([]byte, 5) + + // Test with io.SeekStart + if p, err := rs.Seek(10, io.SeekStart); err != nil || p != 10 { + t.Fatalf("want %d got %d, err=%v", 10, p, err) + } + r.assertSeeked(t, []seekRecord{{10, io.SeekStart}}) + if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{10, 11, 12, 13, 14}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{10, 11, 12, 13, 14}, got, err) + } + if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 15 { + t.Fatalf("want %d got %d, err=%v", 15, p, err) + } + r.assertSeeked(t, nil) + + // Test with io.SeekCurrent and positive offset within buffer. + if p, err := rs.Seek(5, io.SeekCurrent); err != nil || p != 20 { + t.Fatalf("want %d got %d, err=%v", 20, p, err) + } + r.assertSeeked(t, nil) + if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{20, 21, 22, 23, 24}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{20, 21, 22, 23, 24}, got, err) + } + if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 25 { + t.Fatalf("want %d got %d, err=%v", 25, p, err) + } + + // Test with io.SeekCurrent and negative offset within buffer. + if p, err := rs.Seek(-10, io.SeekCurrent); err != nil || p != 15 { + t.Fatalf("want %d got %d, err=%v", 15, p, err) + } + r.assertSeeked(t, nil) + if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{15, 16, 17, 18, 19}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{15, 16, 17, 18, 19}, got, err) + } + if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 20 { + t.Fatalf("want %d got %d, err=%v", 20, p, err) + } + + // Test with io.SeekCurrent and positive offset outside buffer. + if p, err := rs.Seek(30, io.SeekCurrent); err != nil || p != 50 { + t.Fatalf("want %d got %d, err=%v", 50, p, err) + } + r.assertSeeked(t, []seekRecord{{50, io.SeekStart}}) + if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{50, 51, 52, 53, 54}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{50, 51, 52, 53, 54}, got, err) + } + if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 55 { + t.Fatalf("want %d got %d, err=%v", 55, p, err) + } + + // Test seek with io.SeekEnd within buffer. + if p, err := rs.Seek(-45, io.SeekEnd); err != nil || p != 55 { + t.Fatalf("want %d got %d, err=%v", 55, p, err) + } + r.assertSeeked(t, []seekRecord{{-45, io.SeekEnd}}) + if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{55, 56, 57, 58, 59}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{55, 56, 57, 58, 59}, got, err) + } + if p, err := rs.Seek(0, io.SeekCurrent); err != nil || p != 60 { + t.Fatalf("want %d got %d, err=%v", 60, p, err) + } + + // Test seek with error. + if _, err := rs.Seek(-100, io.SeekStart); err == nil || err.Error() != "bytes.Reader.Seek: negative position" { + t.Fatalf("want error 'bytes.Reader.Seek: negative position' got %v", err) + } + r.assertSeeked(t, []seekRecord{{-100, io.SeekStart}}) + + // Test seek after error. + if p, err := rs.Seek(10, io.SeekStart); err != nil || p != 10 { + t.Fatalf("want %d got %d, err=%v", 10, p, err) + } + r.assertSeeked(t, []seekRecord{{10, io.SeekStart}}) + if n, err := rs.Read(got); err != nil || n != 5 || !reflect.DeepEqual(got, []byte{10, 11, 12, 13, 14}) { + t.Fatalf("want n read %d got %d, want buffer %v got %v, err=%v", 5, n, []byte{10, 11, 12, 13, 14}, got, err) + } +} + +type seekRecord struct { + offset int64 + whence int +} + +type seekRecorder struct { + rs io.ReadSeeker + seeks []seekRecord +} + +func (r *seekRecorder) Read(p []byte) (n int, err error) { + return r.rs.Read(p) +} + +func (r *seekRecorder) Seek(offset int64, whence int) (int64, error) { + r.seeks = append(r.seeks, seekRecord{offset: offset, whence: whence}) + return r.rs.Seek(offset, whence) +} + +func (r *seekRecorder) assertSeeked(t *testing.T, expected []seekRecord) { + t.Helper() + + if !reflect.DeepEqual(expected, r.seeks) { + t.Fatalf("seek mismatch; expected %#v, got %#v", expected, r.seeks) + } + r.reset() +} + +func (r *seekRecorder) reset() { + r.seeks = nil +} diff --git a/internal/hashutil/crc16/crc16.go b/internal/hashutil/crc16/crc16.go new file mode 100755 index 0000000..4e963c6 --- /dev/null +++ b/internal/hashutil/crc16/crc16.go @@ -0,0 +1,115 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package crc16 implements the 16-bit cyclic redundancy check, or CRC-16, +// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check and +// http://www.ross.net/crc/download/crc_v3.txt for information. +package crc16 + +import "github.com/mewkiz/flac/internal/hashutil" + +// Size of a CRC-16 checksum in bytes. +const Size = 2 + +// Predefined polynomials. +const ( + IBM = 0x8005 // x^16 + x^15 + x^2 + x^0 +) + +// Table is a 256-word table representing the polynomial for efficient +// processing. +type Table [256]uint16 + +// IBMTable is the table for the IBM polynomial. +var IBMTable = makeTable(IBM) + +// MakeTable returns the Table constructed from the specified polynomial. +func MakeTable(poly uint16) (table *Table) { + switch poly { + case IBM: + return IBMTable + } + return makeTable(poly) +} + +// makeTable returns the Table constructed from the specified polynomial. +func makeTable(poly uint16) (table *Table) { + table = new(Table) + for i := range table { + crc := uint16(i << 8) + for j := 0; j < 8; j++ { + if crc&0x8000 != 0 { + crc = crc<<1 ^ poly + } else { + crc <<= 1 + } + } + table[i] = crc + } + return table +} + +// digest represents the partial evaluation of a checksum. +type digest struct { + crc uint16 + table *Table +} + +// New creates a new hashutil.Hash16 computing the CRC-16 checksum using the +// polynomial represented by the Table. +func New(table *Table) hashutil.Hash16 { + return &digest{0, table} +} + +// NewIBM creates a new hashutil.Hash16 computing the CRC-16 checksum using the +// IBM polynomial. +func NewIBM() hashutil.Hash16 { + return New(IBMTable) +} + +func (d *digest) Size() int { + return Size +} + +func (d *digest) BlockSize() int { + return 1 +} + +func (d *digest) Reset() { + d.crc = 0 +} + +// Update returns the result of adding the bytes in p to the crc. +func Update(crc uint16, table *Table, p []byte) uint16 { + for _, v := range p { + crc = crc<<8 ^ table[crc>>8^uint16(v)] + } + return crc +} + +func (d *digest) Write(p []byte) (n int, err error) { + d.crc = Update(d.crc, d.table, p) + return len(p), nil +} + +// Sum16 returns the 16-bit checksum of the hash. +func (d *digest) Sum16() uint16 { + return d.crc +} + +func (d *digest) Sum(in []byte) []byte { + s := d.Sum16() + return append(in, byte(s>>8), byte(s)) +} + +// Checksum returns the CRC-16 checksum of data, using the polynomial +// represented by the Table. +func Checksum(data []byte, table *Table) uint16 { + return Update(0, table, data) +} + +// ChecksumIBM returns the CRC-16 checksum of data using the IBM polynomial. +func ChecksumIBM(data []byte) uint16 { + return Update(0, IBMTable, data) +} diff --git a/internal/hashutil/crc16/crc16_test.go b/internal/hashutil/crc16/crc16_test.go new file mode 100755 index 0000000..1741087 --- /dev/null +++ b/internal/hashutil/crc16/crc16_test.go @@ -0,0 +1,106 @@ +package crc16 + +import ( + "io" + "testing" +) + +type test struct { + want uint16 + in string +} + +var golden = []test{ + {0x0000, ""}, + {0x8145, "a"}, + {0xC749, "ab"}, + {0xCADB, "abc"}, + {0x58E7, "abcd"}, + {0x678D, "abcde"}, + {0x0D05, "abcdef"}, + {0x047C, "abcdefg"}, + {0x7D68, "abcdefgh"}, + {0x6878, "abcdefghi"}, + {0xF80F, "abcdefghij"}, + {0x0F8E, "Discard medicine more than two years old."}, + {0xE149, "He who has a shady past knows that nice guys finish last."}, + {0x02B7, "I wouldn't marry him with a ten foot pole."}, + {0x7F6A, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, + {0x28BD, "The days of the digital watch are numbered. -Tom Stoppard"}, + {0x7C55, "Nepal premier won't resign."}, + {0xC92B, "For every action there is an equal and opposite government program."}, + {0x3E41, "His money is twice tainted: 'taint yours and 'taint mine."}, + {0xDA56, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, + {0x7F66, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, + {0x2A00, "size: a.out: bad magic"}, + {0x25B2, "The major problem is with sendmail. -Mark Horton"}, + {0xBD71, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, + {0x8596, "If the enemy is within range, then so are you."}, + {0x74A2, "It's well we cannot hear the screams/That we create in others' dreams."}, + {0x0D73, "You remind me of a TV show, but that's all right: I watch it anyway."}, + {0xEE65, "C is as portable as Stonehedge!!"}, + {0xA94E, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, + {0x0B98, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, + {0xF560, "How can you write a big system without C++? -Paul Glick"}, + {0x60AE, "The quick brown fox jumps over the lazy dog"}, +} + +func TestCrc16IBM(t *testing.T) { + for _, g := range golden { + h := NewIBM() + if _, err := io.WriteString(h, g.in); err != nil { + t.Error(err) + continue + } + got := h.Sum16() + if got != g.want { + t.Errorf("IBM(%q); expected 0x%04X, got 0x%04X.", g.in, g.want, got) + } + } +} + +func BenchmarkNewIBM(b *testing.B) { + for i := 0; i < b.N; i++ { + NewIBM() + } +} + +func BenchmarkCrc16_1K(b *testing.B) { + benchmarkCrc16(b, 1024) +} + +func BenchmarkCrc16_2K(b *testing.B) { + benchmarkCrc16(b, 2*1024) +} + +func BenchmarkCrc16_4K(b *testing.B) { + benchmarkCrc16(b, 4*1024) +} + +func BenchmarkCrc16_8K(b *testing.B) { + benchmarkCrc16(b, 8*1024) +} + +func BenchmarkCrc16_16K(b *testing.B) { + benchmarkCrc16(b, 16*1024) +} + +func benchmarkCrc16(b *testing.B, count int64) { + b.SetBytes(count) + data := make([]byte, count) + for i := range data { + data[i] = byte(i) + } + h := NewIBM() + in := make([]byte, 0, h.Size()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + h.Reset() + if _, err := h.Write(data); err != nil { + b.Error(err) + continue + } + h.Sum(in) + } +} diff --git a/internal/hashutil/crc8/crc8.go b/internal/hashutil/crc8/crc8.go new file mode 100755 index 0000000..f701373 --- /dev/null +++ b/internal/hashutil/crc8/crc8.go @@ -0,0 +1,114 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package crc8 implements the 8-bit cyclic redundancy check, or CRC-8, +// checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check and +// http://www.ross.net/crc/download/crc_v3.txt for information. +package crc8 + +import "github.com/mewkiz/flac/internal/hashutil" + +// Size of a CRC-8 checksum in bytes. +const Size = 1 + +// Predefined polynomials. +const ( + ATM = 0x07 // x^8 + x^2 + x + 1 +) + +// Table is a 256-word table representing the polynomial for efficient +// processing. +type Table [256]uint8 + +// ATMTable is the table for the ATM polynomial. +var ATMTable = makeTable(ATM) + +// MakeTable returns the Table constructed from the specified polynomial. +func MakeTable(poly uint8) (table *Table) { + switch poly { + case ATM: + return ATMTable + } + return makeTable(poly) +} + +// makeTable returns the Table constructed from the specified polynomial. +func makeTable(poly uint8) (table *Table) { + table = new(Table) + for i := range table { + crc := uint8(i) + for j := 0; j < 8; j++ { + if crc&0x80 != 0 { + crc = crc<<1 ^ poly + } else { + crc <<= 1 + } + } + table[i] = crc + } + return table +} + +// digest represents the partial evaluation of a checksum. +type digest struct { + crc uint8 + table *Table +} + +// New creates a new hashutil.Hash8 computing the CRC-8 checksum using the +// polynomial represented by the Table. +func New(table *Table) hashutil.Hash8 { + return &digest{0, table} +} + +// NewATM creates a new hashutil.Hash8 computing the CRC-8 checksum using the +// ATM polynomial. +func NewATM() hashutil.Hash8 { + return New(ATMTable) +} + +func (d *digest) Size() int { + return Size +} + +func (d *digest) BlockSize() int { + return 1 +} + +func (d *digest) Reset() { + d.crc = 0 +} + +// Update returns the result of adding the bytes in p to the crc. +func Update(crc uint8, table *Table, p []byte) uint8 { + for _, v := range p { + crc = table[crc^v] + } + return crc +} + +func (d *digest) Write(p []byte) (n int, err error) { + d.crc = Update(d.crc, d.table, p) + return len(p), nil +} + +// Sum8 returns the 8-bit checksum of the hash. +func (d *digest) Sum8() uint8 { + return d.crc +} + +func (d *digest) Sum(in []byte) []byte { + return append(in, d.crc) +} + +// Checksum returns the CRC-8 checksum of data, using the polynomial represented +// by the Table. +func Checksum(data []byte, table *Table) uint8 { + return Update(0, table, data) +} + +// ChecksumATM returns the CRC-8 checksum of data using the ATM polynomial. +func ChecksumATM(data []byte) uint8 { + return Update(0, ATMTable, data) +} diff --git a/internal/hashutil/crc8/crc8_test.go b/internal/hashutil/crc8/crc8_test.go new file mode 100755 index 0000000..5e639ab --- /dev/null +++ b/internal/hashutil/crc8/crc8_test.go @@ -0,0 +1,106 @@ +package crc8 + +import ( + "io" + "testing" +) + +type test struct { + want uint8 + in string +} + +var golden = []test{ + {0x00, ""}, + {0x20, "a"}, + {0xC9, "ab"}, + {0x5F, "abc"}, + {0xA1, "abcd"}, + {0x52, "abcde"}, + {0x8C, "abcdef"}, + {0x9F, "abcdefg"}, + {0xCB, "abcdefgh"}, + {0x67, "abcdefghi"}, + {0x23, "abcdefghij"}, + {0x56, "Discard medicine more than two years old."}, + {0x6B, "He who has a shady past knows that nice guys finish last."}, + {0x70, "I wouldn't marry him with a ten foot pole."}, + {0x8F, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, + {0x48, "The days of the digital watch are numbered. -Tom Stoppard"}, + {0x5E, "Nepal premier won't resign."}, + {0x3C, "For every action there is an equal and opposite government program."}, + {0xA8, "His money is twice tainted: 'taint yours and 'taint mine."}, + {0x46, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, + {0xC7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, + {0x31, "size: a.out: bad magic"}, + {0xB6, "The major problem is with sendmail. -Mark Horton"}, + {0x7D, "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, + {0xDC, "If the enemy is within range, then so are you."}, + {0x13, "It's well we cannot hear the screams/That we create in others' dreams."}, + {0x96, "You remind me of a TV show, but that's all right: I watch it anyway."}, + {0x96, "C is as portable as Stonehedge!!"}, + {0x3C, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, + {0xEE, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, + {0x33, "How can you write a big system without C++? -Paul Glick"}, + {0xC1, "The quick brown fox jumps over the lazy dog"}, +} + +func TestCrc8ATM(t *testing.T) { + for _, g := range golden { + h := NewATM() + if _, err := io.WriteString(h, g.in); err != nil { + t.Error(err) + continue + } + got := h.Sum8() + if got != g.want { + t.Errorf("ATM(%q); expected 0x%02X, got 0x%02X.", g.in, g.want, got) + } + } +} + +func BenchmarkNewATM(b *testing.B) { + for i := 0; i < b.N; i++ { + NewATM() + } +} + +func BenchmarkCrc8_1K(b *testing.B) { + benchmarkCrc8(b, 1024) +} + +func BenchmarkCrc8_2K(b *testing.B) { + benchmarkCrc8(b, 2*1024) +} + +func BenchmarkCrc8_4K(b *testing.B) { + benchmarkCrc8(b, 4*1024) +} + +func BenchmarkCrc8_8K(b *testing.B) { + benchmarkCrc8(b, 8*1024) +} + +func BenchmarkCrc8_16K(b *testing.B) { + benchmarkCrc8(b, 16*1024) +} + +func benchmarkCrc8(b *testing.B, count int64) { + b.SetBytes(count) + data := make([]byte, count) + for i := range data { + data[i] = byte(i) + } + h := NewATM() + in := make([]byte, 0, h.Size()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + h.Reset() + if _, err := h.Write(data); err != nil { + b.Error(err) + continue + } + h.Sum(in) + } +} diff --git a/internal/hashutil/hashutil.go b/internal/hashutil/hashutil.go new file mode 100755 index 0000000..5976032 --- /dev/null +++ b/internal/hashutil/hashutil.go @@ -0,0 +1,18 @@ +// Package hashutil provides utility interfaces for hash functions. +package hashutil + +import "hash" + +// Hash8 is the common interface implemented by all 8-bit hash functions. +type Hash8 interface { + hash.Hash + // Sum8 returns the 8-bit checksum of the hash. + Sum8() uint8 +} + +// Hash16 is the common interface implemented by all 16-bit hash functions. +type Hash16 interface { + hash.Hash + // Sum16 returns the 16-bit checksum of the hash. + Sum16() uint16 +} diff --git a/internal/ioutilx/byte.go b/internal/ioutilx/byte.go new file mode 100755 index 0000000..33b9dd0 --- /dev/null +++ b/internal/ioutilx/byte.go @@ -0,0 +1,24 @@ +// Package ioutilx implements extended input/output utility functions. +package ioutilx + +import ( + "io" +) + +// ReadByte reads and returns the next byte from r. +func ReadByte(r io.Reader) (byte, error) { + var buf [1]byte + if _, err := io.ReadFull(r, buf[:]); err != nil { + return 0, err + } + return buf[0], nil +} + +// WriteByte writes the given byte to w. +func WriteByte(w io.Writer, b byte) error { + buf := [1]byte{b} + if _, err := w.Write(buf[:]); err != nil { + return err + } + return nil +} diff --git a/internal/ioutilx/zero.go b/internal/ioutilx/zero.go new file mode 100755 index 0000000..bdd9a14 --- /dev/null +++ b/internal/ioutilx/zero.go @@ -0,0 +1,17 @@ +package ioutilx + +// Zero is an io.Reader which always reads zero bytes. +var Zero zero + +// zero is an io.Reader which always reads zero bytes. +type zero struct { +} + +// Read reads len(b) zero bytes into b. It returns the number of bytes read and +// a nil error value. +func (zero) Read(b []byte) (n int, err error) { + for i := range b { + b[i] = 0 + } + return len(b), nil +} diff --git a/internal/utf8/decode.go b/internal/utf8/decode.go new file mode 100755 index 0000000..ce7fde5 --- /dev/null +++ b/internal/utf8/decode.go @@ -0,0 +1,160 @@ +// Package utf8 implements encoding and decoding of UTF-8 coded numbers. +package utf8 + +import ( + "errors" + "fmt" + "io" + + "github.com/mewkiz/flac/internal/ioutilx" +) + +const ( + tx = 0x80 // 1000 0000 + t2 = 0xC0 // 1100 0000 + t3 = 0xE0 // 1110 0000 + t4 = 0xF0 // 1111 0000 + t5 = 0xF8 // 1111 1000 + t6 = 0xFC // 1111 1100 + t7 = 0xFE // 1111 1110 + t8 = 0xFF // 1111 1111 + + maskx = 0x3F // 0011 1111 + mask2 = 0x1F // 0001 1111 + mask3 = 0x0F // 0000 1111 + mask4 = 0x07 // 0000 0111 + mask5 = 0x03 // 0000 0011 + mask6 = 0x01 // 0000 0001 + + rune1Max = 1<<7 - 1 + rune2Max = 1<<11 - 1 + rune3Max = 1<<16 - 1 + rune4Max = 1<<21 - 1 + rune5Max = 1<<26 - 1 + rune6Max = 1<<31 - 1 + rune7Max = 1<<36 - 1 +) + +// Decode decodes a "UTF-8" coded number and returns it. +// +// ref: http://permalink.gmane.org/gmane.comp.audio.compression.flac.devel/3033 +// +// Algorithm description: +// - read one byte B0 from the stream +// - if B0 = 0xxxxxxx then the read value is B0 -> end +// - if B0 = 10xxxxxx, the encoding is invalid +// - if B0 = 11xxxxxx, set L to the number of leading binary 1s minus 1: +// B0 = 110xxxxx -> L = 1 +// B0 = 1110xxxx -> L = 2 +// B0 = 11110xxx -> L = 3 +// B0 = 111110xx -> L = 4 +// B0 = 1111110x -> L = 5 +// B0 = 11111110 -> L = 6 +// - assign the bits following the encoding (the x bits in the examples) to +// a variable R with a magnitude of at least 36 bits +// - loop from 1 to L +// - left shift R 6 bits +// - read B from the stream +// - if B does not match 10xxxxxx, the encoding is invalid +// - set R = R or +// - the read value is R +func Decode(r io.Reader) (x uint64, err error) { + c0, err := ioutilx.ReadByte(r) + if err != nil { + return 0, err + } + + // 1-byte, 7-bit sequence? + if c0 < tx { + // if c0 == 0xxxxxxx + // total: 7 bits (7) + return uint64(c0), nil + } + + // unexpected continuation byte? + if c0 < t2 { + // if c0 == 10xxxxxx + return 0, errors.New("frame.decodeUTF8Int: unexpected continuation byte") + } + + // get number of continuation bytes and store bits from c0. + var l int + switch { + case c0 < t3: + // if c0 == 110xxxxx + // total: 11 bits (5 + 6) + l = 1 + x = uint64(c0 & mask2) + case c0 < t4: + // if c0 == 1110xxxx + // total: 16 bits (4 + 6 + 6) + l = 2 + x = uint64(c0 & mask3) + case c0 < t5: + // if c0 == 11110xxx + // total: 21 bits (3 + 6 + 6 + 6) + l = 3 + x = uint64(c0 & mask4) + case c0 < t6: + // if c0 == 111110xx + // total: 26 bits (2 + 6 + 6 + 6 + 6) + l = 4 + x = uint64(c0 & mask5) + case c0 < t7: + // if c0 == 1111110x + // total: 31 bits (1 + 6 + 6 + 6 + 6 + 6) + l = 5 + x = uint64(c0 & mask6) + case c0 < t8: + // if c0 == 11111110 + // total: 36 bits (0 + 6 + 6 + 6 + 6 + 6 + 6) + l = 6 + x = 0 + } + + // store bits from continuation bytes. + for i := 0; i < l; i++ { + x <<= 6 + c, err := ioutilx.ReadByte(r) + if err != nil { + if err == io.EOF { + return 0, io.ErrUnexpectedEOF + } + return 0, err + } + if c < tx || t2 <= c { + // if c != 10xxxxxx + return 0, errors.New("frame.decodeUTF8Int: expected continuation byte") + } + x |= uint64(c & maskx) + } + + // check if number representation is larger than necessary. + switch l { + case 1: + if x <= rune1Max { + return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l) + } + case 2: + if x <= rune2Max { + return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l) + } + case 3: + if x <= rune3Max { + return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l) + } + case 4: + if x <= rune4Max { + return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l) + } + case 5: + if x <= rune5Max { + return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l) + } + case 6: + if x <= rune6Max { + return 0, fmt.Errorf("frame.decodeUTF8Int: larger number representation than necessary; x (%d) stored in %d bytes, could be stored in %d bytes", x, l+1, l) + } + } + return x, nil +} diff --git a/internal/utf8/encode.go b/internal/utf8/encode.go new file mode 100755 index 0000000..43f263b --- /dev/null +++ b/internal/utf8/encode.go @@ -0,0 +1,72 @@ +package utf8 + +import ( + "io" + + "github.com/mewkiz/flac/internal/ioutilx" + "github.com/mewkiz/pkg/errutil" +) + +// Encode encodes x as a "UTF-8" coded number. +func Encode(w io.Writer, x uint64) error { + // 1-byte, 7-bit sequence? + if x <= rune1Max { + if err := ioutilx.WriteByte(w, byte(x)); err != nil { + return errutil.Err(err) + } + return nil + } + + // get number of continuation bytes and store bits of c0. + var ( + // number of continuation bytes., + l int + // bits of c0. + bits uint64 + ) + switch { + case x <= rune2Max: + // if c0 == 110xxxxx + // total: 11 bits (5 + 6) + l = 1 + bits = t2 | (x>>6)&mask2 + case x <= rune3Max: + // if c0 == 1110xxxx + // total: 16 bits (4 + 6 + 6) + l = 2 + bits = t3 | (x>>(6*2))&mask3 + case x <= rune4Max: + // if c0 == 11110xxx + // total: 21 bits (3 + 6 + 6 + 6) + l = 3 + bits = t4 | (x>>(6*3))&mask4 + case x <= rune5Max: + // if c0 == 111110xx + // total: 26 bits (2 + 6 + 6 + 6 + 6) + l = 4 + bits = t5 | (x>>(6*4))&mask5 + case x <= rune6Max: + // if c0 == 1111110x + // total: 31 bits (1 + 6 + 6 + 6 + 6 + 6) + l = 5 + bits = t6 | (x>>(6*5))&mask6 + case x <= rune7Max: + // if c0 == 11111110 + // total: 36 bits (0 + 6 + 6 + 6 + 6 + 6 + 6) + l = 6 + bits = 0 + } + // Store bits of c0. + if err := ioutilx.WriteByte(w, byte(bits)); err != nil { + return errutil.Err(err) + } + + // Store continuation bytes. + for i := l - 1; i >= 0; i-- { + bits := tx | (x>>uint(6*i))&maskx + if err := ioutilx.WriteByte(w, byte(bits)); err != nil { + return errutil.Err(err) + } + } + return nil +} diff --git a/meta/application.go b/meta/application.go new file mode 100755 index 0000000..6f5a2e2 --- /dev/null +++ b/meta/application.go @@ -0,0 +1,38 @@ +package meta + +import ( + "encoding/binary" + "io/ioutil" +) + +// Application contains third party application specific data. +// +// ref: https://www.xiph.org/flac/format.html#metadata_block_application +type Application struct { + // Registered application ID. + // + // ref: https://www.xiph.org/flac/id.html + ID uint32 + // Application data. + Data []byte +} + +// parseApplication reads and parses the body of an Application metadata block. +func (block *Block) parseApplication() error { + // 32 bits: ID. + app := new(Application) + block.Body = app + err := binary.Read(block.lr, binary.BigEndian, &app.ID) + if err != nil { + return unexpected(err) + } + + // Check if the Application block only contains an ID. + if block.Length == 4 { + return nil + } + + // (block length)-4 bytes: Data. + app.Data, err = ioutil.ReadAll(block.lr) + return unexpected(err) +} diff --git a/meta/cuesheet.go b/meta/cuesheet.go new file mode 100755 index 0000000..d066267 --- /dev/null +++ b/meta/cuesheet.go @@ -0,0 +1,242 @@ +package meta + +import ( + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "strings" +) + +// A CueSheet describes how tracks are laid out within a FLAC stream. +// +// ref: https://www.xiph.org/flac/format.html#metadata_block_cuesheet +type CueSheet struct { + // Media catalog number. + MCN string + // Number of lead-in samples. This field only has meaning for CD-DA cue + // sheets; for other uses it should be 0. Refer to the spec for additional + // information. + NLeadInSamples uint64 + // Specifies if the cue sheet corresponds to a Compact Disc. + IsCompactDisc bool + // One or more tracks. The last track of a cue sheet is always the lead-out + // track. + Tracks []CueSheetTrack +} + +// parseCueSheet reads and parses the body of a CueSheet metadata block. +func (block *Block) parseCueSheet() error { + // Parse cue sheet. + // 128 bytes: MCN. + szMCN, err := readString(block.lr, 128) + if err != nil { + return unexpected(err) + } + cs := &CueSheet{ + MCN: stringFromSZ(szMCN), + } + block.Body = cs + + // 64 bits: NLeadInSamples. + if err = binary.Read(block.lr, binary.BigEndian, &cs.NLeadInSamples); err != nil { + return unexpected(err) + } + + // 1 bit: IsCompactDisc. + var x uint8 + if err := binary.Read(block.lr, binary.BigEndian, &x); err != nil { + return unexpected(err) + } + // mask = 10000000 + if x&0x80 != 0 { + cs.IsCompactDisc = true + } + + // 7 bits and 258 bytes: reserved. + // mask = 01111111 + if x&0x7F != 0 { + return ErrInvalidPadding + } + lr := io.LimitReader(block.lr, 258) + zr := zeros{r: lr} + if _, err := io.Copy(ioutil.Discard, zr); err != nil { + return err + } + + // Parse cue sheet tracks. + // 8 bits: (number of tracks) + if err := binary.Read(block.lr, binary.BigEndian, &x); err != nil { + return unexpected(err) + } + if x < 1 { + return errors.New("meta.Block.parseCueSheet: at least one track required") + } + if cs.IsCompactDisc && x > 100 { + return fmt.Errorf("meta.Block.parseCueSheet: number of CD-DA tracks (%d) exceeds 100", x) + } + cs.Tracks = make([]CueSheetTrack, x) + // Each track number within a cue sheet must be unique; use uniq to keep + // track. + uniq := make(map[uint8]struct{}) + for i := range cs.Tracks { + if err := block.parseTrack(cs, i, uniq); err != nil { + return err + } + } + + return nil +} + +// parseTrack parses the i:th cue sheet track, and ensures that its track number +// is unique. +func (block *Block) parseTrack(cs *CueSheet, i int, uniq map[uint8]struct{}) error { + track := &cs.Tracks[i] + // 64 bits: Offset. + if err := binary.Read(block.lr, binary.BigEndian, &track.Offset); err != nil { + return unexpected(err) + } + if cs.IsCompactDisc && track.Offset%588 != 0 { + return fmt.Errorf("meta.Block.parseCueSheet: CD-DA track offset (%d) must be evenly divisible by 588", track.Offset) + } + + // 8 bits: Num. + if err := binary.Read(block.lr, binary.BigEndian, &track.Num); err != nil { + return unexpected(err) + } + if _, ok := uniq[track.Num]; ok { + return fmt.Errorf("meta.Block.parseCueSheet: duplicated track number %d", track.Num) + } + uniq[track.Num] = struct{}{} + if track.Num == 0 { + return errors.New("meta.Block.parseCueSheet: invalid track number (0)") + } + isLeadOut := i == len(cs.Tracks)-1 + if cs.IsCompactDisc { + if !isLeadOut { + if track.Num >= 100 { + return fmt.Errorf("meta.Block.parseCueSheet: CD-DA track number (%d) exceeds 99", track.Num) + } + } else { + if track.Num != 170 { + return fmt.Errorf("meta.Block.parseCueSheet: invalid lead-out CD-DA track number; expected 170, got %d", track.Num) + } + } + } else { + if isLeadOut && track.Num != 255 { + return fmt.Errorf("meta.Block.parseCueSheet: invalid lead-out track number; expected 255, got %d", track.Num) + } + } + + // 12 bytes: ISRC. + szISRC, err := readString(block.lr, 12) + if err != nil { + return unexpected(err) + } + track.ISRC = stringFromSZ(szISRC) + + // 1 bit: IsAudio. + var x uint8 + if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil { + return unexpected(err) + } + // mask = 10000000 + if x&0x80 == 0 { + track.IsAudio = true + } + + // 1 bit: HasPreEmphasis. + // mask = 01000000 + if x&0x40 != 0 { + track.HasPreEmphasis = true + } + + // 6 bits and 13 bytes: reserved. + // mask = 00111111 + if x&0x3F != 0 { + return ErrInvalidPadding + } + lr := io.LimitReader(block.lr, 13) + zr := zeros{r: lr} + _, err = io.Copy(ioutil.Discard, zr) + if err != nil { + return err + } + + // Parse indicies. + // 8 bits: (number of indicies) + if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil { + return unexpected(err) + } + if x < 1 { + if !isLeadOut { + return errors.New("meta.Block.parseCueSheet: at least one track index required") + } + // Lead-out track has no track indices to parse; return early. + return nil + } + track.Indicies = make([]CueSheetTrackIndex, x) + for i := range track.Indicies { + index := &track.Indicies[i] + // 64 bits: Offset. + if err = binary.Read(block.lr, binary.BigEndian, &index.Offset); err != nil { + return unexpected(err) + } + + // 8 bits: Num. + if err = binary.Read(block.lr, binary.BigEndian, &index.Num); err != nil { + return unexpected(err) + } + + // 3 bytes: reserved. + lr = io.LimitReader(block.lr, 3) + zr = zeros{r: lr} + _, err = io.Copy(ioutil.Discard, zr) + if err != nil { + return err + } + } + return nil +} + +// stringFromSZ returns a copy of the given string terminated at the first +// occurrence of a NULL character. +func stringFromSZ(szStr string) string { + pos := strings.IndexByte(szStr, '\x00') + if pos == -1 { + return szStr + } + return string(szStr[:pos]) +} + +// CueSheetTrack contains the start offset of a track and other track specific +// metadata. +type CueSheetTrack struct { + // Track offset in samples, relative to the beginning of the FLAC audio + // stream. + Offset uint64 + // Track number; never 0, always unique. + Num uint8 + // International Standard Recording Code; empty string if not present. + // + // ref: http://isrc.ifpi.org/ + ISRC string + // Specifies if the track contains audio or data. + IsAudio bool + // Specifies if the track has been recorded with pre-emphasis + HasPreEmphasis bool + // Every track has one or more track index points, except for the lead-out + // track which has zero. Each index point specifies a position within the + // track. + Indicies []CueSheetTrackIndex +} + +// A CueSheetTrackIndex specifies a position within a track. +type CueSheetTrackIndex struct { + // Index point offset in samples, relative to the track offset. + Offset uint64 + // Index point number; subsequently incrementing by 1 and always unique + // within a track. + Num uint8 +} diff --git a/meta/meta.go b/meta/meta.go new file mode 100755 index 0000000..9f91db2 --- /dev/null +++ b/meta/meta.go @@ -0,0 +1,210 @@ +// Package meta implements access to FLAC metadata blocks. +// +// A brief introduction of the FLAC metadata format [1] follows. FLAC metadata +// is stored in blocks; each block contains a header followed by a body. The +// block header describes the type of the block body, its length in bytes, and +// specifies if the block was the last metadata block in a FLAC stream. The +// contents of the block body depends on the type specified in the block header. +// +// At the time of this writing, the FLAC metadata format defines seven different +// metadata block types, namely: +// - StreamInfo [2] +// - Padding [3] +// - Application [4] +// - SeekTable [5] +// - VorbisComment [6] +// - CueSheet [7] +// - Picture [8] +// +// Please refer to their respective documentation for further information. +// +// [1]: https://www.xiph.org/flac/format.html#format_overview +// [2]: https://godoc.org/github.com/mewkiz/flac/meta#StreamInfo +// [3]: https://www.xiph.org/flac/format.html#metadata_block_padding +// [4]: https://godoc.org/github.com/mewkiz/flac/meta#Application +// [5]: https://godoc.org/github.com/mewkiz/flac/meta#SeekTable +// [6]: https://godoc.org/github.com/mewkiz/flac/meta#VorbisComment +// [7]: https://godoc.org/github.com/mewkiz/flac/meta#CueSheet +// [8]: https://godoc.org/github.com/mewkiz/flac/meta#Picture +package meta + +import ( + "errors" + "io" + "io/ioutil" + + "github.com/mewkiz/flac/internal/bits" +) + +// A Block contains the header and body of a metadata block. +// +// ref: https://www.xiph.org/flac/format.html#metadata_block +type Block struct { + // Metadata block header. + Header + // Metadata block body of type *StreamInfo, *Application, ... etc. Body is + // initially nil, and gets populated by a call to Block.Parse. + Body interface{} + // Underlying io.Reader; limited by the length of the block body. + lr io.Reader +} + +// New creates a new Block for accessing the metadata of r. It reads and parses +// a metadata block header. +// +// Call Block.Parse to parse the metadata block body, and call Block.Skip to +// ignore it. +func New(r io.Reader) (block *Block, err error) { + block = new(Block) + if err = block.parseHeader(r); err != nil { + return block, err + } + block.lr = io.LimitReader(r, block.Length) + return block, nil +} + +// Parse reads and parses the header and body of a metadata block. Use New for +// additional granularity. +func Parse(r io.Reader) (block *Block, err error) { + block, err = New(r) + if err != nil { + return block, err + } + if err = block.Parse(); err != nil { + return block, err + } + return block, nil +} + +// Errors returned by Parse. +var ( + ErrReservedType = errors.New("meta.Block.Parse: reserved block type") + ErrInvalidType = errors.New("meta.Block.Parse: invalid block type") +) + +// Parse reads and parses the metadata block body. +func (block *Block) Parse() error { + switch block.Type { + case TypeStreamInfo: + return block.parseStreamInfo() + case TypePadding: + return block.verifyPadding() + case TypeApplication: + return block.parseApplication() + case TypeSeekTable: + return block.parseSeekTable() + case TypeVorbisComment: + return block.parseVorbisComment() + case TypeCueSheet: + return block.parseCueSheet() + case TypePicture: + return block.parsePicture() + } + if block.Type >= 7 && block.Type <= 126 { + return ErrReservedType + } + return ErrInvalidType +} + +// Skip ignores the contents of the metadata block body. +func (block *Block) Skip() error { + if sr, ok := block.lr.(io.Seeker); ok { + _, err := sr.Seek(0, io.SeekEnd) + return err + } + _, err := io.Copy(ioutil.Discard, block.lr) + return err +} + +// A Header contains information about the type and length of a metadata block. +// +// ref: https://www.xiph.org/flac/format.html#metadata_block_header +type Header struct { + // Metadata block body type. + Type Type + // Length of body data in bytes. + Length int64 + // IsLast specifies if the block is the last metadata block. + IsLast bool +} + +// parseHeader reads and parses the header of a metadata block. +func (block *Block) parseHeader(r io.Reader) error { + // 1 bit: IsLast. + br := bits.NewReader(r) + x, err := br.Read(1) + if err != nil { + // This is the only place a metadata block may return io.EOF, which + // signals a graceful end of a FLAC stream (from a metadata point of + // view). + // + // Note that valid FLAC streams always contain at least one audio frame + // after the last metadata block. Therefore an io.EOF error at this + // location is always invalid. This logic is to be handled by the flac + // package however. + return err + } + if x != 0 { + block.IsLast = true + } + + // 7 bits: Type. + x, err = br.Read(7) + if err != nil { + return unexpected(err) + } + block.Type = Type(x) + + // 24 bits: Length. + x, err = br.Read(24) + if err != nil { + return unexpected(err) + } + block.Length = int64(x) + + return nil +} + +// Type represents the type of a metadata block body. +type Type uint8 + +// Metadata block body types. +const ( + TypeStreamInfo Type = 0 + TypePadding Type = 1 + TypeApplication Type = 2 + TypeSeekTable Type = 3 + TypeVorbisComment Type = 4 + TypeCueSheet Type = 5 + TypePicture Type = 6 +) + +func (t Type) String() string { + switch t { + case TypeStreamInfo: + return "stream info" + case TypePadding: + return "padding" + case TypeApplication: + return "application" + case TypeSeekTable: + return "seek table" + case TypeVorbisComment: + return "vorbis comment" + case TypeCueSheet: + return "cue sheet" + case TypePicture: + return "picture" + default: + return "" + } +} + +// unexpected returns io.ErrUnexpectedEOF if err is io.EOF, and returns err +// otherwise. +func unexpected(err error) error { + if err == io.EOF { + return io.ErrUnexpectedEOF + } + return err +} diff --git a/meta/meta_test.go b/meta/meta_test.go new file mode 100755 index 0000000..268e63a --- /dev/null +++ b/meta/meta_test.go @@ -0,0 +1,260 @@ +package meta_test + +import ( + "bytes" + "io/ioutil" + "reflect" + "testing" + + "github.com/mewkiz/flac" + "github.com/mewkiz/flac/meta" +) + +var golden = []struct { + path string + info *meta.StreamInfo + blocks []*meta.Block +}{ + { + path: "../testdata/59996.flac", + info: &meta.StreamInfo{BlockSizeMin: 0x1000, BlockSizeMax: 0x1000, FrameSizeMin: 0x44c5, FrameSizeMax: 0x4588, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x18, NSamples: 0x2000, MD5sum: [16]uint8{0x95, 0xba, 0xe5, 0xe2, 0xc7, 0x45, 0xbb, 0x3c, 0xa9, 0x5c, 0xa3, 0xb1, 0x35, 0xc9, 0x43, 0xf4}}, + blocks: []*meta.Block{ + { + Header: meta.Header{Type: 0x4, Length: 202, IsLast: true}, + Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.2.1 20070917", Tags: [][2]string{{"Description", "Waving a bamboo staff"}, {"YEAR", "2008"}, {"ARTIST", "qubodup aka Iwan Gabovitch | qubodup@gmail.com"}, {"COMMENTS", "I release this file into the public domain"}}}, + }, + }, + }, + { + path: "../testdata/172960.flac", + info: &meta.StreamInfo{BlockSizeMin: 0x1000, BlockSizeMax: 0x1000, FrameSizeMin: 0xb7c, FrameSizeMax: 0x256b, SampleRate: 0x17700, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0xaaa3, MD5sum: [16]uint8{0x76, 0x3d, 0xa8, 0xa5, 0xb7, 0x58, 0xe6, 0x2, 0x61, 0xb4, 0xd4, 0xc2, 0x88, 0x4d, 0x8e, 0xe}}, + blocks: []*meta.Block{ + { + Header: meta.Header{Type: 0x4, Length: 180, IsLast: true}, + Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.2.1 20070917", Tags: [][2]string{{"GENRE", "Sound Clip"}, {"ARTIST", "Iwan 'qubodup' Gabovitch"}, {"Artist Homepage", "http://qubodup.net"}, {"Artist Email", "qubodup@gmail.com"}, {"DATE", "2012"}}}, + }, + }, + }, + { + path: "../testdata/189983.flac", + info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0x94d, FrameSizeMax: 0x264a, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x50f4, MD5sum: [16]uint8{0x63, 0x28, 0xed, 0x6d, 0xd3, 0xe, 0x55, 0xfb, 0xa5, 0x73, 0x69, 0x2b, 0xb7, 0x35, 0x73, 0xb7}}, + blocks: []*meta.Block{ + { + Header: meta.Header{Type: 0x4, Length: 40, IsLast: true}, + Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.2.1 20070917", Tags: nil}, + }, + }, + }, + { + path: "testdata/input-SCPAP.flac", + info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}}, + blocks: []*meta.Block{ + { + Header: meta.Header{Type: 0x3, Length: 180, IsLast: false}, + Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}}, + }, + { + Header: meta.Header{Type: 0x5, Length: 540, IsLast: false}, + Body: &meta.CueSheet{MCN: "1234567890123", NLeadInSamples: 0x15888, IsCompactDisc: true, Tracks: []meta.CueSheetTrack{{Offset: 0x0, Num: 0x1, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}, {Offset: 0x24c, Num: 0x2}}}, {Offset: 0xb7c, Num: 0x2, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}}}, {Offset: 0x16f8, Num: 0xaa, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex(nil)}}}, + }, + { + Header: meta.Header{Type: 0x1, Length: 4, IsLast: false}, + Body: nil, + }, + { + Header: meta.Header{Type: 0x2, Length: 4, IsLast: false}, + Body: &meta.Application{ID: 0x66616b65, Data: nil}, + }, + { + Header: meta.Header{Type: 0x1, Length: 3201, IsLast: true}, + Body: nil, + }, + }, + }, + { + path: "testdata/input-SCVA.flac", + info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}}, + blocks: []*meta.Block{ + { + Header: meta.Header{Type: 0x3, Length: 180, IsLast: false}, + Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}}, + }, + { + Header: meta.Header{Type: 0x5, Length: 540, IsLast: false}, + Body: &meta.CueSheet{MCN: "1234567890123", NLeadInSamples: 0x15888, IsCompactDisc: true, Tracks: []meta.CueSheetTrack{{Offset: 0x0, Num: 0x1, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}, {Offset: 0x24c, Num: 0x2}}}, {Offset: 0xb7c, Num: 0x2, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}}}, {Offset: 0x16f8, Num: 0xaa, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex(nil)}}}, + }, + { + Header: meta.Header{Type: 0x4, Length: 203, IsLast: false}, + Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}}, + }, + { + Header: meta.Header{Type: 0x2, Length: 4, IsLast: true}, + Body: &meta.Application{ID: 0x66616b65, Data: nil}, + }, + }, + }, + { + path: "testdata/input-SCVAUP.flac", + info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}}, + blocks: []*meta.Block{ + { + Header: meta.Header{Type: 0x3, Length: 180, IsLast: false}, + Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}}, + }, + { + Header: meta.Header{Type: 0x5, Length: 540, IsLast: false}, + Body: &meta.CueSheet{MCN: "1234567890123", NLeadInSamples: 0x15888, IsCompactDisc: true, Tracks: []meta.CueSheetTrack{{Offset: 0x0, Num: 0x1, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}, {Offset: 0x24c, Num: 0x2}}}, {Offset: 0xb7c, Num: 0x2, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}}}, {Offset: 0x16f8, Num: 0xaa, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex(nil)}}}, + }, + { + Header: meta.Header{Type: 0x4, Length: 203, IsLast: false}, + Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}}, + }, + { + Header: meta.Header{Type: 0x2, Length: 4, IsLast: false}, + Body: &meta.Application{ID: 0x66616b65, Data: nil}, + }, + { + Header: meta.Header{Type: 0x7e, Length: 0, IsLast: false}, + Body: nil, + }, + { + Header: meta.Header{Type: 0x1, Length: 3201, IsLast: true}, + Body: nil, + }, + }, + }, + { + path: "testdata/input-SCVPAP.flac", + info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}}, + blocks: []*meta.Block{ + { + Header: meta.Header{Type: 0x3, Length: 180, IsLast: false}, + Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}}, + }, + { + Header: meta.Header{Type: 0x5, Length: 540, IsLast: false}, + Body: &meta.CueSheet{MCN: "1234567890123", NLeadInSamples: 0x15888, IsCompactDisc: true, Tracks: []meta.CueSheetTrack{{Offset: 0x0, Num: 0x1, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}, {Offset: 0x24c, Num: 0x2}}}, {Offset: 0xb7c, Num: 0x2, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex{{Offset: 0x0, Num: 0x1}}}, {Offset: 0x16f8, Num: 0xaa, ISRC: "", IsAudio: true, HasPreEmphasis: false, Indicies: []meta.CueSheetTrackIndex(nil)}}}, + }, + { + Header: meta.Header{Type: 0x4, Length: 203, IsLast: false}, + Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}}, + }, + { + Header: meta.Header{Type: 0x1, Length: 4, IsLast: false}, + Body: nil, + }, + { + Header: meta.Header{Type: 0x2, Length: 4, IsLast: false}, + Body: &meta.Application{ID: 0x66616b65, Data: nil}, + }, + { + Header: meta.Header{Type: 0x1, Length: 3201, IsLast: true}, + Body: nil, + }, + }, + }, + { + path: "testdata/input-SVAUP.flac", + info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}}, + blocks: []*meta.Block{ + { + Header: meta.Header{Type: 0x3, Length: 180, IsLast: false}, + Body: &meta.SeekTable{Points: []meta.SeekPoint{{SampleNum: 0x0, Offset: 0x0, NSamples: 0x1200}, {SampleNum: 0x1200, Offset: 0xe, NSamples: 0x4f8}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}, {SampleNum: 0xffffffffffffffff, Offset: 0x0, NSamples: 0x0}}}, + }, + { + Header: meta.Header{Type: 0x4, Length: 203, IsLast: false}, + Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}}, + }, + { + Header: meta.Header{Type: 0x2, Length: 4, IsLast: false}, + Body: &meta.Application{ID: 0x66616b65, Data: nil}, + }, + { + Header: meta.Header{Type: 0x7e, Length: 0, IsLast: false}, + Body: nil, + }, + { + Header: meta.Header{Type: 0x1, Length: 3201, IsLast: true}, + Body: nil, + }, + }, + }, + { + path: "testdata/input-VA.flac", + info: &meta.StreamInfo{BlockSizeMin: 0x1200, BlockSizeMax: 0x1200, FrameSizeMin: 0xe, FrameSizeMax: 0x10, SampleRate: 0xac44, NChannels: 0x2, BitsPerSample: 0x10, NSamples: 0x16f8, MD5sum: [16]uint8{0x74, 0xff, 0xd4, 0x73, 0x7e, 0xb5, 0x48, 0x8d, 0x51, 0x2b, 0xe4, 0xaf, 0x58, 0x94, 0x33, 0x62}}, + blocks: []*meta.Block{ + { + Header: meta.Header{Type: 0x4, Length: 203, IsLast: false}, + Body: &meta.VorbisComment{Vendor: "reference libFLAC 1.1.3 20060805", Tags: [][2]string{{"REPLAYGAIN_TRACK_PEAK", "0.99996948"}, {"REPLAYGAIN_TRACK_GAIN", "-7.89 dB"}, {"REPLAYGAIN_ALBUM_PEAK", "0.99996948"}, {"REPLAYGAIN_ALBUM_GAIN", "-7.89 dB"}, {"artist", "1"}, {"title", "2"}}}, + }, + { + Header: meta.Header{Type: 0x2, Length: 4, IsLast: true}, + Body: &meta.Application{ID: 0x66616b65, Data: nil}, + }, + }, + }, +} + +func TestParseBlocks(t *testing.T) { + for _, g := range golden { + stream, err := flac.ParseFile(g.path) + if err != nil { + t.Fatal(err) + } + defer stream.Close() + blocks := stream.Blocks + + if len(blocks) != len(g.blocks) { + t.Errorf("path=%q: invalid number of metadata blocks; expected %d, got %d", g.path, len(g.blocks), len(blocks)) + continue + } + + got := stream.Info + want := g.info + if !reflect.DeepEqual(got, want) { + t.Errorf("path=%q: metadata StreamInfo block bodies differ; expected %#v, got %#v", g.path, want, got) + } + + for blockNum, got := range blocks { + want := g.blocks[blockNum] + if !reflect.DeepEqual(got.Header, want.Header) { + t.Errorf("path=%q, blockNum=%d: metadata block headers differ; expected %#v, got %#v", g.path, blockNum, want.Header, got.Header) + } + if !reflect.DeepEqual(got.Body, want.Body) { + t.Errorf("path=%q, blockNum=%d: metadata block bodies differ; expected %#v, got %#v", g.path, blockNum, want.Body, got.Body) + } + } + } +} + +func TestParsePicture(t *testing.T) { + stream, err := flac.ParseFile("testdata/silence.flac") + if err != nil { + t.Fatal(err) + } + defer stream.Close() + + want, err := ioutil.ReadFile("testdata/silence.jpg") + if err != nil { + t.Fatal(err) + } + + for _, block := range stream.Blocks { + if block.Type == meta.TypePicture { + pic := block.Body.(*meta.Picture) + got := pic.Data + if !bytes.Equal(got, want) { + t.Errorf("picture data differ; expected %v, got %v", want, got) + } + break + } + } +} + +// TODO: better error verification than string-based comparisons. +func TestMissingValue(t *testing.T) { + _, err := flac.ParseFile("testdata/missing-value.flac") + if err.Error() != `meta.Block.parseVorbisComment: unable to locate '=' in vector "title 2"` { + t.Fatal(err) + } +} diff --git a/meta/padding.go b/meta/padding.go new file mode 100755 index 0000000..0d66fa3 --- /dev/null +++ b/meta/padding.go @@ -0,0 +1,39 @@ +package meta + +import ( + "errors" + "io" + "io/ioutil" +) + +// verifyPadding verifies the body of a Padding metadata block. It should only +// contain zero-padding. +// +// ref: https://www.xiph.org/flac/format.html#metadata_block_padding +func (block *Block) verifyPadding() error { + zr := zeros{r: block.lr} + _, err := io.Copy(ioutil.Discard, zr) + return err +} + +// Errors returned by zeros.Read. +var ( + ErrInvalidPadding = errors.New("invalid padding") +) + +// zeros implements an io.Reader, with a Read method which returns an error if +// any byte read isn't zero. +type zeros struct { + r io.Reader +} + +// Read returns an error if any byte read isn't zero. +func (zr zeros) Read(p []byte) (n int, err error) { + n, err = zr.r.Read(p) + for i := 0; i < n; i++ { + if p[i] != 0 { + return n, ErrInvalidPadding + } + } + return n, err +} diff --git a/meta/picture.go b/meta/picture.go new file mode 100755 index 0000000..5c52d8a --- /dev/null +++ b/meta/picture.go @@ -0,0 +1,120 @@ +package meta + +import ( + "encoding/binary" + "io" +) + +// Picture contains the image data of an embedded picture. +// +// ref: https://www.xiph.org/flac/format.html#metadata_block_picture +type Picture struct { + // Picture type according to the ID3v2 APIC frame: + // + // 0: Other + // 1: 32x32 pixels 'file icon' (PNG only) + // 2: Other file icon + // 3: Cover (front) + // 4: Cover (back) + // 5: Leaflet page + // 6: Media (e.g. label side of CD) + // 7: Lead artist/lead performer/soloist + // 8: Artist/performer + // 9: Conductor + // 10: Band/Orchestra + // 11: Composer + // 12: Lyricist/text writer + // 13: Recording Location + // 14: During recording + // 15: During performance + // 16: Movie/video screen capture + // 17: A bright coloured fish + // 18: Illustration + // 19: Band/artist logotype + // 20: Publisher/Studio logotype + // + // ref: http://id3.org/id3v2.4.0-frames + Type uint32 + // MIME type string. The MIME type "-->" specifies that the picture data is + // to be interpreted as an URL instead of image data. + MIME string + // Description of the picture. + Desc string + // Image dimensions. + Width, Height uint32 + // Color depth in bits-per-pixel. + Depth uint32 + // Number of colors in palette; 0 for non-indexed images. + NPalColors uint32 + // Image data. + Data []byte +} + +// parsePicture reads and parses the body of a Picture metadata block. +func (block *Block) parsePicture() error { + // 32 bits: Type. + pic := new(Picture) + block.Body = pic + err := binary.Read(block.lr, binary.BigEndian, &pic.Type) + if err != nil { + return unexpected(err) + } + + // 32 bits: (MIME type length). + var x uint32 + if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil { + return unexpected(err) + } + + // (MIME type length) bytes: MIME. + mime, err := readString(block.lr, int(x)) + if err != nil { + return unexpected(err) + } + pic.MIME = mime + + // 32 bits: (description length). + if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil { + return unexpected(err) + } + + // (description length) bytes: Desc. + desc, err := readString(block.lr, int(x)) + if err != nil { + return unexpected(err) + } + pic.Desc = desc + + // 32 bits: Width. + if err = binary.Read(block.lr, binary.BigEndian, &pic.Width); err != nil { + return unexpected(err) + } + + // 32 bits: Height. + if err = binary.Read(block.lr, binary.BigEndian, &pic.Height); err != nil { + return unexpected(err) + } + + // 32 bits: Depth. + if err = binary.Read(block.lr, binary.BigEndian, &pic.Depth); err != nil { + return unexpected(err) + } + + // 32 bits: NPalColors. + if err = binary.Read(block.lr, binary.BigEndian, &pic.NPalColors); err != nil { + return unexpected(err) + } + + // 32 bits: (data length). + if err = binary.Read(block.lr, binary.BigEndian, &x); err != nil { + return unexpected(err) + } + if x == 0 { + return nil + } + + // (data length) bytes: Data. + pic.Data = make([]byte, x) + _, err = io.ReadFull(block.lr, pic.Data) + return unexpected(err) +} diff --git a/meta/reader.go b/meta/reader.go new file mode 100755 index 0000000..58f55b6 --- /dev/null +++ b/meta/reader.go @@ -0,0 +1,24 @@ +package meta + +import "io" + +// readString reads and returns exactly n bytes from the provided io.Reader. +// +// The error is io.EOF only if no bytes were read. If an io.EOF happens after +// reading some but not all the bytes, ReadFull returns io.ErrUnexpectedEOF. On +// return, n == len(buf) if and only if err == nil. +func readString(r io.Reader, n int) (string, error) { + // readBuf is the local buffer used by readBytes. + var backingArray [4096]byte // hopefully allocated on stack. + readBuf := backingArray[:] + if n > len(readBuf) { + // The local buffer is initially 4096 bytes and will grow automatically if + // so required. + readBuf = make([]byte, n) + } + _, err := io.ReadFull(r, readBuf[:n]) + if err != nil { + return "", err + } + return string(readBuf[:n]), nil +} diff --git a/meta/seektable.go b/meta/seektable.go new file mode 100755 index 0000000..c0b96ce --- /dev/null +++ b/meta/seektable.go @@ -0,0 +1,67 @@ +package meta + +import ( + "encoding/binary" + "errors" + "fmt" +) + +// SeekTable contains one or more pre-calculated audio frame seek points. +// +// ref: https://www.xiph.org/flac/format.html#metadata_block_seektable +type SeekTable struct { + // One or more seek points. + Points []SeekPoint +} + +// parseSeekTable reads and parses the body of a SeekTable metadata block. +func (block *Block) parseSeekTable() error { + // The number of seek points is derived from the header length, divided by + // the size of a SeekPoint; which is 18 bytes. + n := block.Length / 18 + if n < 1 { + return errors.New("meta.Block.parseSeekTable: at least one seek point is required") + } + table := &SeekTable{Points: make([]SeekPoint, n)} + block.Body = table + var prev uint64 + for i := range table.Points { + point := &table.Points[i] + err := binary.Read(block.lr, binary.BigEndian, point) + if err != nil { + return unexpected(err) + } + // Seek points within a table must be sorted in ascending order by sample + // number. Each seek point must have a unique sample number, except for + // placeholder points. + sampleNum := point.SampleNum + if i != 0 && sampleNum != PlaceholderPoint { + switch { + case sampleNum < prev: + return fmt.Errorf("meta.Block.parseSeekTable: invalid seek point order; sample number (%d) < prev (%d)", sampleNum, prev) + case sampleNum == prev: + return fmt.Errorf("meta.Block.parseSeekTable: duplicate seek point with sample number (%d)", sampleNum) + } + } + } + return nil +} + +// A SeekPoint specifies the byte offset and initial sample number of a given +// target frame. +// +// ref: https://www.xiph.org/flac/format.html#seekpoint +type SeekPoint struct { + // Sample number of the first sample in the target frame, or + // 0xFFFFFFFFFFFFFFFF for a placeholder point. + SampleNum uint64 + // Offset in bytes from the first byte of the first frame header to the first + // byte of the target frame's header. + Offset uint64 + // Number of samples in the target frame. + NSamples uint16 +} + +// PlaceholderPoint represent the sample number used to specify placeholder seek +// points. +const PlaceholderPoint = 0xFFFFFFFFFFFFFFFF diff --git a/meta/streaminfo.go b/meta/streaminfo.go new file mode 100755 index 0000000..f72fbfc --- /dev/null +++ b/meta/streaminfo.go @@ -0,0 +1,116 @@ +package meta + +import ( + "crypto/md5" + "errors" + "fmt" + "io" + + "github.com/mewkiz/flac/internal/bits" +) + +// StreamInfo contains the basic properties of a FLAC audio stream, such as its +// sample rate and channel count. It is the only mandatory metadata block and +// must be present as the first metadata block of a FLAC stream. +// +// ref: https://www.xiph.org/flac/format.html#metadata_block_streaminfo +type StreamInfo struct { + // Minimum block size (in samples) used in the stream; between 16 and 65535 + // samples. + BlockSizeMin uint16 + // Maximum block size (in samples) used in the stream; between 16 and 65535 + // samples. + BlockSizeMax uint16 + // Minimum frame size in bytes; a 0 value implies unknown. + FrameSizeMin uint32 + // Maximum frame size in bytes; a 0 value implies unknown. + FrameSizeMax uint32 + // Sample rate in Hz; between 1 and 655350 Hz. + SampleRate uint32 + // Number of channels; between 1 and 8 channels. + NChannels uint8 + // Sample size in bits-per-sample; between 4 and 32 bits. + BitsPerSample uint8 + // Total number of inter-channel samples in the stream. One second of 44.1 + // KHz audio will have 44100 samples regardless of the number of channels. A + // 0 value implies unknown. + NSamples uint64 + // MD5 checksum of the unencoded audio data. + MD5sum [md5.Size]uint8 +} + +// parseStreamInfo reads and parses the body of a StreamInfo metadata block. +func (block *Block) parseStreamInfo() error { + // 16 bits: BlockSizeMin. + br := bits.NewReader(block.lr) + x, err := br.Read(16) + if err != nil { + return unexpected(err) + } + if x < 16 { + return fmt.Errorf("meta.Block.parseStreamInfo: invalid minimum block size (%d); expected >= 16", x) + } + si := new(StreamInfo) + block.Body = si + si.BlockSizeMin = uint16(x) + + // 16 bits: BlockSizeMax. + x, err = br.Read(16) + if err != nil { + return unexpected(err) + } + if x < 16 { + return fmt.Errorf("meta.Block.parseStreamInfo: invalid maximum block size (%d); expected >= 16", x) + } + si.BlockSizeMax = uint16(x) + + // 24 bits: FrameSizeMin. + x, err = br.Read(24) + if err != nil { + return unexpected(err) + } + si.FrameSizeMin = uint32(x) + + // 24 bits: FrameSizeMax. + x, err = br.Read(24) + if err != nil { + return unexpected(err) + } + si.FrameSizeMax = uint32(x) + + // 20 bits: SampleRate. + x, err = br.Read(20) + if err != nil { + return unexpected(err) + } + if x == 0 { + return errors.New("meta.Block.parseStreamInfo: invalid sample rate (0)") + } + si.SampleRate = uint32(x) + + // 3 bits: NChannels. + x, err = br.Read(3) + if err != nil { + return unexpected(err) + } + // x contains: (number of channels) - 1 + si.NChannels = uint8(x + 1) + + // 5 bits: BitsPerSample. + x, err = br.Read(5) + if err != nil { + return unexpected(err) + } + // x contains: (bits-per-sample) - 1 + si.BitsPerSample = uint8(x + 1) + + // 36 bits: NSamples. + si.NSamples, err = br.Read(36) + if err != nil { + return unexpected(err) + } + + // 16 bytes: MD5sum. + _, err = io.ReadFull(block.lr, si.MD5sum[:]) + return unexpected(err) +} diff --git a/meta/testdata/README.md b/meta/testdata/README.md new file mode 100755 index 0000000..f2ec6b0 --- /dev/null +++ b/meta/testdata/README.md @@ -0,0 +1,35 @@ +# Testcase Licences + +## BSD License + +The following testcase sounds have been copied from the [reference implementation] library, which is released under a [BSD license]. + +* input-SCPAP.flac +* input-SCVA.flac +* input-SCVAUP.flac +* input-SCVPAP.flac +* input-SVAUP.flac +* input-VA.flac +* `missing-value.flac`, created using the following command. + +```shell +sed 's/title=/title /' input-SCVA.flac > missing-value.flac +``` + +[reference implementation]: https://git.xiph.org/?p=flac.git +[BSD license]: https://git.xiph.org/?p=flac.git;a=blob_plain;f=COPYING.Xiph + +## Public domain + +The following testcase images and sounds have been released into the [public domain]. + +* [silence.jpg](http://www.pdpics.com/photo/2546-silence-word-magnified/) +* `silence.flac`, created using the following commands. + +```shell +ffmpeg -f lavfi -i "aevalsrc=0|0:d=3" silence.wav +flac silence.wav +metaflac --import-picture=silence.jpg silence.flac +``` + +[public domain]: https://creativecommons.org/publicdomain/zero/1.0/ diff --git a/meta/testdata/silence.jpg b/meta/testdata/silence.jpg new file mode 100755 index 0000000..6236e6d Binary files /dev/null and b/meta/testdata/silence.jpg differ diff --git a/meta/vorbiscomment.go b/meta/vorbiscomment.go new file mode 100755 index 0000000..313f857 --- /dev/null +++ b/meta/vorbiscomment.go @@ -0,0 +1,69 @@ +package meta + +import ( + "encoding/binary" + "fmt" + "strings" +) + +// VorbisComment contains a list of name-value pairs. +// +// ref: https://www.xiph.org/flac/format.html#metadata_block_vorbis_comment +type VorbisComment struct { + // Vendor name. + Vendor string + // A list of tags, each represented by a name-value pair. + Tags [][2]string +} + +// parseVorbisComment reads and parses the body of a VorbisComment metadata +// block. +func (block *Block) parseVorbisComment() (err error) { + // 32 bits: vendor length. + var x uint32 + if err = binary.Read(block.lr, binary.LittleEndian, &x); err != nil { + return unexpected(err) + } + + // (vendor length) bits: Vendor. + vendor, err := readString(block.lr, int(x)) + if err != nil { + return unexpected(err) + } + comment := new(VorbisComment) + block.Body = comment + comment.Vendor = vendor + + // Parse tags. + // 32 bits: number of tags. + if err = binary.Read(block.lr, binary.LittleEndian, &x); err != nil { + return unexpected(err) + } + if x < 1 { + return nil + } + comment.Tags = make([][2]string, x) + for i := range comment.Tags { + // 32 bits: vector length + if err = binary.Read(block.lr, binary.LittleEndian, &x); err != nil { + return unexpected(err) + } + + // (vector length): vector. + vector, err := readString(block.lr, int(x)) + if err != nil { + return unexpected(err) + } + + // Parse tag, which has the following format: + // NAME=VALUE + pos := strings.Index(vector, "=") + if pos == -1 { + return fmt.Errorf("meta.Block.parseVorbisComment: unable to locate '=' in vector %q", vector) + } + comment.Tags[i][0] = vector[:pos] + comment.Tags[i][1] = vector[pos+1:] + } + + return nil +} diff --git a/testdata/README.md b/testdata/README.md new file mode 100755 index 0000000..ac6d321 --- /dev/null +++ b/testdata/README.md @@ -0,0 +1,22 @@ +## Public domain + +The following testcase sounds have been released into the [public domain]. + +* [19875.flac](http://freesound.org/people/yawfle/sounds/19875/) +* [44127.flac](http://freesound.org/people/dland/sounds/44127/) +* [59996.flac](http://freesound.org/people/qubodup/sounds/59996/) +* [80574.flac](http://freesound.org/people/EsbenSloth/sounds/80574/) +* [172960.flac](http://freesound.org/people/qubodup/sounds/172960/) +* [189983.flac](http://freesound.org/people/raygrote/sounds/189983/) +* [191885.flac](http://freesound.org/people/Hedmarking/sounds/191885/) +* [212768.flac](http://freesound.org/people/qubodup/sounds/212768/) +* [220014.flac](http://freesound.org/people/djani00/sounds/220014/) +* [243749.flac](http://freesound.org/people/unfa/sounds/243749/) +* [256529.flac](http://freesound.org/people/tymorafarr/sounds/256529/) +* [257344.flac](http://freesound.org/people/arseniiv/sounds/257344/) + +[public domain]: https://creativecommons.org/publicdomain/zero/1.0/ + +The following flac files are CC BY 4.0: + +* [8297-275156-0011.flac](http://www.openslr.org/12/) - a single file from the LibriSpeech ASR corpus, by Vassil Panyotov and DanielPovey.