extlz4 0.2.5 → 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc2c22224769c26e8e6c7fe4eded483f7963203ddc87da1b834c4597d3e6e593
4
- data.tar.gz: 615d87e1be068ecc93a1c262127d1ad28787a5d25ede531fb15cb1dda1c4a533
3
+ metadata.gz: 738042afe5d85d9e24155d0351f9120df4ec2258ffa1f311a821c6bb399dd2a9
4
+ data.tar.gz: 88e1057d4fc464ed4cef3ac93c0e979821e07c87a6fba70d3d644d07e21d0913
5
5
  SHA512:
6
- metadata.gz: db7354b91b1776a973eb323680509c30f0c9704a8ee61c00f88fa20bf020128a4bb5cd53e9393d8115fa54e10b137bbd43a570a830d75bbf9d7c5d4ef6e1148d
7
- data.tar.gz: fc2e568642e6ffd47d8b941dff6edf54fca9a9cf19017e31808c0382c3e481d5714316db915a1cae3e15a2d04833e4bc8fdb5094e38ae122f069826f2d73a92d
6
+ metadata.gz: d12a084e3a34c27a64cf0b236f7475760b9be86c0654062c0d89a6d148b75811122015925a75d4c9699a5b07472b8c692abb9cd427e0aba05c0e8d0a17e4384c
7
+ data.tar.gz: b3902b0162ce3c5dc244c3c2975819a896aa294ec37f1012536eed07862e7dc6541ce10ba1869644fef8c3d6602c55ebfa1514a9128f4eded98863284843f6bd
@@ -1,4 +1,12 @@
1
- # extlz4-0.2.4.4 (平成30114日 日曜日)
1
+ # extlz4-0.3 (平成314月)
2
+
3
+ * lz4-1.9.0 に更新
4
+ * `LZ4` モジュールをリファインメントとして利用できるように機能を追加
5
+ * `Object` および `String` クラスで `.to_lz4frame` `.unlz4frame` メソッドが利用できるようになりました。
6
+ * `String` クラスで `.to_lz4block` `.unlz4block` メソッドが利用できるようになりました。
7
+
8
+
9
+ # extlz4-0.2.5 (平成30年1月14日 日曜日)
2
10
 
3
11
  * lz4 ライブラリを [1.8.1](https://github.com/lz4/lz4/releases/tag/v1.8.1) に更新
4
12
 
data/README.md CHANGED
@@ -5,28 +5,28 @@
5
5
 
6
6
  LZ4 データストリームを圧縮・伸張できます。lz4-cli で扱うことが出来ます。
7
7
 
8
- ``` shell:shell
8
+ ```shell:shell
9
9
  $ dmesg | ruby -r extlz4 -e 'LZ4.encode_file($stdin.binmode, $stdout.binmode)' | lz4c -d | more
10
10
  ```
11
11
 
12
12
  ほかの ruby 向けの lz4 バインディングライブラリとしては KOMIYA Atsushi さんによる [lz4-ruby (http://rubygems.org/gems/lz4-ruby)](http://rubygems.org/gems/lz4-ruby) があります。
13
13
 
14
14
 
15
- ## SUMMARY (概要)
16
-
17
- * package name: extlz4
18
- * author: dearblue (mailto:dearblue@users.noreply.github.com)
19
- * report issue to: <https://github.com/dearblue/ruby-extlz4/issues>
20
- * how to install: `gem install extlz4`
21
- * version: 0.2.5
22
- * product quality: technical preview
23
- * licensing: BSD-2-Clause License
24
- * dependency gems: none
25
- * dependency external c libraries: none
26
- * bundled external c libraries:
27
- * lz4-1.8.1 <https://github.com/lz4/lz4/tree/v1.8.1>
28
- under [BSD 2-Clause license](https://github.com/lz4/lz4/tree/v1.8.1/LICENSE)
29
- by [Yann Collet](https://github.com/Cyan4973)
15
+ ## FEATURES (機能)
16
+
17
+ * Generic LZ4 frame data process (for `.lz4` file format)
18
+ * Decode LZ4 Frame data : `LZ4.decode`
19
+ * Encode LZ4 Frame data : `LZ4.encode`
20
+ * Generic LZ4 frame data file process (for `.lz4` file format)
21
+ * Decode LZ4 Frame data file : `LZ4.decode_file`
22
+ * Encode LZ4 Frame data file : `LZ4.encode_file`
23
+ * LZ4 block data process
24
+ * Decode LZ4 block data : `LZ4.block_decode`
25
+ * Encode LZ4 block data : `LZ4.block_encode` (supporting high compression level)
26
+ * Streaming Decode LZ4 block data : `LZ4.block_stream_decode` and `LZ4::BlockDecoder#update`
27
+ * Streaming Encode LZ4 block data : `LZ4.block_stream_encode` and `LZ4::BlockEncoder#update` (supporting high compression level)
28
+
29
+ See [Quick reference](QUICKREF.md) for more details.
30
30
 
31
31
 
32
32
  ## ATTENTIONS (注意事項)
@@ -59,21 +59,6 @@ extlz4-0.1.1 でその不具合の修正を行いました。
59
59
  修復できるのはあくまで extlz4-0.1 のこの不具合に起因するファイルのみとなります。
60
60
 
61
61
 
62
- ## FEATURES (機能)
63
-
64
- * Generic LZ4 frame data process
65
- * Decode LZ4 Frame data : LZ4.decode
66
- * Encode LZ4 Frame data : LZ4.encode
67
- * Generic LZ4 frame data file process
68
- * Decode LZ4 Frame data file : LZ4.decode\_file
69
- * Encode LZ4 Frame data file : LZ4.encode\_file
70
- * LZ4 block data process
71
- * Decode LZ4 block data : LZ4.block\_decode
72
- * Encode LZ4 block data : LZ4.block\_encode (supporting high compression level)
73
- * Streaming Decode LZ4 block data : LZ4.block\_stream\_decode and LZ4::BlockDecoder#update
74
- * Streaming Encode LZ4 block data : LZ4.block\_stream\_encode and LZ4::BlockEncoder#update (supporting high compression level)
75
-
76
-
77
62
  ## ABOUT TAINT STATE AND SECURITY (汚染状態とセキュリティについて)
78
63
 
79
64
  extlz4 はオブジェクト間での汚染状態を一方向伝播します。
@@ -92,25 +77,25 @@ First, load extlz4. (最初に extlz4 を読み込んでください)
92
77
  require "extlz4"
93
78
  ```
94
79
 
95
- ### Decoding (伸張処理)
80
+ ### One shot decoding from LZ4 Frame (LZ4 Frame 伸張処理)
96
81
 
97
82
  ``` ruby:ruby
98
83
  uncompressed_data_string = LZ4.decode(compressed_data_string)
99
84
  ```
100
85
 
101
- ### Encoding (通常圧縮処理)
86
+ ### One shot encoding to LZ4 Frame (LZ4 Frame 通常圧縮処理)
102
87
 
103
88
  ``` ruby:ruby
104
89
  compressed_data_string = LZ4.encode(uncompressed_data_string)
105
90
  ```
106
91
 
107
- ### High compression encoding (高圧縮処理)
92
+ ### One shot high compression encoding to LZ4 Frame (LZ4 Frame 高圧縮処理)
108
93
 
109
94
  ``` ruby:ruby
110
95
  compressed_data_string = LZ4.encode(uncompressed_data_string, 9)
111
96
  ```
112
97
 
113
- ### Frame decoding
98
+ ### Stream decoding to LZ4 Frame
114
99
 
115
100
  ``` ruby:ruby
116
101
  File.open("sample.txt.lz4", "rb") do |file|
@@ -122,7 +107,7 @@ File.open("sample.txt.lz4", "rb") do |file|
122
107
  end
123
108
  ```
124
109
 
125
- ### Frame encoding by high compression
110
+ ### Stream encoding by high compression to LZ4 Frame
126
111
 
127
112
  ``` ruby:ruby
128
113
  File.open("sample.txt.lz4", "wb") do |file|
@@ -133,7 +118,7 @@ File.open("sample.txt.lz4", "wb") do |file|
133
118
  end
134
119
  ```
135
120
 
136
- ### Frame encoding without block
121
+ ### Stream encoding without block to LZ4 Frame
137
122
 
138
123
  ``` ruby:ruby
139
124
  file = File.open("sample.txt.lz4", "wb")
@@ -142,7 +127,7 @@ lz4 << "abcdefghijklmnopqrstuvwxyz\n"
142
127
  lz4.close # VERY IMPORTANT!
143
128
  ```
144
129
 
145
- ### Block data processing (fast compression encoding and decoding)
130
+ ### One shot block data processing to/from LZ4 Block (fast compression encoding and decoding)
146
131
 
147
132
  ``` ruby:ruby
148
133
  src = "abcdefg" * 100
@@ -151,7 +136,7 @@ data = LZ4.block_decode(lz4data)
151
136
  p src == data # => true
152
137
  ```
153
138
 
154
- ### Block data processing (high compression encoding and decoding)
139
+ ### One shot block data processing to/from LZ4 Block (high compression encoding and decoding)
155
140
 
156
141
  ``` ruby:ruby
157
142
  src = "abcdefg" * 100
@@ -161,7 +146,7 @@ data = LZ4.block_decode(lz4data)
161
146
  p src == data # => true
162
147
  ```
163
148
 
164
- ### Block data processing (high speed encoding)
149
+ ### One shot block data processing to/from LZ4 Block (high speed encoding)
165
150
 
166
151
  ``` ruby:ruby
167
152
  src = "abcdefg" * 100
@@ -169,7 +154,7 @@ level = -19 # transform to one's complement as acceleration
169
154
  lz4data = LZ4.block_encode(level, src)
170
155
  ```
171
156
 
172
- ### Block stream data processing (high compression encoding and decoding)
157
+ ### Block stream data processing to/from LZ4 Block (high compression encoding and decoding)
173
158
 
174
159
  ``` ruby:ruby
175
160
  level = 8 # (OPTIONAL PARAMETER)
@@ -201,3 +186,21 @@ p src2 == data # => true
201
186
  これは lz4 と同程度の機能を持ちます (車輪の再発明とも言う)。
202
187
 
203
188
  とはいえ、引数のとり方を変えてあり、gzip のような形で利用できます。
189
+
190
+
191
+ ## SPECIFICATION (仕様)
192
+
193
+ - package name: extlz4
194
+ - author: dearblue (mailto:dearblue@users.noreply.github.com)
195
+ - project page: <https://github.com/dearblue/ruby-extlz4>
196
+ - how to install: `gem install extlz4`
197
+ - version: 0.3
198
+ - product quality: technical preview
199
+ - licensing: [2 clause BSD License](LICENSE)
200
+ - dependency gems: none
201
+ - dependency external c libraries: none
202
+ - bundled external c libraries (git submodules):
203
+ - [lz4](https://github.com/lz4/lz4)
204
+ [version 1.9.0](https://github.com/lz4/lz4/tree/v1.9.0)
205
+ under [2 clause BSD license](https://github.com/lz4/lz4/blob/v1.9.0/LICENSE)
206
+ by [Yann Collet](https://github.com/Cyan4973)
@@ -1,3 +1,36 @@
1
+ v1.9.0
2
+ perf: large decompression speed improvement on x86/x64 (up to +20%) by @djwatson
3
+ api : changed : _destSize() compression variants are promoted to stable API
4
+ api : new : LZ4_initStream(HC), replacing LZ4_resetStream(HC)
5
+ api : changed : LZ4_resetStream(HC) as recommended reset function, for better performance on small data
6
+ cli : support custom block sizes, by @blezsan
7
+ build: source code can be amalgamated, by Bing Xu
8
+ build: added meson build, by @lzutao
9
+ build: new build macros : LZ4_DISTANCE_MAX, LZ4_FAST_DEC_LOOP
10
+ install: MidnightBSD, by @laffer1
11
+ install: msys2 on Windows 10, by @vtorri
12
+
13
+ v1.8.3
14
+ perf: minor decompression speed improvement (~+2%) with gcc
15
+ fix : corruption in v1.8.2 at level 9 for files > 64KB under rare conditions (#560)
16
+ cli : new command --fast, by @jennifermliu
17
+ cli : fixed elapsed time, and added cpu load indicator (on -vv) (#555)
18
+ api : LZ4_decompress_safe_partial() now decodes exactly the nb of bytes requested (feature request #566)
19
+ build : added Haiku target, by @fbrosson, and MidnightBSD, by @laffer1
20
+ doc : updated documentation regarding dictionary compression
21
+
22
+ v1.8.2
23
+ perf: *much* faster dictionary compression on small files, by @felixhandte
24
+ perf: improved decompression speed and binary size, by Alexey Tourbin (@svpv)
25
+ perf: slightly faster HC compression and decompression speed
26
+ perf: very small compression ratio improvement
27
+ fix : compression compatible with low memory addresses (< 0xFFFF)
28
+ fix : decompression segfault when provided with NULL input, by @terrelln
29
+ cli : new command --favor-decSpeed
30
+ cli : benchmark mode more accurate for small inputs
31
+ fullbench : can bench _destSize() variants, by @felixhandte
32
+ doc : clarified block format parsing restrictions, by Alexey Tourbin (@svpv)
33
+
1
34
  v1.8.1
2
35
  perf : faster and stronger ultra modes (levels 10+)
3
36
  perf : slightly faster compression and decompression speed
@@ -2,18 +2,25 @@ LZ4 - Extremely fast compression
2
2
  ================================
3
3
 
4
4
  LZ4 is lossless compression algorithm,
5
- providing compression speed at 400 MB/s per core,
5
+ providing compression speed > 500 MB/s per core,
6
6
  scalable with multi-cores CPU.
7
7
  It features an extremely fast decoder,
8
8
  with speed in multiple GB/s per core,
9
9
  typically reaching RAM speed limits on multi-core systems.
10
10
 
11
11
  Speed can be tuned dynamically, selecting an "acceleration" factor
12
- which trades compression ratio for more speed up.
12
+ which trades compression ratio for faster speed.
13
13
  On the other end, a high compression derivative, LZ4_HC, is also provided,
14
14
  trading CPU time for improved compression ratio.
15
15
  All versions feature the same decompression speed.
16
16
 
17
+ LZ4 is also compatible with [dictionary compression](https://github.com/facebook/zstd#the-case-for-small-data-compression),
18
+ both at [API](https://github.com/lz4/lz4/blob/v1.8.3/lib/lz4frame.h#L481) and [CLI](https://github.com/lz4/lz4/blob/v1.8.3/programs/lz4.1.md#operation-modifiers) levels.
19
+ It can ingest any input file as dictionary, though only the final 64KB are used.
20
+ This capability can be combined with the [Zstandard Dictionary Builder](https://github.com/facebook/zstd/blob/v1.3.5/programs/zstd.1.md#dictionary-builder),
21
+ in order to drastically improve compression performance on small files.
22
+
23
+
17
24
  LZ4 library is provided as open-source software using BSD 2-Clause license.
18
25
 
19
26
 
@@ -43,33 +50,32 @@ Benchmarks
43
50
  -------------------------
44
51
 
45
52
  The benchmark uses [lzbench], from @inikep
46
- compiled with GCC v6.2.0 on Linux 64-bits.
47
- The reference system uses a Core i7-3930K CPU @ 4.5GHz.
53
+ compiled with GCC v8.2.0 on Linux 64-bits (Ubuntu 4.18.0-17).
54
+ The reference system uses a Core i7-9700K CPU @ 4.9GHz (w/ turbo boost).
48
55
  Benchmark evaluates the compression of reference [Silesia Corpus]
49
56
  in single-thread mode.
50
57
 
51
58
  [lzbench]: https://github.com/inikep/lzbench
52
59
  [Silesia Corpus]: http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia
53
60
 
54
- | Compressor | Ratio | Compression | Decompression |
55
- | ---------- | ----- | ----------- | ------------- |
56
- | memcpy | 1.000 | 7300 MB/s | 7300 MB/s |
57
- |**LZ4 fast 8 (v1.7.3)**| 1.799 |**911 MB/s** | **3360 MB/s** |
58
- |**LZ4 default (v1.7.3)**|**2.101**|**625 MB/s** | **3220 MB/s** |
59
- | LZO 2.09 | 2.108 | 620 MB/s | 845 MB/s |
60
- | QuickLZ 1.5.0 | 2.238 | 510 MB/s | 600 MB/s |
61
- | Snappy 1.1.3 | 2.091 | 450 MB/s | 1550 MB/s |
62
- | LZF v3.6 | 2.073 | 365 MB/s | 820 MB/s |
63
- | [Zstandard] 1.1.1 -1 | 2.876 | 330 MB/s | 930 MB/s |
64
- | [Zstandard] 1.1.1 -3 | 3.164 | 200 MB/s | 810 MB/s |
65
- | [zlib] deflate 1.2.8 -1| 2.730 | 100 MB/s | 370 MB/s |
66
- |**LZ4 HC -9 (v1.7.3)** |**2.720**| 34 MB/s | **3240 MB/s** |
67
- | [zlib] deflate 1.2.8 -6| 3.099 | 33 MB/s | 390 MB/s |
61
+ | Compressor | Ratio | Compression | Decompression |
62
+ | ---------- | ----- | ----------- | ------------- |
63
+ | memcpy | 1.000 | 13700 MB/s | 13700 MB/s |
64
+ |**LZ4 default (v1.9.0)** |**2.101**| **780 MB/s**| **4970 MB/s** |
65
+ | LZO 2.09 | 2.108 | 670 MB/s | 860 MB/s |
66
+ | QuickLZ 1.5.0 | 2.238 | 575 MB/s | 780 MB/s |
67
+ | Snappy 1.1.4 | 2.091 | 565 MB/s | 1950 MB/s |
68
+ | [Zstandard] 1.4.0 -1 | 2.883 | 515 MB/s | 1380 MB/s |
69
+ | LZF v3.6 | 2.073 | 415 MB/s | 910 MB/s |
70
+ | [zlib] deflate 1.2.11 -1| 2.730 | 100 MB/s | 415 MB/s |
71
+ |**LZ4 HC -9 (v1.8.2)** |**2.721**| 41 MB/s | **4900 MB/s** |
72
+ | [zlib] deflate 1.2.11 -6| 3.099 | 36 MB/s | 445 MB/s |
68
73
 
69
74
  [zlib]: http://www.zlib.net/
70
75
  [Zstandard]: http://www.zstd.net/
71
76
 
72
- LZ4 is also compatible and well optimized for x32 mode, for which it provides an additional +10% speed performance.
77
+ LZ4 is also compatible and optimized for x32 mode,
78
+ for which it provides additional speed performance.
73
79
 
74
80
 
75
81
  Installation
@@ -77,7 +83,7 @@ Installation
77
83
 
78
84
  ```
79
85
  make
80
- make install # this command may require root access
86
+ make install # this command may require root permissions
81
87
  ```
82
88
 
83
89
  LZ4's `Makefile` supports standard [Makefile conventions],
@@ -95,10 +101,10 @@ Documentation
95
101
 
96
102
  The raw LZ4 block compression format is detailed within [lz4_Block_format].
97
103
 
98
- To compress an arbitrarily long file or data stream, multiple blocks are required.
99
- Organizing these blocks and providing a common header format to handle their content
100
- is the purpose of the Frame format, defined into [lz4_Frame_format].
101
- Interoperable versions of LZ4 must respect this frame format.
104
+ Arbitrarily long files or data streams are compressed using multiple blocks,
105
+ for streaming requirements. These blocks are organized into a frame,
106
+ defined into [lz4_Frame_format].
107
+ Interoperable versions of LZ4 must also respect the frame format.
102
108
 
103
109
  [lz4_Block_format]: doc/lz4_Block_format.md
104
110
  [lz4_Frame_format]: doc/lz4_Frame_format.md
@@ -7,22 +7,23 @@ not all of them are necessary.
7
7
  #### Minimal LZ4 build
8
8
 
9
9
  The minimum required is **`lz4.c`** and **`lz4.h`**,
10
- which provides the fast compression and decompression algorithm.
11
- They generate and decode data using [LZ4 block format].
10
+ which provides the fast compression and decompression algorithms.
11
+ They generate and decode data using the [LZ4 block format].
12
12
 
13
13
 
14
14
  #### High Compression variant
15
15
 
16
16
  For more compression ratio at the cost of compression speed,
17
17
  the High Compression variant called **lz4hc** is available.
18
- Add files **`lz4hc.c`**, **`lz4hc.h`** and **`lz4opt.h`**.
19
- The variant still depends on regular `lib/lz4.*` source files.
18
+ Add files **`lz4hc.c`** and **`lz4hc.h`**.
19
+ This variant also compresses data using the [LZ4 block format],
20
+ and depends on regular `lib/lz4.*` source files.
20
21
 
21
22
 
22
- #### Frame variant, for interoperability
23
+ #### Frame support, for interoperability
23
24
 
24
25
  In order to produce compressed data compatible with `lz4` command line utility,
25
- it's necessary to encode lz4-compressed blocks using the [official interoperable frame format].
26
+ it's necessary to use the [official interoperable frame format].
26
27
  This format is generated and decoded automatically by the **lz4frame** library.
27
28
  Its public API is described in `lib/lz4frame.h`.
28
29
  In order to work properly, lz4frame needs all other modules present in `/lib`,
@@ -32,15 +33,63 @@ So it's necessary to include all `*.c` and `*.h` files present in `/lib`.
32
33
 
33
34
  #### Advanced / Experimental API
34
35
 
35
- A complex API defined in `lz4frame_static.h` contains definitions
36
- which are not guaranteed to remain stable in future versions.
37
- As a consequence, it must be used with static linking ***only***.
36
+ Definitions which are not guaranteed to remain stable in future versions,
37
+ are protected behind macros, such as `LZ4_STATIC_LINKING_ONLY`.
38
+ As the name implies, these definitions can only be invoked
39
+ in the context of static linking ***only***.
40
+ Otherwise, dependent application may fail on API or ABI break in the future.
41
+ The associated symbols are also not present in dynamic library by default.
42
+ Should they be nonetheless needed, it's possible to force their publication
43
+ by using build macro `LZ4_PUBLISH_STATIC_FUNCTIONS`.
44
+
45
+
46
+ #### Build macros
47
+
48
+ The following build macro can be selected at compilation time :
49
+
50
+ - `LZ4_FAST_DEC_LOOP` : this triggers the optimized decompression loop.
51
+ This loops works great on x86/x64 cpus, and is automatically enabled on this platform.
52
+ It's possible to enable or disable it manually, by passing `LZ4_FAST_DEC_LOOP=1` or `0` to the preprocessor.
53
+ For example, with `gcc` : `-DLZ4_FAST_DEC_LOOP=1`,
54
+ and with `make` : `CPPFLAGS+=-DLZ4_FAST_DEC_LOOP=1 make lz4`.
55
+
56
+ - `LZ4_DISTANCE_MAX` : control the maximum offset that the compressor will allow.
57
+ Set to 65535 by default, which is the maximum value supported by lz4 format.
58
+ Reducing maximum distance will reduce opportunities for LZ4 to find matches,
59
+ hence will produce worse the compression ratio.
60
+ However, a smaller max distance may allow compatibility with specific decoders using limited memory budget.
61
+ This build macro only influences the compressed output of the compressor.
62
+
63
+ - `LZ4_DISABLE_DEPRECATE_WARNINGS` : invoking a deprecated function will make the compiler generate a warning.
64
+ This is meant to invite users to update their source code.
65
+ Should this be a problem, it's generally possible to make the compiler ignore these warnings,
66
+ for example with `-Wno-deprecated-declarations` on `gcc`,
67
+ or `_CRT_SECURE_NO_WARNINGS` for Visual Studio.
68
+ Another method is to define `LZ4_DISABLE_DEPRECATE_WARNINGS`
69
+ before including the LZ4 header files.
70
+
71
+
72
+ #### Amalgamation
73
+
74
+ lz4 source code can be amalgamated into a single file.
75
+ One can combine all source code into `lz4_all.c` by using following command:
76
+ ```
77
+ cat lz4.c > lz4_all.c
78
+ cat lz4hc.c >> lz4_all.c
79
+ cat lz4frame.c >> lz4_all.c
80
+ ```
81
+ (`cat` file order is important) then compile `lz4_all.c`.
82
+ All `*.h` files present in `/lib` remain necessary to compile `lz4_all.c`.
38
83
 
39
84
 
40
85
  #### Windows : using MinGW+MSYS to create DLL
41
86
 
42
87
  DLL can be created using MinGW+MSYS with the `make liblz4` command.
43
88
  This command creates `dll\liblz4.dll` and the import library `dll\liblz4.lib`.
89
+ To override the `dlltool` command when cross-compiling on Linux, just set the `DLLTOOL` variable. Example of cross compilation on Linux with mingw-w64 64 bits:
90
+ ```
91
+ make BUILD_STATIC=no CC=x86_64-w64-mingw32-gcc DLLTOOL=x86_64-w64-mingw32-dlltool OS=Windows_NT
92
+ ```
44
93
  The import library is only required with Visual C++.
45
94
  The header files `lz4.h`, `lz4hc.h`, `lz4frame.h` and the dynamic library
46
95
  `dll\liblz4.dll` are required to compile a project using gcc/MinGW.
@@ -48,7 +97,7 @@ The dynamic library has to be added to linking options.
48
97
  It means that if a project that uses LZ4 consists of a single `test-dll.c`
49
98
  file it should be linked with `dll\liblz4.dll`. For example:
50
99
  ```
51
- gcc $(CFLAGS) -Iinclude/ test-dll.c -o test-dll dll\liblz4.dll
100
+ $(CC) $(CFLAGS) -Iinclude/ test-dll.c -o test-dll dll\liblz4.dll
52
101
  ```
53
102
  The compiled executable will require LZ4 DLL which is available at `dll\liblz4.dll`.
54
103
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  LZ4 - Fast LZ compression algorithm
3
- Copyright (C) 2011-2017, Yann Collet.
3
+ Copyright (C) 2011-present, Yann Collet.
4
4
 
5
5
  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
6
 
@@ -32,7 +32,6 @@
32
32
  - LZ4 source repository : https://github.com/lz4/lz4
33
33
  */
34
34
 
35
-
36
35
  /*-************************************
37
36
  * Tuning parameters
38
37
  **************************************/
@@ -69,9 +68,11 @@
69
68
  * Prefer these methods in priority order (0 > 1 > 2)
70
69
  */
71
70
  #ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally */
72
- # if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
71
+ # if defined(__GNUC__) && \
72
+ ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) \
73
+ || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
73
74
  # define LZ4_FORCE_MEMORY_ACCESS 2
74
- # elif defined(__INTEL_COMPILER) || defined(__GNUC__)
75
+ # elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__)
75
76
  # define LZ4_FORCE_MEMORY_ACCESS 1
76
77
  # endif
77
78
  #endif
@@ -80,7 +81,7 @@
80
81
  * LZ4_FORCE_SW_BITCOUNT
81
82
  * Define this parameter if your target system or compiler does not support hardware bit count
82
83
  */
83
- #if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */
84
+ #if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for WinCE doesn't support Hardware bit count */
84
85
  # define LZ4_FORCE_SW_BITCOUNT
85
86
  #endif
86
87
 
@@ -89,6 +90,16 @@
89
90
  /*-************************************
90
91
  * Dependency
91
92
  **************************************/
93
+ /*
94
+ * LZ4_SRC_INCLUDED:
95
+ * Amalgamation flag, whether lz4.c is included
96
+ */
97
+ #ifndef LZ4_SRC_INCLUDED
98
+ # define LZ4_SRC_INCLUDED 1
99
+ #endif
100
+
101
+ #define LZ4_STATIC_LINKING_ONLY
102
+ #define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */
92
103
  #include "lz4.h"
93
104
  /* see also "memory routines" below */
94
105
 
@@ -132,7 +143,7 @@
132
143
  * and also LZ4_wildCopy is forcibly inlined, so that the O2 attribute
133
144
  * of LZ4_wildCopy does not affect the compression speed.
134
145
  */
135
- #if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__)
146
+ #if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__)
136
147
  # define LZ4_FORCE_O2_GCC_PPC64LE __attribute__((optimize("O2")))
137
148
  # define LZ4_FORCE_O2_INLINE_GCC_PPC64LE __attribute__((optimize("O2"))) LZ4_FORCE_INLINE
138
149
  #else
@@ -146,22 +157,27 @@
146
157
  # define expect(expr,value) (expr)
147
158
  #endif
148
159
 
160
+ #ifndef likely
149
161
  #define likely(expr) expect((expr) != 0, 1)
162
+ #endif
163
+ #ifndef unlikely
150
164
  #define unlikely(expr) expect((expr) != 0, 0)
165
+ #endif
151
166
 
152
167
 
153
168
  /*-************************************
154
169
  * Memory routines
155
170
  **************************************/
156
171
  #include <stdlib.h> /* malloc, calloc, free */
157
- #define ALLOCATOR(n,s) calloc(n,s)
158
- #define FREEMEM free
172
+ #define ALLOC(s) malloc(s)
173
+ #define ALLOC_AND_ZERO(s) calloc(1,s)
174
+ #define FREEMEM(p) free(p)
159
175
  #include <string.h> /* memset, memcpy */
160
- #define MEM_INIT memset
176
+ #define MEM_INIT(p,v,s) memset((p),(v),(s))
161
177
 
162
178
 
163
179
  /*-************************************
164
- * Basic Types
180
+ * Types
165
181
  **************************************/
166
182
  #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
167
183
  # include <stdint.h>
@@ -186,6 +202,13 @@
186
202
  typedef size_t reg_t; /* 32-bits in x32 mode */
187
203
  #endif
188
204
 
205
+ typedef enum {
206
+ notLimited = 0,
207
+ limitedOutput = 1,
208
+ fillOutput = 2
209
+ } limitedOutput_directive;
210
+
211
+
189
212
  /*-************************************
190
213
  * Reading and writing into memory
191
214
  **************************************/
@@ -219,7 +242,7 @@ static reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArc
219
242
  static void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
220
243
  static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
221
244
 
222
- #else /* safe and portable access through memcpy() */
245
+ #else /* safe and portable access using memcpy() */
223
246
 
224
247
  static U16 LZ4_read16(const void* memPtr)
225
248
  {
@@ -270,11 +293,6 @@ static void LZ4_writeLE16(void* memPtr, U16 value)
270
293
  }
271
294
  }
272
295
 
273
- static void LZ4_copy8(void* dst, const void* src)
274
- {
275
- memcpy(dst,src,8);
276
- }
277
-
278
296
  /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */
279
297
  LZ4_FORCE_O2_INLINE_GCC_PPC64LE
280
298
  void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
@@ -283,8 +301,88 @@ void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
283
301
  const BYTE* s = (const BYTE*)srcPtr;
284
302
  BYTE* const e = (BYTE*)dstEnd;
285
303
 
286
- do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e);
304
+ do { memcpy(d,s,8); d+=8; s+=8; } while (d<e);
305
+ }
306
+
307
+ static const unsigned inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4};
308
+ static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3};
309
+
310
+
311
+ #ifndef LZ4_FAST_DEC_LOOP
312
+ # if defined(__i386__) || defined(__x86_64__)
313
+ # define LZ4_FAST_DEC_LOOP 1
314
+ # else
315
+ # define LZ4_FAST_DEC_LOOP 0
316
+ # endif
317
+ #endif
318
+
319
+ #if LZ4_FAST_DEC_LOOP
320
+
321
+ LZ4_FORCE_O2_INLINE_GCC_PPC64LE void
322
+ LZ4_memcpy_using_offset_base(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)
323
+ {
324
+ if (offset < 8) {
325
+ dstPtr[0] = srcPtr[0];
326
+ dstPtr[1] = srcPtr[1];
327
+ dstPtr[2] = srcPtr[2];
328
+ dstPtr[3] = srcPtr[3];
329
+ srcPtr += inc32table[offset];
330
+ memcpy(dstPtr+4, srcPtr, 4);
331
+ srcPtr -= dec64table[offset];
332
+ dstPtr += 8;
333
+ } else {
334
+ memcpy(dstPtr, srcPtr, 8);
335
+ dstPtr += 8;
336
+ srcPtr += 8;
337
+ }
338
+
339
+ LZ4_wildCopy(dstPtr, srcPtr, dstEnd);
340
+ }
341
+
342
+ /* customized variant of memcpy, which can overwrite up to 32 bytes beyond dstEnd
343
+ * this version copies two times 16 bytes (instead of one time 32 bytes)
344
+ * because it must be compatible with offsets >= 16. */
345
+ LZ4_FORCE_O2_INLINE_GCC_PPC64LE void
346
+ LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd)
347
+ {
348
+ BYTE* d = (BYTE*)dstPtr;
349
+ const BYTE* s = (const BYTE*)srcPtr;
350
+ BYTE* const e = (BYTE*)dstEnd;
351
+
352
+ do { memcpy(d,s,16); memcpy(d+16,s+16,16); d+=32; s+=32; } while (d<e);
353
+ }
354
+
355
+ LZ4_FORCE_O2_INLINE_GCC_PPC64LE void
356
+ LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)
357
+ {
358
+ BYTE v[8];
359
+ switch(offset) {
360
+ case 1:
361
+ memset(v, *srcPtr, 8);
362
+ goto copy_loop;
363
+ case 2:
364
+ memcpy(v, srcPtr, 2);
365
+ memcpy(&v[2], srcPtr, 2);
366
+ memcpy(&v[4], &v[0], 4);
367
+ goto copy_loop;
368
+ case 4:
369
+ memcpy(v, srcPtr, 4);
370
+ memcpy(&v[4], srcPtr, 4);
371
+ goto copy_loop;
372
+ default:
373
+ LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset);
374
+ return;
375
+ }
376
+
377
+ copy_loop:
378
+ memcpy(dstPtr, v, 8);
379
+ dstPtr += 8;
380
+ while (dstPtr < dstEnd) {
381
+ memcpy(dstPtr, v, 8);
382
+ dstPtr += 8;
383
+ }
287
384
  }
385
+ #endif
288
386
 
289
387
 
290
388
  /*-************************************
@@ -293,16 +391,23 @@ void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
293
391
  #define MINMATCH 4
294
392
 
295
393
  #define WILDCOPYLENGTH 8
296
- #define LASTLITERALS 5
297
- #define MFLIMIT (WILDCOPYLENGTH+MINMATCH)
394
+ #define LASTLITERALS 5 /* see ../doc/lz4_Block_format.md#parsing-restrictions */
395
+ #define MFLIMIT 12 /* see ../doc/lz4_Block_format.md#parsing-restrictions */
396
+ #define MATCH_SAFEGUARD_DISTANCE ((2*WILDCOPYLENGTH) - MINMATCH) /* ensure it's possible to write 2 x wildcopyLength without overflowing output buffer */
397
+ #define FASTLOOP_SAFE_DISTANCE 64
298
398
  static const int LZ4_minLength = (MFLIMIT+1);
299
399
 
300
400
  #define KB *(1 <<10)
301
401
  #define MB *(1 <<20)
302
402
  #define GB *(1U<<30)
303
403
 
304
- #define MAXD_LOG 16
305
- #define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
404
+ #ifndef LZ4_DISTANCE_MAX /* can be user - defined at compile time */
405
+ # define LZ4_DISTANCE_MAX 65535
406
+ #endif
407
+
408
+ #if (LZ4_DISTANCE_MAX > 65535) /* max supported by LZ4 format */
409
+ # error "LZ4_DISTANCE_MAX is too big : must be <= 65535"
410
+ #endif
306
411
 
307
412
  #define ML_BITS 4
308
413
  #define ML_MASK ((1U<<ML_BITS)-1)
@@ -321,7 +426,7 @@ static const int LZ4_minLength = (MFLIMIT+1);
321
426
  # endif
322
427
  #endif
323
428
 
324
- #define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
429
+ #define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use after variable declarations */
325
430
 
326
431
  #if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2)
327
432
  # include <stdio.h>
@@ -450,15 +555,34 @@ static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression ru
450
555
  /*-************************************
451
556
  * Local Structures and types
452
557
  **************************************/
453
- typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive;
454
- typedef enum { byPtr, byU32, byU16 } tableType_t;
455
-
456
- typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
558
+ typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;
559
+
560
+ /**
561
+ * This enum distinguishes several different modes of accessing previous
562
+ * content in the stream.
563
+ *
564
+ * - noDict : There is no preceding content.
565
+ * - withPrefix64k : Table entries up to ctx->dictSize before the current blob
566
+ * blob being compressed are valid and refer to the preceding
567
+ * content (of length ctx->dictSize), which is available
568
+ * contiguously preceding in memory the content currently
569
+ * being compressed.
570
+ * - usingExtDict : Like withPrefix64k, but the preceding content is somewhere
571
+ * else in memory, starting at ctx->dictionary with length
572
+ * ctx->dictSize.
573
+ * - usingDictCtx : Like usingExtDict, but everything concerning the preceding
574
+ * content is in a separate context, pointed to by
575
+ * ctx->dictCtx. ctx->dictionary, ctx->dictSize, and table
576
+ * entries in the current context that refer to positions
577
+ * preceding the beginning of the current compression are
578
+ * ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx
579
+ * ->dictSize describe the location and size of the preceding
580
+ * content, and matches are found by looking in the ctx
581
+ * ->dictCtx->hashTable.
582
+ */
583
+ typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive;
457
584
  typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
458
585
 
459
- typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
460
- typedef enum { full = 0, partial = 1 } earlyEnd_directive;
461
-
462
586
 
463
587
  /*-************************************
464
588
  * Local Utils
@@ -469,6 +593,21 @@ int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); }
469
593
  int LZ4_sizeofState() { return LZ4_STREAMSIZE; }
470
594
 
471
595
 
596
+ /*-************************************
597
+ * Internal Definitions used in Tests
598
+ **************************************/
599
+ #if defined (__cplusplus)
600
+ extern "C" {
601
+ #endif
602
+
603
+ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize);
604
+
605
+ int LZ4_decompress_safe_forceExtDict(const char* in, char* out, int inSize, int outSize, const void* dict, size_t dictSize);
606
+
607
+ #if defined (__cplusplus)
608
+ }
609
+ #endif
610
+
472
611
  /*-******************************
473
612
  * Compression functions
474
613
  ********************************/
@@ -482,13 +621,14 @@ static U32 LZ4_hash4(U32 sequence, tableType_t const tableType)
482
621
 
483
622
  static U32 LZ4_hash5(U64 sequence, tableType_t const tableType)
484
623
  {
485
- static const U64 prime5bytes = 889523592379ULL;
486
- static const U64 prime8bytes = 11400714785074694791ULL;
487
624
  const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;
488
- if (LZ4_isLittleEndian())
625
+ if (LZ4_isLittleEndian()) {
626
+ const U64 prime5bytes = 889523592379ULL;
489
627
  return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));
490
- else
628
+ } else {
629
+ const U64 prime8bytes = 11400714785074694791ULL;
491
630
  return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));
631
+ }
492
632
  }
493
633
 
494
634
  LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType)
@@ -497,10 +637,25 @@ LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tab
497
637
  return LZ4_hash4(LZ4_read32(p), tableType);
498
638
  }
499
639
 
500
- static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase)
640
+ static void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType)
641
+ {
642
+ switch (tableType)
643
+ {
644
+ default: /* fallthrough */
645
+ case clearedTable: /* fallthrough */
646
+ case byPtr: { /* illegal! */ assert(0); return; }
647
+ case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; }
648
+ case byU16: { U16* hashTable = (U16*) tableBase; assert(idx < 65536); hashTable[h] = (U16)idx; return; }
649
+ }
650
+ }
651
+
652
+ static void LZ4_putPositionOnHash(const BYTE* p, U32 h,
653
+ void* tableBase, tableType_t const tableType,
654
+ const BYTE* srcBase)
501
655
  {
502
656
  switch (tableType)
503
657
  {
658
+ case clearedTable: { /* illegal! */ assert(0); return; }
504
659
  case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }
505
660
  case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }
506
661
  case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }
@@ -513,19 +668,90 @@ LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_
513
668
  LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
514
669
  }
515
670
 
516
- static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
671
+ /* LZ4_getIndexOnHash() :
672
+ * Index of match position registered in hash table.
673
+ * hash position must be calculated by using base+index, or dictBase+index.
674
+ * Assumption 1 : only valid if tableType == byU32 or byU16.
675
+ * Assumption 2 : h is presumed valid (within limits of hash table)
676
+ */
677
+ static U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType)
678
+ {
679
+ LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2);
680
+ if (tableType == byU32) {
681
+ const U32* const hashTable = (const U32*) tableBase;
682
+ assert(h < (1U << (LZ4_MEMORY_USAGE-2)));
683
+ return hashTable[h];
684
+ }
685
+ if (tableType == byU16) {
686
+ const U16* const hashTable = (const U16*) tableBase;
687
+ assert(h < (1U << (LZ4_MEMORY_USAGE-1)));
688
+ return hashTable[h];
689
+ }
690
+ assert(0); return 0; /* forbidden case */
691
+ }
692
+
693
+ static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType, const BYTE* srcBase)
517
694
  {
518
- if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
519
- if (tableType == byU32) { const U32* const hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
520
- { const U16* const hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
695
+ if (tableType == byPtr) { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; }
696
+ if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; return hashTable[h] + srcBase; }
697
+ { const U16* const hashTable = (const U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
521
698
  }
522
699
 
523
- LZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
700
+ LZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p,
701
+ const void* tableBase, tableType_t tableType,
702
+ const BYTE* srcBase)
524
703
  {
525
704
  U32 const h = LZ4_hashPosition(p, tableType);
526
705
  return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
527
706
  }
528
707
 
708
+ LZ4_FORCE_INLINE void LZ4_prepareTable(
709
+ LZ4_stream_t_internal* const cctx,
710
+ const int inputSize,
711
+ const tableType_t tableType) {
712
+ /* If compression failed during the previous step, then the context
713
+ * is marked as dirty, therefore, it has to be fully reset.
714
+ */
715
+ if (cctx->dirty) {
716
+ DEBUGLOG(5, "LZ4_prepareTable: Full reset for %p", cctx);
717
+ MEM_INIT(cctx, 0, sizeof(LZ4_stream_t_internal));
718
+ return;
719
+ }
720
+
721
+ /* If the table hasn't been used, it's guaranteed to be zeroed out, and is
722
+ * therefore safe to use no matter what mode we're in. Otherwise, we figure
723
+ * out if it's safe to leave as is or whether it needs to be reset.
724
+ */
725
+ if (cctx->tableType != clearedTable) {
726
+ if (cctx->tableType != tableType
727
+ || (tableType == byU16 && cctx->currentOffset + inputSize >= 0xFFFFU)
728
+ || (tableType == byU32 && cctx->currentOffset > 1 GB)
729
+ || tableType == byPtr
730
+ || inputSize >= 4 KB)
731
+ {
732
+ DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx);
733
+ MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE);
734
+ cctx->currentOffset = 0;
735
+ cctx->tableType = clearedTable;
736
+ } else {
737
+ DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)");
738
+ }
739
+ }
740
+
741
+ /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back, is faster
742
+ * than compressing without a gap. However, compressing with
743
+ * currentOffset == 0 is faster still, so we preserve that case.
744
+ */
745
+ if (cctx->currentOffset != 0 && tableType == byU32) {
746
+ DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset");
747
+ cctx->currentOffset += 64 KB;
748
+ }
749
+
750
+ /* Finally, clear history */
751
+ cctx->dictCtx = NULL;
752
+ cctx->dictionary = NULL;
753
+ cctx->dictSize = 0;
754
+ }
529
755
 
530
756
  /** LZ4_compress_generic() :
531
757
  inlined, to ensure branches are decided at compilation time */
@@ -534,50 +760,72 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
534
760
  const char* const source,
535
761
  char* const dest,
536
762
  const int inputSize,
763
+ int *inputConsumed, /* only written when outputDirective == fillOutput */
537
764
  const int maxOutputSize,
538
- const limitedOutput_directive outputLimited,
765
+ const limitedOutput_directive outputDirective,
539
766
  const tableType_t tableType,
540
- const dict_directive dict,
767
+ const dict_directive dictDirective,
541
768
  const dictIssue_directive dictIssue,
542
- const U32 acceleration)
769
+ const int acceleration)
543
770
  {
771
+ int result;
544
772
  const BYTE* ip = (const BYTE*) source;
545
- const BYTE* base;
773
+
774
+ U32 const startIndex = cctx->currentOffset;
775
+ const BYTE* base = (const BYTE*) source - startIndex;
546
776
  const BYTE* lowLimit;
547
- const BYTE* const lowRefLimit = ip - cctx->dictSize;
548
- const BYTE* const dictionary = cctx->dictionary;
549
- const BYTE* const dictEnd = dictionary + cctx->dictSize;
550
- const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source;
777
+
778
+ const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx;
779
+ const BYTE* const dictionary =
780
+ dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary;
781
+ const U32 dictSize =
782
+ dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize;
783
+ const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0; /* make indexes in dictCtx comparable with index in current context */
784
+
785
+ int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx);
786
+ U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */
787
+ const BYTE* const dictEnd = dictionary + dictSize;
551
788
  const BYTE* anchor = (const BYTE*) source;
552
789
  const BYTE* const iend = ip + inputSize;
553
- const BYTE* const mflimit = iend - MFLIMIT;
790
+ const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1;
554
791
  const BYTE* const matchlimit = iend - LASTLITERALS;
555
792
 
793
+ /* the dictCtx currentOffset is indexed on the start of the dictionary,
794
+ * while a dictionary in the current context precedes the currentOffset */
795
+ const BYTE* dictBase = (dictDirective == usingDictCtx) ?
796
+ dictionary + dictSize - dictCtx->currentOffset :
797
+ dictionary + dictSize - startIndex;
798
+
556
799
  BYTE* op = (BYTE*) dest;
557
800
  BYTE* const olimit = op + maxOutputSize;
558
801
 
802
+ U32 offset = 0;
559
803
  U32 forwardH;
560
804
 
561
- /* Init conditions */
562
- if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */
563
- switch(dict)
564
- {
565
- case noDict:
566
- default:
567
- base = (const BYTE*)source;
568
- lowLimit = (const BYTE*)source;
569
- break;
570
- case withPrefix64k:
571
- base = (const BYTE*)source - cctx->currentOffset;
572
- lowLimit = (const BYTE*)source - cctx->dictSize;
573
- break;
574
- case usingExtDict:
575
- base = (const BYTE*)source - cctx->currentOffset;
576
- lowLimit = (const BYTE*)source;
577
- break;
805
+ DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, tableType=%u", inputSize, tableType);
806
+ /* If init conditions are not met, we don't have to mark stream
807
+ * as having dirty context, since no action was taken yet */
808
+ if (outputDirective == fillOutput && maxOutputSize < 1) return 0; /* Impossible to store anything */
809
+ if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported inputSize, too large (or negative) */
810
+ if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
811
+ if (tableType==byPtr) assert(dictDirective==noDict); /* only supported use case with byPtr */
812
+ assert(acceleration >= 1);
813
+
814
+ lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0);
815
+
816
+ /* Update context state */
817
+ if (dictDirective == usingDictCtx) {
818
+ /* Subsequent linked blocks can't use the dictionary. */
819
+ /* Instead, they use the block we just compressed. */
820
+ cctx->dictCtx = NULL;
821
+ cctx->dictSize = (U32)inputSize;
822
+ } else {
823
+ cctx->dictSize += (U32)inputSize;
578
824
  }
579
- if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
580
- if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
825
+ cctx->currentOffset += (U32)inputSize;
826
+ cctx->tableType = (U16)tableType;
827
+
828
+ if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
581
829
 
582
830
  /* First Byte */
583
831
  LZ4_putPosition(ip, cctx->hashTable, tableType, base);
@@ -585,50 +833,106 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
585
833
 
586
834
  /* Main Loop */
587
835
  for ( ; ; ) {
588
- ptrdiff_t refDelta = 0;
589
836
  const BYTE* match;
590
837
  BYTE* token;
591
838
 
592
839
  /* Find a match */
593
- { const BYTE* forwardIp = ip;
594
- unsigned step = 1;
595
- unsigned searchMatchNb = acceleration << LZ4_skipTrigger;
840
+ if (tableType == byPtr) {
841
+ const BYTE* forwardIp = ip;
842
+ int step = 1;
843
+ int searchMatchNb = acceleration << LZ4_skipTrigger;
596
844
  do {
597
845
  U32 const h = forwardH;
598
846
  ip = forwardIp;
599
847
  forwardIp += step;
600
848
  step = (searchMatchNb++ >> LZ4_skipTrigger);
601
849
 
602
- if (unlikely(forwardIp > mflimit)) goto _last_literals;
850
+ if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;
851
+ assert(ip < mflimitPlusOne);
603
852
 
604
853
  match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);
605
- if (dict==usingExtDict) {
606
- if (match < (const BYTE*)source) {
607
- refDelta = dictDelta;
854
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
855
+ LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);
856
+
857
+ } while ( (match+LZ4_DISTANCE_MAX < ip)
858
+ || (LZ4_read32(match) != LZ4_read32(ip)) );
859
+
860
+ } else { /* byU32, byU16 */
861
+
862
+ const BYTE* forwardIp = ip;
863
+ int step = 1;
864
+ int searchMatchNb = acceleration << LZ4_skipTrigger;
865
+ do {
866
+ U32 const h = forwardH;
867
+ U32 const current = (U32)(forwardIp - base);
868
+ U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);
869
+ assert(matchIndex <= current);
870
+ assert(forwardIp - base < (ptrdiff_t)(2 GB - 1));
871
+ ip = forwardIp;
872
+ forwardIp += step;
873
+ step = (searchMatchNb++ >> LZ4_skipTrigger);
874
+
875
+ if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;
876
+ assert(ip < mflimitPlusOne);
877
+
878
+ if (dictDirective == usingDictCtx) {
879
+ if (matchIndex < startIndex) {
880
+ /* there was no match, try the dictionary */
881
+ assert(tableType == byU32);
882
+ matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);
883
+ match = dictBase + matchIndex;
884
+ matchIndex += dictDelta; /* make dictCtx index comparable with current context */
608
885
  lowLimit = dictionary;
609
886
  } else {
610
- refDelta = 0;
887
+ match = base + matchIndex;
611
888
  lowLimit = (const BYTE*)source;
612
- } }
889
+ }
890
+ } else if (dictDirective==usingExtDict) {
891
+ if (matchIndex < startIndex) {
892
+ DEBUGLOG(7, "extDict candidate: matchIndex=%5u < startIndex=%5u", matchIndex, startIndex);
893
+ assert(startIndex - matchIndex >= MINMATCH);
894
+ match = dictBase + matchIndex;
895
+ lowLimit = dictionary;
896
+ } else {
897
+ match = base + matchIndex;
898
+ lowLimit = (const BYTE*)source;
899
+ }
900
+ } else { /* single continuous memory segment */
901
+ match = base + matchIndex;
902
+ }
613
903
  forwardH = LZ4_hashPosition(forwardIp, tableType);
614
- LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);
904
+ LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);
905
+
906
+ if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) continue; /* match outside of valid area */
907
+ assert(matchIndex < current);
908
+ if ((tableType != byU16) && (matchIndex+LZ4_DISTANCE_MAX < current)) continue; /* too far */
909
+ if (tableType == byU16) assert((current - matchIndex) <= LZ4_DISTANCE_MAX); /* too_far presumed impossible with byU16 */
615
910
 
616
- } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0)
617
- || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
618
- || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) );
911
+ if (LZ4_read32(match) == LZ4_read32(ip)) {
912
+ if (maybe_extMem) offset = current - matchIndex;
913
+ break; /* match found */
914
+ }
915
+
916
+ } while(1);
619
917
  }
620
918
 
621
919
  /* Catch up */
622
- while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; }
920
+ while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }
623
921
 
624
922
  /* Encode Literals */
625
923
  { unsigned const litLength = (unsigned)(ip - anchor);
626
924
  token = op++;
627
- if ((outputLimited) && /* Check output buffer overflow */
628
- (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
629
- return 0;
925
+ if ((outputDirective == limitedOutput) && /* Check output buffer overflow */
926
+ (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)) )
927
+ return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
928
+
929
+ if ((outputDirective == fillOutput) &&
930
+ (unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) {
931
+ op--;
932
+ goto _last_literals;
933
+ }
630
934
  if (litLength >= RUN_MASK) {
631
- int len = (int)litLength-RUN_MASK;
935
+ int len = (int)(litLength - RUN_MASK);
632
936
  *token = (RUN_MASK<<ML_BITS);
633
937
  for(; len >= 255 ; len-=255) *op++ = 255;
634
938
  *op++ = (BYTE)len;
@@ -638,35 +942,71 @@ LZ4_FORCE_INLINE int LZ4_compress_generic(
638
942
  /* Copy Literals */
639
943
  LZ4_wildCopy(op, anchor, op+litLength);
640
944
  op+=litLength;
945
+ DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i",
946
+ (int)(anchor-(const BYTE*)source), litLength, (int)(ip-(const BYTE*)source));
641
947
  }
642
948
 
643
949
  _next_match:
950
+ /* at this stage, the following variables must be correctly set :
951
+ * - ip : at start of LZ operation
952
+ * - match : at start of previous pattern occurence; can be within current prefix, or within extDict
953
+ * - offset : if maybe_ext_memSegment==1 (constant)
954
+ * - lowLimit : must be == dictionary to mean "match is within extDict"; must be == source otherwise
955
+ * - token and *token : position to write 4-bits for match length; higher 4-bits for literal length supposed already written
956
+ */
957
+
958
+ if ((outputDirective == fillOutput) &&
959
+ (op + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit)) {
960
+ /* the match was too close to the end, rewind and go to last literals */
961
+ op = token;
962
+ goto _last_literals;
963
+ }
964
+
644
965
  /* Encode Offset */
645
- LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
966
+ if (maybe_extMem) { /* static test */
967
+ DEBUGLOG(6, " with offset=%u (ext if > %i)", offset, (int)(ip - (const BYTE*)source));
968
+ assert(offset <= LZ4_DISTANCE_MAX && offset > 0);
969
+ LZ4_writeLE16(op, (U16)offset); op+=2;
970
+ } else {
971
+ DEBUGLOG(6, " with offset=%u (same segment)", (U32)(ip - match));
972
+ assert(ip-match <= LZ4_DISTANCE_MAX);
973
+ LZ4_writeLE16(op, (U16)(ip - match)); op+=2;
974
+ }
646
975
 
647
976
  /* Encode MatchLength */
648
977
  { unsigned matchCode;
649
978
 
650
- if ((dict==usingExtDict) && (lowLimit==dictionary)) {
651
- const BYTE* limit;
652
- match += refDelta;
653
- limit = ip + (dictEnd-match);
979
+ if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx)
980
+ && (lowLimit==dictionary) /* match within extDict */ ) {
981
+ const BYTE* limit = ip + (dictEnd-match);
982
+ assert(dictEnd > match);
654
983
  if (limit > matchlimit) limit = matchlimit;
655
984
  matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
656
- ip += MINMATCH + matchCode;
985
+ ip += (size_t)matchCode + MINMATCH;
657
986
  if (ip==limit) {
658
- unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit);
987
+ unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit);
659
988
  matchCode += more;
660
989
  ip += more;
661
990
  }
991
+ DEBUGLOG(6, " with matchLength=%u starting in extDict", matchCode+MINMATCH);
662
992
  } else {
663
993
  matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
664
- ip += MINMATCH + matchCode;
994
+ ip += (size_t)matchCode + MINMATCH;
995
+ DEBUGLOG(6, " with matchLength=%u", matchCode+MINMATCH);
665
996
  }
666
997
 
667
- if ( outputLimited && /* Check output buffer overflow */
668
- (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) )
669
- return 0;
998
+ if ((outputDirective) && /* Check output buffer overflow */
999
+ (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) {
1000
+ if (outputDirective == fillOutput) {
1001
+ /* Match description too long : reduce it */
1002
+ U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 2 - 1 - LASTLITERALS) * 255;
1003
+ ip -= matchCode - newMatchCode;
1004
+ matchCode = newMatchCode;
1005
+ } else {
1006
+ assert(outputDirective == limitedOutput);
1007
+ return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
1008
+ }
1009
+ }
670
1010
  if (matchCode >= ML_MASK) {
671
1011
  *token += ML_MASK;
672
1012
  matchCode -= ML_MASK;
@@ -685,37 +1025,82 @@ _next_match:
685
1025
  anchor = ip;
686
1026
 
687
1027
  /* Test end of chunk */
688
- if (ip > mflimit) break;
1028
+ if (ip >= mflimitPlusOne) break;
689
1029
 
690
1030
  /* Fill table */
691
1031
  LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);
692
1032
 
693
1033
  /* Test next position */
694
- match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);
695
- if (dict==usingExtDict) {
696
- if (match < (const BYTE*)source) {
697
- refDelta = dictDelta;
698
- lowLimit = dictionary;
699
- } else {
700
- refDelta = 0;
701
- lowLimit = (const BYTE*)source;
702
- } }
703
- LZ4_putPosition(ip, cctx->hashTable, tableType, base);
704
- if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1)
705
- && (match+MAX_DISTANCE>=ip)
706
- && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) )
707
- { token=op++; *token=0; goto _next_match; }
1034
+ if (tableType == byPtr) {
1035
+
1036
+ match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);
1037
+ LZ4_putPosition(ip, cctx->hashTable, tableType, base);
1038
+ if ( (match+LZ4_DISTANCE_MAX >= ip)
1039
+ && (LZ4_read32(match) == LZ4_read32(ip)) )
1040
+ { token=op++; *token=0; goto _next_match; }
1041
+
1042
+ } else { /* byU32, byU16 */
1043
+
1044
+ U32 const h = LZ4_hashPosition(ip, tableType);
1045
+ U32 const current = (U32)(ip-base);
1046
+ U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);
1047
+ assert(matchIndex < current);
1048
+ if (dictDirective == usingDictCtx) {
1049
+ if (matchIndex < startIndex) {
1050
+ /* there was no match, try the dictionary */
1051
+ matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);
1052
+ match = dictBase + matchIndex;
1053
+ lowLimit = dictionary; /* required for match length counter */
1054
+ matchIndex += dictDelta;
1055
+ } else {
1056
+ match = base + matchIndex;
1057
+ lowLimit = (const BYTE*)source; /* required for match length counter */
1058
+ }
1059
+ } else if (dictDirective==usingExtDict) {
1060
+ if (matchIndex < startIndex) {
1061
+ match = dictBase + matchIndex;
1062
+ lowLimit = dictionary; /* required for match length counter */
1063
+ } else {
1064
+ match = base + matchIndex;
1065
+ lowLimit = (const BYTE*)source; /* required for match length counter */
1066
+ }
1067
+ } else { /* single memory segment */
1068
+ match = base + matchIndex;
1069
+ }
1070
+ LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);
1071
+ assert(matchIndex < current);
1072
+ if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1)
1073
+ && ((tableType==byU16) ? 1 : (matchIndex+LZ4_DISTANCE_MAX >= current))
1074
+ && (LZ4_read32(match) == LZ4_read32(ip)) ) {
1075
+ token=op++;
1076
+ *token=0;
1077
+ if (maybe_extMem) offset = current - matchIndex;
1078
+ DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i",
1079
+ (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source));
1080
+ goto _next_match;
1081
+ }
1082
+ }
708
1083
 
709
1084
  /* Prepare next loop */
710
1085
  forwardH = LZ4_hashPosition(++ip, tableType);
1086
+
711
1087
  }
712
1088
 
713
1089
  _last_literals:
714
1090
  /* Encode Last Literals */
715
- { size_t const lastRun = (size_t)(iend - anchor);
716
- if ( (outputLimited) && /* Check output buffer overflow */
717
- ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) )
718
- return 0;
1091
+ { size_t lastRun = (size_t)(iend - anchor);
1092
+ if ( (outputDirective) && /* Check output buffer overflow */
1093
+ (op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) {
1094
+ if (outputDirective == fillOutput) {
1095
+ /* adapt lastRun to fill 'dst' */
1096
+ assert(olimit >= op);
1097
+ lastRun = (size_t)(olimit-op) - 1;
1098
+ lastRun -= (lastRun+240)/255;
1099
+ } else {
1100
+ assert(outputDirective == limitedOutput);
1101
+ return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
1102
+ }
1103
+ }
719
1104
  if (lastRun >= RUN_MASK) {
720
1105
  size_t accumulator = lastRun - RUN_MASK;
721
1106
  *op++ = RUN_MASK << ML_BITS;
@@ -725,44 +1110,99 @@ _last_literals:
725
1110
  *op++ = (BYTE)(lastRun<<ML_BITS);
726
1111
  }
727
1112
  memcpy(op, anchor, lastRun);
1113
+ ip = anchor + lastRun;
728
1114
  op += lastRun;
729
1115
  }
730
1116
 
731
- /* End */
732
- return (int) (((char*)op)-dest);
1117
+ if (outputDirective == fillOutput) {
1118
+ *inputConsumed = (int) (((const char*)ip)-source);
1119
+ }
1120
+ DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, (int)(((char*)op) - dest));
1121
+ result = (int)(((char*)op) - dest);
1122
+ assert(result > 0);
1123
+ return result;
733
1124
  }
734
1125
 
735
1126
 
736
1127
  int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
1128
+ {
1129
+ LZ4_stream_t_internal* const ctx = & LZ4_initStream(state, sizeof(LZ4_stream_t)) -> internal_donotuse;
1130
+ assert(ctx != NULL);
1131
+ if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
1132
+ if (maxOutputSize >= LZ4_compressBound(inputSize)) {
1133
+ if (inputSize < LZ4_64Klimit) {
1134
+ return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
1135
+ } else {
1136
+ const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
1137
+ return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);
1138
+ }
1139
+ } else {
1140
+ if (inputSize < LZ4_64Klimit) {;
1141
+ return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
1142
+ } else {
1143
+ const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
1144
+ return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);
1145
+ }
1146
+ }
1147
+ }
1148
+
1149
+ /**
1150
+ * LZ4_compress_fast_extState_fastReset() :
1151
+ * A variant of LZ4_compress_fast_extState().
1152
+ *
1153
+ * Using this variant avoids an expensive initialization step. It is only safe
1154
+ * to call if the state buffer is known to be correctly initialized already
1155
+ * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of
1156
+ * "correctly initialized").
1157
+ */
1158
+ int LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration)
737
1159
  {
738
1160
  LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse;
739
- LZ4_resetStream((LZ4_stream_t*)state);
740
1161
  if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
741
1162
 
742
- if (maxOutputSize >= LZ4_compressBound(inputSize)) {
743
- if (inputSize < LZ4_64Klimit)
744
- return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
745
- else
746
- return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
1163
+ if (dstCapacity >= LZ4_compressBound(srcSize)) {
1164
+ if (srcSize < LZ4_64Klimit) {
1165
+ const tableType_t tableType = byU16;
1166
+ LZ4_prepareTable(ctx, srcSize, tableType);
1167
+ if (ctx->currentOffset) {
1168
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, dictSmall, acceleration);
1169
+ } else {
1170
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);
1171
+ }
1172
+ } else {
1173
+ const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
1174
+ LZ4_prepareTable(ctx, srcSize, tableType);
1175
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);
1176
+ }
747
1177
  } else {
748
- if (inputSize < LZ4_64Klimit)
749
- return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
750
- else
751
- return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
1178
+ if (srcSize < LZ4_64Klimit) {
1179
+ const tableType_t tableType = byU16;
1180
+ LZ4_prepareTable(ctx, srcSize, tableType);
1181
+ if (ctx->currentOffset) {
1182
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration);
1183
+ } else {
1184
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);
1185
+ }
1186
+ } else {
1187
+ const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
1188
+ LZ4_prepareTable(ctx, srcSize, tableType);
1189
+ return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);
1190
+ }
752
1191
  }
753
1192
  }
754
1193
 
755
1194
 
756
1195
  int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
757
1196
  {
1197
+ int result;
758
1198
  #if (LZ4_HEAPMODE)
759
- void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
1199
+ LZ4_stream_t* ctxPtr = ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
1200
+ if (ctxPtr == NULL) return 0;
760
1201
  #else
761
1202
  LZ4_stream_t ctx;
762
- void* const ctxPtr = &ctx;
1203
+ LZ4_stream_t* const ctxPtr = &ctx;
763
1204
  #endif
764
-
765
- int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
1205
+ result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
766
1206
 
767
1207
  #if (LZ4_HEAPMODE)
768
1208
  FREEMEM(ctxPtr);
@@ -771,205 +1211,53 @@ int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutp
771
1211
  }
772
1212
 
773
1213
 
774
- int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize)
1214
+ int LZ4_compress_default(const char* src, char* dst, int srcSize, int maxOutputSize)
775
1215
  {
776
- return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1);
1216
+ return LZ4_compress_fast(src, dst, srcSize, maxOutputSize, 1);
777
1217
  }
778
1218
 
779
1219
 
780
1220
  /* hidden debug function */
781
1221
  /* strangely enough, gcc generates faster code when this function is uncommented, even if unused */
782
- int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
1222
+ int LZ4_compress_fast_force(const char* src, char* dst, int srcSize, int dstCapacity, int acceleration)
783
1223
  {
784
1224
  LZ4_stream_t ctx;
785
- LZ4_resetStream(&ctx);
786
-
787
- if (inputSize < LZ4_64Klimit)
788
- return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
789
- else
790
- return LZ4_compress_generic(&ctx.internal_donotuse, source, dest, inputSize, maxOutputSize, limitedOutput, sizeof(void*)==8 ? byU32 : byPtr, noDict, noDictIssue, acceleration);
791
- }
792
-
793
-
794
- /*-******************************
795
- * *_destSize() variant
796
- ********************************/
797
-
798
- static int LZ4_compress_destSize_generic(
799
- LZ4_stream_t_internal* const ctx,
800
- const char* const src,
801
- char* const dst,
802
- int* const srcSizePtr,
803
- const int targetDstSize,
804
- const tableType_t tableType)
805
- {
806
- const BYTE* ip = (const BYTE*) src;
807
- const BYTE* base = (const BYTE*) src;
808
- const BYTE* lowLimit = (const BYTE*) src;
809
- const BYTE* anchor = ip;
810
- const BYTE* const iend = ip + *srcSizePtr;
811
- const BYTE* const mflimit = iend - MFLIMIT;
812
- const BYTE* const matchlimit = iend - LASTLITERALS;
813
-
814
- BYTE* op = (BYTE*) dst;
815
- BYTE* const oend = op + targetDstSize;
816
- BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */;
817
- BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */);
818
- BYTE* const oMaxSeq = oMaxLit - 1 /* token */;
819
-
820
- U32 forwardH;
821
-
822
-
823
- /* Init conditions */
824
- if (targetDstSize < 1) return 0; /* Impossible to store anything */
825
- if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
826
- if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
827
- if (*srcSizePtr<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
828
-
829
- /* First Byte */
830
- *srcSizePtr = 0;
831
- LZ4_putPosition(ip, ctx->hashTable, tableType, base);
832
- ip++; forwardH = LZ4_hashPosition(ip, tableType);
833
-
834
- /* Main Loop */
835
- for ( ; ; ) {
836
- const BYTE* match;
837
- BYTE* token;
838
-
839
- /* Find a match */
840
- { const BYTE* forwardIp = ip;
841
- unsigned step = 1;
842
- unsigned searchMatchNb = 1 << LZ4_skipTrigger;
843
-
844
- do {
845
- U32 h = forwardH;
846
- ip = forwardIp;
847
- forwardIp += step;
848
- step = (searchMatchNb++ >> LZ4_skipTrigger);
849
-
850
- if (unlikely(forwardIp > mflimit)) goto _last_literals;
851
-
852
- match = LZ4_getPositionOnHash(h, ctx->hashTable, tableType, base);
853
- forwardH = LZ4_hashPosition(forwardIp, tableType);
854
- LZ4_putPositionOnHash(ip, h, ctx->hashTable, tableType, base);
855
-
856
- } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
857
- || (LZ4_read32(match) != LZ4_read32(ip)) );
858
- }
859
-
860
- /* Catch up */
861
- while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }
862
-
863
- /* Encode Literal length */
864
- { unsigned litLength = (unsigned)(ip - anchor);
865
- token = op++;
866
- if (op + ((litLength+240)/255) + litLength > oMaxLit) {
867
- /* Not enough space for a last match */
868
- op--;
869
- goto _last_literals;
870
- }
871
- if (litLength>=RUN_MASK) {
872
- unsigned len = litLength - RUN_MASK;
873
- *token=(RUN_MASK<<ML_BITS);
874
- for(; len >= 255 ; len-=255) *op++ = 255;
875
- *op++ = (BYTE)len;
876
- }
877
- else *token = (BYTE)(litLength<<ML_BITS);
878
-
879
- /* Copy Literals */
880
- LZ4_wildCopy(op, anchor, op+litLength);
881
- op += litLength;
882
- }
883
-
884
- _next_match:
885
- /* Encode Offset */
886
- LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
887
-
888
- /* Encode MatchLength */
889
- { size_t matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
890
-
891
- if (op + ((matchLength+240)/255) > oMaxMatch) {
892
- /* Match description too long : reduce it */
893
- matchLength = (15-1) + (oMaxMatch-op) * 255;
894
- }
895
- ip += MINMATCH + matchLength;
896
-
897
- if (matchLength>=ML_MASK) {
898
- *token += ML_MASK;
899
- matchLength -= ML_MASK;
900
- while (matchLength >= 255) { matchLength-=255; *op++ = 255; }
901
- *op++ = (BYTE)matchLength;
902
- }
903
- else *token += (BYTE)(matchLength);
904
- }
905
-
906
- anchor = ip;
907
-
908
- /* Test end of block */
909
- if (ip > mflimit) break;
910
- if (op > oMaxSeq) break;
911
-
912
- /* Fill table */
913
- LZ4_putPosition(ip-2, ctx->hashTable, tableType, base);
914
-
915
- /* Test next position */
916
- match = LZ4_getPosition(ip, ctx->hashTable, tableType, base);
917
- LZ4_putPosition(ip, ctx->hashTable, tableType, base);
918
- if ( (match+MAX_DISTANCE>=ip)
919
- && (LZ4_read32(match)==LZ4_read32(ip)) )
920
- { token=op++; *token=0; goto _next_match; }
921
-
922
- /* Prepare next loop */
923
- forwardH = LZ4_hashPosition(++ip, tableType);
924
- }
925
-
926
- _last_literals:
927
- /* Encode Last Literals */
928
- { size_t lastRunSize = (size_t)(iend - anchor);
929
- if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) {
930
- /* adapt lastRunSize to fill 'dst' */
931
- lastRunSize = (oend-op) - 1;
932
- lastRunSize -= (lastRunSize+240)/255;
933
- }
934
- ip = anchor + lastRunSize;
1225
+ LZ4_initStream(&ctx, sizeof(ctx));
935
1226
 
936
- if (lastRunSize >= RUN_MASK) {
937
- size_t accumulator = lastRunSize - RUN_MASK;
938
- *op++ = RUN_MASK << ML_BITS;
939
- for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
940
- *op++ = (BYTE) accumulator;
941
- } else {
942
- *op++ = (BYTE)(lastRunSize<<ML_BITS);
943
- }
944
- memcpy(op, anchor, lastRunSize);
945
- op += lastRunSize;
1227
+ if (srcSize < LZ4_64Klimit) {
1228
+ return LZ4_compress_generic(&ctx.internal_donotuse, src, dst, srcSize, NULL, dstCapacity, limitedOutput, byU16, noDict, noDictIssue, acceleration);
1229
+ } else {
1230
+ tableType_t const addrMode = (sizeof(void*) > 4) ? byU32 : byPtr;
1231
+ return LZ4_compress_generic(&ctx.internal_donotuse, src, dst, srcSize, NULL, dstCapacity, limitedOutput, addrMode, noDict, noDictIssue, acceleration);
946
1232
  }
947
-
948
- /* End */
949
- *srcSizePtr = (int) (((const char*)ip)-src);
950
- return (int) (((char*)op)-dst);
951
1233
  }
952
1234
 
953
1235
 
1236
+ /* Note!: This function leaves the stream in an unclean/broken state!
1237
+ * It is not safe to subsequently use the same state with a _fastReset() or
1238
+ * _continue() call without resetting it. */
954
1239
  static int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)
955
1240
  {
956
- LZ4_resetStream(state);
1241
+ void* const s = LZ4_initStream(state, sizeof (*state));
1242
+ assert(s != NULL); (void)s;
957
1243
 
958
1244
  if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */
959
1245
  return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);
960
1246
  } else {
961
- if (*srcSizePtr < LZ4_64Klimit)
962
- return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, byU16);
963
- else
964
- return LZ4_compress_destSize_generic(&state->internal_donotuse, src, dst, srcSizePtr, targetDstSize, sizeof(void*)==8 ? byU32 : byPtr);
965
- }
1247
+ if (*srcSizePtr < LZ4_64Klimit) {
1248
+ return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, 1);
1249
+ } else {
1250
+ tableType_t const addrMode = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;
1251
+ return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, addrMode, noDict, noDictIssue, 1);
1252
+ } }
966
1253
  }
967
1254
 
968
1255
 
969
1256
  int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)
970
1257
  {
971
1258
  #if (LZ4_HEAPMODE)
972
- LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
1259
+ LZ4_stream_t* ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
1260
+ if (ctx == NULL) return 0;
973
1261
  #else
974
1262
  LZ4_stream_t ctxBody;
975
1263
  LZ4_stream_t* ctx = &ctxBody;
@@ -991,21 +1279,54 @@ int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targe
991
1279
 
992
1280
  LZ4_stream_t* LZ4_createStream(void)
993
1281
  {
994
- LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64);
1282
+ LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));
995
1283
  LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */
996
- LZ4_resetStream(lz4s);
1284
+ DEBUGLOG(4, "LZ4_createStream %p", lz4s);
1285
+ if (lz4s == NULL) return NULL;
1286
+ LZ4_initStream(lz4s, sizeof(*lz4s));
997
1287
  return lz4s;
998
1288
  }
999
1289
 
1290
+ #ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :
1291
+ it reports an aligment of 8-bytes,
1292
+ while actually aligning LZ4_stream_t on 4 bytes. */
1293
+ static size_t LZ4_stream_t_alignment(void)
1294
+ {
1295
+ struct { char c; LZ4_stream_t t; } t_a;
1296
+ return sizeof(t_a) - sizeof(t_a.t);
1297
+ }
1298
+ #endif
1299
+
1300
+ LZ4_stream_t* LZ4_initStream (void* buffer, size_t size)
1301
+ {
1302
+ DEBUGLOG(5, "LZ4_initStream");
1303
+ if (buffer == NULL) return NULL;
1304
+ if (size < sizeof(LZ4_stream_t)) return NULL;
1305
+ #ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :
1306
+ it reports an aligment of 8-bytes,
1307
+ while actually aligning LZ4_stream_t on 4 bytes. */
1308
+ if (((size_t)buffer) & (LZ4_stream_t_alignment() - 1)) return NULL; /* alignment check */
1309
+ #endif
1310
+ MEM_INIT(buffer, 0, sizeof(LZ4_stream_t));
1311
+ return (LZ4_stream_t*)buffer;
1312
+ }
1313
+
1314
+ /* resetStream is now deprecated,
1315
+ * prefer initStream() which is more general */
1000
1316
  void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
1001
1317
  {
1002
- DEBUGLOG(4, "LZ4_resetStream");
1318
+ DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream);
1003
1319
  MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));
1004
1320
  }
1005
1321
 
1322
+ void LZ4_resetStream_fast(LZ4_stream_t* ctx) {
1323
+ LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32);
1324
+ }
1325
+
1006
1326
  int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
1007
1327
  {
1008
1328
  if (!LZ4_stream) return 0; /* support free on NULL */
1329
+ DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream);
1009
1330
  FREEMEM(LZ4_stream);
1010
1331
  return (0);
1011
1332
  }
@@ -1015,43 +1336,77 @@ int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
1015
1336
  int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)
1016
1337
  {
1017
1338
  LZ4_stream_t_internal* dict = &LZ4_dict->internal_donotuse;
1339
+ const tableType_t tableType = byU32;
1018
1340
  const BYTE* p = (const BYTE*)dictionary;
1019
1341
  const BYTE* const dictEnd = p + dictSize;
1020
1342
  const BYTE* base;
1021
1343
 
1022
- if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */
1023
- LZ4_resetStream(LZ4_dict);
1344
+ DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict);
1024
1345
 
1025
- if (dictSize < (int)HASH_UNIT) {
1026
- dict->dictionary = NULL;
1027
- dict->dictSize = 0;
1028
- return 0;
1029
- }
1346
+ /* It's necessary to reset the context,
1347
+ * and not just continue it with prepareTable()
1348
+ * to avoid any risk of generating overflowing matchIndex
1349
+ * when compressing using this dictionary */
1350
+ LZ4_resetStream(LZ4_dict);
1351
+
1352
+ /* We always increment the offset by 64 KB, since, if the dict is longer,
1353
+ * we truncate it to the last 64k, and if it's shorter, we still want to
1354
+ * advance by a whole window length so we can provide the guarantee that
1355
+ * there are only valid offsets in the window, which allows an optimization
1356
+ * in LZ4_compress_fast_continue() where it uses noDictIssue even when the
1357
+ * dictionary isn't a full 64k. */
1030
1358
 
1031
1359
  if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;
1032
- dict->currentOffset += 64 KB;
1033
- base = p - dict->currentOffset;
1360
+ base = dictEnd - 64 KB - dict->currentOffset;
1034
1361
  dict->dictionary = p;
1035
1362
  dict->dictSize = (U32)(dictEnd - p);
1036
- dict->currentOffset += dict->dictSize;
1363
+ dict->currentOffset += 64 KB;
1364
+ dict->tableType = tableType;
1365
+
1366
+ if (dictSize < (int)HASH_UNIT) {
1367
+ return 0;
1368
+ }
1037
1369
 
1038
1370
  while (p <= dictEnd-HASH_UNIT) {
1039
- LZ4_putPosition(p, dict->hashTable, byU32, base);
1371
+ LZ4_putPosition(p, dict->hashTable, tableType, base);
1040
1372
  p+=3;
1041
1373
  }
1042
1374
 
1043
- return dict->dictSize;
1375
+ return (int)dict->dictSize;
1376
+ }
1377
+
1378
+ void LZ4_attach_dictionary(LZ4_stream_t *working_stream, const LZ4_stream_t *dictionary_stream) {
1379
+ /* Calling LZ4_resetStream_fast() here makes sure that changes will not be
1380
+ * erased by subsequent calls to LZ4_resetStream_fast() in case stream was
1381
+ * marked as having dirty context, e.g. requiring full reset.
1382
+ */
1383
+ LZ4_resetStream_fast(working_stream);
1384
+
1385
+ if (dictionary_stream != NULL) {
1386
+ /* If the current offset is zero, we will never look in the
1387
+ * external dictionary context, since there is no value a table
1388
+ * entry can take that indicate a miss. In that case, we need
1389
+ * to bump the offset to something non-zero.
1390
+ */
1391
+ if (working_stream->internal_donotuse.currentOffset == 0) {
1392
+ working_stream->internal_donotuse.currentOffset = 64 KB;
1393
+ }
1394
+ working_stream->internal_donotuse.dictCtx = &(dictionary_stream->internal_donotuse);
1395
+ } else {
1396
+ working_stream->internal_donotuse.dictCtx = NULL;
1397
+ }
1044
1398
  }
1045
1399
 
1046
1400
 
1047
- static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src)
1401
+ static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize)
1048
1402
  {
1049
- if ((LZ4_dict->currentOffset > 0x80000000) ||
1050
- ((uptrval)LZ4_dict->currentOffset > (uptrval)src)) { /* address space overflow */
1403
+ assert(nextSize >= 0);
1404
+ if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) { /* potential ptrdiff_t overflow (32-bits mode) */
1051
1405
  /* rescale hash table */
1052
1406
  U32 const delta = LZ4_dict->currentOffset - 64 KB;
1053
1407
  const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;
1054
1408
  int i;
1409
+ DEBUGLOG(4, "LZ4_renormDictT");
1055
1410
  for (i=0; i<LZ4_HASH_SIZE_U32; i++) {
1056
1411
  if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;
1057
1412
  else LZ4_dict->hashTable[i] -= delta;
@@ -1063,17 +1418,30 @@ static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src)
1063
1418
  }
1064
1419
 
1065
1420
 
1066
- int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
1421
+ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream,
1422
+ const char* source, char* dest,
1423
+ int inputSize, int maxOutputSize,
1424
+ int acceleration)
1067
1425
  {
1426
+ const tableType_t tableType = byU32;
1068
1427
  LZ4_stream_t_internal* streamPtr = &LZ4_stream->internal_donotuse;
1069
- const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
1428
+ const BYTE* dictEnd = streamPtr->dictionary + streamPtr->dictSize;
1070
1429
 
1071
- const BYTE* smallest = (const BYTE*) source;
1072
- if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */
1073
- if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd;
1074
- LZ4_renormDictT(streamPtr, smallest);
1430
+ DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i)", inputSize);
1431
+
1432
+ if (streamPtr->dirty) return 0; /* Uninitialized structure detected */
1433
+ LZ4_renormDictT(streamPtr, inputSize); /* avoid index overflow */
1075
1434
  if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
1076
1435
 
1436
+ /* invalidate tiny dictionaries */
1437
+ if ( (streamPtr->dictSize-1 < 4-1) /* intentional underflow */
1438
+ && (dictEnd != (const BYTE*)source) ) {
1439
+ DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary);
1440
+ streamPtr->dictSize = 0;
1441
+ streamPtr->dictionary = (const BYTE*)source;
1442
+ dictEnd = (const BYTE*)source;
1443
+ }
1444
+
1077
1445
  /* Check overlapping input/dictionary space */
1078
1446
  { const BYTE* sourceEnd = (const BYTE*) source + inputSize;
1079
1447
  if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) {
@@ -1086,46 +1454,61 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, ch
1086
1454
 
1087
1455
  /* prefix mode : source data follows dictionary */
1088
1456
  if (dictEnd == (const BYTE*)source) {
1089
- int result;
1090
1457
  if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
1091
- result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration);
1458
+ return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration);
1092
1459
  else
1093
- result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration);
1094
- streamPtr->dictSize += (U32)inputSize;
1095
- streamPtr->currentOffset += (U32)inputSize;
1096
- return result;
1460
+ return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration);
1097
1461
  }
1098
1462
 
1099
1463
  /* external dictionary mode */
1100
1464
  { int result;
1101
- if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
1102
- result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration);
1103
- else
1104
- result = LZ4_compress_generic(streamPtr, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration);
1465
+ if (streamPtr->dictCtx) {
1466
+ /* We depend here on the fact that dictCtx'es (produced by
1467
+ * LZ4_loadDict) guarantee that their tables contain no references
1468
+ * to offsets between dictCtx->currentOffset - 64 KB and
1469
+ * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe
1470
+ * to use noDictIssue even when the dict isn't a full 64 KB.
1471
+ */
1472
+ if (inputSize > 4 KB) {
1473
+ /* For compressing large blobs, it is faster to pay the setup
1474
+ * cost to copy the dictionary's tables into the active context,
1475
+ * so that the compression loop is only looking into one table.
1476
+ */
1477
+ memcpy(streamPtr, streamPtr->dictCtx, sizeof(LZ4_stream_t));
1478
+ result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);
1479
+ } else {
1480
+ result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration);
1481
+ }
1482
+ } else {
1483
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {
1484
+ result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration);
1485
+ } else {
1486
+ result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);
1487
+ }
1488
+ }
1105
1489
  streamPtr->dictionary = (const BYTE*)source;
1106
1490
  streamPtr->dictSize = (U32)inputSize;
1107
- streamPtr->currentOffset += (U32)inputSize;
1108
1491
  return result;
1109
1492
  }
1110
1493
  }
1111
1494
 
1112
1495
 
1113
- /* Hidden debug function, to force external dictionary mode */
1114
- int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize)
1496
+ /* Hidden debug function, to force-test external dictionary mode */
1497
+ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize)
1115
1498
  {
1116
1499
  LZ4_stream_t_internal* streamPtr = &LZ4_dict->internal_donotuse;
1117
1500
  int result;
1118
- const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
1119
1501
 
1120
- const BYTE* smallest = dictEnd;
1121
- if (smallest > (const BYTE*) source) smallest = (const BYTE*) source;
1122
- LZ4_renormDictT(streamPtr, smallest);
1502
+ LZ4_renormDictT(streamPtr, srcSize);
1123
1503
 
1124
- result = LZ4_compress_generic(streamPtr, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
1504
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {
1505
+ result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, dictSmall, 1);
1506
+ } else {
1507
+ result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
1508
+ }
1125
1509
 
1126
1510
  streamPtr->dictionary = (const BYTE*)source;
1127
- streamPtr->dictSize = (U32)inputSize;
1128
- streamPtr->currentOffset += (U32)inputSize;
1511
+ streamPtr->dictSize = (U32)srcSize;
1129
1512
 
1130
1513
  return result;
1131
1514
  }
@@ -1144,7 +1527,7 @@ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)
1144
1527
  const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize;
1145
1528
 
1146
1529
  if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */
1147
- if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize;
1530
+ if ((U32)dictSize > dict->dictSize) dictSize = (int)dict->dictSize;
1148
1531
 
1149
1532
  memmove(safeBuffer, previousDictEnd - dictSize, dictSize);
1150
1533
 
@@ -1156,234 +1539,541 @@ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)
1156
1539
 
1157
1540
 
1158
1541
 
1159
- /*-*****************************
1160
- * Decompression functions
1161
- *******************************/
1542
+ /*-*******************************
1543
+ * Decompression functions
1544
+ ********************************/
1545
+
1546
+ typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
1547
+ typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;
1548
+
1549
+ #undef MIN
1550
+ #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
1551
+
1552
+ /* Read the variable-length literal or match length.
1553
+ *
1554
+ * ip - pointer to use as input.
1555
+ * lencheck - end ip. Return an error if ip advances >= lencheck.
1556
+ * loop_check - check ip >= lencheck in body of loop. Returns loop_error if so.
1557
+ * initial_check - check ip >= lencheck before start of loop. Returns initial_error if so.
1558
+ * error (output) - error code. Should be set to 0 before call.
1559
+ */
1560
+ typedef enum { loop_error = -2, initial_error = -1, ok = 0 } variable_length_error;
1561
+ LZ4_FORCE_INLINE unsigned
1562
+ read_variable_length(const BYTE**ip, const BYTE* lencheck, int loop_check, int initial_check, variable_length_error* error)
1563
+ {
1564
+ unsigned length = 0;
1565
+ unsigned s;
1566
+ if (initial_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
1567
+ *error = initial_error;
1568
+ return length;
1569
+ }
1570
+ do {
1571
+ s = **ip;
1572
+ (*ip)++;
1573
+ length += s;
1574
+ if (loop_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
1575
+ *error = loop_error;
1576
+ return length;
1577
+ }
1578
+ } while (s==255);
1579
+
1580
+ return length;
1581
+ }
1582
+
1162
1583
  /*! LZ4_decompress_generic() :
1163
1584
  * This generic decompression function covers all use cases.
1164
1585
  * It shall be instantiated several times, using different sets of directives.
1165
1586
  * Note that it is important for performance that this function really get inlined,
1166
1587
  * in order to remove useless branches during compilation optimization.
1167
1588
  */
1168
- LZ4_FORCE_O2_GCC_PPC64LE
1169
- LZ4_FORCE_INLINE int LZ4_decompress_generic(
1589
+ LZ4_FORCE_INLINE int
1590
+ LZ4_decompress_generic(
1170
1591
  const char* const src,
1171
1592
  char* const dst,
1172
1593
  int srcSize,
1173
1594
  int outputSize, /* If endOnInput==endOnInputSize, this value is `dstCapacity` */
1174
1595
 
1175
- int endOnInput, /* endOnOutputSize, endOnInputSize */
1176
- int partialDecoding, /* full, partial */
1177
- int targetOutputSize, /* only used if partialDecoding==partial */
1178
- int dict, /* noDict, withPrefix64k, usingExtDict */
1596
+ endCondition_directive endOnInput, /* endOnOutputSize, endOnInputSize */
1597
+ earlyEnd_directive partialDecoding, /* full, partial */
1598
+ dict_directive dict, /* noDict, withPrefix64k, usingExtDict */
1179
1599
  const BYTE* const lowPrefix, /* always <= dst, == dst when no prefix */
1180
1600
  const BYTE* const dictStart, /* only if dict==usingExtDict */
1181
1601
  const size_t dictSize /* note : = 0 if noDict */
1182
1602
  )
1183
1603
  {
1184
- const BYTE* ip = (const BYTE*) src;
1185
- const BYTE* const iend = ip + srcSize;
1604
+ if (src == NULL) return -1;
1186
1605
 
1187
- BYTE* op = (BYTE*) dst;
1188
- BYTE* const oend = op + outputSize;
1189
- BYTE* cpy;
1190
- BYTE* oexit = op + targetOutputSize;
1606
+ { const BYTE* ip = (const BYTE*) src;
1607
+ const BYTE* const iend = ip + srcSize;
1191
1608
 
1192
- const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize;
1193
- const unsigned inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4};
1194
- const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3};
1609
+ BYTE* op = (BYTE*) dst;
1610
+ BYTE* const oend = op + outputSize;
1611
+ BYTE* cpy;
1195
1612
 
1196
- const int safeDecode = (endOnInput==endOnInputSize);
1197
- const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
1613
+ const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize;
1198
1614
 
1615
+ const int safeDecode = (endOnInput==endOnInputSize);
1616
+ const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
1199
1617
 
1200
- /* Special cases */
1201
- if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => just decode everything */
1202
- if ((endOnInput) && (unlikely(outputSize==0))) return ((srcSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
1203
- if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
1204
1618
 
1205
- /* Main Loop : decode sequences */
1206
- while (1) {
1207
- size_t length;
1619
+ /* Set up the "end" pointers for the shortcut. */
1620
+ const BYTE* const shortiend = iend - (endOnInput ? 14 : 8) /*maxLL*/ - 2 /*offset*/;
1621
+ const BYTE* const shortoend = oend - (endOnInput ? 14 : 8) /*maxLL*/ - 18 /*maxML*/;
1622
+
1208
1623
  const BYTE* match;
1209
1624
  size_t offset;
1625
+ unsigned token;
1626
+ size_t length;
1627
+
1628
+
1629
+ DEBUGLOG(5, "LZ4_decompress_generic (srcSize:%i, dstSize:%i)", srcSize, outputSize);
1630
+
1631
+ /* Special cases */
1632
+ assert(lowPrefix <= op);
1633
+ if ((endOnInput) && (unlikely(outputSize==0))) return ((srcSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
1634
+ if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0 ? 1 : -1);
1635
+ if ((endOnInput) && unlikely(srcSize==0)) return -1;
1636
+
1637
+ /* Currently the fast loop shows a regression on qualcomm arm chips. */
1638
+ #if LZ4_FAST_DEC_LOOP
1639
+ if ((oend - op) < FASTLOOP_SAFE_DISTANCE)
1640
+ goto safe_decode;
1641
+
1642
+ /* Fast loop : decode sequences as long as output < iend-FASTLOOP_SAFE_DISTANCE */
1643
+ while (1) {
1644
+ /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */
1645
+ assert(oend - op >= FASTLOOP_SAFE_DISTANCE);
1646
+
1647
+ token = *ip++;
1648
+ length = token >> ML_BITS; /* literal length */
1649
+
1650
+ assert(!endOnInput || ip <= iend); /* ip < iend before the increment */
1651
+
1652
+ /* decode literal length */
1653
+ if (length == RUN_MASK) {
1654
+ variable_length_error error = ok;
1655
+ length += read_variable_length(&ip, iend-RUN_MASK, endOnInput, endOnInput, &error);
1656
+ if (error == initial_error) goto _output_error;
1657
+ if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) goto _output_error; /* overflow detection */
1658
+ if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) goto _output_error; /* overflow detection */
1659
+
1660
+ /* copy literals */
1661
+ cpy = op+length;
1662
+ LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);
1663
+ if ( ((endOnInput) && ((cpy>oend-FASTLOOP_SAFE_DISTANCE) || (ip+length>iend-(2+1+LASTLITERALS))) )
1664
+ || ((!endOnInput) && (cpy>oend-FASTLOOP_SAFE_DISTANCE)) )
1665
+ {
1666
+ goto safe_literal_copy;
1667
+ }
1668
+ LZ4_wildCopy32(op, ip, cpy);
1669
+ ip += length; op = cpy;
1670
+ } else {
1671
+ cpy = op+length;
1672
+ /* We don't need to check oend, since we check it once for each loop below */
1673
+ if ( ((endOnInput) && (ip+16>iend-(2+1+LASTLITERALS))))
1674
+ {
1675
+ goto safe_literal_copy;
1676
+ }
1677
+ /* Literals can only be 14, but hope compilers optimize if we copy by a register size */
1678
+ memcpy(op, ip, 16);
1679
+ ip += length; op = cpy;
1680
+ }
1210
1681
 
1211
- unsigned const token = *ip++;
1212
-
1213
- /* shortcut for common case :
1214
- * in most circumstances, we expect to decode small matches (<= 18 bytes) separated by few literals (<= 14 bytes).
1215
- * this shortcut was tested on x86 and x64, where it improves decoding speed.
1216
- * it has not yet been benchmarked on ARM, Power, mips, etc. */
1217
- if (((ip + 14 /*maxLL*/ + 2 /*offset*/ <= iend)
1218
- & (op + 14 /*maxLL*/ + 18 /*maxML*/ <= oend))
1219
- & ((token < (15<<ML_BITS)) & ((token & ML_MASK) != 15)) ) {
1220
- size_t const ll = token >> ML_BITS;
1221
- size_t const off = LZ4_readLE16(ip+ll);
1222
- const BYTE* const matchPtr = op + ll - off; /* pointer underflow risk ? */
1223
- if ((off >= 18) /* do not deal with overlapping matches */ & (matchPtr >= lowPrefix)) {
1224
- size_t const ml = (token & ML_MASK) + MINMATCH;
1225
- memcpy(op, ip, 16); op += ll; ip += ll + 2 /*offset*/;
1226
- memcpy(op, matchPtr, 18); op += ml;
1682
+ /* get offset */
1683
+ offset = LZ4_readLE16(ip); ip+=2;
1684
+ match = op - offset;
1685
+
1686
+ /* get matchlength */
1687
+ length = token & ML_MASK;
1688
+
1689
+ if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */
1690
+
1691
+ if (length == ML_MASK) {
1692
+ variable_length_error error = ok;
1693
+ length += read_variable_length(&ip, iend - LASTLITERALS + 1, endOnInput, 0, &error);
1694
+ if (error != ok) goto _output_error;
1695
+ if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */
1696
+ length += MINMATCH;
1697
+ if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {
1698
+ goto safe_match_copy;
1699
+ }
1700
+ } else {
1701
+ length += MINMATCH;
1702
+ if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {
1703
+ goto safe_match_copy;
1704
+ }
1705
+
1706
+ /* Fastpath check: Avoids a branch in LZ4_wildCopy32 if true */
1707
+ if (!(dict == usingExtDict) || (match >= lowPrefix)) {
1708
+ if (offset >= 8) {
1709
+ memcpy(op, match, 8);
1710
+ memcpy(op+8, match+8, 8);
1711
+ memcpy(op+16, match+16, 2);
1712
+ op += length;
1713
+ continue;
1714
+ } } }
1715
+
1716
+ /* match starting within external dictionary */
1717
+ if ((dict==usingExtDict) && (match < lowPrefix)) {
1718
+ if (unlikely(op+length > oend-LASTLITERALS)) {
1719
+ if (partialDecoding) length = MIN(length, (size_t)(oend-op));
1720
+ else goto _output_error; /* doesn't respect parsing restriction */
1721
+ }
1722
+
1723
+ if (length <= (size_t)(lowPrefix-match)) {
1724
+ /* match fits entirely within external dictionary : just copy */
1725
+ memmove(op, dictEnd - (lowPrefix-match), length);
1726
+ op += length;
1727
+ } else {
1728
+ /* match stretches into both external dictionary and current block */
1729
+ size_t const copySize = (size_t)(lowPrefix - match);
1730
+ size_t const restSize = length - copySize;
1731
+ memcpy(op, dictEnd - copySize, copySize);
1732
+ op += copySize;
1733
+ if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */
1734
+ BYTE* const endOfMatch = op + restSize;
1735
+ const BYTE* copyFrom = lowPrefix;
1736
+ while (op < endOfMatch) *op++ = *copyFrom++;
1737
+ } else {
1738
+ memcpy(op, lowPrefix, restSize);
1739
+ op += restSize;
1740
+ } }
1227
1741
  continue;
1228
1742
  }
1229
- }
1230
1743
 
1231
- /* decode literal length */
1232
- if ((length=(token>>ML_BITS)) == RUN_MASK) {
1233
- unsigned s;
1234
- do {
1235
- s = *ip++;
1236
- length += s;
1237
- } while ( likely(endOnInput ? ip<iend-RUN_MASK : 1) & (s==255) );
1238
- if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) goto _output_error; /* overflow detection */
1239
- if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) goto _output_error; /* overflow detection */
1240
- }
1744
+ /* copy match within block */
1745
+ cpy = op + length;
1241
1746
 
1242
- /* copy literals */
1243
- cpy = op+length;
1244
- if ( ((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
1245
- || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) )
1246
- {
1247
- if (partialDecoding) {
1248
- if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
1249
- if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
1747
+ assert((op <= oend) && (oend-op >= 32));
1748
+ if (unlikely(offset<16)) {
1749
+ LZ4_memcpy_using_offset(op, match, cpy, offset);
1250
1750
  } else {
1251
- if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
1252
- if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
1751
+ LZ4_wildCopy32(op, match, cpy);
1253
1752
  }
1254
- memcpy(op, ip, length);
1255
- ip += length;
1256
- op += length;
1257
- break; /* Necessarily EOF, due to parsing restrictions */
1258
- }
1259
- LZ4_wildCopy(op, ip, cpy);
1260
- ip += length; op = cpy;
1261
-
1262
- /* get offset */
1263
- offset = LZ4_readLE16(ip); ip+=2;
1264
- match = op - offset;
1265
- if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */
1266
- LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */
1267
-
1268
- /* get matchlength */
1269
- length = token & ML_MASK;
1270
- if (length == ML_MASK) {
1271
- unsigned s;
1272
- do {
1273
- s = *ip++;
1274
- if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
1275
- length += s;
1276
- } while (s==255);
1277
- if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */
1753
+
1754
+ op = cpy; /* wildcopy correction */
1278
1755
  }
1279
- length += MINMATCH;
1756
+ safe_decode:
1757
+ #endif
1280
1758
 
1281
- /* check external dictionary */
1282
- if ((dict==usingExtDict) && (match < lowPrefix)) {
1283
- if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
1759
+ /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */
1760
+ while (1) {
1761
+ token = *ip++;
1762
+ length = token >> ML_BITS; /* literal length */
1763
+
1764
+ assert(!endOnInput || ip <= iend); /* ip < iend before the increment */
1765
+
1766
+ /* A two-stage shortcut for the most common case:
1767
+ * 1) If the literal length is 0..14, and there is enough space,
1768
+ * enter the shortcut and copy 16 bytes on behalf of the literals
1769
+ * (in the fast mode, only 8 bytes can be safely copied this way).
1770
+ * 2) Further if the match length is 4..18, copy 18 bytes in a similar
1771
+ * manner; but we ensure that there's enough space in the output for
1772
+ * those 18 bytes earlier, upon entering the shortcut (in other words,
1773
+ * there is a combined check for both stages).
1774
+ */
1775
+ if ( (endOnInput ? length != RUN_MASK : length <= 8)
1776
+ /* strictly "less than" on input, to re-enter the loop with at least one byte */
1777
+ && likely((endOnInput ? ip < shortiend : 1) & (op <= shortoend)) ) {
1778
+ /* Copy the literals */
1779
+ memcpy(op, ip, endOnInput ? 16 : 8);
1780
+ op += length; ip += length;
1781
+
1782
+ /* The second stage: prepare for match copying, decode full info.
1783
+ * If it doesn't work out, the info won't be wasted. */
1784
+ length = token & ML_MASK; /* match length */
1785
+ offset = LZ4_readLE16(ip); ip += 2;
1786
+ match = op - offset;
1787
+ assert(match <= op); /* check overflow */
1788
+
1789
+ /* Do not deal with overlapping matches. */
1790
+ if ( (length != ML_MASK)
1791
+ && (offset >= 8)
1792
+ && (dict==withPrefix64k || match >= lowPrefix) ) {
1793
+ /* Copy the match. */
1794
+ memcpy(op + 0, match + 0, 8);
1795
+ memcpy(op + 8, match + 8, 8);
1796
+ memcpy(op +16, match +16, 2);
1797
+ op += length + MINMATCH;
1798
+ /* Both stages worked, load the next token. */
1799
+ continue;
1800
+ }
1284
1801
 
1285
- if (length <= (size_t)(lowPrefix-match)) {
1286
- /* match can be copied as a single segment from external dictionary */
1287
- memmove(op, dictEnd - (lowPrefix-match), length);
1802
+ /* The second stage didn't work out, but the info is ready.
1803
+ * Propel it right to the point of match copying. */
1804
+ goto _copy_match;
1805
+ }
1806
+
1807
+ /* decode literal length */
1808
+ if (length == RUN_MASK) {
1809
+ variable_length_error error = ok;
1810
+ length += read_variable_length(&ip, iend-RUN_MASK, endOnInput, endOnInput, &error);
1811
+ if (error == initial_error) goto _output_error;
1812
+ if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) goto _output_error; /* overflow detection */
1813
+ if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) goto _output_error; /* overflow detection */
1814
+ }
1815
+
1816
+ /* copy literals */
1817
+ cpy = op+length;
1818
+ #if LZ4_FAST_DEC_LOOP
1819
+ safe_literal_copy:
1820
+ #endif
1821
+ LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);
1822
+ if ( ((endOnInput) && ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) )
1823
+ || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) )
1824
+ {
1825
+ if (partialDecoding) {
1826
+ if (cpy > oend) { cpy = oend; assert(op<=oend); length = (size_t)(oend-op); } /* Partial decoding : stop in the middle of literal segment */
1827
+ if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
1828
+ } else {
1829
+ if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
1830
+ if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
1831
+ }
1832
+ memcpy(op, ip, length);
1833
+ ip += length;
1288
1834
  op += length;
1835
+ if (!partialDecoding || (cpy == oend)) {
1836
+ /* Necessarily EOF, due to parsing restrictions */
1837
+ break;
1838
+ }
1839
+
1289
1840
  } else {
1290
- /* match encompass external dictionary and current block */
1291
- size_t const copySize = (size_t)(lowPrefix-match);
1292
- size_t const restSize = length - copySize;
1293
- memcpy(op, dictEnd - copySize, copySize);
1294
- op += copySize;
1295
- if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */
1296
- BYTE* const endOfMatch = op + restSize;
1297
- const BYTE* copyFrom = lowPrefix;
1298
- while (op < endOfMatch) *op++ = *copyFrom++;
1841
+ LZ4_wildCopy(op, ip, cpy); /* may overwrite up to WILDCOPYLENGTH beyond cpy */
1842
+ ip += length; op = cpy;
1843
+ }
1844
+
1845
+ /* get offset */
1846
+ offset = LZ4_readLE16(ip); ip+=2;
1847
+ match = op - offset;
1848
+
1849
+ /* get matchlength */
1850
+ length = token & ML_MASK;
1851
+
1852
+ _copy_match:
1853
+ if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */
1854
+ if (!partialDecoding) {
1855
+ assert(oend > op);
1856
+ assert(oend - op >= 4);
1857
+ LZ4_write32(op, 0); /* silence an msan warning when offset==0; costs <1%; */
1858
+ } /* note : when partialDecoding, there is no guarantee that at least 4 bytes remain available in output buffer */
1859
+
1860
+ if (length == ML_MASK) {
1861
+ variable_length_error error = ok;
1862
+ length += read_variable_length(&ip, iend - LASTLITERALS + 1, endOnInput, 0, &error);
1863
+ if (error != ok) goto _output_error;
1864
+ if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */
1865
+ }
1866
+ length += MINMATCH;
1867
+
1868
+ #if LZ4_FAST_DEC_LOOP
1869
+ safe_match_copy:
1870
+ #endif
1871
+ /* match starting within external dictionary */
1872
+ if ((dict==usingExtDict) && (match < lowPrefix)) {
1873
+ if (unlikely(op+length > oend-LASTLITERALS)) {
1874
+ if (partialDecoding) length = MIN(length, (size_t)(oend-op));
1875
+ else goto _output_error; /* doesn't respect parsing restriction */
1876
+ }
1877
+
1878
+ if (length <= (size_t)(lowPrefix-match)) {
1879
+ /* match fits entirely within external dictionary : just copy */
1880
+ memmove(op, dictEnd - (lowPrefix-match), length);
1881
+ op += length;
1299
1882
  } else {
1300
- memcpy(op, lowPrefix, restSize);
1301
- op += restSize;
1302
- } }
1303
- continue;
1304
- }
1883
+ /* match stretches into both external dictionary and current block */
1884
+ size_t const copySize = (size_t)(lowPrefix - match);
1885
+ size_t const restSize = length - copySize;
1886
+ memcpy(op, dictEnd - copySize, copySize);
1887
+ op += copySize;
1888
+ if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */
1889
+ BYTE* const endOfMatch = op + restSize;
1890
+ const BYTE* copyFrom = lowPrefix;
1891
+ while (op < endOfMatch) *op++ = *copyFrom++;
1892
+ } else {
1893
+ memcpy(op, lowPrefix, restSize);
1894
+ op += restSize;
1895
+ } }
1896
+ continue;
1897
+ }
1305
1898
 
1306
- /* copy match within block */
1307
- cpy = op + length;
1308
- if (unlikely(offset<8)) {
1309
- op[0] = match[0];
1310
- op[1] = match[1];
1311
- op[2] = match[2];
1312
- op[3] = match[3];
1313
- match += inc32table[offset];
1314
- memcpy(op+4, match, 4);
1315
- match -= dec64table[offset];
1316
- } else { LZ4_copy8(op, match); match+=8; }
1317
- op += 8;
1318
-
1319
- if (unlikely(cpy>oend-12)) {
1320
- BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1);
1321
- if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */
1322
- if (op < oCopyLimit) {
1323
- LZ4_wildCopy(op, match, oCopyLimit);
1324
- match += oCopyLimit - op;
1325
- op = oCopyLimit;
1899
+ /* copy match within block */
1900
+ cpy = op + length;
1901
+
1902
+ /* partialDecoding : may end anywhere within the block */
1903
+ assert(op<=oend);
1904
+ if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {
1905
+ size_t const mlen = MIN(length, (size_t)(oend-op));
1906
+ const BYTE* const matchEnd = match + mlen;
1907
+ BYTE* const copyEnd = op + mlen;
1908
+ if (matchEnd > op) { /* overlap copy */
1909
+ while (op < copyEnd) *op++ = *match++;
1910
+ } else {
1911
+ memcpy(op, match, mlen);
1912
+ }
1913
+ op = copyEnd;
1914
+ if (op==oend) break;
1915
+ continue;
1326
1916
  }
1327
- while (op<cpy) *op++ = *match++;
1328
- } else {
1329
- LZ4_copy8(op, match);
1330
- if (length>16) LZ4_wildCopy(op+8, match+8, cpy);
1917
+
1918
+ if (unlikely(offset<8)) {
1919
+ op[0] = match[0];
1920
+ op[1] = match[1];
1921
+ op[2] = match[2];
1922
+ op[3] = match[3];
1923
+ match += inc32table[offset];
1924
+ memcpy(op+4, match, 4);
1925
+ match -= dec64table[offset];
1926
+ } else {
1927
+ memcpy(op, match, 8);
1928
+ match += 8;
1929
+ }
1930
+ op += 8;
1931
+
1932
+ if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {
1933
+ BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1);
1934
+ if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */
1935
+ if (op < oCopyLimit) {
1936
+ LZ4_wildCopy(op, match, oCopyLimit);
1937
+ match += oCopyLimit - op;
1938
+ op = oCopyLimit;
1939
+ }
1940
+ while (op < cpy) *op++ = *match++;
1941
+ } else {
1942
+ memcpy(op, match, 8);
1943
+ if (length > 16) LZ4_wildCopy(op+8, match+8, cpy);
1944
+ }
1945
+ op = cpy; /* wildcopy correction */
1331
1946
  }
1332
- op = cpy; /* correction */
1333
- }
1334
1947
 
1335
- /* end of decoding */
1336
- if (endOnInput)
1337
- return (int) (((char*)op)-dst); /* Nb of output bytes decoded */
1338
- else
1339
- return (int) (((const char*)ip)-src); /* Nb of input bytes read */
1948
+ /* end of decoding */
1949
+ if (endOnInput)
1950
+ return (int) (((char*)op)-dst); /* Nb of output bytes decoded */
1951
+ else
1952
+ return (int) (((const char*)ip)-src); /* Nb of input bytes read */
1340
1953
 
1341
- /* Overflow error detected */
1342
- _output_error:
1343
- return (int) (-(((const char*)ip)-src))-1;
1954
+ /* Overflow error detected */
1955
+ _output_error:
1956
+ return (int) (-(((const char*)ip)-src))-1;
1957
+ }
1344
1958
  }
1345
1959
 
1346
1960
 
1961
+ /*===== Instantiate the API decoding functions. =====*/
1962
+
1347
1963
  LZ4_FORCE_O2_GCC_PPC64LE
1348
1964
  int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)
1349
1965
  {
1350
- return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0);
1966
+ return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize,
1967
+ endOnInputSize, decode_full_block, noDict,
1968
+ (BYTE*)dest, NULL, 0);
1351
1969
  }
1352
1970
 
1353
1971
  LZ4_FORCE_O2_GCC_PPC64LE
1354
- int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize)
1972
+ int LZ4_decompress_safe_partial(const char* src, char* dst, int compressedSize, int targetOutputSize, int dstCapacity)
1355
1973
  {
1356
- return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0);
1974
+ dstCapacity = MIN(targetOutputSize, dstCapacity);
1975
+ return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity,
1976
+ endOnInputSize, partial_decode,
1977
+ noDict, (BYTE*)dst, NULL, 0);
1357
1978
  }
1358
1979
 
1359
1980
  LZ4_FORCE_O2_GCC_PPC64LE
1360
1981
  int LZ4_decompress_fast(const char* source, char* dest, int originalSize)
1361
1982
  {
1362
- return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB);
1983
+ return LZ4_decompress_generic(source, dest, 0, originalSize,
1984
+ endOnOutputSize, decode_full_block, withPrefix64k,
1985
+ (BYTE*)dest - 64 KB, NULL, 0);
1986
+ }
1987
+
1988
+ /*===== Instantiate a few more decoding cases, used more than once. =====*/
1989
+
1990
+ LZ4_FORCE_O2_GCC_PPC64LE /* Exported, an obsolete API function. */
1991
+ int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)
1992
+ {
1993
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
1994
+ endOnInputSize, decode_full_block, withPrefix64k,
1995
+ (BYTE*)dest - 64 KB, NULL, 0);
1996
+ }
1997
+
1998
+ /* Another obsolete API function, paired with the previous one. */
1999
+ int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)
2000
+ {
2001
+ /* LZ4_decompress_fast doesn't validate match offsets,
2002
+ * and thus serves well with any prefixed dictionary. */
2003
+ return LZ4_decompress_fast(source, dest, originalSize);
2004
+ }
2005
+
2006
+ LZ4_FORCE_O2_GCC_PPC64LE
2007
+ static int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, int compressedSize, int maxOutputSize,
2008
+ size_t prefixSize)
2009
+ {
2010
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
2011
+ endOnInputSize, decode_full_block, noDict,
2012
+ (BYTE*)dest-prefixSize, NULL, 0);
2013
+ }
2014
+
2015
+ LZ4_FORCE_O2_GCC_PPC64LE
2016
+ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest,
2017
+ int compressedSize, int maxOutputSize,
2018
+ const void* dictStart, size_t dictSize)
2019
+ {
2020
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
2021
+ endOnInputSize, decode_full_block, usingExtDict,
2022
+ (BYTE*)dest, (const BYTE*)dictStart, dictSize);
2023
+ }
2024
+
2025
+ LZ4_FORCE_O2_GCC_PPC64LE
2026
+ static int LZ4_decompress_fast_extDict(const char* source, char* dest, int originalSize,
2027
+ const void* dictStart, size_t dictSize)
2028
+ {
2029
+ return LZ4_decompress_generic(source, dest, 0, originalSize,
2030
+ endOnOutputSize, decode_full_block, usingExtDict,
2031
+ (BYTE*)dest, (const BYTE*)dictStart, dictSize);
1363
2032
  }
1364
2033
 
2034
+ /* The "double dictionary" mode, for use with e.g. ring buffers: the first part
2035
+ * of the dictionary is passed as prefix, and the second via dictStart + dictSize.
2036
+ * These routines are used only once, in LZ4_decompress_*_continue().
2037
+ */
2038
+ LZ4_FORCE_INLINE
2039
+ int LZ4_decompress_safe_doubleDict(const char* source, char* dest, int compressedSize, int maxOutputSize,
2040
+ size_t prefixSize, const void* dictStart, size_t dictSize)
2041
+ {
2042
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
2043
+ endOnInputSize, decode_full_block, usingExtDict,
2044
+ (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize);
2045
+ }
2046
+
2047
+ LZ4_FORCE_INLINE
2048
+ int LZ4_decompress_fast_doubleDict(const char* source, char* dest, int originalSize,
2049
+ size_t prefixSize, const void* dictStart, size_t dictSize)
2050
+ {
2051
+ return LZ4_decompress_generic(source, dest, 0, originalSize,
2052
+ endOnOutputSize, decode_full_block, usingExtDict,
2053
+ (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize);
2054
+ }
1365
2055
 
1366
2056
  /*===== streaming decompression functions =====*/
1367
2057
 
1368
2058
  LZ4_streamDecode_t* LZ4_createStreamDecode(void)
1369
2059
  {
1370
- LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t));
2060
+ LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t));
2061
+ LZ4_STATIC_ASSERT(LZ4_STREAMDECODESIZE >= sizeof(LZ4_streamDecode_t_internal)); /* A compilation error here means LZ4_STREAMDECODESIZE is not large enough */
1371
2062
  return lz4s;
1372
2063
  }
1373
2064
 
1374
2065
  int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)
1375
2066
  {
1376
- if (!LZ4_stream) return 0; /* support free on NULL */
2067
+ if (LZ4_stream == NULL) return 0; /* support free on NULL */
1377
2068
  FREEMEM(LZ4_stream);
1378
2069
  return 0;
1379
2070
  }
1380
2071
 
1381
- /*!
1382
- * LZ4_setStreamDecode() :
1383
- * Use this function to instruct where to find the dictionary.
1384
- * This function is not necessary if previous data is still available where it was decoded.
1385
- * Loading a size of 0 is allowed (same effect as no dictionary).
1386
- * Return : 1 if OK, 0 if error
2072
+ /*! LZ4_setStreamDecode() :
2073
+ * Use this function to instruct where to find the dictionary.
2074
+ * This function is not necessary if previous data is still available where it was decoded.
2075
+ * Loading a size of 0 is allowed (same effect as no dictionary).
2076
+ * @return : 1 if OK, 0 if error
1387
2077
  */
1388
2078
  int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)
1389
2079
  {
@@ -1395,6 +2085,25 @@ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dicti
1395
2085
  return 1;
1396
2086
  }
1397
2087
 
2088
+ /*! LZ4_decoderRingBufferSize() :
2089
+ * when setting a ring buffer for streaming decompression (optional scenario),
2090
+ * provides the minimum size of this ring buffer
2091
+ * to be compatible with any source respecting maxBlockSize condition.
2092
+ * Note : in a ring buffer scenario,
2093
+ * blocks are presumed decompressed next to each other.
2094
+ * When not enough space remains for next block (remainingSize < maxBlockSize),
2095
+ * decoding resumes from beginning of ring buffer.
2096
+ * @return : minimum ring buffer size,
2097
+ * or 0 if there is an error (invalid maxBlockSize).
2098
+ */
2099
+ int LZ4_decoderRingBufferSize(int maxBlockSize)
2100
+ {
2101
+ if (maxBlockSize < 0) return 0;
2102
+ if (maxBlockSize > LZ4_MAX_INPUT_SIZE) return 0;
2103
+ if (maxBlockSize < 16) maxBlockSize = 16;
2104
+ return LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize);
2105
+ }
2106
+
1398
2107
  /*
1399
2108
  *_continue() :
1400
2109
  These decoding functions allow decompression of multiple blocks in "streaming" mode.
@@ -1408,21 +2117,34 @@ int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const ch
1408
2117
  LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;
1409
2118
  int result;
1410
2119
 
1411
- if (lz4sd->prefixEnd == (BYTE*)dest) {
1412
- result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
1413
- endOnInputSize, full, 0,
1414
- usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
2120
+ if (lz4sd->prefixSize == 0) {
2121
+ /* The first call, no dictionary yet. */
2122
+ assert(lz4sd->extDictSize == 0);
2123
+ result = LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);
2124
+ if (result <= 0) return result;
2125
+ lz4sd->prefixSize = (size_t)result;
2126
+ lz4sd->prefixEnd = (BYTE*)dest + result;
2127
+ } else if (lz4sd->prefixEnd == (BYTE*)dest) {
2128
+ /* They're rolling the current segment. */
2129
+ if (lz4sd->prefixSize >= 64 KB - 1)
2130
+ result = LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);
2131
+ else if (lz4sd->extDictSize == 0)
2132
+ result = LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize,
2133
+ lz4sd->prefixSize);
2134
+ else
2135
+ result = LZ4_decompress_safe_doubleDict(source, dest, compressedSize, maxOutputSize,
2136
+ lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
1415
2137
  if (result <= 0) return result;
1416
- lz4sd->prefixSize += result;
2138
+ lz4sd->prefixSize += (size_t)result;
1417
2139
  lz4sd->prefixEnd += result;
1418
2140
  } else {
2141
+ /* The buffer wraps around, or they're switching to another buffer. */
1419
2142
  lz4sd->extDictSize = lz4sd->prefixSize;
1420
2143
  lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
1421
- result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
1422
- endOnInputSize, full, 0,
1423
- usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
2144
+ result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize,
2145
+ lz4sd->externalDict, lz4sd->extDictSize);
1424
2146
  if (result <= 0) return result;
1425
- lz4sd->prefixSize = result;
2147
+ lz4sd->prefixSize = (size_t)result;
1426
2148
  lz4sd->prefixEnd = (BYTE*)dest + result;
1427
2149
  }
1428
2150
 
@@ -1434,22 +2156,30 @@ int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const ch
1434
2156
  {
1435
2157
  LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;
1436
2158
  int result;
2159
+ assert(originalSize >= 0);
1437
2160
 
1438
- if (lz4sd->prefixEnd == (BYTE*)dest) {
1439
- result = LZ4_decompress_generic(source, dest, 0, originalSize,
1440
- endOnOutputSize, full, 0,
1441
- usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
2161
+ if (lz4sd->prefixSize == 0) {
2162
+ assert(lz4sd->extDictSize == 0);
2163
+ result = LZ4_decompress_fast(source, dest, originalSize);
1442
2164
  if (result <= 0) return result;
1443
- lz4sd->prefixSize += originalSize;
2165
+ lz4sd->prefixSize = (size_t)originalSize;
2166
+ lz4sd->prefixEnd = (BYTE*)dest + originalSize;
2167
+ } else if (lz4sd->prefixEnd == (BYTE*)dest) {
2168
+ if (lz4sd->prefixSize >= 64 KB - 1 || lz4sd->extDictSize == 0)
2169
+ result = LZ4_decompress_fast(source, dest, originalSize);
2170
+ else
2171
+ result = LZ4_decompress_fast_doubleDict(source, dest, originalSize,
2172
+ lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
2173
+ if (result <= 0) return result;
2174
+ lz4sd->prefixSize += (size_t)originalSize;
1444
2175
  lz4sd->prefixEnd += originalSize;
1445
2176
  } else {
1446
2177
  lz4sd->extDictSize = lz4sd->prefixSize;
1447
2178
  lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
1448
- result = LZ4_decompress_generic(source, dest, 0, originalSize,
1449
- endOnOutputSize, full, 0,
1450
- usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
2179
+ result = LZ4_decompress_fast_extDict(source, dest, originalSize,
2180
+ lz4sd->externalDict, lz4sd->extDictSize);
1451
2181
  if (result <= 0) return result;
1452
- lz4sd->prefixSize = originalSize;
2182
+ lz4sd->prefixSize = (size_t)originalSize;
1453
2183
  lz4sd->prefixEnd = (BYTE*)dest + originalSize;
1454
2184
  }
1455
2185
 
@@ -1464,36 +2194,23 @@ Advanced decoding functions :
1464
2194
  the dictionary must be explicitly provided within parameters
1465
2195
  */
1466
2196
 
1467
- LZ4_FORCE_O2_GCC_PPC64LE
1468
- LZ4_FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize)
2197
+ int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
1469
2198
  {
1470
2199
  if (dictSize==0)
1471
- return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0);
2200
+ return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);
1472
2201
  if (dictStart+dictSize == dest) {
1473
- if (dictSize >= (int)(64 KB - 1))
1474
- return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0);
1475
- return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0);
2202
+ if (dictSize >= 64 KB - 1)
2203
+ return LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);
2204
+ return LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, dictSize);
1476
2205
  }
1477
- return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
2206
+ return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, dictSize);
1478
2207
  }
1479
2208
 
1480
- LZ4_FORCE_O2_GCC_PPC64LE
1481
- int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
1482
- {
1483
- return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize);
1484
- }
1485
-
1486
- LZ4_FORCE_O2_GCC_PPC64LE
1487
2209
  int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)
1488
2210
  {
1489
- return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize);
1490
- }
1491
-
1492
- /* debug function */
1493
- LZ4_FORCE_O2_GCC_PPC64LE
1494
- int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
1495
- {
1496
- return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
2211
+ if (dictSize==0 || dictStart+dictSize == dest)
2212
+ return LZ4_decompress_fast(source, dest, originalSize);
2213
+ return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, dictSize);
1497
2214
  }
1498
2215
 
1499
2216
 
@@ -1501,64 +2218,67 @@ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compres
1501
2218
  * Obsolete Functions
1502
2219
  ***************************************************/
1503
2220
  /* obsolete compression functions */
1504
- int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); }
1505
- int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); }
1506
- int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); }
1507
- int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); }
1508
- int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); }
1509
- int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); }
2221
+ int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)
2222
+ {
2223
+ return LZ4_compress_default(source, dest, inputSize, maxOutputSize);
2224
+ }
2225
+ int LZ4_compress(const char* source, char* dest, int inputSize)
2226
+ {
2227
+ return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize));
2228
+ }
2229
+ int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize)
2230
+ {
2231
+ return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1);
2232
+ }
2233
+ int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize)
2234
+ {
2235
+ return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1);
2236
+ }
2237
+ int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int dstCapacity)
2238
+ {
2239
+ return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, dstCapacity, 1);
2240
+ }
2241
+ int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize)
2242
+ {
2243
+ return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1);
2244
+ }
1510
2245
 
1511
2246
  /*
1512
- These function names are deprecated and should no longer be used.
2247
+ These decompression functions are deprecated and should no longer be used.
1513
2248
  They are only provided here for compatibility with older user programs.
1514
2249
  - LZ4_uncompress is totally equivalent to LZ4_decompress_fast
1515
2250
  - LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe
1516
2251
  */
1517
- int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
1518
- int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
1519
-
2252
+ int LZ4_uncompress (const char* source, char* dest, int outputSize)
2253
+ {
2254
+ return LZ4_decompress_fast(source, dest, outputSize);
2255
+ }
2256
+ int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize)
2257
+ {
2258
+ return LZ4_decompress_safe(source, dest, isize, maxOutputSize);
2259
+ }
1520
2260
 
1521
2261
  /* Obsolete Streaming functions */
1522
2262
 
1523
2263
  int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; }
1524
2264
 
1525
- static void LZ4_init(LZ4_stream_t* lz4ds, BYTE* base)
1526
- {
1527
- MEM_INIT(lz4ds, 0, sizeof(LZ4_stream_t));
1528
- lz4ds->internal_donotuse.bufferStart = base;
1529
- }
1530
-
1531
2265
  int LZ4_resetStreamState(void* state, char* inputBuffer)
1532
2266
  {
1533
- if ((((uptrval)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */
1534
- LZ4_init((LZ4_stream_t*)state, (BYTE*)inputBuffer);
2267
+ (void)inputBuffer;
2268
+ LZ4_resetStream((LZ4_stream_t*)state);
1535
2269
  return 0;
1536
2270
  }
1537
2271
 
1538
2272
  void* LZ4_create (char* inputBuffer)
1539
2273
  {
1540
- LZ4_stream_t* lz4ds = (LZ4_stream_t*)ALLOCATOR(8, sizeof(LZ4_stream_t));
1541
- LZ4_init (lz4ds, (BYTE*)inputBuffer);
1542
- return lz4ds;
1543
- }
1544
-
1545
- char* LZ4_slideInputBuffer (void* LZ4_Data)
1546
- {
1547
- LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)LZ4_Data)->internal_donotuse;
1548
- int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB);
1549
- return (char*)(ctx->bufferStart + dictSize);
2274
+ (void)inputBuffer;
2275
+ return LZ4_createStream();
1550
2276
  }
1551
2277
 
1552
- /* Obsolete streaming decompression functions */
1553
-
1554
- int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)
1555
- {
1556
- return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
1557
- }
1558
-
1559
- int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)
2278
+ char* LZ4_slideInputBuffer (void* state)
1560
2279
  {
1561
- return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
2280
+ /* avoid const char * -> char * conversion warning */
2281
+ return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary;
1562
2282
  }
1563
2283
 
1564
2284
  #endif /* LZ4_COMMONDEFS_ONLY */