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 +4 -4
- data/HISTORY.ja.md +9 -1
- data/README.md +44 -41
- data/contrib/lz4/NEWS +33 -0
- data/contrib/lz4/README.md +30 -24
- data/contrib/lz4/lib/README.md +59 -10
- data/contrib/lz4/lib/lz4.c +1303 -583
- data/contrib/lz4/lib/lz4.h +376 -176
- data/contrib/lz4/lib/lz4frame.c +447 -286
- data/contrib/lz4/lib/lz4frame.h +289 -74
- data/contrib/lz4/lib/lz4frame_static.h +4 -111
- data/contrib/lz4/lib/lz4hc.c +789 -207
- data/contrib/lz4/lib/lz4hc.h +256 -93
- data/contrib/lz4/lib/xxhash.c +376 -240
- data/contrib/lz4/lib/xxhash.h +128 -93
- data/ext/blockapi.c +2 -2
- data/ext/lz4_amalgam.c +0 -23
- data/gemstub.rb +4 -4
- data/lib/extlz4.rb +46 -0
- data/lib/extlz4/version.rb +1 -1
- metadata +33 -10
- data/contrib/lz4/circle.yml +0 -38
- data/contrib/lz4/lib/lz4opt.h +0 -356
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 738042afe5d85d9e24155d0351f9120df4ec2258ffa1f311a821c6bb399dd2a9
|
4
|
+
data.tar.gz: 88e1057d4fc464ed4cef3ac93c0e979821e07c87a6fba70d3d644d07e21d0913
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d12a084e3a34c27a64cf0b236f7475760b9be86c0654062c0d89a6d148b75811122015925a75d4c9699a5b07472b8c692abb9cd427e0aba05c0e8d0a17e4384c
|
7
|
+
data.tar.gz: b3902b0162ce3c5dc244c3c2975819a896aa294ec37f1012536eed07862e7dc6541ce10ba1869644fef8c3d6602c55ebfa1514a9128f4eded98863284843f6bd
|
data/HISTORY.ja.md
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
# extlz4-0.
|
1
|
+
# extlz4-0.3 (平成31年4月)
|
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
|
-
```
|
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
|
-
##
|
16
|
-
|
17
|
-
*
|
18
|
-
|
19
|
-
|
20
|
-
*
|
21
|
-
|
22
|
-
|
23
|
-
*
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
*
|
28
|
-
|
29
|
-
|
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
|
-
###
|
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
|
-
###
|
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
|
-
###
|
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
|
-
###
|
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
|
-
###
|
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
|
-
###
|
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
|
-
###
|
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
|
-
###
|
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
|
-
###
|
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)
|
data/contrib/lz4/NEWS
CHANGED
@@ -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
|
data/contrib/lz4/README.md
CHANGED
@@ -2,18 +2,25 @@ LZ4 - Extremely fast compression
|
|
2
2
|
================================
|
3
3
|
|
4
4
|
LZ4 is lossless compression algorithm,
|
5
|
-
providing compression speed
|
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
|
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
|
47
|
-
The reference system uses a Core i7-
|
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
|
55
|
-
| ----------
|
56
|
-
| memcpy
|
57
|
-
|**LZ4
|
58
|
-
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
| LZF v3.6
|
63
|
-
|
|
64
|
-
|
65
|
-
| [zlib] deflate 1.2.
|
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
|
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
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
Interoperable versions of LZ4 must respect
|
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
|
data/contrib/lz4/lib/README.md
CHANGED
@@ -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
|
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
|
19
|
-
|
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
|
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
|
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
|
-
|
36
|
-
|
37
|
-
As
|
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
|
-
|
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
|
|
data/contrib/lz4/lib/lz4.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
LZ4 - Fast LZ compression algorithm
|
3
|
-
Copyright (C) 2011-
|
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__) &&
|
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
|
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
|
158
|
-
#define
|
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
|
176
|
+
#define MEM_INIT(p,v,s) memset((p),(v),(s))
|
161
177
|
|
162
178
|
|
163
179
|
/*-************************************
|
164
|
-
*
|
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
|
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 {
|
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
|
297
|
-
#define MFLIMIT
|
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
|
-
#
|
305
|
-
#define
|
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
|
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 {
|
454
|
-
|
455
|
-
|
456
|
-
|
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
|
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
|
-
|
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
|
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,
|
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
|
765
|
+
const limitedOutput_directive outputDirective,
|
539
766
|
const tableType_t tableType,
|
540
|
-
const dict_directive
|
767
|
+
const dict_directive dictDirective,
|
541
768
|
const dictIssue_directive dictIssue,
|
542
|
-
const
|
769
|
+
const int acceleration)
|
543
770
|
{
|
771
|
+
int result;
|
544
772
|
const BYTE* ip = (const BYTE*) source;
|
545
|
-
|
773
|
+
|
774
|
+
U32 const startIndex = cctx->currentOffset;
|
775
|
+
const BYTE* base = (const BYTE*) source - startIndex;
|
546
776
|
const BYTE* lowLimit;
|
547
|
-
|
548
|
-
const
|
549
|
-
const BYTE* const
|
550
|
-
|
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
|
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
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
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
|
-
|
580
|
-
|
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
|
-
|
594
|
-
|
595
|
-
|
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 >
|
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
|
-
|
606
|
-
|
607
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
617
|
-
|
618
|
-
|
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
|
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 ((
|
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
|
-
|
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 ((
|
651
|
-
|
652
|
-
|
653
|
-
|
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 +=
|
985
|
+
ip += (size_t)matchCode + MINMATCH;
|
657
986
|
if (ip==limit) {
|
658
|
-
unsigned const more = LZ4_count(
|
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 +=
|
994
|
+
ip += (size_t)matchCode + MINMATCH;
|
995
|
+
DEBUGLOG(6, " with matchLength=%u", matchCode+MINMATCH);
|
665
996
|
}
|
666
997
|
|
667
|
-
if (
|
668
|
-
(unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) )
|
669
|
-
|
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
|
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
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
}
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
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
|
716
|
-
if ( (
|
717
|
-
(
|
718
|
-
|
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
|
-
|
732
|
-
|
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 (
|
743
|
-
if (
|
744
|
-
|
745
|
-
|
746
|
-
|
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 (
|
749
|
-
|
750
|
-
|
751
|
-
|
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
|
-
|
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
|
-
|
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*
|
1214
|
+
int LZ4_compress_default(const char* src, char* dst, int srcSize, int maxOutputSize)
|
775
1215
|
{
|
776
|
-
return LZ4_compress_fast(
|
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*
|
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
|
-
|
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
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
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
|
-
|
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
|
963
|
-
else
|
964
|
-
|
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*)
|
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*)
|
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
|
-
|
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(
|
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
|
-
|
1023
|
-
LZ4_resetStream(LZ4_dict);
|
1344
|
+
DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict);
|
1024
1345
|
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
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
|
-
|
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 +=
|
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,
|
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,
|
1401
|
+
static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize)
|
1048
1402
|
{
|
1049
|
-
|
1050
|
-
|
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,
|
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*
|
1428
|
+
const BYTE* dictEnd = streamPtr->dictionary + streamPtr->dictSize;
|
1070
1429
|
|
1071
|
-
|
1072
|
-
|
1073
|
-
if (
|
1074
|
-
LZ4_renormDictT(streamPtr,
|
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
|
-
|
1458
|
+
return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration);
|
1092
1459
|
else
|
1093
|
-
|
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 (
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
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
|
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
|
-
|
1121
|
-
if (smallest > (const BYTE*) source) smallest = (const BYTE*) source;
|
1122
|
-
LZ4_renormDictT(streamPtr, smallest);
|
1502
|
+
LZ4_renormDictT(streamPtr, srcSize);
|
1123
1503
|
|
1124
|
-
|
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)
|
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
|
-
|
1169
|
-
|
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
|
-
|
1176
|
-
|
1177
|
-
|
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
|
-
|
1185
|
-
const BYTE* const iend = ip + srcSize;
|
1604
|
+
if (src == NULL) return -1;
|
1186
1605
|
|
1187
|
-
BYTE*
|
1188
|
-
|
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
|
-
|
1193
|
-
|
1194
|
-
|
1609
|
+
BYTE* op = (BYTE*) dst;
|
1610
|
+
BYTE* const oend = op + outputSize;
|
1611
|
+
BYTE* cpy;
|
1195
1612
|
|
1196
|
-
|
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
|
-
|
1206
|
-
|
1207
|
-
|
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
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
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
|
-
|
1232
|
-
|
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
|
-
|
1243
|
-
|
1244
|
-
|
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
|
-
|
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
|
-
|
1255
|
-
|
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
|
-
|
1756
|
+
safe_decode:
|
1757
|
+
#endif
|
1280
1758
|
|
1281
|
-
/*
|
1282
|
-
|
1283
|
-
|
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
|
-
|
1286
|
-
|
1287
|
-
|
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
|
-
/*
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
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
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
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
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
op
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
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
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
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
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
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
|
-
|
1342
|
-
_output_error:
|
1343
|
-
|
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,
|
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*
|
1972
|
+
int LZ4_decompress_safe_partial(const char* src, char* dst, int compressedSize, int targetOutputSize, int dstCapacity)
|
1355
1973
|
{
|
1356
|
-
|
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,
|
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*)
|
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 (
|
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
|
-
*
|
1383
|
-
*
|
1384
|
-
*
|
1385
|
-
*
|
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->
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
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 =
|
1422
|
-
|
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->
|
1439
|
-
|
1440
|
-
|
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
|
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 =
|
1449
|
-
|
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
|
-
|
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
|
2200
|
+
return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);
|
1472
2201
|
if (dictStart+dictSize == dest) {
|
1473
|
-
if (dictSize >=
|
1474
|
-
return
|
1475
|
-
return
|
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
|
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
|
-
|
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)
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
int
|
1509
|
-
|
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
|
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)
|
1518
|
-
|
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
|
-
|
1534
|
-
|
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
|
-
|
1541
|
-
|
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
|
-
|
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
|
-
|
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 */
|