blob: c70e6fa0f737a8f09c4635bca37581d454d62742 [file] [log] [blame]
khenaidoo7d3c5582021-08-11 18:09:44 -04001// Copyright 2019+ Klaus Post. All rights reserved.
2// License information can be found in the LICENSE file.
3// Based on work by Yann Collet, released under BSD License.
4
5package zstd
6
7import (
8 "errors"
9 "runtime"
10)
11
12// DOption is an option for creating a decoder.
13type DOption func(*decoderOptions) error
14
15// options retains accumulated state of multiple options.
16type decoderOptions struct {
17 lowMem bool
18 concurrent int
19 maxDecodedSize uint64
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053020 maxWindowSize uint64
khenaidoo7d3c5582021-08-11 18:09:44 -040021 dicts []dict
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053022 ignoreChecksum bool
khenaidoo7d3c5582021-08-11 18:09:44 -040023}
24
25func (o *decoderOptions) setDefault() {
26 *o = decoderOptions{
27 // use less ram: true for now, but may change.
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053028 lowMem: true,
29 concurrent: runtime.GOMAXPROCS(0),
30 maxWindowSize: MaxWindowSize,
khenaidoo7d3c5582021-08-11 18:09:44 -040031 }
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053032 if o.concurrent > 4 {
33 o.concurrent = 4
34 }
35 o.maxDecodedSize = 64 << 30
khenaidoo7d3c5582021-08-11 18:09:44 -040036}
37
38// WithDecoderLowmem will set whether to use a lower amount of memory,
39// but possibly have to allocate more while running.
40func WithDecoderLowmem(b bool) DOption {
41 return func(o *decoderOptions) error { o.lowMem = b; return nil }
42}
43
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053044// WithDecoderConcurrency sets the number of created decoders.
45// When decoding block with DecodeAll, this will limit the number
46// of possible concurrently running decodes.
47// When decoding streams, this will limit the number of
48// inflight blocks.
49// When decoding streams and setting maximum to 1,
50// no async decoding will be done.
51// When a value of 0 is provided GOMAXPROCS will be used.
52// By default this will be set to 4 or GOMAXPROCS, whatever is lower.
khenaidoo7d3c5582021-08-11 18:09:44 -040053func WithDecoderConcurrency(n int) DOption {
54 return func(o *decoderOptions) error {
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053055 if n < 0 {
khenaidoo7d3c5582021-08-11 18:09:44 -040056 return errors.New("concurrency must be at least 1")
57 }
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053058 if n == 0 {
59 o.concurrent = runtime.GOMAXPROCS(0)
60 } else {
61 o.concurrent = n
62 }
khenaidoo7d3c5582021-08-11 18:09:44 -040063 return nil
64 }
65}
66
67// WithDecoderMaxMemory allows to set a maximum decoded size for in-memory
68// non-streaming operations or maximum window size for streaming operations.
69// This can be used to control memory usage of potentially hostile content.
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053070// Maximum is 1 << 63 bytes. Default is 64GiB.
khenaidoo7d3c5582021-08-11 18:09:44 -040071func WithDecoderMaxMemory(n uint64) DOption {
72 return func(o *decoderOptions) error {
73 if n == 0 {
74 return errors.New("WithDecoderMaxMemory must be at least 1")
75 }
76 if n > 1<<63 {
77 return errors.New("WithDecoderMaxmemory must be less than 1 << 63")
78 }
79 o.maxDecodedSize = n
80 return nil
81 }
82}
83
84// WithDecoderDicts allows to register one or more dictionaries for the decoder.
85// If several dictionaries with the same ID is provided the last one will be used.
86func WithDecoderDicts(dicts ...[]byte) DOption {
87 return func(o *decoderOptions) error {
88 for _, b := range dicts {
89 d, err := loadDict(b)
90 if err != nil {
91 return err
92 }
93 o.dicts = append(o.dicts, *d)
94 }
95 return nil
96 }
97}
Akash Reddy Kankanalac28f0e22025-06-16 11:00:55 +053098
99// WithDecoderMaxWindow allows to set a maximum window size for decodes.
100// This allows rejecting packets that will cause big memory usage.
101// The Decoder will likely allocate more memory based on the WithDecoderLowmem setting.
102// If WithDecoderMaxMemory is set to a lower value, that will be used.
103// Default is 512MB, Maximum is ~3.75 TB as per zstandard spec.
104func WithDecoderMaxWindow(size uint64) DOption {
105 return func(o *decoderOptions) error {
106 if size < MinWindowSize {
107 return errors.New("WithMaxWindowSize must be at least 1KB, 1024 bytes")
108 }
109 if size > (1<<41)+7*(1<<38) {
110 return errors.New("WithMaxWindowSize must be less than (1<<41) + 7*(1<<38) ~ 3.75TB")
111 }
112 o.maxWindowSize = size
113 return nil
114 }
115}
116
117// IgnoreChecksum allows to forcibly ignore checksum checking.
118func IgnoreChecksum(b bool) DOption {
119 return func(o *decoderOptions) error {
120 o.ignoreChecksum = b
121 return nil
122 }
123}