decoder_options.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // 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. package zstd
  5. import (
  6. "errors"
  7. "runtime"
  8. )
  9. // DOption is an option for creating a decoder.
  10. type DOption func(*decoderOptions) error
  11. // options retains accumulated state of multiple options.
  12. type decoderOptions struct {
  13. lowMem bool
  14. concurrent int
  15. maxDecodedSize uint64
  16. maxWindowSize uint64
  17. dicts []dict
  18. }
  19. func (o *decoderOptions) setDefault() {
  20. *o = decoderOptions{
  21. // use less ram: true for now, but may change.
  22. lowMem: true,
  23. concurrent: runtime.GOMAXPROCS(0),
  24. maxWindowSize: MaxWindowSize,
  25. }
  26. o.maxDecodedSize = 1 << 63
  27. }
  28. // WithDecoderLowmem will set whether to use a lower amount of memory,
  29. // but possibly have to allocate more while running.
  30. func WithDecoderLowmem(b bool) DOption {
  31. return func(o *decoderOptions) error { o.lowMem = b; return nil }
  32. }
  33. // WithDecoderConcurrency will set the concurrency,
  34. // meaning the maximum number of decoders to run concurrently.
  35. // The value supplied must be at least 1.
  36. // By default this will be set to GOMAXPROCS.
  37. func WithDecoderConcurrency(n int) DOption {
  38. return func(o *decoderOptions) error {
  39. if n <= 0 {
  40. return errors.New("concurrency must be at least 1")
  41. }
  42. o.concurrent = n
  43. return nil
  44. }
  45. }
  46. // WithDecoderMaxMemory allows to set a maximum decoded size for in-memory
  47. // non-streaming operations or maximum window size for streaming operations.
  48. // This can be used to control memory usage of potentially hostile content.
  49. // Maximum and default is 1 << 63 bytes.
  50. func WithDecoderMaxMemory(n uint64) DOption {
  51. return func(o *decoderOptions) error {
  52. if n == 0 {
  53. return errors.New("WithDecoderMaxMemory must be at least 1")
  54. }
  55. if n > 1<<63 {
  56. return errors.New("WithDecoderMaxmemory must be less than 1 << 63")
  57. }
  58. o.maxDecodedSize = n
  59. return nil
  60. }
  61. }
  62. // WithDecoderDicts allows to register one or more dictionaries for the decoder.
  63. // If several dictionaries with the same ID is provided the last one will be used.
  64. func WithDecoderDicts(dicts ...[]byte) DOption {
  65. return func(o *decoderOptions) error {
  66. for _, b := range dicts {
  67. d, err := loadDict(b)
  68. if err != nil {
  69. return err
  70. }
  71. o.dicts = append(o.dicts, *d)
  72. }
  73. return nil
  74. }
  75. }
  76. // WithDecoderMaxWindow allows to set a maximum window size for decodes.
  77. // This allows rejecting packets that will cause big memory usage.
  78. // The Decoder will likely allocate more memory based on the WithDecoderLowmem setting.
  79. // If WithDecoderMaxMemory is set to a lower value, that will be used.
  80. // Default is 512MB, Maximum is ~3.75 TB as per zstandard spec.
  81. func WithDecoderMaxWindow(size uint64) DOption {
  82. return func(o *decoderOptions) error {
  83. if size < MinWindowSize {
  84. return errors.New("WithMaxWindowSize must be at least 1KB, 1024 bytes")
  85. }
  86. if size > (1<<41)+7*(1<<38) {
  87. return errors.New("WithMaxWindowSize must be less than (1<<41) + 7*(1<<38) ~ 3.75TB")
  88. }
  89. o.maxWindowSize = size
  90. return nil
  91. }
  92. }