##// END OF EJS Templates
zstd: vendor python-zstandard 0.6.0...
Gregory Szorc -
r30822:b54a2984 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,2 +1,5 b''
1 graft c-ext
1 2 graft zstd
2 3 include make_cffi.py
4 include setup_zstd.py
5 include zstd.c
@@ -1,63 +1,90 b''
1 1 Version History
2 2 ===============
3 3
4 0.6.0 (released 2017-01-14)
5 ---------------------------
6
7 * Support for legacy zstd protocols (build time opt in feature).
8 * Automation improvements to test against Python 3.6, latest versions
9 of Tox, more deterministic AppVeyor behavior.
10 * CFFI "parser" improved to use a compiler preprocessor instead of rewriting
11 source code manually.
12 * Vendored version of zstd updated to 1.1.2.
13 * Documentation improvements.
14 * Introduce a bench.py script for performing (crude) benchmarks.
15 * ZSTD_CCtx instances are now reused across multiple compress() operations.
16 * ZstdCompressor.write_to() now has a flush() method.
17 * ZstdCompressor.compressobj()'s flush() method now accepts an argument to
18 flush a block (as opposed to ending the stream).
19 * Disallow compress(b'') when writing content sizes by default (issue #11).
20
21 0.5.2 (released 2016-11-12)
22 ---------------------------
23
24 * more packaging fixes for source distribution
25
26 0.5.1 (released 2016-11-12)
27 ---------------------------
28
29 * setup_zstd.py is included in the source distribution
30
4 31 0.5.0 (released 2016-11-10)
5 32 ---------------------------
6 33
7 34 * Vendored version of zstd updated to 1.1.1.
8 35 * Continuous integration for Python 3.6 and 3.7
9 36 * Continuous integration for Conda
10 37 * Added compression and decompression APIs providing similar interfaces
11 38 to the standard library ``zlib`` and ``bz2`` modules. This allows
12 39 coding to a common interface.
13 40 * ``zstd.__version__` is now defined.
14 41 * ``read_from()`` on various APIs now accepts objects implementing the buffer
15 42 protocol.
16 43 * ``read_from()`` has gained a ``skip_bytes`` argument. This allows callers
17 44 to pass in an existing buffer with a header without having to create a
18 45 slice or a new object.
19 46 * Implemented ``ZstdCompressionDict.as_bytes()``.
20 47 * Python's memory allocator is now used instead of ``malloc()``.
21 48 * Low-level zstd data structures are reused in more instances, cutting down
22 49 on overhead for certain operations.
23 50 * ``distutils`` boilerplate for obtaining an ``Extension`` instance
24 51 has now been refactored into a standalone ``setup_zstd.py`` file. This
25 52 allows other projects with ``setup.py`` files to reuse the
26 53 ``distutils`` code for this project without copying code.
27 54 * The monolithic ``zstd.c`` file has been split into a header file defining
28 55 types and separate ``.c`` source files for the implementation.
29 56
30 57 History of the Project
31 58 ======================
32 59
33 60 2016-08-31 - Zstandard 1.0.0 is released and Gregory starts hacking on a
34 61 Python extension for use by the Mercurial project. A very hacky prototype
35 62 is sent to the mercurial-devel list for RFC.
36 63
37 64 2016-09-03 - Most functionality from Zstandard C API implemented. Source
38 65 code published on https://github.com/indygreg/python-zstandard. Travis-CI
39 66 automation configured. 0.0.1 release on PyPI.
40 67
41 68 2016-09-05 - After the API was rounded out a bit and support for Python
42 69 2.6 and 2.7 was added, version 0.1 was released to PyPI.
43 70
44 71 2016-09-05 - After the compressor and decompressor APIs were changed, 0.2
45 72 was released to PyPI.
46 73
47 74 2016-09-10 - 0.3 is released with a bunch of new features. ZstdCompressor
48 75 now accepts arguments controlling frame parameters. The source size can now
49 76 be declared when performing streaming compression. ZstdDecompressor.decompress()
50 77 is implemented. Compression dictionaries are now cached when using the simple
51 78 compression and decompression APIs. Memory size APIs added.
52 79 ZstdCompressor.read_from() and ZstdDecompressor.read_from() have been
53 80 implemented. This rounds out the major compression/decompression APIs planned
54 81 by the author.
55 82
56 83 2016-10-02 - 0.3.3 is released with a bug fix for read_from not fully
57 84 decoding a zstd frame (issue #2).
58 85
59 86 2016-10-02 - 0.4.0 is released with zstd 1.1.0, support for custom read and
60 87 write buffer sizes, and a few bug fixes involving failure to read/write
61 88 all data when buffer sizes were too small to hold remaining data.
62 89
63 90 2016-11-10 - 0.5.0 is released with zstd 1.1.1 and other enhancements.
@@ -1,776 +1,829 b''
1 1 ================
2 2 python-zstandard
3 3 ================
4 4
5 This project provides a Python C extension for interfacing with the
6 `Zstandard <http://www.zstd.net>`_ compression library.
5 This project provides Python bindings for interfacing with the
6 `Zstandard <http://www.zstd.net>`_ compression library. A C extension
7 and CFFI interface is provided.
7 8
8 9 The primary goal of the extension is to provide a Pythonic interface to
9 10 the underlying C API. This means exposing most of the features and flexibility
10 11 of the C API while not sacrificing usability or safety that Python provides.
11 12
13 The canonical home for this project is
14 https://github.com/indygreg/python-zstandard.
15
12 16 | |ci-status| |win-ci-status|
13 17
14 18 State of Project
15 19 ================
16 20
17 21 The project is officially in beta state. The author is reasonably satisfied
18 22 with the current API and that functionality works as advertised. There
19 23 may be some backwards incompatible changes before 1.0. Though the author
20 24 does not intend to make any major changes to the Python API.
21 25
22 26 There is continuous integration for Python versions 2.6, 2.7, and 3.3+
23 27 on Linux x86_x64 and Windows x86 and x86_64. The author is reasonably
24 28 confident the extension is stable and works as advertised on these
25 29 platforms.
26 30
27 31 Expected Changes
28 32 ----------------
29 33
30 34 The author is reasonably confident in the current state of what's
31 35 implemented on the ``ZstdCompressor`` and ``ZstdDecompressor`` types.
32 36 Those APIs likely won't change significantly. Some low-level behavior
33 37 (such as naming and types expected by arguments) may change.
34 38
35 39 There will likely be arguments added to control the input and output
36 40 buffer sizes (currently, certain operations read and write in chunk
37 41 sizes using zstd's preferred defaults).
38 42
39 43 There should be an API that accepts an object that conforms to the buffer
40 44 interface and returns an iterator over compressed or decompressed output.
41 45
42 46 The author is on the fence as to whether to support the extremely
43 47 low level compression and decompression APIs. It could be useful to
44 48 support compression without the framing headers. But the author doesn't
45 49 believe it a high priority at this time.
46 50
47 51 The CFFI bindings are half-baked and need to be finished.
48 52
49 53 Requirements
50 54 ============
51 55
52 56 This extension is designed to run with Python 2.6, 2.7, 3.3, 3.4, and 3.5
53 57 on common platforms (Linux, Windows, and OS X). Only x86_64 is currently
54 58 well-tested as an architecture.
55 59
56 60 Installing
57 61 ==========
58 62
59 63 This package is uploaded to PyPI at https://pypi.python.org/pypi/zstandard.
60 64 So, to install this package::
61 65
62 66 $ pip install zstandard
63 67
64 68 Binary wheels are made available for some platforms. If you need to
65 69 install from a source distribution, all you should need is a working C
66 70 compiler and the Python development headers/libraries. On many Linux
67 71 distributions, you can install a ``python-dev`` or ``python-devel``
68 72 package to provide these dependencies.
69 73
70 74 Packages are also uploaded to Anaconda Cloud at
71 75 https://anaconda.org/indygreg/zstandard. See that URL for how to install
72 76 this package with ``conda``.
73 77
74 78 Performance
75 79 ===========
76 80
77 81 Very crude and non-scientific benchmarking (most benchmarks fall in this
78 82 category because proper benchmarking is hard) show that the Python bindings
79 83 perform within 10% of the native C implementation.
80 84
81 85 The following table compares the performance of compressing and decompressing
82 86 a 1.1 GB tar file comprised of the files in a Firefox source checkout. Values
83 87 obtained with the ``zstd`` program are on the left. The remaining columns detail
84 88 performance of various compression APIs in the Python bindings.
85 89
86 90 +-------+-----------------+-----------------+-----------------+---------------+
87 91 | Level | Native | Simple | Stream In | Stream Out |
88 92 | | Comp / Decomp | Comp / Decomp | Comp / Decomp | Comp |
89 93 +=======+=================+=================+=================+===============+
90 94 | 1 | 490 / 1338 MB/s | 458 / 1266 MB/s | 407 / 1156 MB/s | 405 MB/s |
91 95 +-------+-----------------+-----------------+-----------------+---------------+
92 96 | 2 | 412 / 1288 MB/s | 381 / 1203 MB/s | 345 / 1128 MB/s | 349 MB/s |
93 97 +-------+-----------------+-----------------+-----------------+---------------+
94 98 | 3 | 342 / 1312 MB/s | 319 / 1182 MB/s | 285 / 1165 MB/s | 287 MB/s |
95 99 +-------+-----------------+-----------------+-----------------+---------------+
96 100 | 11 | 64 / 1506 MB/s | 66 / 1436 MB/s | 56 / 1342 MB/s | 57 MB/s |
97 101 +-------+-----------------+-----------------+-----------------+---------------+
98 102
99 103 Again, these are very unscientific. But it shows that Python is capable of
100 104 compressing at several hundred MB/s and decompressing at over 1 GB/s.
101 105
102 106 Comparison to Other Python Bindings
103 107 ===================================
104 108
105 109 https://pypi.python.org/pypi/zstd is an alternative Python binding to
106 110 Zstandard. At the time this was written, the latest release of that
107 111 package (1.0.0.2) had the following significant differences from this package:
108 112
109 113 * It only exposes the simple API for compression and decompression operations.
110 114 This extension exposes the streaming API, dictionary training, and more.
111 115 * It adds a custom framing header to compressed data and there is no way to
112 116 disable it. This means that data produced with that module cannot be used by
113 117 other Zstandard implementations.
114 118
115 119 Bundling of Zstandard Source Code
116 120 =================================
117 121
118 122 The source repository for this project contains a vendored copy of the
119 123 Zstandard source code. This is done for a few reasons.
120 124
121 125 First, Zstandard is relatively new and not yet widely available as a system
122 126 package. Providing a copy of the source code enables the Python C extension
123 127 to be compiled without requiring the user to obtain the Zstandard source code
124 128 separately.
125 129
126 130 Second, Zstandard has both a stable *public* API and an *experimental* API.
127 131 The *experimental* API is actually quite useful (contains functionality for
128 132 training dictionaries for example), so it is something we wish to expose to
129 133 Python. However, the *experimental* API is only available via static linking.
130 134 Furthermore, the *experimental* API can change at any time. So, control over
131 135 the exact version of the Zstandard library linked against is important to
132 136 ensure known behavior.
133 137
134 138 Instructions for Building and Testing
135 139 =====================================
136 140
137 141 Once you have the source code, the extension can be built via setup.py::
138 142
139 143 $ python setup.py build_ext
140 144
141 145 We recommend testing with ``nose``::
142 146
143 147 $ nosetests
144 148
145 149 A Tox configuration is present to test against multiple Python versions::
146 150
147 151 $ tox
148 152
149 153 Tests use the ``hypothesis`` Python package to perform fuzzing. If you
150 154 don't have it, those tests won't run.
151 155
152 156 There is also an experimental CFFI module. You need the ``cffi`` Python
153 157 package installed to build and test that.
154 158
155 159 To create a virtualenv with all development dependencies, do something
156 160 like the following::
157 161
158 162 # Python 2
159 163 $ virtualenv venv
160 164
161 165 # Python 3
162 166 $ python3 -m venv venv
163 167
164 168 $ source venv/bin/activate
165 169 $ pip install cffi hypothesis nose tox
166 170
167 171 API
168 172 ===
169 173
170 174 The compiled C extension provides a ``zstd`` Python module. This module
171 175 exposes the following interfaces.
172 176
173 177 ZstdCompressor
174 178 --------------
175 179
176 180 The ``ZstdCompressor`` class provides an interface for performing
177 181 compression operations.
178 182
179 183 Each instance is associated with parameters that control compression
180 184 behavior. These come from the following named arguments (all optional):
181 185
182 186 level
183 187 Integer compression level. Valid values are between 1 and 22.
184 188 dict_data
185 189 Compression dictionary to use.
186 190
187 191 Note: When using dictionary data and ``compress()`` is called multiple
188 192 times, the ``CompressionParameters`` derived from an integer compression
189 193 ``level`` and the first compressed data's size will be reused for all
190 194 subsequent operations. This may not be desirable if source data size
191 195 varies significantly.
192 196 compression_params
193 197 A ``CompressionParameters`` instance (overrides the ``level`` value).
194 198 write_checksum
195 199 Whether a 4 byte checksum should be written with the compressed data.
196 200 Defaults to False. If True, the decompressor can verify that decompressed
197 201 data matches the original input data.
198 202 write_content_size
199 203 Whether the size of the uncompressed data will be written into the
200 204 header of compressed data. Defaults to False. The data will only be
201 205 written if the compressor knows the size of the input data. This is
202 206 likely not true for streaming compression.
203 207 write_dict_id
204 208 Whether to write the dictionary ID into the compressed data.
205 209 Defaults to True. The dictionary ID is only written if a dictionary
206 210 is being used.
207 211
212 Unless specified otherwise, assume that no two methods of ``ZstdCompressor``
213 instances can be called from multiple Python threads simultaneously. In other
214 words, assume instances are not thread safe unless stated otherwise.
215
208 216 Simple API
209 217 ^^^^^^^^^^
210 218
211 219 ``compress(data)`` compresses and returns data as a one-shot operation.::
212 220
213 cctx = zstd.ZsdCompressor()
221 cctx = zstd.ZstdCompressor()
214 222 compressed = cctx.compress(b'data to compress')
215 223
224 Unless ``compression_params`` or ``dict_data`` are passed to the
225 ``ZstdCompressor``, each invocation of ``compress()`` will calculate the
226 optimal compression parameters for the configured compression ``level`` and
227 input data size (some parameters are fine-tuned for small input sizes).
228
229 If a compression dictionary is being used, the compression parameters
230 determined from the first input's size will be reused for subsequent
231 operations.
232
233 There is currently a deficiency in zstd's C APIs that makes it difficult
234 to round trip empty inputs when ``write_content_size=True``. Attempting
235 this will raise a ``ValueError`` unless ``allow_empty=True`` is passed
236 to ``compress()``.
237
216 238 Streaming Input API
217 239 ^^^^^^^^^^^^^^^^^^^
218 240
219 241 ``write_to(fh)`` (which behaves as a context manager) allows you to *stream*
220 242 data into a compressor.::
221 243
222 244 cctx = zstd.ZstdCompressor(level=10)
223 245 with cctx.write_to(fh) as compressor:
224 246 compressor.write(b'chunk 0')
225 247 compressor.write(b'chunk 1')
226 248 ...
227 249
228 250 The argument to ``write_to()`` must have a ``write(data)`` method. As
229 compressed data is available, ``write()`` will be called with the comrpessed
251 compressed data is available, ``write()`` will be called with the compressed
230 252 data as its argument. Many common Python types implement ``write()``, including
231 253 open file handles and ``io.BytesIO``.
232 254
233 255 ``write_to()`` returns an object representing a streaming compressor instance.
234 256 It **must** be used as a context manager. That object's ``write(data)`` method
235 257 is used to feed data into the compressor.
236 258
259 A ``flush()`` method can be called to evict whatever data remains within the
260 compressor's internal state into the output object. This may result in 0 or
261 more ``write()`` calls to the output object.
262
237 263 If the size of the data being fed to this streaming compressor is known,
238 264 you can declare it before compression begins::
239 265
240 266 cctx = zstd.ZstdCompressor()
241 267 with cctx.write_to(fh, size=data_len) as compressor:
242 268 compressor.write(chunk0)
243 269 compressor.write(chunk1)
244 270 ...
245 271
246 272 Declaring the size of the source data allows compression parameters to
247 273 be tuned. And if ``write_content_size`` is used, it also results in the
248 274 content size being written into the frame header of the output data.
249 275
250 276 The size of chunks being ``write()`` to the destination can be specified::
251 277
252 278 cctx = zstd.ZstdCompressor()
253 279 with cctx.write_to(fh, write_size=32768) as compressor:
254 280 ...
255 281
256 282 To see how much memory is being used by the streaming compressor::
257 283
258 284 cctx = zstd.ZstdCompressor()
259 285 with cctx.write_to(fh) as compressor:
260 286 ...
261 287 byte_size = compressor.memory_size()
262 288
263 289 Streaming Output API
264 290 ^^^^^^^^^^^^^^^^^^^^
265 291
266 292 ``read_from(reader)`` provides a mechanism to stream data out of a compressor
267 293 as an iterator of data chunks.::
268 294
269 295 cctx = zstd.ZstdCompressor()
270 296 for chunk in cctx.read_from(fh):
271 297 # Do something with emitted data.
272 298
273 299 ``read_from()`` accepts an object that has a ``read(size)`` method or conforms
274 300 to the buffer protocol. (``bytes`` and ``memoryview`` are 2 common types that
275 301 provide the buffer protocol.)
276 302
277 303 Uncompressed data is fetched from the source either by calling ``read(size)``
278 304 or by fetching a slice of data from the object directly (in the case where
279 305 the buffer protocol is being used). The returned iterator consists of chunks
280 306 of compressed data.
281 307
308 If reading from the source via ``read()``, ``read()`` will be called until
309 it raises or returns an empty bytes (``b''``). It is perfectly valid for
310 the source to deliver fewer bytes than were what requested by ``read(size)``.
311
282 312 Like ``write_to()``, ``read_from()`` also accepts a ``size`` argument
283 313 declaring the size of the input stream::
284 314
285 315 cctx = zstd.ZstdCompressor()
286 316 for chunk in cctx.read_from(fh, size=some_int):
287 317 pass
288 318
289 319 You can also control the size that data is ``read()`` from the source and
290 320 the ideal size of output chunks::
291 321
292 322 cctx = zstd.ZstdCompressor()
293 323 for chunk in cctx.read_from(fh, read_size=16384, write_size=8192):
294 324 pass
295 325
326 Unlike ``write_to()``, ``read_from()`` does not give direct control over the
327 sizes of chunks fed into the compressor. Instead, chunk sizes will be whatever
328 the object being read from delivers. These will often be of a uniform size.
329
296 330 Stream Copying API
297 331 ^^^^^^^^^^^^^^^^^^
298 332
299 333 ``copy_stream(ifh, ofh)`` can be used to copy data between 2 streams while
300 334 compressing it.::
301 335
302 336 cctx = zstd.ZstdCompressor()
303 337 cctx.copy_stream(ifh, ofh)
304 338
305 339 For example, say you wish to compress a file::
306 340
307 341 cctx = zstd.ZstdCompressor()
308 342 with open(input_path, 'rb') as ifh, open(output_path, 'wb') as ofh:
309 343 cctx.copy_stream(ifh, ofh)
310 344
311 345 It is also possible to declare the size of the source stream::
312 346
313 347 cctx = zstd.ZstdCompressor()
314 348 cctx.copy_stream(ifh, ofh, size=len_of_input)
315 349
316 350 You can also specify how large the chunks that are ``read()`` and ``write()``
317 351 from and to the streams::
318 352
319 353 cctx = zstd.ZstdCompressor()
320 354 cctx.copy_stream(ifh, ofh, read_size=32768, write_size=16384)
321 355
322 356 The stream copier returns a 2-tuple of bytes read and written::
323 357
324 358 cctx = zstd.ZstdCompressor()
325 359 read_count, write_count = cctx.copy_stream(ifh, ofh)
326 360
327 361 Compressor API
328 362 ^^^^^^^^^^^^^^
329 363
330 364 ``compressobj()`` returns an object that exposes ``compress(data)`` and
331 365 ``flush()`` methods. Each returns compressed data or an empty bytes.
332 366
333 367 The purpose of ``compressobj()`` is to provide an API-compatible interface
334 368 with ``zlib.compressobj`` and ``bz2.BZ2Compressor``. This allows callers to
335 369 swap in different compressor objects while using the same API.
336 370
337 Once ``flush()`` is called, the compressor will no longer accept new data
338 to ``compress()``. ``flush()`` **must** be called to end the compression
339 context. If not called, the returned data may be incomplete.
371 ``flush()`` accepts an optional argument indicating how to end the stream.
372 ``zstd.COMPRESSOBJ_FLUSH_FINISH`` (the default) ends the compression stream.
373 Once this type of flush is performed, ``compress()`` and ``flush()`` can
374 no longer be called. This type of flush **must** be called to end the
375 compression context. If not called, returned data may be incomplete.
376
377 A ``zstd.COMPRESSOBJ_FLUSH_BLOCK`` argument to ``flush()`` will flush a
378 zstd block. Flushes of this type can be performed multiple times. The next
379 call to ``compress()`` will begin a new zstd block.
340 380
341 381 Here is how this API should be used::
342 382
343 383 cctx = zstd.ZstdCompressor()
344 384 cobj = cctx.compressobj()
345 385 data = cobj.compress(b'raw input 0')
346 386 data = cobj.compress(b'raw input 1')
347 387 data = cobj.flush()
348 388
389 Or to flush blocks::
390
391 cctx.zstd.ZstdCompressor()
392 cobj = cctx.compressobj()
393 data = cobj.compress(b'chunk in first block')
394 data = cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK)
395 data = cobj.compress(b'chunk in second block')
396 data = cobj.flush()
397
349 398 For best performance results, keep input chunks under 256KB. This avoids
350 399 extra allocations for a large output object.
351 400
352 401 It is possible to declare the input size of the data that will be fed into
353 402 the compressor::
354 403
355 404 cctx = zstd.ZstdCompressor()
356 405 cobj = cctx.compressobj(size=6)
357 406 data = cobj.compress(b'foobar')
358 407 data = cobj.flush()
359 408
360 409 ZstdDecompressor
361 410 ----------------
362 411
363 412 The ``ZstdDecompressor`` class provides an interface for performing
364 413 decompression.
365 414
366 415 Each instance is associated with parameters that control decompression. These
367 416 come from the following named arguments (all optional):
368 417
369 418 dict_data
370 419 Compression dictionary to use.
371 420
372 421 The interface of this class is very similar to ``ZstdCompressor`` (by design).
373 422
423 Unless specified otherwise, assume that no two methods of ``ZstdDecompressor``
424 instances can be called from multiple Python threads simultaneously. In other
425 words, assume instances are not thread safe unless stated otherwise.
426
374 427 Simple API
375 428 ^^^^^^^^^^
376 429
377 430 ``decompress(data)`` can be used to decompress an entire compressed zstd
378 431 frame in a single operation.::
379 432
380 433 dctx = zstd.ZstdDecompressor()
381 434 decompressed = dctx.decompress(data)
382 435
383 436 By default, ``decompress(data)`` will only work on data written with the content
384 437 size encoded in its header. This can be achieved by creating a
385 438 ``ZstdCompressor`` with ``write_content_size=True``. If compressed data without
386 439 an embedded content size is seen, ``zstd.ZstdError`` will be raised.
387 440
388 441 If the compressed data doesn't have its content size embedded within it,
389 442 decompression can be attempted by specifying the ``max_output_size``
390 443 argument.::
391 444
392 445 dctx = zstd.ZstdDecompressor()
393 446 uncompressed = dctx.decompress(data, max_output_size=1048576)
394 447
395 448 Ideally, ``max_output_size`` will be identical to the decompressed output
396 449 size.
397 450
398 451 If ``max_output_size`` is too small to hold the decompressed data,
399 452 ``zstd.ZstdError`` will be raised.
400 453
401 454 If ``max_output_size`` is larger than the decompressed data, the allocated
402 455 output buffer will be resized to only use the space required.
403 456
404 457 Please note that an allocation of the requested ``max_output_size`` will be
405 458 performed every time the method is called. Setting to a very large value could
406 459 result in a lot of work for the memory allocator and may result in
407 460 ``MemoryError`` being raised if the allocation fails.
408 461
409 462 If the exact size of decompressed data is unknown, it is **strongly**
410 463 recommended to use a streaming API.
411 464
412 465 Streaming Input API
413 466 ^^^^^^^^^^^^^^^^^^^
414 467
415 468 ``write_to(fh)`` can be used to incrementally send compressed data to a
416 469 decompressor.::
417 470
418 471 dctx = zstd.ZstdDecompressor()
419 472 with dctx.write_to(fh) as decompressor:
420 473 decompressor.write(compressed_data)
421 474
422 475 This behaves similarly to ``zstd.ZstdCompressor``: compressed data is written to
423 476 the decompressor by calling ``write(data)`` and decompressed output is written
424 477 to the output object by calling its ``write(data)`` method.
425 478
426 479 The size of chunks being ``write()`` to the destination can be specified::
427 480
428 481 dctx = zstd.ZstdDecompressor()
429 482 with dctx.write_to(fh, write_size=16384) as decompressor:
430 483 pass
431 484
432 485 You can see how much memory is being used by the decompressor::
433 486
434 487 dctx = zstd.ZstdDecompressor()
435 488 with dctx.write_to(fh) as decompressor:
436 489 byte_size = decompressor.memory_size()
437 490
438 491 Streaming Output API
439 492 ^^^^^^^^^^^^^^^^^^^^
440 493
441 494 ``read_from(fh)`` provides a mechanism to stream decompressed data out of a
442 495 compressed source as an iterator of data chunks.::
443 496
444 497 dctx = zstd.ZstdDecompressor()
445 498 for chunk in dctx.read_from(fh):
446 499 # Do something with original data.
447 500
448 501 ``read_from()`` accepts a) an object with a ``read(size)`` method that will
449 502 return compressed bytes b) an object conforming to the buffer protocol that
450 503 can expose its data as a contiguous range of bytes. The ``bytes`` and
451 504 ``memoryview`` types expose this buffer protocol.
452 505
453 506 ``read_from()`` returns an iterator whose elements are chunks of the
454 507 decompressed data.
455 508
456 509 The size of requested ``read()`` from the source can be specified::
457 510
458 511 dctx = zstd.ZstdDecompressor()
459 512 for chunk in dctx.read_from(fh, read_size=16384):
460 513 pass
461 514
462 515 It is also possible to skip leading bytes in the input data::
463 516
464 517 dctx = zstd.ZstdDecompressor()
465 518 for chunk in dctx.read_from(fh, skip_bytes=1):
466 519 pass
467 520
468 521 Skipping leading bytes is useful if the source data contains extra
469 522 *header* data but you want to avoid the overhead of making a buffer copy
470 523 or allocating a new ``memoryview`` object in order to decompress the data.
471 524
472 525 Similarly to ``ZstdCompressor.read_from()``, the consumer of the iterator
473 526 controls when data is decompressed. If the iterator isn't consumed,
474 527 decompression is put on hold.
475 528
476 529 When ``read_from()`` is passed an object conforming to the buffer protocol,
477 530 the behavior may seem similar to what occurs when the simple decompression
478 531 API is used. However, this API works when the decompressed size is unknown.
479 532 Furthermore, if feeding large inputs, the decompressor will work in chunks
480 533 instead of performing a single operation.
481 534
482 535 Stream Copying API
483 536 ^^^^^^^^^^^^^^^^^^
484 537
485 538 ``copy_stream(ifh, ofh)`` can be used to copy data across 2 streams while
486 539 performing decompression.::
487 540
488 541 dctx = zstd.ZstdDecompressor()
489 542 dctx.copy_stream(ifh, ofh)
490 543
491 544 e.g. to decompress a file to another file::
492 545
493 546 dctx = zstd.ZstdDecompressor()
494 547 with open(input_path, 'rb') as ifh, open(output_path, 'wb') as ofh:
495 548 dctx.copy_stream(ifh, ofh)
496 549
497 550 The size of chunks being ``read()`` and ``write()`` from and to the streams
498 551 can be specified::
499 552
500 553 dctx = zstd.ZstdDecompressor()
501 554 dctx.copy_stream(ifh, ofh, read_size=8192, write_size=16384)
502 555
503 556 Decompressor API
504 557 ^^^^^^^^^^^^^^^^
505 558
506 559 ``decompressobj()`` returns an object that exposes a ``decompress(data)``
507 560 methods. Compressed data chunks are fed into ``decompress(data)`` and
508 561 uncompressed output (or an empty bytes) is returned. Output from subsequent
509 562 calls needs to be concatenated to reassemble the full decompressed byte
510 563 sequence.
511 564
512 565 The purpose of ``decompressobj()`` is to provide an API-compatible interface
513 566 with ``zlib.decompressobj`` and ``bz2.BZ2Decompressor``. This allows callers
514 567 to swap in different decompressor objects while using the same API.
515 568
516 569 Each object is single use: once an input frame is decoded, ``decompress()``
517 570 can no longer be called.
518 571
519 572 Here is how this API should be used::
520 573
521 574 dctx = zstd.ZstdDeompressor()
522 575 dobj = cctx.decompressobj()
523 576 data = dobj.decompress(compressed_chunk_0)
524 577 data = dobj.decompress(compressed_chunk_1)
525 578
526 579 Choosing an API
527 580 ---------------
528 581
529 582 Various forms of compression and decompression APIs are provided because each
530 583 are suitable for different use cases.
531 584
532 585 The simple/one-shot APIs are useful for small data, when the decompressed
533 586 data size is known (either recorded in the zstd frame header via
534 587 ``write_content_size`` or known via an out-of-band mechanism, such as a file
535 588 size).
536 589
537 590 A limitation of the simple APIs is that input or output data must fit in memory.
538 591 And unless using advanced tricks with Python *buffer objects*, both input and
539 592 output must fit in memory simultaneously.
540 593
541 594 Another limitation is that compression or decompression is performed as a single
542 595 operation. So if you feed large input, it could take a long time for the
543 596 function to return.
544 597
545 598 The streaming APIs do not have the limitations of the simple API. The cost to
546 599 this is they are more complex to use than a single function call.
547 600
548 601 The streaming APIs put the caller in control of compression and decompression
549 602 behavior by allowing them to directly control either the input or output side
550 603 of the operation.
551 604
552 605 With the streaming input APIs, the caller feeds data into the compressor or
553 606 decompressor as they see fit. Output data will only be written after the caller
554 607 has explicitly written data.
555 608
556 609 With the streaming output APIs, the caller consumes output from the compressor
557 610 or decompressor as they see fit. The compressor or decompressor will only
558 611 consume data from the source when the caller is ready to receive it.
559 612
560 613 One end of the streaming APIs involves a file-like object that must
561 614 ``write()`` output data or ``read()`` input data. Depending on what the
562 615 backing storage for these objects is, those operations may not complete quickly.
563 616 For example, when streaming compressed data to a file, the ``write()`` into
564 617 a streaming compressor could result in a ``write()`` to the filesystem, which
565 618 may take a long time to finish due to slow I/O on the filesystem. So, there
566 619 may be overhead in streaming APIs beyond the compression and decompression
567 620 operations.
568 621
569 622 Dictionary Creation and Management
570 623 ----------------------------------
571 624
572 625 Zstandard allows *dictionaries* to be used when compressing and
573 626 decompressing data. The idea is that if you are compressing a lot of similar
574 627 data, you can precompute common properties of that data (such as recurring
575 628 byte sequences) to achieve better compression ratios.
576 629
577 630 In Python, compression dictionaries are represented as the
578 631 ``ZstdCompressionDict`` type.
579 632
580 633 Instances can be constructed from bytes::
581 634
582 635 dict_data = zstd.ZstdCompressionDict(data)
583 636
584 637 More interestingly, instances can be created by *training* on sample data::
585 638
586 639 dict_data = zstd.train_dictionary(size, samples)
587 640
588 641 This takes a list of bytes instances and creates and returns a
589 642 ``ZstdCompressionDict``.
590 643
591 644 You can see how many bytes are in the dictionary by calling ``len()``::
592 645
593 646 dict_data = zstd.train_dictionary(size, samples)
594 647 dict_size = len(dict_data) # will not be larger than ``size``
595 648
596 649 Once you have a dictionary, you can pass it to the objects performing
597 650 compression and decompression::
598 651
599 652 dict_data = zstd.train_dictionary(16384, samples)
600 653
601 654 cctx = zstd.ZstdCompressor(dict_data=dict_data)
602 655 for source_data in input_data:
603 656 compressed = cctx.compress(source_data)
604 657 # Do something with compressed data.
605 658
606 659 dctx = zstd.ZstdDecompressor(dict_data=dict_data)
607 660 for compressed_data in input_data:
608 661 buffer = io.BytesIO()
609 662 with dctx.write_to(buffer) as decompressor:
610 663 decompressor.write(compressed_data)
611 664 # Do something with raw data in ``buffer``.
612 665
613 666 Dictionaries have unique integer IDs. You can retrieve this ID via::
614 667
615 668 dict_id = zstd.dictionary_id(dict_data)
616 669
617 670 You can obtain the raw data in the dict (useful for persisting and constructing
618 671 a ``ZstdCompressionDict`` later) via ``as_bytes()``::
619 672
620 673 dict_data = zstd.train_dictionary(size, samples)
621 674 raw_data = dict_data.as_bytes()
622 675
623 676 Explicit Compression Parameters
624 677 -------------------------------
625 678
626 679 Zstandard's integer compression levels along with the input size and dictionary
627 680 size are converted into a data structure defining multiple parameters to tune
628 681 behavior of the compression algorithm. It is possible to use define this
629 682 data structure explicitly to have lower-level control over compression behavior.
630 683
631 684 The ``zstd.CompressionParameters`` type represents this data structure.
632 685 You can see how Zstandard converts compression levels to this data structure
633 686 by calling ``zstd.get_compression_parameters()``. e.g.::
634 687
635 688 params = zstd.get_compression_parameters(5)
636 689
637 690 This function also accepts the uncompressed data size and dictionary size
638 691 to adjust parameters::
639 692
640 693 params = zstd.get_compression_parameters(3, source_size=len(data), dict_size=len(dict_data))
641 694
642 695 You can also construct compression parameters from their low-level components::
643 696
644 697 params = zstd.CompressionParameters(20, 6, 12, 5, 4, 10, zstd.STRATEGY_FAST)
645 698
646 699 You can then configure a compressor to use the custom parameters::
647 700
648 701 cctx = zstd.ZstdCompressor(compression_params=params)
649 702
650 703 The members of the ``CompressionParameters`` tuple are as follows::
651 704
652 705 * 0 - Window log
653 706 * 1 - Chain log
654 707 * 2 - Hash log
655 708 * 3 - Search log
656 709 * 4 - Search length
657 710 * 5 - Target length
658 711 * 6 - Strategy (one of the ``zstd.STRATEGY_`` constants)
659 712
660 713 You'll need to read the Zstandard documentation for what these parameters
661 714 do.
662 715
663 716 Misc Functionality
664 717 ------------------
665 718
666 719 estimate_compression_context_size(CompressionParameters)
667 720 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
668 721
669 722 Given a ``CompressionParameters`` struct, estimate the memory size required
670 723 to perform compression.
671 724
672 725 estimate_decompression_context_size()
673 726 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
674 727
675 728 Estimate the memory size requirements for a decompressor instance.
676 729
677 730 Constants
678 731 ---------
679 732
680 733 The following module constants/attributes are exposed:
681 734
682 735 ZSTD_VERSION
683 736 This module attribute exposes a 3-tuple of the Zstandard version. e.g.
684 737 ``(1, 0, 0)``
685 738 MAX_COMPRESSION_LEVEL
686 739 Integer max compression level accepted by compression functions
687 740 COMPRESSION_RECOMMENDED_INPUT_SIZE
688 741 Recommended chunk size to feed to compressor functions
689 742 COMPRESSION_RECOMMENDED_OUTPUT_SIZE
690 743 Recommended chunk size for compression output
691 744 DECOMPRESSION_RECOMMENDED_INPUT_SIZE
692 745 Recommended chunk size to feed into decompresor functions
693 746 DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE
694 747 Recommended chunk size for decompression output
695 748
696 749 FRAME_HEADER
697 750 bytes containing header of the Zstandard frame
698 751 MAGIC_NUMBER
699 752 Frame header as an integer
700 753
701 754 WINDOWLOG_MIN
702 755 Minimum value for compression parameter
703 756 WINDOWLOG_MAX
704 757 Maximum value for compression parameter
705 758 CHAINLOG_MIN
706 759 Minimum value for compression parameter
707 760 CHAINLOG_MAX
708 761 Maximum value for compression parameter
709 762 HASHLOG_MIN
710 763 Minimum value for compression parameter
711 764 HASHLOG_MAX
712 765 Maximum value for compression parameter
713 766 SEARCHLOG_MIN
714 767 Minimum value for compression parameter
715 768 SEARCHLOG_MAX
716 769 Maximum value for compression parameter
717 770 SEARCHLENGTH_MIN
718 771 Minimum value for compression parameter
719 772 SEARCHLENGTH_MAX
720 773 Maximum value for compression parameter
721 774 TARGETLENGTH_MIN
722 775 Minimum value for compression parameter
723 776 TARGETLENGTH_MAX
724 777 Maximum value for compression parameter
725 778 STRATEGY_FAST
726 779 Compression strategory
727 780 STRATEGY_DFAST
728 781 Compression strategory
729 782 STRATEGY_GREEDY
730 783 Compression strategory
731 784 STRATEGY_LAZY
732 785 Compression strategory
733 786 STRATEGY_LAZY2
734 787 Compression strategory
735 788 STRATEGY_BTLAZY2
736 789 Compression strategory
737 790 STRATEGY_BTOPT
738 791 Compression strategory
739 792
740 793 Note on Zstandard's *Experimental* API
741 794 ======================================
742 795
743 796 Many of the Zstandard APIs used by this module are marked as *experimental*
744 797 within the Zstandard project. This includes a large number of useful
745 798 features, such as compression and frame parameters and parts of dictionary
746 799 compression.
747 800
748 801 It is unclear how Zstandard's C API will evolve over time, especially with
749 802 regards to this *experimental* functionality. We will try to maintain
750 803 backwards compatibility at the Python API level. However, we cannot
751 804 guarantee this for things not under our control.
752 805
753 806 Since a copy of the Zstandard source code is distributed with this
754 807 module and since we compile against it, the behavior of a specific
755 808 version of this module should be constant for all of time. So if you
756 809 pin the version of this module used in your projects (which is a Python
757 810 best practice), you should be buffered from unwanted future changes.
758 811
759 812 Donate
760 813 ======
761 814
762 815 A lot of time has been invested into this project by the author.
763 816
764 817 If you find this project useful and would like to thank the author for
765 818 their work, consider donating some money. Any amount is appreciated.
766 819
767 820 .. image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif
768 821 :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=gregory%2eszorc%40gmail%2ecom&lc=US&item_name=python%2dzstandard&currency_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted
769 822 :alt: Donate via PayPal
770 823
771 824 .. |ci-status| image:: https://travis-ci.org/indygreg/python-zstandard.svg?branch=master
772 825 :target: https://travis-ci.org/indygreg/python-zstandard
773 826
774 827 .. |win-ci-status| image:: https://ci.appveyor.com/api/projects/status/github/indygreg/python-zstandard?svg=true
775 828 :target: https://ci.appveyor.com/project/indygreg/python-zstandard
776 829 :alt: Windows build status
@@ -1,247 +1,247 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Gregory Szorc
3 3 * All rights reserved.
4 4 *
5 5 * This software may be modified and distributed under the terms
6 6 * of the BSD license. See the LICENSE file for details.
7 7 */
8 8
9 9 #include "python-zstandard.h"
10 10
11 11 extern PyObject* ZstdError;
12 12
13 13 ZstdCompressionDict* train_dictionary(PyObject* self, PyObject* args, PyObject* kwargs) {
14 14 static char *kwlist[] = { "dict_size", "samples", "parameters", NULL };
15 15 size_t capacity;
16 16 PyObject* samples;
17 17 Py_ssize_t samplesLen;
18 18 PyObject* parameters = NULL;
19 19 ZDICT_params_t zparams;
20 20 Py_ssize_t sampleIndex;
21 21 Py_ssize_t sampleSize;
22 22 PyObject* sampleItem;
23 23 size_t zresult;
24 24 void* sampleBuffer;
25 25 void* sampleOffset;
26 26 size_t samplesSize = 0;
27 27 size_t* sampleSizes;
28 28 void* dict;
29 29 ZstdCompressionDict* result;
30 30
31 31 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "nO!|O!", kwlist,
32 32 &capacity,
33 33 &PyList_Type, &samples,
34 34 (PyObject*)&DictParametersType, &parameters)) {
35 35 return NULL;
36 36 }
37 37
38 38 /* Validate parameters first since it is easiest. */
39 39 zparams.selectivityLevel = 0;
40 40 zparams.compressionLevel = 0;
41 41 zparams.notificationLevel = 0;
42 42 zparams.dictID = 0;
43 43 zparams.reserved[0] = 0;
44 44 zparams.reserved[1] = 0;
45 45
46 46 if (parameters) {
47 47 /* TODO validate data ranges */
48 48 zparams.selectivityLevel = PyLong_AsUnsignedLong(PyTuple_GetItem(parameters, 0));
49 49 zparams.compressionLevel = PyLong_AsLong(PyTuple_GetItem(parameters, 1));
50 50 zparams.notificationLevel = PyLong_AsUnsignedLong(PyTuple_GetItem(parameters, 2));
51 51 zparams.dictID = PyLong_AsUnsignedLong(PyTuple_GetItem(parameters, 3));
52 52 }
53 53
54 54 /* Figure out the size of the raw samples */
55 55 samplesLen = PyList_Size(samples);
56 56 for (sampleIndex = 0; sampleIndex < samplesLen; sampleIndex++) {
57 57 sampleItem = PyList_GetItem(samples, sampleIndex);
58 58 if (!PyBytes_Check(sampleItem)) {
59 59 PyErr_SetString(PyExc_ValueError, "samples must be bytes");
60 60 /* TODO probably need to perform DECREF here */
61 61 return NULL;
62 62 }
63 63 samplesSize += PyBytes_GET_SIZE(sampleItem);
64 64 }
65 65
66 66 /* Now that we know the total size of the raw simples, we can allocate
67 67 a buffer for the raw data */
68 sampleBuffer = malloc(samplesSize);
68 sampleBuffer = PyMem_Malloc(samplesSize);
69 69 if (!sampleBuffer) {
70 70 PyErr_NoMemory();
71 71 return NULL;
72 72 }
73 sampleSizes = malloc(samplesLen * sizeof(size_t));
73 sampleSizes = PyMem_Malloc(samplesLen * sizeof(size_t));
74 74 if (!sampleSizes) {
75 free(sampleBuffer);
75 PyMem_Free(sampleBuffer);
76 76 PyErr_NoMemory();
77 77 return NULL;
78 78 }
79 79
80 80 sampleOffset = sampleBuffer;
81 81 /* Now iterate again and assemble the samples in the buffer */
82 82 for (sampleIndex = 0; sampleIndex < samplesLen; sampleIndex++) {
83 83 sampleItem = PyList_GetItem(samples, sampleIndex);
84 84 sampleSize = PyBytes_GET_SIZE(sampleItem);
85 85 sampleSizes[sampleIndex] = sampleSize;
86 86 memcpy(sampleOffset, PyBytes_AS_STRING(sampleItem), sampleSize);
87 87 sampleOffset = (char*)sampleOffset + sampleSize;
88 88 }
89 89
90 dict = malloc(capacity);
90 dict = PyMem_Malloc(capacity);
91 91 if (!dict) {
92 free(sampleSizes);
93 free(sampleBuffer);
92 PyMem_Free(sampleSizes);
93 PyMem_Free(sampleBuffer);
94 94 PyErr_NoMemory();
95 95 return NULL;
96 96 }
97 97
98 98 zresult = ZDICT_trainFromBuffer_advanced(dict, capacity,
99 99 sampleBuffer, sampleSizes, (unsigned int)samplesLen,
100 100 zparams);
101 101 if (ZDICT_isError(zresult)) {
102 102 PyErr_Format(ZstdError, "Cannot train dict: %s", ZDICT_getErrorName(zresult));
103 free(dict);
104 free(sampleSizes);
105 free(sampleBuffer);
103 PyMem_Free(dict);
104 PyMem_Free(sampleSizes);
105 PyMem_Free(sampleBuffer);
106 106 return NULL;
107 107 }
108 108
109 109 result = PyObject_New(ZstdCompressionDict, &ZstdCompressionDictType);
110 110 if (!result) {
111 111 return NULL;
112 112 }
113 113
114 114 result->dictData = dict;
115 115 result->dictSize = zresult;
116 116 return result;
117 117 }
118 118
119 119
120 120 PyDoc_STRVAR(ZstdCompressionDict__doc__,
121 121 "ZstdCompressionDict(data) - Represents a computed compression dictionary\n"
122 122 "\n"
123 123 "This type holds the results of a computed Zstandard compression dictionary.\n"
124 124 "Instances are obtained by calling ``train_dictionary()`` or by passing bytes\n"
125 125 "obtained from another source into the constructor.\n"
126 126 );
127 127
128 128 static int ZstdCompressionDict_init(ZstdCompressionDict* self, PyObject* args) {
129 129 const char* source;
130 130 Py_ssize_t sourceSize;
131 131
132 132 self->dictData = NULL;
133 133 self->dictSize = 0;
134 134
135 135 #if PY_MAJOR_VERSION >= 3
136 136 if (!PyArg_ParseTuple(args, "y#", &source, &sourceSize)) {
137 137 #else
138 138 if (!PyArg_ParseTuple(args, "s#", &source, &sourceSize)) {
139 139 #endif
140 140 return -1;
141 141 }
142 142
143 self->dictData = malloc(sourceSize);
143 self->dictData = PyMem_Malloc(sourceSize);
144 144 if (!self->dictData) {
145 145 PyErr_NoMemory();
146 146 return -1;
147 147 }
148 148
149 149 memcpy(self->dictData, source, sourceSize);
150 150 self->dictSize = sourceSize;
151 151
152 152 return 0;
153 153 }
154 154
155 155 static void ZstdCompressionDict_dealloc(ZstdCompressionDict* self) {
156 156 if (self->dictData) {
157 free(self->dictData);
157 PyMem_Free(self->dictData);
158 158 self->dictData = NULL;
159 159 }
160 160
161 161 PyObject_Del(self);
162 162 }
163 163
164 164 static PyObject* ZstdCompressionDict_dict_id(ZstdCompressionDict* self) {
165 165 unsigned dictID = ZDICT_getDictID(self->dictData, self->dictSize);
166 166
167 167 return PyLong_FromLong(dictID);
168 168 }
169 169
170 170 static PyObject* ZstdCompressionDict_as_bytes(ZstdCompressionDict* self) {
171 171 return PyBytes_FromStringAndSize(self->dictData, self->dictSize);
172 172 }
173 173
174 174 static PyMethodDef ZstdCompressionDict_methods[] = {
175 175 { "dict_id", (PyCFunction)ZstdCompressionDict_dict_id, METH_NOARGS,
176 176 PyDoc_STR("dict_id() -- obtain the numeric dictionary ID") },
177 177 { "as_bytes", (PyCFunction)ZstdCompressionDict_as_bytes, METH_NOARGS,
178 178 PyDoc_STR("as_bytes() -- obtain the raw bytes constituting the dictionary data") },
179 179 { NULL, NULL }
180 180 };
181 181
182 182 static Py_ssize_t ZstdCompressionDict_length(ZstdCompressionDict* self) {
183 183 return self->dictSize;
184 184 }
185 185
186 186 static PySequenceMethods ZstdCompressionDict_sq = {
187 187 (lenfunc)ZstdCompressionDict_length, /* sq_length */
188 188 0, /* sq_concat */
189 189 0, /* sq_repeat */
190 190 0, /* sq_item */
191 191 0, /* sq_ass_item */
192 192 0, /* sq_contains */
193 193 0, /* sq_inplace_concat */
194 194 0 /* sq_inplace_repeat */
195 195 };
196 196
197 197 PyTypeObject ZstdCompressionDictType = {
198 198 PyVarObject_HEAD_INIT(NULL, 0)
199 199 "zstd.ZstdCompressionDict", /* tp_name */
200 200 sizeof(ZstdCompressionDict), /* tp_basicsize */
201 201 0, /* tp_itemsize */
202 202 (destructor)ZstdCompressionDict_dealloc, /* tp_dealloc */
203 203 0, /* tp_print */
204 204 0, /* tp_getattr */
205 205 0, /* tp_setattr */
206 206 0, /* tp_compare */
207 207 0, /* tp_repr */
208 208 0, /* tp_as_number */
209 209 &ZstdCompressionDict_sq, /* tp_as_sequence */
210 210 0, /* tp_as_mapping */
211 211 0, /* tp_hash */
212 212 0, /* tp_call */
213 213 0, /* tp_str */
214 214 0, /* tp_getattro */
215 215 0, /* tp_setattro */
216 216 0, /* tp_as_buffer */
217 217 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
218 218 ZstdCompressionDict__doc__, /* tp_doc */
219 219 0, /* tp_traverse */
220 220 0, /* tp_clear */
221 221 0, /* tp_richcompare */
222 222 0, /* tp_weaklistoffset */
223 223 0, /* tp_iter */
224 224 0, /* tp_iternext */
225 225 ZstdCompressionDict_methods, /* tp_methods */
226 226 0, /* tp_members */
227 227 0, /* tp_getset */
228 228 0, /* tp_base */
229 229 0, /* tp_dict */
230 230 0, /* tp_descr_get */
231 231 0, /* tp_descr_set */
232 232 0, /* tp_dictoffset */
233 233 (initproc)ZstdCompressionDict_init, /* tp_init */
234 234 0, /* tp_alloc */
235 235 PyType_GenericNew, /* tp_new */
236 236 };
237 237
238 238 void compressiondict_module_init(PyObject* mod) {
239 239 Py_TYPE(&ZstdCompressionDictType) = &PyType_Type;
240 240 if (PyType_Ready(&ZstdCompressionDictType) < 0) {
241 241 return;
242 242 }
243 243
244 244 Py_INCREF((PyObject*)&ZstdCompressionDictType);
245 245 PyModule_AddObject(mod, "ZstdCompressionDict",
246 246 (PyObject*)&ZstdCompressionDictType);
247 247 }
@@ -1,235 +1,288 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Gregory Szorc
3 3 * All rights reserved.
4 4 *
5 5 * This software may be modified and distributed under the terms
6 6 * of the BSD license. See the LICENSE file for details.
7 7 */
8 8
9 9 #include "python-zstandard.h"
10 10
11 11 extern PyObject* ZstdError;
12 12
13 13 PyDoc_STRVAR(ZstdCompresssionWriter__doc__,
14 14 """A context manager used for writing compressed output to a writer.\n"
15 15 );
16 16
17 17 static void ZstdCompressionWriter_dealloc(ZstdCompressionWriter* self) {
18 18 Py_XDECREF(self->compressor);
19 19 Py_XDECREF(self->writer);
20 20
21 21 if (self->cstream) {
22 22 ZSTD_freeCStream(self->cstream);
23 23 self->cstream = NULL;
24 24 }
25 25
26 26 PyObject_Del(self);
27 27 }
28 28
29 29 static PyObject* ZstdCompressionWriter_enter(ZstdCompressionWriter* self) {
30 30 if (self->entered) {
31 31 PyErr_SetString(ZstdError, "cannot __enter__ multiple times");
32 32 return NULL;
33 33 }
34 34
35 35 self->cstream = CStream_from_ZstdCompressor(self->compressor, self->sourceSize);
36 36 if (!self->cstream) {
37 37 return NULL;
38 38 }
39 39
40 40 self->entered = 1;
41 41
42 42 Py_INCREF(self);
43 43 return (PyObject*)self;
44 44 }
45 45
46 46 static PyObject* ZstdCompressionWriter_exit(ZstdCompressionWriter* self, PyObject* args) {
47 47 PyObject* exc_type;
48 48 PyObject* exc_value;
49 49 PyObject* exc_tb;
50 50 size_t zresult;
51 51
52 52 ZSTD_outBuffer output;
53 53 PyObject* res;
54 54
55 55 if (!PyArg_ParseTuple(args, "OOO", &exc_type, &exc_value, &exc_tb)) {
56 56 return NULL;
57 57 }
58 58
59 59 self->entered = 0;
60 60
61 61 if (self->cstream && exc_type == Py_None && exc_value == Py_None &&
62 62 exc_tb == Py_None) {
63 63
64 output.dst = malloc(self->outSize);
64 output.dst = PyMem_Malloc(self->outSize);
65 65 if (!output.dst) {
66 66 return PyErr_NoMemory();
67 67 }
68 68 output.size = self->outSize;
69 69 output.pos = 0;
70 70
71 71 while (1) {
72 72 zresult = ZSTD_endStream(self->cstream, &output);
73 73 if (ZSTD_isError(zresult)) {
74 74 PyErr_Format(ZstdError, "error ending compression stream: %s",
75 75 ZSTD_getErrorName(zresult));
76 free(output.dst);
76 PyMem_Free(output.dst);
77 77 return NULL;
78 78 }
79 79
80 80 if (output.pos) {
81 81 #if PY_MAJOR_VERSION >= 3
82 82 res = PyObject_CallMethod(self->writer, "write", "y#",
83 83 #else
84 84 res = PyObject_CallMethod(self->writer, "write", "s#",
85 85 #endif
86 86 output.dst, output.pos);
87 87 Py_XDECREF(res);
88 88 }
89 89
90 90 if (!zresult) {
91 91 break;
92 92 }
93 93
94 94 output.pos = 0;
95 95 }
96 96
97 free(output.dst);
97 PyMem_Free(output.dst);
98 98 ZSTD_freeCStream(self->cstream);
99 99 self->cstream = NULL;
100 100 }
101 101
102 102 Py_RETURN_FALSE;
103 103 }
104 104
105 105 static PyObject* ZstdCompressionWriter_memory_size(ZstdCompressionWriter* self) {
106 106 if (!self->cstream) {
107 107 PyErr_SetString(ZstdError, "cannot determine size of an inactive compressor; "
108 108 "call when a context manager is active");
109 109 return NULL;
110 110 }
111 111
112 112 return PyLong_FromSize_t(ZSTD_sizeof_CStream(self->cstream));
113 113 }
114 114
115 115 static PyObject* ZstdCompressionWriter_write(ZstdCompressionWriter* self, PyObject* args) {
116 116 const char* source;
117 117 Py_ssize_t sourceSize;
118 118 size_t zresult;
119 119 ZSTD_inBuffer input;
120 120 ZSTD_outBuffer output;
121 121 PyObject* res;
122 122
123 123 #if PY_MAJOR_VERSION >= 3
124 124 if (!PyArg_ParseTuple(args, "y#", &source, &sourceSize)) {
125 125 #else
126 126 if (!PyArg_ParseTuple(args, "s#", &source, &sourceSize)) {
127 127 #endif
128 128 return NULL;
129 129 }
130 130
131 131 if (!self->entered) {
132 132 PyErr_SetString(ZstdError, "compress must be called from an active context manager");
133 133 return NULL;
134 134 }
135 135
136 output.dst = malloc(self->outSize);
136 output.dst = PyMem_Malloc(self->outSize);
137 137 if (!output.dst) {
138 138 return PyErr_NoMemory();
139 139 }
140 140 output.size = self->outSize;
141 141 output.pos = 0;
142 142
143 143 input.src = source;
144 144 input.size = sourceSize;
145 145 input.pos = 0;
146 146
147 147 while ((ssize_t)input.pos < sourceSize) {
148 148 Py_BEGIN_ALLOW_THREADS
149 149 zresult = ZSTD_compressStream(self->cstream, &output, &input);
150 150 Py_END_ALLOW_THREADS
151 151
152 152 if (ZSTD_isError(zresult)) {
153 free(output.dst);
153 PyMem_Free(output.dst);
154 154 PyErr_Format(ZstdError, "zstd compress error: %s", ZSTD_getErrorName(zresult));
155 155 return NULL;
156 156 }
157 157
158 158 /* Copy data from output buffer to writer. */
159 159 if (output.pos) {
160 160 #if PY_MAJOR_VERSION >= 3
161 161 res = PyObject_CallMethod(self->writer, "write", "y#",
162 162 #else
163 163 res = PyObject_CallMethod(self->writer, "write", "s#",
164 164 #endif
165 165 output.dst, output.pos);
166 166 Py_XDECREF(res);
167 167 }
168 168 output.pos = 0;
169 169 }
170 170
171 free(output.dst);
171 PyMem_Free(output.dst);
172 172
173 173 /* TODO return bytes written */
174 174 Py_RETURN_NONE;
175 }
176
177 static PyObject* ZstdCompressionWriter_flush(ZstdCompressionWriter* self, PyObject* args) {
178 size_t zresult;
179 ZSTD_outBuffer output;
180 PyObject* res;
181
182 if (!self->entered) {
183 PyErr_SetString(ZstdError, "flush must be called from an active context manager");
184 return NULL;
175 185 }
176 186
187 output.dst = PyMem_Malloc(self->outSize);
188 if (!output.dst) {
189 return PyErr_NoMemory();
190 }
191 output.size = self->outSize;
192 output.pos = 0;
193
194 while (1) {
195 Py_BEGIN_ALLOW_THREADS
196 zresult = ZSTD_flushStream(self->cstream, &output);
197 Py_END_ALLOW_THREADS
198
199 if (ZSTD_isError(zresult)) {
200 PyMem_Free(output.dst);
201 PyErr_Format(ZstdError, "zstd compress error: %s", ZSTD_getErrorName(zresult));
202 return NULL;
203 }
204
205 if (!output.pos) {
206 break;
207 }
208
209 /* Copy data from output buffer to writer. */
210 if (output.pos) {
211 #if PY_MAJOR_VERSION >= 3
212 res = PyObject_CallMethod(self->writer, "write", "y#",
213 #else
214 res = PyObject_CallMethod(self->writer, "write", "s#",
215 #endif
216 output.dst, output.pos);
217 Py_XDECREF(res);
218 }
219 output.pos = 0;
220 }
221
222 PyMem_Free(output.dst);
223
224 /* TODO return bytes written */
225 Py_RETURN_NONE;
226 }
227
177 228 static PyMethodDef ZstdCompressionWriter_methods[] = {
178 229 { "__enter__", (PyCFunction)ZstdCompressionWriter_enter, METH_NOARGS,
179 230 PyDoc_STR("Enter a compression context.") },
180 231 { "__exit__", (PyCFunction)ZstdCompressionWriter_exit, METH_VARARGS,
181 232 PyDoc_STR("Exit a compression context.") },
182 233 { "memory_size", (PyCFunction)ZstdCompressionWriter_memory_size, METH_NOARGS,
183 234 PyDoc_STR("Obtain the memory size of the underlying compressor") },
184 235 { "write", (PyCFunction)ZstdCompressionWriter_write, METH_VARARGS,
185 236 PyDoc_STR("Compress data") },
237 { "flush", (PyCFunction)ZstdCompressionWriter_flush, METH_NOARGS,
238 PyDoc_STR("Flush data and finish a zstd frame") },
186 239 { NULL, NULL }
187 240 };
188 241
189 242 PyTypeObject ZstdCompressionWriterType = {
190 243 PyVarObject_HEAD_INIT(NULL, 0)
191 244 "zstd.ZstdCompressionWriter", /* tp_name */
192 245 sizeof(ZstdCompressionWriter), /* tp_basicsize */
193 246 0, /* tp_itemsize */
194 247 (destructor)ZstdCompressionWriter_dealloc, /* tp_dealloc */
195 248 0, /* tp_print */
196 249 0, /* tp_getattr */
197 250 0, /* tp_setattr */
198 251 0, /* tp_compare */
199 252 0, /* tp_repr */
200 253 0, /* tp_as_number */
201 254 0, /* tp_as_sequence */
202 255 0, /* tp_as_mapping */
203 256 0, /* tp_hash */
204 257 0, /* tp_call */
205 258 0, /* tp_str */
206 259 0, /* tp_getattro */
207 260 0, /* tp_setattro */
208 261 0, /* tp_as_buffer */
209 262 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
210 263 ZstdCompresssionWriter__doc__, /* tp_doc */
211 264 0, /* tp_traverse */
212 265 0, /* tp_clear */
213 266 0, /* tp_richcompare */
214 267 0, /* tp_weaklistoffset */
215 268 0, /* tp_iter */
216 269 0, /* tp_iternext */
217 270 ZstdCompressionWriter_methods, /* tp_methods */
218 271 0, /* tp_members */
219 272 0, /* tp_getset */
220 273 0, /* tp_base */
221 274 0, /* tp_dict */
222 275 0, /* tp_descr_get */
223 276 0, /* tp_descr_set */
224 277 0, /* tp_dictoffset */
225 278 0, /* tp_init */
226 279 0, /* tp_alloc */
227 280 PyType_GenericNew, /* tp_new */
228 281 };
229 282
230 283 void compressionwriter_module_init(PyObject* mod) {
231 284 Py_TYPE(&ZstdCompressionWriterType) = &PyType_Type;
232 285 if (PyType_Ready(&ZstdCompressionWriterType) < 0) {
233 286 return;
234 287 }
235 288 }
@@ -1,205 +1,250 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Gregory Szorc
3 3 * All rights reserved.
4 4 *
5 5 * This software may be modified and distributed under the terms
6 6 * of the BSD license. See the LICENSE file for details.
7 7 */
8 8
9 9 #include "python-zstandard.h"
10 10
11 11 extern PyObject* ZstdError;
12 12
13 13 PyDoc_STRVAR(ZstdCompressionObj__doc__,
14 14 "Perform compression using a standard library compatible API.\n"
15 15 );
16 16
17 17 static void ZstdCompressionObj_dealloc(ZstdCompressionObj* self) {
18 18 PyMem_Free(self->output.dst);
19 19 self->output.dst = NULL;
20 20
21 21 if (self->cstream) {
22 22 ZSTD_freeCStream(self->cstream);
23 23 self->cstream = NULL;
24 24 }
25 25
26 26 Py_XDECREF(self->compressor);
27 27
28 28 PyObject_Del(self);
29 29 }
30 30
31 31 static PyObject* ZstdCompressionObj_compress(ZstdCompressionObj* self, PyObject* args) {
32 32 const char* source;
33 33 Py_ssize_t sourceSize;
34 34 ZSTD_inBuffer input;
35 35 size_t zresult;
36 36 PyObject* result = NULL;
37 37 Py_ssize_t resultSize = 0;
38 38
39 if (self->flushed) {
40 PyErr_SetString(ZstdError, "cannot call compress() after flush() has been called");
39 if (self->finished) {
40 PyErr_SetString(ZstdError, "cannot call compress() after compressor finished");
41 41 return NULL;
42 42 }
43 43
44 44 #if PY_MAJOR_VERSION >= 3
45 45 if (!PyArg_ParseTuple(args, "y#", &source, &sourceSize)) {
46 46 #else
47 47 if (!PyArg_ParseTuple(args, "s#", &source, &sourceSize)) {
48 48 #endif
49 49 return NULL;
50 50 }
51 51
52 52 input.src = source;
53 53 input.size = sourceSize;
54 54 input.pos = 0;
55 55
56 56 while ((ssize_t)input.pos < sourceSize) {
57 57 Py_BEGIN_ALLOW_THREADS
58 58 zresult = ZSTD_compressStream(self->cstream, &self->output, &input);
59 59 Py_END_ALLOW_THREADS
60 60
61 61 if (ZSTD_isError(zresult)) {
62 62 PyErr_Format(ZstdError, "zstd compress error: %s", ZSTD_getErrorName(zresult));
63 63 return NULL;
64 64 }
65 65
66 66 if (self->output.pos) {
67 67 if (result) {
68 68 resultSize = PyBytes_GET_SIZE(result);
69 69 if (-1 == _PyBytes_Resize(&result, resultSize + self->output.pos)) {
70 70 return NULL;
71 71 }
72 72
73 73 memcpy(PyBytes_AS_STRING(result) + resultSize,
74 74 self->output.dst, self->output.pos);
75 75 }
76 76 else {
77 77 result = PyBytes_FromStringAndSize(self->output.dst, self->output.pos);
78 78 if (!result) {
79 79 return NULL;
80 80 }
81 81 }
82 82
83 83 self->output.pos = 0;
84 84 }
85 85 }
86 86
87 87 if (result) {
88 88 return result;
89 89 }
90 90 else {
91 91 return PyBytes_FromString("");
92 92 }
93 93 }
94 94
95 static PyObject* ZstdCompressionObj_flush(ZstdCompressionObj* self) {
95 static PyObject* ZstdCompressionObj_flush(ZstdCompressionObj* self, PyObject* args) {
96 int flushMode = compressorobj_flush_finish;
96 97 size_t zresult;
97 98 PyObject* result = NULL;
98 99 Py_ssize_t resultSize = 0;
99 100
100 if (self->flushed) {
101 PyErr_SetString(ZstdError, "flush() already called");
101 if (!PyArg_ParseTuple(args, "|i", &flushMode)) {
102 return NULL;
103 }
104
105 if (flushMode != compressorobj_flush_finish && flushMode != compressorobj_flush_block) {
106 PyErr_SetString(PyExc_ValueError, "flush mode not recognized");
107 return NULL;
108 }
109
110 if (self->finished) {
111 PyErr_SetString(ZstdError, "compressor object already finished");
102 112 return NULL;
103 113 }
104 114
105 self->flushed = 1;
115 assert(self->output.pos == 0);
116
117 if (flushMode == compressorobj_flush_block) {
118 /* The output buffer is of size ZSTD_CStreamOutSize(), which is
119 guaranteed to hold a full block. */
120 Py_BEGIN_ALLOW_THREADS
121 zresult = ZSTD_flushStream(self->cstream, &self->output);
122 Py_END_ALLOW_THREADS
123
124 if (ZSTD_isError(zresult)) {
125 PyErr_Format(ZstdError, "zstd compress error: %s", ZSTD_getErrorName(zresult));
126 return NULL;
127 }
128
129 /* Output buffer is guaranteed to hold full block. */
130 assert(zresult == 0);
131
132 if (self->output.pos) {
133 result = PyBytes_FromStringAndSize(self->output.dst, self->output.pos);
134 if (!result) {
135 return NULL;
136 }
137 }
138
139 self->output.pos = 0;
140
141 if (result) {
142 return result;
143 }
144 else {
145 return PyBytes_FromString("");
146 }
147 }
148
149 assert(flushMode == compressorobj_flush_finish);
150 self->finished = 1;
106 151
107 152 while (1) {
108 153 zresult = ZSTD_endStream(self->cstream, &self->output);
109 154 if (ZSTD_isError(zresult)) {
110 155 PyErr_Format(ZstdError, "error ending compression stream: %s",
111 156 ZSTD_getErrorName(zresult));
112 157 return NULL;
113 158 }
114 159
115 160 if (self->output.pos) {
116 161 if (result) {
117 162 resultSize = PyBytes_GET_SIZE(result);
118 163 if (-1 == _PyBytes_Resize(&result, resultSize + self->output.pos)) {
119 164 return NULL;
120 165 }
121 166
122 167 memcpy(PyBytes_AS_STRING(result) + resultSize,
123 168 self->output.dst, self->output.pos);
124 169 }
125 170 else {
126 171 result = PyBytes_FromStringAndSize(self->output.dst, self->output.pos);
127 172 if (!result) {
128 173 return NULL;
129 174 }
130 175 }
131 176
132 177 self->output.pos = 0;
133 178 }
134 179
135 180 if (!zresult) {
136 181 break;
137 182 }
138 183 }
139 184
140 185 ZSTD_freeCStream(self->cstream);
141 186 self->cstream = NULL;
142 187
143 188 if (result) {
144 189 return result;
145 190 }
146 191 else {
147 192 return PyBytes_FromString("");
148 193 }
149 194 }
150 195
151 196 static PyMethodDef ZstdCompressionObj_methods[] = {
152 197 { "compress", (PyCFunction)ZstdCompressionObj_compress, METH_VARARGS,
153 198 PyDoc_STR("compress data") },
154 { "flush", (PyCFunction)ZstdCompressionObj_flush, METH_NOARGS,
199 { "flush", (PyCFunction)ZstdCompressionObj_flush, METH_VARARGS,
155 200 PyDoc_STR("finish compression operation") },
156 201 { NULL, NULL }
157 202 };
158 203
159 204 PyTypeObject ZstdCompressionObjType = {
160 205 PyVarObject_HEAD_INIT(NULL, 0)
161 206 "zstd.ZstdCompressionObj", /* tp_name */
162 207 sizeof(ZstdCompressionObj), /* tp_basicsize */
163 208 0, /* tp_itemsize */
164 209 (destructor)ZstdCompressionObj_dealloc, /* tp_dealloc */
165 210 0, /* tp_print */
166 211 0, /* tp_getattr */
167 212 0, /* tp_setattr */
168 213 0, /* tp_compare */
169 214 0, /* tp_repr */
170 215 0, /* tp_as_number */
171 216 0, /* tp_as_sequence */
172 217 0, /* tp_as_mapping */
173 218 0, /* tp_hash */
174 219 0, /* tp_call */
175 220 0, /* tp_str */
176 221 0, /* tp_getattro */
177 222 0, /* tp_setattro */
178 223 0, /* tp_as_buffer */
179 224 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
180 225 ZstdCompressionObj__doc__, /* tp_doc */
181 226 0, /* tp_traverse */
182 227 0, /* tp_clear */
183 228 0, /* tp_richcompare */
184 229 0, /* tp_weaklistoffset */
185 230 0, /* tp_iter */
186 231 0, /* tp_iternext */
187 232 ZstdCompressionObj_methods, /* tp_methods */
188 233 0, /* tp_members */
189 234 0, /* tp_getset */
190 235 0, /* tp_base */
191 236 0, /* tp_dict */
192 237 0, /* tp_descr_get */
193 238 0, /* tp_descr_set */
194 239 0, /* tp_dictoffset */
195 240 0, /* tp_init */
196 241 0, /* tp_alloc */
197 242 PyType_GenericNew, /* tp_new */
198 243 };
199 244
200 245 void compressobj_module_init(PyObject* module) {
201 246 Py_TYPE(&ZstdCompressionObjType) = &PyType_Type;
202 247 if (PyType_Ready(&ZstdCompressionObjType) < 0) {
203 248 return;
204 249 }
205 250 }
@@ -1,757 +1,788 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Gregory Szorc
3 3 * All rights reserved.
4 4 *
5 5 * This software may be modified and distributed under the terms
6 6 * of the BSD license. See the LICENSE file for details.
7 7 */
8 8
9 9 #include "python-zstandard.h"
10 10
11 11 extern PyObject* ZstdError;
12 12
13 int populate_cdict(ZstdCompressor* compressor, void* dictData, size_t dictSize, ZSTD_parameters* zparams) {
14 ZSTD_customMem zmem;
15 assert(!compressor->cdict);
16 Py_BEGIN_ALLOW_THREADS
17 memset(&zmem, 0, sizeof(zmem));
18 compressor->cdict = ZSTD_createCDict_advanced(compressor->dict->dictData,
19 compressor->dict->dictSize, *zparams, zmem);
20 Py_END_ALLOW_THREADS
21
22 if (!compressor->cdict) {
23 PyErr_SetString(ZstdError, "could not create compression dictionary");
24 return 1;
25 }
26
27 return 0;
28 }
29
13 30 /**
14 31 * Initialize a zstd CStream from a ZstdCompressor instance.
15 32 *
16 33 * Returns a ZSTD_CStream on success or NULL on failure. If NULL, a Python
17 34 * exception will be set.
18 35 */
19 36 ZSTD_CStream* CStream_from_ZstdCompressor(ZstdCompressor* compressor, Py_ssize_t sourceSize) {
20 37 ZSTD_CStream* cstream;
21 38 ZSTD_parameters zparams;
22 39 void* dictData = NULL;
23 40 size_t dictSize = 0;
24 41 size_t zresult;
25 42
26 43 cstream = ZSTD_createCStream();
27 44 if (!cstream) {
28 45 PyErr_SetString(ZstdError, "cannot create CStream");
29 46 return NULL;
30 47 }
31 48
32 49 if (compressor->dict) {
33 50 dictData = compressor->dict->dictData;
34 51 dictSize = compressor->dict->dictSize;
35 52 }
36 53
37 54 memset(&zparams, 0, sizeof(zparams));
38 55 if (compressor->cparams) {
39 56 ztopy_compression_parameters(compressor->cparams, &zparams.cParams);
40 57 /* Do NOT call ZSTD_adjustCParams() here because the compression params
41 58 come from the user. */
42 59 }
43 60 else {
44 61 zparams.cParams = ZSTD_getCParams(compressor->compressionLevel, sourceSize, dictSize);
45 62 }
46 63
47 64 zparams.fParams = compressor->fparams;
48 65
49 66 zresult = ZSTD_initCStream_advanced(cstream, dictData, dictSize, zparams, sourceSize);
50 67
51 68 if (ZSTD_isError(zresult)) {
52 69 ZSTD_freeCStream(cstream);
53 70 PyErr_Format(ZstdError, "cannot init CStream: %s", ZSTD_getErrorName(zresult));
54 71 return NULL;
55 72 }
56 73
57 74 return cstream;
58 75 }
59 76
60
61 77 PyDoc_STRVAR(ZstdCompressor__doc__,
62 78 "ZstdCompressor(level=None, dict_data=None, compression_params=None)\n"
63 79 "\n"
64 80 "Create an object used to perform Zstandard compression.\n"
65 81 "\n"
66 82 "An instance can compress data various ways. Instances can be used multiple\n"
67 83 "times. Each compression operation will use the compression parameters\n"
68 84 "defined at construction time.\n"
69 85 "\n"
70 86 "Compression can be configured via the following names arguments:\n"
71 87 "\n"
72 88 "level\n"
73 89 " Integer compression level.\n"
74 90 "dict_data\n"
75 91 " A ``ZstdCompressionDict`` to be used to compress with dictionary data.\n"
76 92 "compression_params\n"
77 93 " A ``CompressionParameters`` instance defining low-level compression"
78 94 " parameters. If defined, this will overwrite the ``level`` argument.\n"
79 95 "write_checksum\n"
80 96 " If True, a 4 byte content checksum will be written with the compressed\n"
81 97 " data, allowing the decompressor to perform content verification.\n"
82 98 "write_content_size\n"
83 99 " If True, the decompressed content size will be included in the header of\n"
84 100 " the compressed data. This data will only be written if the compressor\n"
85 101 " knows the size of the input data.\n"
86 102 "write_dict_id\n"
87 103 " Determines whether the dictionary ID will be written into the compressed\n"
88 104 " data. Defaults to True. Only adds content to the compressed data if\n"
89 105 " a dictionary is being used.\n"
90 106 );
91 107
92 108 static int ZstdCompressor_init(ZstdCompressor* self, PyObject* args, PyObject* kwargs) {
93 109 static char* kwlist[] = {
94 110 "level",
95 111 "dict_data",
96 112 "compression_params",
97 113 "write_checksum",
98 114 "write_content_size",
99 115 "write_dict_id",
100 116 NULL
101 117 };
102 118
103 119 int level = 3;
104 120 ZstdCompressionDict* dict = NULL;
105 121 CompressionParametersObject* params = NULL;
106 122 PyObject* writeChecksum = NULL;
107 123 PyObject* writeContentSize = NULL;
108 124 PyObject* writeDictID = NULL;
109 125
126 self->cctx = NULL;
110 127 self->dict = NULL;
111 128 self->cparams = NULL;
112 129 self->cdict = NULL;
113 130
114 131 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iO!O!OOO", kwlist,
115 132 &level, &ZstdCompressionDictType, &dict,
116 133 &CompressionParametersType, &params,
117 134 &writeChecksum, &writeContentSize, &writeDictID)) {
118 135 return -1;
119 136 }
120 137
121 138 if (level < 1) {
122 139 PyErr_SetString(PyExc_ValueError, "level must be greater than 0");
123 140 return -1;
124 141 }
125 142
126 143 if (level > ZSTD_maxCLevel()) {
127 144 PyErr_Format(PyExc_ValueError, "level must be less than %d",
128 145 ZSTD_maxCLevel() + 1);
129 146 return -1;
130 147 }
131 148
149 /* We create a ZSTD_CCtx for reuse among multiple operations to reduce the
150 overhead of each compression operation. */
151 self->cctx = ZSTD_createCCtx();
152 if (!self->cctx) {
153 PyErr_NoMemory();
154 return -1;
155 }
156
132 157 self->compressionLevel = level;
133 158
134 159 if (dict) {
135 160 self->dict = dict;
136 161 Py_INCREF(dict);
137 162 }
138 163
139 164 if (params) {
140 165 self->cparams = params;
141 166 Py_INCREF(params);
142 167 }
143 168
144 169 memset(&self->fparams, 0, sizeof(self->fparams));
145 170
146 171 if (writeChecksum && PyObject_IsTrue(writeChecksum)) {
147 172 self->fparams.checksumFlag = 1;
148 173 }
149 174 if (writeContentSize && PyObject_IsTrue(writeContentSize)) {
150 175 self->fparams.contentSizeFlag = 1;
151 176 }
152 177 if (writeDictID && PyObject_Not(writeDictID)) {
153 178 self->fparams.noDictIDFlag = 1;
154 179 }
155 180
156 181 return 0;
157 182 }
158 183
159 184 static void ZstdCompressor_dealloc(ZstdCompressor* self) {
160 185 Py_XDECREF(self->cparams);
161 186 Py_XDECREF(self->dict);
162 187
163 188 if (self->cdict) {
164 189 ZSTD_freeCDict(self->cdict);
165 190 self->cdict = NULL;
166 191 }
167 192
193 if (self->cctx) {
194 ZSTD_freeCCtx(self->cctx);
195 self->cctx = NULL;
196 }
197
168 198 PyObject_Del(self);
169 199 }
170 200
171 201 PyDoc_STRVAR(ZstdCompressor_copy_stream__doc__,
172 202 "copy_stream(ifh, ofh[, size=0, read_size=default, write_size=default])\n"
173 203 "compress data between streams\n"
174 204 "\n"
175 205 "Data will be read from ``ifh``, compressed, and written to ``ofh``.\n"
176 206 "``ifh`` must have a ``read(size)`` method. ``ofh`` must have a ``write(data)``\n"
177 207 "method.\n"
178 208 "\n"
179 209 "An optional ``size`` argument specifies the size of the source stream.\n"
180 210 "If defined, compression parameters will be tuned based on the size.\n"
181 211 "\n"
182 212 "Optional arguments ``read_size`` and ``write_size`` define the chunk sizes\n"
183 213 "of ``read()`` and ``write()`` operations, respectively. By default, they use\n"
184 214 "the default compression stream input and output sizes, respectively.\n"
185 215 );
186 216
187 217 static PyObject* ZstdCompressor_copy_stream(ZstdCompressor* self, PyObject* args, PyObject* kwargs) {
188 218 static char* kwlist[] = {
189 219 "ifh",
190 220 "ofh",
191 221 "size",
192 222 "read_size",
193 223 "write_size",
194 224 NULL
195 225 };
196 226
197 227 PyObject* source;
198 228 PyObject* dest;
199 229 Py_ssize_t sourceSize = 0;
200 230 size_t inSize = ZSTD_CStreamInSize();
201 231 size_t outSize = ZSTD_CStreamOutSize();
202 232 ZSTD_CStream* cstream;
203 233 ZSTD_inBuffer input;
204 234 ZSTD_outBuffer output;
205 235 Py_ssize_t totalRead = 0;
206 236 Py_ssize_t totalWrite = 0;
207 237 char* readBuffer;
208 238 Py_ssize_t readSize;
209 239 PyObject* readResult;
210 240 PyObject* res = NULL;
211 241 size_t zresult;
212 242 PyObject* writeResult;
213 243 PyObject* totalReadPy;
214 244 PyObject* totalWritePy;
215 245
216 246 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|nkk", kwlist, &source, &dest, &sourceSize,
217 247 &inSize, &outSize)) {
218 248 return NULL;
219 249 }
220 250
221 251 if (!PyObject_HasAttrString(source, "read")) {
222 252 PyErr_SetString(PyExc_ValueError, "first argument must have a read() method");
223 253 return NULL;
224 254 }
225 255
226 256 if (!PyObject_HasAttrString(dest, "write")) {
227 257 PyErr_SetString(PyExc_ValueError, "second argument must have a write() method");
228 258 return NULL;
229 259 }
230 260
231 261 cstream = CStream_from_ZstdCompressor(self, sourceSize);
232 262 if (!cstream) {
233 263 res = NULL;
234 264 goto finally;
235 265 }
236 266
237 267 output.dst = PyMem_Malloc(outSize);
238 268 if (!output.dst) {
239 269 PyErr_NoMemory();
240 270 res = NULL;
241 271 goto finally;
242 272 }
243 273 output.size = outSize;
244 274 output.pos = 0;
245 275
246 276 while (1) {
247 277 /* Try to read from source stream. */
248 278 readResult = PyObject_CallMethod(source, "read", "n", inSize);
249 279 if (!readResult) {
250 280 PyErr_SetString(ZstdError, "could not read() from source");
251 281 goto finally;
252 282 }
253 283
254 284 PyBytes_AsStringAndSize(readResult, &readBuffer, &readSize);
255 285
256 286 /* If no data was read, we're at EOF. */
257 287 if (0 == readSize) {
258 288 break;
259 289 }
260 290
261 291 totalRead += readSize;
262 292
263 293 /* Send data to compressor */
264 294 input.src = readBuffer;
265 295 input.size = readSize;
266 296 input.pos = 0;
267 297
268 298 while (input.pos < input.size) {
269 299 Py_BEGIN_ALLOW_THREADS
270 300 zresult = ZSTD_compressStream(cstream, &output, &input);
271 301 Py_END_ALLOW_THREADS
272 302
273 303 if (ZSTD_isError(zresult)) {
274 304 res = NULL;
275 305 PyErr_Format(ZstdError, "zstd compress error: %s", ZSTD_getErrorName(zresult));
276 306 goto finally;
277 307 }
278 308
279 309 if (output.pos) {
280 310 #if PY_MAJOR_VERSION >= 3
281 311 writeResult = PyObject_CallMethod(dest, "write", "y#",
282 312 #else
283 313 writeResult = PyObject_CallMethod(dest, "write", "s#",
284 314 #endif
285 315 output.dst, output.pos);
286 316 Py_XDECREF(writeResult);
287 317 totalWrite += output.pos;
288 318 output.pos = 0;
289 319 }
290 320 }
291 321 }
292 322
293 323 /* We've finished reading. Now flush the compressor stream. */
294 324 while (1) {
295 325 zresult = ZSTD_endStream(cstream, &output);
296 326 if (ZSTD_isError(zresult)) {
297 327 PyErr_Format(ZstdError, "error ending compression stream: %s",
298 328 ZSTD_getErrorName(zresult));
299 329 res = NULL;
300 330 goto finally;
301 331 }
302 332
303 333 if (output.pos) {
304 334 #if PY_MAJOR_VERSION >= 3
305 335 writeResult = PyObject_CallMethod(dest, "write", "y#",
306 336 #else
307 337 writeResult = PyObject_CallMethod(dest, "write", "s#",
308 338 #endif
309 339 output.dst, output.pos);
310 340 totalWrite += output.pos;
311 341 Py_XDECREF(writeResult);
312 342 output.pos = 0;
313 343 }
314 344
315 345 if (!zresult) {
316 346 break;
317 347 }
318 348 }
319 349
320 350 ZSTD_freeCStream(cstream);
321 351 cstream = NULL;
322 352
323 353 totalReadPy = PyLong_FromSsize_t(totalRead);
324 354 totalWritePy = PyLong_FromSsize_t(totalWrite);
325 355 res = PyTuple_Pack(2, totalReadPy, totalWritePy);
326 356 Py_DecRef(totalReadPy);
327 357 Py_DecRef(totalWritePy);
328 358
329 359 finally:
330 360 if (output.dst) {
331 361 PyMem_Free(output.dst);
332 362 }
333 363
334 364 if (cstream) {
335 365 ZSTD_freeCStream(cstream);
336 366 }
337 367
338 368 return res;
339 369 }
340 370
341 371 PyDoc_STRVAR(ZstdCompressor_compress__doc__,
342 "compress(data)\n"
372 "compress(data, allow_empty=False)\n"
343 373 "\n"
344 374 "Compress data in a single operation.\n"
345 375 "\n"
346 376 "This is the simplest mechanism to perform compression: simply pass in a\n"
347 377 "value and get a compressed value back. It is almost the most prone to abuse.\n"
348 378 "The input and output values must fit in memory, so passing in very large\n"
349 379 "values can result in excessive memory usage. For this reason, one of the\n"
350 380 "streaming based APIs is preferred for larger values.\n"
351 381 );
352 382
353 static PyObject* ZstdCompressor_compress(ZstdCompressor* self, PyObject* args) {
383 static PyObject* ZstdCompressor_compress(ZstdCompressor* self, PyObject* args, PyObject* kwargs) {
384 static char* kwlist[] = {
385 "data",
386 "allow_empty",
387 NULL
388 };
389
354 390 const char* source;
355 391 Py_ssize_t sourceSize;
392 PyObject* allowEmpty = NULL;
356 393 size_t destSize;
357 ZSTD_CCtx* cctx;
358 394 PyObject* output;
359 395 char* dest;
360 396 void* dictData = NULL;
361 397 size_t dictSize = 0;
362 398 size_t zresult;
363 399 ZSTD_parameters zparams;
364 ZSTD_customMem zmem;
365 400
366 401 #if PY_MAJOR_VERSION >= 3
367 if (!PyArg_ParseTuple(args, "y#", &source, &sourceSize)) {
402 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y#|O",
368 403 #else
369 if (!PyArg_ParseTuple(args, "s#", &source, &sourceSize)) {
404 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O",
370 405 #endif
406 kwlist, &source, &sourceSize, &allowEmpty)) {
407 return NULL;
408 }
409
410 /* Limitation in zstd C API doesn't let decompression side distinguish
411 between content size of 0 and unknown content size. This can make round
412 tripping via Python difficult. Until this is fixed, require a flag
413 to fire the footgun.
414 https://github.com/indygreg/python-zstandard/issues/11 */
415 if (0 == sourceSize && self->fparams.contentSizeFlag
416 && (!allowEmpty || PyObject_Not(allowEmpty))) {
417 PyErr_SetString(PyExc_ValueError, "cannot write empty inputs when writing content sizes");
371 418 return NULL;
372 419 }
373 420
374 421 destSize = ZSTD_compressBound(sourceSize);
375 422 output = PyBytes_FromStringAndSize(NULL, destSize);
376 423 if (!output) {
377 424 return NULL;
378 425 }
379 426
380 427 dest = PyBytes_AsString(output);
381 428
382 cctx = ZSTD_createCCtx();
383 if (!cctx) {
384 Py_DECREF(output);
385 PyErr_SetString(ZstdError, "could not create CCtx");
386 return NULL;
387 }
388
389 429 if (self->dict) {
390 430 dictData = self->dict->dictData;
391 431 dictSize = self->dict->dictSize;
392 432 }
393 433
394 434 memset(&zparams, 0, sizeof(zparams));
395 435 if (!self->cparams) {
396 436 zparams.cParams = ZSTD_getCParams(self->compressionLevel, sourceSize, dictSize);
397 437 }
398 438 else {
399 439 ztopy_compression_parameters(self->cparams, &zparams.cParams);
400 440 /* Do NOT call ZSTD_adjustCParams() here because the compression params
401 441 come from the user. */
402 442 }
403 443
404 444 zparams.fParams = self->fparams;
405 445
406 446 /* The raw dict data has to be processed before it can be used. Since this
407 447 adds overhead - especially if multiple dictionary compression operations
408 448 are performed on the same ZstdCompressor instance - we create a
409 ZSTD_CDict once and reuse it for all operations. */
449 ZSTD_CDict once and reuse it for all operations.
410 450
411 /* TODO the zparams (which can be derived from the source data size) used
412 on first invocation are effectively reused for subsequent operations. This
413 may not be appropriate if input sizes vary significantly and could affect
414 chosen compression parameters.
415 https://github.com/facebook/zstd/issues/358 tracks this issue. */
451 Note: the compression parameters used for the first invocation (possibly
452 derived from the source size) will be reused on all subsequent invocations.
453 https://github.com/facebook/zstd/issues/358 contains more info. We could
454 potentially add an argument somewhere to control this behavior.
455 */
416 456 if (dictData && !self->cdict) {
417 Py_BEGIN_ALLOW_THREADS
418 memset(&zmem, 0, sizeof(zmem));
419 self->cdict = ZSTD_createCDict_advanced(dictData, dictSize, zparams, zmem);
420 Py_END_ALLOW_THREADS
421
422 if (!self->cdict) {
457 if (populate_cdict(self, dictData, dictSize, &zparams)) {
423 458 Py_DECREF(output);
424 ZSTD_freeCCtx(cctx);
425 PyErr_SetString(ZstdError, "could not create compression dictionary");
426 459 return NULL;
427 460 }
428 461 }
429 462
430 463 Py_BEGIN_ALLOW_THREADS
431 464 /* By avoiding ZSTD_compress(), we don't necessarily write out content
432 465 size. This means the argument to ZstdCompressor to control frame
433 466 parameters is honored. */
434 467 if (self->cdict) {
435 zresult = ZSTD_compress_usingCDict(cctx, dest, destSize,
468 zresult = ZSTD_compress_usingCDict(self->cctx, dest, destSize,
436 469 source, sourceSize, self->cdict);
437 470 }
438 471 else {
439 zresult = ZSTD_compress_advanced(cctx, dest, destSize,
472 zresult = ZSTD_compress_advanced(self->cctx, dest, destSize,
440 473 source, sourceSize, dictData, dictSize, zparams);
441 474 }
442 475 Py_END_ALLOW_THREADS
443 476
444 ZSTD_freeCCtx(cctx);
445
446 477 if (ZSTD_isError(zresult)) {
447 478 PyErr_Format(ZstdError, "cannot compress: %s", ZSTD_getErrorName(zresult));
448 479 Py_CLEAR(output);
449 480 return NULL;
450 481 }
451 482 else {
452 483 Py_SIZE(output) = zresult;
453 484 }
454 485
455 486 return output;
456 487 }
457 488
458 489 PyDoc_STRVAR(ZstdCompressionObj__doc__,
459 490 "compressobj()\n"
460 491 "\n"
461 492 "Return an object exposing ``compress(data)`` and ``flush()`` methods.\n"
462 493 "\n"
463 494 "The returned object exposes an API similar to ``zlib.compressobj`` and\n"
464 495 "``bz2.BZ2Compressor`` so that callers can swap in the zstd compressor\n"
465 496 "without changing how compression is performed.\n"
466 497 );
467 498
468 499 static ZstdCompressionObj* ZstdCompressor_compressobj(ZstdCompressor* self, PyObject* args, PyObject* kwargs) {
469 500 static char* kwlist[] = {
470 501 "size",
471 502 NULL
472 503 };
473 504
474 505 Py_ssize_t inSize = 0;
475 506 size_t outSize = ZSTD_CStreamOutSize();
476 507 ZstdCompressionObj* result = PyObject_New(ZstdCompressionObj, &ZstdCompressionObjType);
477 508 if (!result) {
478 509 return NULL;
479 510 }
480 511
481 512 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|n", kwlist, &inSize)) {
482 513 return NULL;
483 514 }
484 515
485 516 result->cstream = CStream_from_ZstdCompressor(self, inSize);
486 517 if (!result->cstream) {
487 518 Py_DECREF(result);
488 519 return NULL;
489 520 }
490 521
491 522 result->output.dst = PyMem_Malloc(outSize);
492 523 if (!result->output.dst) {
493 524 PyErr_NoMemory();
494 525 Py_DECREF(result);
495 526 return NULL;
496 527 }
497 528 result->output.size = outSize;
498 529 result->output.pos = 0;
499 530
500 531 result->compressor = self;
501 532 Py_INCREF(result->compressor);
502 533
503 result->flushed = 0;
534 result->finished = 0;
504 535
505 536 return result;
506 537 }
507 538
508 539 PyDoc_STRVAR(ZstdCompressor_read_from__doc__,
509 540 "read_from(reader, [size=0, read_size=default, write_size=default])\n"
510 541 "Read uncompress data from a reader and return an iterator\n"
511 542 "\n"
512 543 "Returns an iterator of compressed data produced from reading from ``reader``.\n"
513 544 "\n"
514 545 "Uncompressed data will be obtained from ``reader`` by calling the\n"
515 546 "``read(size)`` method of it. The source data will be streamed into a\n"
516 547 "compressor. As compressed data is available, it will be exposed to the\n"
517 548 "iterator.\n"
518 549 "\n"
519 550 "Data is read from the source in chunks of ``read_size``. Compressed chunks\n"
520 551 "are at most ``write_size`` bytes. Both values default to the zstd input and\n"
521 552 "and output defaults, respectively.\n"
522 553 "\n"
523 554 "The caller is partially in control of how fast data is fed into the\n"
524 555 "compressor by how it consumes the returned iterator. The compressor will\n"
525 556 "not consume from the reader unless the caller consumes from the iterator.\n"
526 557 );
527 558
528 559 static ZstdCompressorIterator* ZstdCompressor_read_from(ZstdCompressor* self, PyObject* args, PyObject* kwargs) {
529 560 static char* kwlist[] = {
530 561 "reader",
531 562 "size",
532 563 "read_size",
533 564 "write_size",
534 565 NULL
535 566 };
536 567
537 568 PyObject* reader;
538 569 Py_ssize_t sourceSize = 0;
539 570 size_t inSize = ZSTD_CStreamInSize();
540 571 size_t outSize = ZSTD_CStreamOutSize();
541 572 ZstdCompressorIterator* result;
542 573
543 574 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|nkk", kwlist, &reader, &sourceSize,
544 575 &inSize, &outSize)) {
545 576 return NULL;
546 577 }
547 578
548 579 result = PyObject_New(ZstdCompressorIterator, &ZstdCompressorIteratorType);
549 580 if (!result) {
550 581 return NULL;
551 582 }
552 583
553 584 result->compressor = NULL;
554 585 result->reader = NULL;
555 586 result->buffer = NULL;
556 587 result->cstream = NULL;
557 588 result->input.src = NULL;
558 589 result->output.dst = NULL;
559 590 result->readResult = NULL;
560 591
561 592 if (PyObject_HasAttrString(reader, "read")) {
562 593 result->reader = reader;
563 594 Py_INCREF(result->reader);
564 595 }
565 596 else if (1 == PyObject_CheckBuffer(reader)) {
566 597 result->buffer = PyMem_Malloc(sizeof(Py_buffer));
567 598 if (!result->buffer) {
568 599 goto except;
569 600 }
570 601
571 602 memset(result->buffer, 0, sizeof(Py_buffer));
572 603
573 604 if (0 != PyObject_GetBuffer(reader, result->buffer, PyBUF_CONTIG_RO)) {
574 605 goto except;
575 606 }
576 607
577 608 result->bufferOffset = 0;
578 609 sourceSize = result->buffer->len;
579 610 }
580 611 else {
581 612 PyErr_SetString(PyExc_ValueError,
582 613 "must pass an object with a read() method or conforms to buffer protocol");
583 614 goto except;
584 615 }
585 616
586 617 result->compressor = self;
587 618 Py_INCREF(result->compressor);
588 619
589 620 result->sourceSize = sourceSize;
590 621 result->cstream = CStream_from_ZstdCompressor(self, sourceSize);
591 622 if (!result->cstream) {
592 623 goto except;
593 624 }
594 625
595 626 result->inSize = inSize;
596 627 result->outSize = outSize;
597 628
598 629 result->output.dst = PyMem_Malloc(outSize);
599 630 if (!result->output.dst) {
600 631 PyErr_NoMemory();
601 632 goto except;
602 633 }
603 634 result->output.size = outSize;
604 635 result->output.pos = 0;
605 636
606 637 result->input.src = NULL;
607 638 result->input.size = 0;
608 639 result->input.pos = 0;
609 640
610 641 result->finishedInput = 0;
611 642 result->finishedOutput = 0;
612 643
613 644 goto finally;
614 645
615 646 except:
616 647 if (result->cstream) {
617 648 ZSTD_freeCStream(result->cstream);
618 649 result->cstream = NULL;
619 650 }
620 651
621 652 Py_DecRef((PyObject*)result->compressor);
622 653 Py_DecRef(result->reader);
623 654
624 655 Py_DECREF(result);
625 656 result = NULL;
626 657
627 658 finally:
628 659 return result;
629 660 }
630 661
631 662 PyDoc_STRVAR(ZstdCompressor_write_to___doc__,
632 663 "Create a context manager to write compressed data to an object.\n"
633 664 "\n"
634 665 "The passed object must have a ``write()`` method.\n"
635 666 "\n"
636 667 "The caller feeds input data to the object by calling ``compress(data)``.\n"
637 668 "Compressed data is written to the argument given to this function.\n"
638 669 "\n"
639 670 "The function takes an optional ``size`` argument indicating the total size\n"
640 671 "of the eventual input. If specified, the size will influence compression\n"
641 672 "parameter tuning and could result in the size being written into the\n"
642 673 "header of the compressed data.\n"
643 674 "\n"
644 675 "An optional ``write_size`` argument is also accepted. It defines the maximum\n"
645 676 "byte size of chunks fed to ``write()``. By default, it uses the zstd default\n"
646 677 "for a compressor output stream.\n"
647 678 );
648 679
649 680 static ZstdCompressionWriter* ZstdCompressor_write_to(ZstdCompressor* self, PyObject* args, PyObject* kwargs) {
650 681 static char* kwlist[] = {
651 682 "writer",
652 683 "size",
653 684 "write_size",
654 685 NULL
655 686 };
656 687
657 688 PyObject* writer;
658 689 ZstdCompressionWriter* result;
659 690 Py_ssize_t sourceSize = 0;
660 691 size_t outSize = ZSTD_CStreamOutSize();
661 692
662 693 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|nk", kwlist, &writer, &sourceSize,
663 694 &outSize)) {
664 695 return NULL;
665 696 }
666 697
667 698 if (!PyObject_HasAttrString(writer, "write")) {
668 699 PyErr_SetString(PyExc_ValueError, "must pass an object with a write() method");
669 700 return NULL;
670 701 }
671 702
672 703 result = PyObject_New(ZstdCompressionWriter, &ZstdCompressionWriterType);
673 704 if (!result) {
674 705 return NULL;
675 706 }
676 707
677 708 result->compressor = self;
678 709 Py_INCREF(result->compressor);
679 710
680 711 result->writer = writer;
681 712 Py_INCREF(result->writer);
682 713
683 714 result->sourceSize = sourceSize;
684 715
685 716 result->outSize = outSize;
686 717
687 718 result->entered = 0;
688 719 result->cstream = NULL;
689 720
690 721 return result;
691 722 }
692 723
693 724 static PyMethodDef ZstdCompressor_methods[] = {
694 { "compress", (PyCFunction)ZstdCompressor_compress, METH_VARARGS,
695 ZstdCompressor_compress__doc__ },
725 { "compress", (PyCFunction)ZstdCompressor_compress,
726 METH_VARARGS | METH_KEYWORDS, ZstdCompressor_compress__doc__ },
696 727 { "compressobj", (PyCFunction)ZstdCompressor_compressobj,
697 728 METH_VARARGS | METH_KEYWORDS, ZstdCompressionObj__doc__ },
698 729 { "copy_stream", (PyCFunction)ZstdCompressor_copy_stream,
699 730 METH_VARARGS | METH_KEYWORDS, ZstdCompressor_copy_stream__doc__ },
700 731 { "read_from", (PyCFunction)ZstdCompressor_read_from,
701 732 METH_VARARGS | METH_KEYWORDS, ZstdCompressor_read_from__doc__ },
702 733 { "write_to", (PyCFunction)ZstdCompressor_write_to,
703 734 METH_VARARGS | METH_KEYWORDS, ZstdCompressor_write_to___doc__ },
704 735 { NULL, NULL }
705 736 };
706 737
707 738 PyTypeObject ZstdCompressorType = {
708 739 PyVarObject_HEAD_INIT(NULL, 0)
709 740 "zstd.ZstdCompressor", /* tp_name */
710 741 sizeof(ZstdCompressor), /* tp_basicsize */
711 742 0, /* tp_itemsize */
712 743 (destructor)ZstdCompressor_dealloc, /* tp_dealloc */
713 744 0, /* tp_print */
714 745 0, /* tp_getattr */
715 746 0, /* tp_setattr */
716 747 0, /* tp_compare */
717 748 0, /* tp_repr */
718 749 0, /* tp_as_number */
719 750 0, /* tp_as_sequence */
720 751 0, /* tp_as_mapping */
721 752 0, /* tp_hash */
722 753 0, /* tp_call */
723 754 0, /* tp_str */
724 755 0, /* tp_getattro */
725 756 0, /* tp_setattro */
726 757 0, /* tp_as_buffer */
727 758 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
728 759 ZstdCompressor__doc__, /* tp_doc */
729 760 0, /* tp_traverse */
730 761 0, /* tp_clear */
731 762 0, /* tp_richcompare */
732 763 0, /* tp_weaklistoffset */
733 764 0, /* tp_iter */
734 765 0, /* tp_iternext */
735 766 ZstdCompressor_methods, /* tp_methods */
736 767 0, /* tp_members */
737 768 0, /* tp_getset */
738 769 0, /* tp_base */
739 770 0, /* tp_dict */
740 771 0, /* tp_descr_get */
741 772 0, /* tp_descr_set */
742 773 0, /* tp_dictoffset */
743 774 (initproc)ZstdCompressor_init, /* tp_init */
744 775 0, /* tp_alloc */
745 776 PyType_GenericNew, /* tp_new */
746 777 };
747 778
748 779 void compressor_module_init(PyObject* mod) {
749 780 Py_TYPE(&ZstdCompressorType) = &PyType_Type;
750 781 if (PyType_Ready(&ZstdCompressorType) < 0) {
751 782 return;
752 783 }
753 784
754 785 Py_INCREF((PyObject*)&ZstdCompressorType);
755 786 PyModule_AddObject(mod, "ZstdCompressor",
756 787 (PyObject*)&ZstdCompressorType);
757 788 }
@@ -1,84 +1,87 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Gregory Szorc
3 3 * All rights reserved.
4 4 *
5 5 * This software may be modified and distributed under the terms
6 6 * of the BSD license. See the LICENSE file for details.
7 7 */
8 8
9 9 #include "python-zstandard.h"
10 10
11 11 extern PyObject* ZstdError;
12 12
13 13 static char frame_header[] = {
14 14 '\x28',
15 15 '\xb5',
16 16 '\x2f',
17 17 '\xfd',
18 18 };
19 19
20 20 void constants_module_init(PyObject* mod) {
21 21 PyObject* version;
22 22 PyObject* zstdVersion;
23 23 PyObject* frameHeader;
24 24
25 25 #if PY_MAJOR_VERSION >= 3
26 26 version = PyUnicode_FromString(PYTHON_ZSTANDARD_VERSION);
27 27 #else
28 28 version = PyString_FromString(PYTHON_ZSTANDARD_VERSION);
29 29 #endif
30 30 Py_INCREF(version);
31 31 PyModule_AddObject(mod, "__version__", version);
32 32
33 33 ZstdError = PyErr_NewException("zstd.ZstdError", NULL, NULL);
34 34 PyModule_AddObject(mod, "ZstdError", ZstdError);
35 35
36 PyModule_AddIntConstant(mod, "COMPRESSOBJ_FLUSH_FINISH", compressorobj_flush_finish);
37 PyModule_AddIntConstant(mod, "COMPRESSOBJ_FLUSH_BLOCK", compressorobj_flush_block);
38
36 39 /* For now, the version is a simple tuple instead of a dedicated type. */
37 40 zstdVersion = PyTuple_New(3);
38 41 PyTuple_SetItem(zstdVersion, 0, PyLong_FromLong(ZSTD_VERSION_MAJOR));
39 42 PyTuple_SetItem(zstdVersion, 1, PyLong_FromLong(ZSTD_VERSION_MINOR));
40 43 PyTuple_SetItem(zstdVersion, 2, PyLong_FromLong(ZSTD_VERSION_RELEASE));
41 44 Py_IncRef(zstdVersion);
42 45 PyModule_AddObject(mod, "ZSTD_VERSION", zstdVersion);
43 46
44 47 frameHeader = PyBytes_FromStringAndSize(frame_header, sizeof(frame_header));
45 48 if (frameHeader) {
46 49 PyModule_AddObject(mod, "FRAME_HEADER", frameHeader);
47 50 }
48 51 else {
49 52 PyErr_Format(PyExc_ValueError, "could not create frame header object");
50 53 }
51 54
52 55 PyModule_AddIntConstant(mod, "MAX_COMPRESSION_LEVEL", ZSTD_maxCLevel());
53 56 PyModule_AddIntConstant(mod, "COMPRESSION_RECOMMENDED_INPUT_SIZE",
54 57 (long)ZSTD_CStreamInSize());
55 58 PyModule_AddIntConstant(mod, "COMPRESSION_RECOMMENDED_OUTPUT_SIZE",
56 59 (long)ZSTD_CStreamOutSize());
57 60 PyModule_AddIntConstant(mod, "DECOMPRESSION_RECOMMENDED_INPUT_SIZE",
58 61 (long)ZSTD_DStreamInSize());
59 62 PyModule_AddIntConstant(mod, "DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE",
60 63 (long)ZSTD_DStreamOutSize());
61 64
62 65 PyModule_AddIntConstant(mod, "MAGIC_NUMBER", ZSTD_MAGICNUMBER);
63 66 PyModule_AddIntConstant(mod, "WINDOWLOG_MIN", ZSTD_WINDOWLOG_MIN);
64 67 PyModule_AddIntConstant(mod, "WINDOWLOG_MAX", ZSTD_WINDOWLOG_MAX);
65 68 PyModule_AddIntConstant(mod, "CHAINLOG_MIN", ZSTD_CHAINLOG_MIN);
66 69 PyModule_AddIntConstant(mod, "CHAINLOG_MAX", ZSTD_CHAINLOG_MAX);
67 70 PyModule_AddIntConstant(mod, "HASHLOG_MIN", ZSTD_HASHLOG_MIN);
68 71 PyModule_AddIntConstant(mod, "HASHLOG_MAX", ZSTD_HASHLOG_MAX);
69 72 PyModule_AddIntConstant(mod, "HASHLOG3_MAX", ZSTD_HASHLOG3_MAX);
70 73 PyModule_AddIntConstant(mod, "SEARCHLOG_MIN", ZSTD_SEARCHLOG_MIN);
71 74 PyModule_AddIntConstant(mod, "SEARCHLOG_MAX", ZSTD_SEARCHLOG_MAX);
72 75 PyModule_AddIntConstant(mod, "SEARCHLENGTH_MIN", ZSTD_SEARCHLENGTH_MIN);
73 76 PyModule_AddIntConstant(mod, "SEARCHLENGTH_MAX", ZSTD_SEARCHLENGTH_MAX);
74 77 PyModule_AddIntConstant(mod, "TARGETLENGTH_MIN", ZSTD_TARGETLENGTH_MIN);
75 78 PyModule_AddIntConstant(mod, "TARGETLENGTH_MAX", ZSTD_TARGETLENGTH_MAX);
76 79
77 80 PyModule_AddIntConstant(mod, "STRATEGY_FAST", ZSTD_fast);
78 81 PyModule_AddIntConstant(mod, "STRATEGY_DFAST", ZSTD_dfast);
79 82 PyModule_AddIntConstant(mod, "STRATEGY_GREEDY", ZSTD_greedy);
80 83 PyModule_AddIntConstant(mod, "STRATEGY_LAZY", ZSTD_lazy);
81 84 PyModule_AddIntConstant(mod, "STRATEGY_LAZY2", ZSTD_lazy2);
82 85 PyModule_AddIntConstant(mod, "STRATEGY_BTLAZY2", ZSTD_btlazy2);
83 86 PyModule_AddIntConstant(mod, "STRATEGY_BTOPT", ZSTD_btopt);
84 87 }
@@ -1,187 +1,187 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Gregory Szorc
3 3 * All rights reserved.
4 4 *
5 5 * This software may be modified and distributed under the terms
6 6 * of the BSD license. See the LICENSE file for details.
7 7 */
8 8
9 9 #include "python-zstandard.h"
10 10
11 11 extern PyObject* ZstdError;
12 12
13 13 PyDoc_STRVAR(ZstdDecompressionWriter__doc,
14 14 """A context manager used for writing decompressed output.\n"
15 15 );
16 16
17 17 static void ZstdDecompressionWriter_dealloc(ZstdDecompressionWriter* self) {
18 18 Py_XDECREF(self->decompressor);
19 19 Py_XDECREF(self->writer);
20 20
21 21 if (self->dstream) {
22 22 ZSTD_freeDStream(self->dstream);
23 23 self->dstream = NULL;
24 24 }
25 25
26 26 PyObject_Del(self);
27 27 }
28 28
29 29 static PyObject* ZstdDecompressionWriter_enter(ZstdDecompressionWriter* self) {
30 30 if (self->entered) {
31 31 PyErr_SetString(ZstdError, "cannot __enter__ multiple times");
32 32 return NULL;
33 33 }
34 34
35 35 self->dstream = DStream_from_ZstdDecompressor(self->decompressor);
36 36 if (!self->dstream) {
37 37 return NULL;
38 38 }
39 39
40 40 self->entered = 1;
41 41
42 42 Py_INCREF(self);
43 43 return (PyObject*)self;
44 44 }
45 45
46 46 static PyObject* ZstdDecompressionWriter_exit(ZstdDecompressionWriter* self, PyObject* args) {
47 47 self->entered = 0;
48 48
49 49 if (self->dstream) {
50 50 ZSTD_freeDStream(self->dstream);
51 51 self->dstream = NULL;
52 52 }
53 53
54 54 Py_RETURN_FALSE;
55 55 }
56 56
57 57 static PyObject* ZstdDecompressionWriter_memory_size(ZstdDecompressionWriter* self) {
58 58 if (!self->dstream) {
59 59 PyErr_SetString(ZstdError, "cannot determine size of inactive decompressor; "
60 60 "call when context manager is active");
61 61 return NULL;
62 62 }
63 63
64 64 return PyLong_FromSize_t(ZSTD_sizeof_DStream(self->dstream));
65 65 }
66 66
67 67 static PyObject* ZstdDecompressionWriter_write(ZstdDecompressionWriter* self, PyObject* args) {
68 68 const char* source;
69 69 Py_ssize_t sourceSize;
70 70 size_t zresult = 0;
71 71 ZSTD_inBuffer input;
72 72 ZSTD_outBuffer output;
73 73 PyObject* res;
74 74
75 75 #if PY_MAJOR_VERSION >= 3
76 76 if (!PyArg_ParseTuple(args, "y#", &source, &sourceSize)) {
77 77 #else
78 78 if (!PyArg_ParseTuple(args, "s#", &source, &sourceSize)) {
79 79 #endif
80 80 return NULL;
81 81 }
82 82
83 83 if (!self->entered) {
84 84 PyErr_SetString(ZstdError, "write must be called from an active context manager");
85 85 return NULL;
86 86 }
87 87
88 output.dst = malloc(self->outSize);
88 output.dst = PyMem_Malloc(self->outSize);
89 89 if (!output.dst) {
90 90 return PyErr_NoMemory();
91 91 }
92 92 output.size = self->outSize;
93 93 output.pos = 0;
94 94
95 95 input.src = source;
96 96 input.size = sourceSize;
97 97 input.pos = 0;
98 98
99 99 while ((ssize_t)input.pos < sourceSize) {
100 100 Py_BEGIN_ALLOW_THREADS
101 101 zresult = ZSTD_decompressStream(self->dstream, &output, &input);
102 102 Py_END_ALLOW_THREADS
103 103
104 104 if (ZSTD_isError(zresult)) {
105 free(output.dst);
105 PyMem_Free(output.dst);
106 106 PyErr_Format(ZstdError, "zstd decompress error: %s",
107 107 ZSTD_getErrorName(zresult));
108 108 return NULL;
109 109 }
110 110
111 111 if (output.pos) {
112 112 #if PY_MAJOR_VERSION >= 3
113 113 res = PyObject_CallMethod(self->writer, "write", "y#",
114 114 #else
115 115 res = PyObject_CallMethod(self->writer, "write", "s#",
116 116 #endif
117 117 output.dst, output.pos);
118 118 Py_XDECREF(res);
119 119 output.pos = 0;
120 120 }
121 121 }
122 122
123 free(output.dst);
123 PyMem_Free(output.dst);
124 124
125 125 /* TODO return bytes written */
126 126 Py_RETURN_NONE;
127 127 }
128 128
129 129 static PyMethodDef ZstdDecompressionWriter_methods[] = {
130 130 { "__enter__", (PyCFunction)ZstdDecompressionWriter_enter, METH_NOARGS,
131 131 PyDoc_STR("Enter a decompression context.") },
132 132 { "__exit__", (PyCFunction)ZstdDecompressionWriter_exit, METH_VARARGS,
133 133 PyDoc_STR("Exit a decompression context.") },
134 134 { "memory_size", (PyCFunction)ZstdDecompressionWriter_memory_size, METH_NOARGS,
135 135 PyDoc_STR("Obtain the memory size in bytes of the underlying decompressor.") },
136 136 { "write", (PyCFunction)ZstdDecompressionWriter_write, METH_VARARGS,
137 137 PyDoc_STR("Compress data") },
138 138 { NULL, NULL }
139 139 };
140 140
141 141 PyTypeObject ZstdDecompressionWriterType = {
142 142 PyVarObject_HEAD_INIT(NULL, 0)
143 143 "zstd.ZstdDecompressionWriter", /* tp_name */
144 144 sizeof(ZstdDecompressionWriter),/* tp_basicsize */
145 145 0, /* tp_itemsize */
146 146 (destructor)ZstdDecompressionWriter_dealloc, /* tp_dealloc */
147 147 0, /* tp_print */
148 148 0, /* tp_getattr */
149 149 0, /* tp_setattr */
150 150 0, /* tp_compare */
151 151 0, /* tp_repr */
152 152 0, /* tp_as_number */
153 153 0, /* tp_as_sequence */
154 154 0, /* tp_as_mapping */
155 155 0, /* tp_hash */
156 156 0, /* tp_call */
157 157 0, /* tp_str */
158 158 0, /* tp_getattro */
159 159 0, /* tp_setattro */
160 160 0, /* tp_as_buffer */
161 161 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
162 162 ZstdDecompressionWriter__doc, /* tp_doc */
163 163 0, /* tp_traverse */
164 164 0, /* tp_clear */
165 165 0, /* tp_richcompare */
166 166 0, /* tp_weaklistoffset */
167 167 0, /* tp_iter */
168 168 0, /* tp_iternext */
169 169 ZstdDecompressionWriter_methods,/* tp_methods */
170 170 0, /* tp_members */
171 171 0, /* tp_getset */
172 172 0, /* tp_base */
173 173 0, /* tp_dict */
174 174 0, /* tp_descr_get */
175 175 0, /* tp_descr_set */
176 176 0, /* tp_dictoffset */
177 177 0, /* tp_init */
178 178 0, /* tp_alloc */
179 179 PyType_GenericNew, /* tp_new */
180 180 };
181 181
182 182 void decompressionwriter_module_init(PyObject* mod) {
183 183 Py_TYPE(&ZstdDecompressionWriterType) = &PyType_Type;
184 184 if (PyType_Ready(&ZstdDecompressionWriterType) < 0) {
185 185 return;
186 186 }
187 187 }
@@ -1,172 +1,178 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Gregory Szorc
3 3 * All rights reserved.
4 4 *
5 5 * This software may be modified and distributed under the terms
6 6 * of the BSD license. See the LICENSE file for details.
7 7 */
8 8
9 9 #define PY_SSIZE_T_CLEAN
10 10 #include <Python.h>
11 11
12 12 #define ZSTD_STATIC_LINKING_ONLY
13 13 #define ZDICT_STATIC_LINKING_ONLY
14 14 #include "mem.h"
15 15 #include "zstd.h"
16 16 #include "zdict.h"
17 17
18 #define PYTHON_ZSTANDARD_VERSION "0.5.0"
18 #define PYTHON_ZSTANDARD_VERSION "0.6.0"
19
20 typedef enum {
21 compressorobj_flush_finish,
22 compressorobj_flush_block,
23 } CompressorObj_Flush;
19 24
20 25 typedef struct {
21 26 PyObject_HEAD
22 27 unsigned windowLog;
23 28 unsigned chainLog;
24 29 unsigned hashLog;
25 30 unsigned searchLog;
26 31 unsigned searchLength;
27 32 unsigned targetLength;
28 33 ZSTD_strategy strategy;
29 34 } CompressionParametersObject;
30 35
31 36 extern PyTypeObject CompressionParametersType;
32 37
33 38 typedef struct {
34 39 PyObject_HEAD
35 40 unsigned selectivityLevel;
36 41 int compressionLevel;
37 42 unsigned notificationLevel;
38 43 unsigned dictID;
39 44 } DictParametersObject;
40 45
41 46 extern PyTypeObject DictParametersType;
42 47
43 48 typedef struct {
44 49 PyObject_HEAD
45 50
46 51 void* dictData;
47 52 size_t dictSize;
48 53 } ZstdCompressionDict;
49 54
50 55 extern PyTypeObject ZstdCompressionDictType;
51 56
52 57 typedef struct {
53 58 PyObject_HEAD
54 59
55 60 int compressionLevel;
56 61 ZstdCompressionDict* dict;
62 ZSTD_CCtx* cctx;
57 63 ZSTD_CDict* cdict;
58 64 CompressionParametersObject* cparams;
59 65 ZSTD_frameParameters fparams;
60 66 } ZstdCompressor;
61 67
62 68 extern PyTypeObject ZstdCompressorType;
63 69
64 70 typedef struct {
65 71 PyObject_HEAD
66 72
67 73 ZstdCompressor* compressor;
68 74 ZSTD_CStream* cstream;
69 75 ZSTD_outBuffer output;
70 int flushed;
76 int finished;
71 77 } ZstdCompressionObj;
72 78
73 79 extern PyTypeObject ZstdCompressionObjType;
74 80
75 81 typedef struct {
76 82 PyObject_HEAD
77 83
78 84 ZstdCompressor* compressor;
79 85 PyObject* writer;
80 86 Py_ssize_t sourceSize;
81 87 size_t outSize;
82 88 ZSTD_CStream* cstream;
83 89 int entered;
84 90 } ZstdCompressionWriter;
85 91
86 92 extern PyTypeObject ZstdCompressionWriterType;
87 93
88 94 typedef struct {
89 95 PyObject_HEAD
90 96
91 97 ZstdCompressor* compressor;
92 98 PyObject* reader;
93 99 Py_buffer* buffer;
94 100 Py_ssize_t bufferOffset;
95 101 Py_ssize_t sourceSize;
96 102 size_t inSize;
97 103 size_t outSize;
98 104
99 105 ZSTD_CStream* cstream;
100 106 ZSTD_inBuffer input;
101 107 ZSTD_outBuffer output;
102 108 int finishedOutput;
103 109 int finishedInput;
104 110 PyObject* readResult;
105 111 } ZstdCompressorIterator;
106 112
107 113 extern PyTypeObject ZstdCompressorIteratorType;
108 114
109 115 typedef struct {
110 116 PyObject_HEAD
111 117
112 118 ZSTD_DCtx* refdctx;
113 119
114 120 ZstdCompressionDict* dict;
115 121 ZSTD_DDict* ddict;
116 122 } ZstdDecompressor;
117 123
118 124 extern PyTypeObject ZstdDecompressorType;
119 125
120 126 typedef struct {
121 127 PyObject_HEAD
122 128
123 129 ZstdDecompressor* decompressor;
124 130 ZSTD_DStream* dstream;
125 131 int finished;
126 132 } ZstdDecompressionObj;
127 133
128 134 extern PyTypeObject ZstdDecompressionObjType;
129 135
130 136 typedef struct {
131 137 PyObject_HEAD
132 138
133 139 ZstdDecompressor* decompressor;
134 140 PyObject* writer;
135 141 size_t outSize;
136 142 ZSTD_DStream* dstream;
137 143 int entered;
138 144 } ZstdDecompressionWriter;
139 145
140 146 extern PyTypeObject ZstdDecompressionWriterType;
141 147
142 148 typedef struct {
143 149 PyObject_HEAD
144 150
145 151 ZstdDecompressor* decompressor;
146 152 PyObject* reader;
147 153 Py_buffer* buffer;
148 154 Py_ssize_t bufferOffset;
149 155 size_t inSize;
150 156 size_t outSize;
151 157 size_t skipBytes;
152 158 ZSTD_DStream* dstream;
153 159 ZSTD_inBuffer input;
154 160 ZSTD_outBuffer output;
155 161 Py_ssize_t readCount;
156 162 int finishedInput;
157 163 int finishedOutput;
158 164 } ZstdDecompressorIterator;
159 165
160 166 extern PyTypeObject ZstdDecompressorIteratorType;
161 167
162 168 typedef struct {
163 169 int errored;
164 170 PyObject* chunk;
165 171 } DecompressorIteratorResult;
166 172
167 173 void ztopy_compression_parameters(CompressionParametersObject* params, ZSTD_compressionParameters* zparams);
168 174 CompressionParametersObject* get_compression_parameters(PyObject* self, PyObject* args);
169 175 PyObject* estimate_compression_context_size(PyObject* self, PyObject* args);
170 176 ZSTD_CStream* CStream_from_ZstdCompressor(ZstdCompressor* compressor, Py_ssize_t sourceSize);
171 177 ZSTD_DStream* DStream_from_ZstdDecompressor(ZstdDecompressor* decompressor);
172 178 ZstdCompressionDict* train_dictionary(PyObject* self, PyObject* args, PyObject* kwargs);
@@ -1,110 +1,108 b''
1 1 # Copyright (c) 2016-present, Gregory Szorc
2 2 # All rights reserved.
3 3 #
4 4 # This software may be modified and distributed under the terms
5 5 # of the BSD license. See the LICENSE file for details.
6 6
7 7 from __future__ import absolute_import
8 8
9 9 import cffi
10 import distutils.ccompiler
10 11 import os
12 import subprocess
13 import tempfile
11 14
12 15
13 16 HERE = os.path.abspath(os.path.dirname(__file__))
14 17
15 18 SOURCES = ['zstd/%s' % p for p in (
16 19 'common/entropy_common.c',
17 20 'common/error_private.c',
18 21 'common/fse_decompress.c',
19 22 'common/xxhash.c',
20 23 'common/zstd_common.c',
21 24 'compress/fse_compress.c',
22 25 'compress/huf_compress.c',
23 'compress/zbuff_compress.c',
24 26 'compress/zstd_compress.c',
25 27 'decompress/huf_decompress.c',
26 'decompress/zbuff_decompress.c',
27 28 'decompress/zstd_decompress.c',
28 29 'dictBuilder/divsufsort.c',
29 30 'dictBuilder/zdict.c',
30 31 )]
31 32
32 33 INCLUDE_DIRS = [os.path.join(HERE, d) for d in (
33 34 'zstd',
34 35 'zstd/common',
35 36 'zstd/compress',
36 37 'zstd/decompress',
37 38 'zstd/dictBuilder',
38 39 )]
39 40
41 # cffi can't parse some of the primitives in zstd.h. So we invoke the
42 # preprocessor and feed its output into cffi.
43 compiler = distutils.ccompiler.new_compiler()
44
45 # Needed for MSVC.
46 if hasattr(compiler, 'initialize'):
47 compiler.initialize()
48
49 # Distutils doesn't set compiler.preprocessor, so invoke the preprocessor
50 # manually.
51 if compiler.compiler_type == 'unix':
52 args = list(compiler.executables['compiler'])
53 args.extend([
54 '-E',
55 '-DZSTD_STATIC_LINKING_ONLY',
56 ])
57 elif compiler.compiler_type == 'msvc':
58 args = [compiler.cc]
59 args.extend([
60 '/EP',
61 '/DZSTD_STATIC_LINKING_ONLY',
62 ])
63 else:
64 raise Exception('unsupported compiler type: %s' % compiler.compiler_type)
65
66 # zstd.h includes <stddef.h>, which is also included by cffi's boilerplate.
67 # This can lead to duplicate declarations. So we strip this include from the
68 # preprocessor invocation.
69
40 70 with open(os.path.join(HERE, 'zstd', 'zstd.h'), 'rb') as fh:
41 zstd_h = fh.read()
71 lines = [l for l in fh if not l.startswith(b'#include <stddef.h>')]
72
73 fd, input_file = tempfile.mkstemp(suffix='.h')
74 os.write(fd, b''.join(lines))
75 os.close(fd)
76
77 args.append(input_file)
78
79 try:
80 process = subprocess.Popen(args, stdout=subprocess.PIPE)
81 output = process.communicate()[0]
82 ret = process.poll()
83 if ret:
84 raise Exception('preprocessor exited with error')
85 finally:
86 os.unlink(input_file)
87
88 def normalize_output():
89 lines = []
90 for line in output.splitlines():
91 # CFFI's parser doesn't like __attribute__ on UNIX compilers.
92 if line.startswith(b'__attribute__ ((visibility ("default"))) '):
93 line = line[len(b'__attribute__ ((visibility ("default"))) '):]
94
95 lines.append(line)
96
97 return b'\n'.join(lines)
42 98
43 99 ffi = cffi.FFI()
44 100 ffi.set_source('_zstd_cffi', '''
45 /* needed for typedefs like U32 references in zstd.h */
46 #include "mem.h"
47 101 #define ZSTD_STATIC_LINKING_ONLY
48 102 #include "zstd.h"
49 ''',
50 sources=SOURCES, include_dirs=INCLUDE_DIRS)
51
52 # Rather than define the API definitions from zstd.h inline, munge the
53 # source in a way that cdef() will accept.
54 lines = zstd_h.splitlines()
55 lines = [l.rstrip() for l in lines if l.strip()]
56
57 # Strip preprocessor directives - they aren't important for our needs.
58 lines = [l for l in lines
59 if not l.startswith((b'#if', b'#else', b'#endif', b'#include'))]
60
61 # Remove extern C block
62 lines = [l for l in lines if l not in (b'extern "C" {', b'}')]
63
64 # The version #defines don't parse and aren't necessary. Strip them.
65 lines = [l for l in lines if not l.startswith((
66 b'#define ZSTD_H_235446',
67 b'#define ZSTD_LIB_VERSION',
68 b'#define ZSTD_QUOTE',
69 b'#define ZSTD_EXPAND_AND_QUOTE',
70 b'#define ZSTD_VERSION_STRING',
71 b'#define ZSTD_VERSION_NUMBER'))]
103 ''', sources=SOURCES, include_dirs=INCLUDE_DIRS)
72 104
73 # The C parser also doesn't like some constant defines referencing
74 # other constants.
75 # TODO we pick the 64-bit constants here. We should assert somewhere
76 # we're compiling for 64-bit.
77 def fix_constants(l):
78 if l.startswith(b'#define ZSTD_WINDOWLOG_MAX '):
79 return b'#define ZSTD_WINDOWLOG_MAX 27'
80 elif l.startswith(b'#define ZSTD_CHAINLOG_MAX '):
81 return b'#define ZSTD_CHAINLOG_MAX 28'
82 elif l.startswith(b'#define ZSTD_HASHLOG_MAX '):
83 return b'#define ZSTD_HASHLOG_MAX 27'
84 elif l.startswith(b'#define ZSTD_CHAINLOG_MAX '):
85 return b'#define ZSTD_CHAINLOG_MAX 28'
86 elif l.startswith(b'#define ZSTD_CHAINLOG_MIN '):
87 return b'#define ZSTD_CHAINLOG_MIN 6'
88 elif l.startswith(b'#define ZSTD_SEARCHLOG_MAX '):
89 return b'#define ZSTD_SEARCHLOG_MAX 26'
90 elif l.startswith(b'#define ZSTD_BLOCKSIZE_ABSOLUTEMAX '):
91 return b'#define ZSTD_BLOCKSIZE_ABSOLUTEMAX 131072'
92 else:
93 return l
94 lines = map(fix_constants, lines)
95
96 # ZSTDLIB_API isn't handled correctly. Strip it.
97 lines = [l for l in lines if not l.startswith(b'# define ZSTDLIB_API')]
98 def strip_api(l):
99 if l.startswith(b'ZSTDLIB_API '):
100 return l[len(b'ZSTDLIB_API '):]
101 else:
102 return l
103 lines = map(strip_api, lines)
104
105 source = b'\n'.join(lines)
106 ffi.cdef(source.decode('latin1'))
107
105 ffi.cdef(normalize_output().decode('latin1'))
108 106
109 107 if __name__ == '__main__':
110 108 ffi.compile()
@@ -1,62 +1,69 b''
1 1 #!/usr/bin/env python
2 2 # Copyright (c) 2016-present, Gregory Szorc
3 3 # All rights reserved.
4 4 #
5 5 # This software may be modified and distributed under the terms
6 6 # of the BSD license. See the LICENSE file for details.
7 7
8 import sys
8 9 from setuptools import setup
9 10
10 11 try:
11 12 import cffi
12 13 except ImportError:
13 14 cffi = None
14 15
15 16 import setup_zstd
16 17
18 SUPPORT_LEGACY = False
19
20 if "--legacy" in sys.argv:
21 SUPPORT_LEGACY = True
22 sys.argv.remove("--legacy")
23
17 24 # Code for obtaining the Extension instance is in its own module to
18 25 # facilitate reuse in other projects.
19 extensions = [setup_zstd.get_c_extension()]
26 extensions = [setup_zstd.get_c_extension(SUPPORT_LEGACY, 'zstd')]
20 27
21 28 if cffi:
22 29 import make_cffi
23 30 extensions.append(make_cffi.ffi.distutils_extension())
24 31
25 32 version = None
26 33
27 34 with open('c-ext/python-zstandard.h', 'r') as fh:
28 35 for line in fh:
29 36 if not line.startswith('#define PYTHON_ZSTANDARD_VERSION'):
30 37 continue
31 38
32 39 version = line.split()[2][1:-1]
33 40 break
34 41
35 42 if not version:
36 43 raise Exception('could not resolve package version; '
37 44 'this should never happen')
38 45
39 46 setup(
40 47 name='zstandard',
41 48 version=version,
42 49 description='Zstandard bindings for Python',
43 50 long_description=open('README.rst', 'r').read(),
44 51 url='https://github.com/indygreg/python-zstandard',
45 52 author='Gregory Szorc',
46 53 author_email='gregory.szorc@gmail.com',
47 54 license='BSD',
48 55 classifiers=[
49 56 'Development Status :: 4 - Beta',
50 57 'Intended Audience :: Developers',
51 58 'License :: OSI Approved :: BSD License',
52 59 'Programming Language :: C',
53 60 'Programming Language :: Python :: 2.6',
54 61 'Programming Language :: Python :: 2.7',
55 62 'Programming Language :: Python :: 3.3',
56 63 'Programming Language :: Python :: 3.4',
57 64 'Programming Language :: Python :: 3.5',
58 65 ],
59 66 keywords='zstandard zstd compression',
60 67 ext_modules=extensions,
61 68 test_suite='tests',
62 69 )
@@ -1,64 +1,91 b''
1 1 # Copyright (c) 2016-present, Gregory Szorc
2 2 # All rights reserved.
3 3 #
4 4 # This software may be modified and distributed under the terms
5 5 # of the BSD license. See the LICENSE file for details.
6 6
7 7 import os
8 8 from distutils.extension import Extension
9 9
10 10
11 11 zstd_sources = ['zstd/%s' % p for p in (
12 12 'common/entropy_common.c',
13 13 'common/error_private.c',
14 14 'common/fse_decompress.c',
15 15 'common/xxhash.c',
16 16 'common/zstd_common.c',
17 17 'compress/fse_compress.c',
18 18 'compress/huf_compress.c',
19 'compress/zbuff_compress.c',
20 19 'compress/zstd_compress.c',
21 20 'decompress/huf_decompress.c',
22 'decompress/zbuff_decompress.c',
23 21 'decompress/zstd_decompress.c',
24 22 'dictBuilder/divsufsort.c',
25 23 'dictBuilder/zdict.c',
26 24 )]
27 25
26 zstd_sources_legacy = ['zstd/%s' % p for p in (
27 'deprecated/zbuff_compress.c',
28 'deprecated/zbuff_decompress.c',
29 'legacy/zstd_v01.c',
30 'legacy/zstd_v02.c',
31 'legacy/zstd_v03.c',
32 'legacy/zstd_v04.c',
33 'legacy/zstd_v05.c',
34 'legacy/zstd_v06.c',
35 'legacy/zstd_v07.c'
36 )]
28 37
29 38 zstd_includes = [
30 39 'c-ext',
31 40 'zstd',
32 41 'zstd/common',
33 42 'zstd/compress',
34 43 'zstd/decompress',
35 44 'zstd/dictBuilder',
36 45 ]
37 46
47 zstd_includes_legacy = [
48 'zstd/deprecated',
49 'zstd/legacy',
50 ]
51
38 52 ext_sources = [
39 53 'zstd.c',
40 54 'c-ext/compressiondict.c',
41 55 'c-ext/compressobj.c',
42 56 'c-ext/compressor.c',
43 57 'c-ext/compressoriterator.c',
44 58 'c-ext/compressionparams.c',
45 59 'c-ext/compressionwriter.c',
46 60 'c-ext/constants.c',
47 61 'c-ext/decompressobj.c',
48 62 'c-ext/decompressor.c',
49 63 'c-ext/decompressoriterator.c',
50 64 'c-ext/decompressionwriter.c',
51 65 'c-ext/dictparams.c',
52 66 ]
53 67
68 zstd_depends = [
69 'c-ext/python-zstandard.h',
70 ]
54 71
55 def get_c_extension(name='zstd'):
72
73 def get_c_extension(support_legacy=False, name='zstd'):
56 74 """Obtain a distutils.extension.Extension for the C extension."""
57 75 root = os.path.abspath(os.path.dirname(__file__))
58 76
59 77 sources = [os.path.join(root, p) for p in zstd_sources + ext_sources]
78 if support_legacy:
79 sources.extend([os.path.join(root, p) for p in zstd_sources_legacy])
80
60 81 include_dirs = [os.path.join(root, d) for d in zstd_includes]
82 if support_legacy:
83 include_dirs.extend([os.path.join(root, d) for d in zstd_includes_legacy])
84
85 depends = [os.path.join(root, p) for p in zstd_depends]
61 86
62 87 # TODO compile with optimizations.
63 88 return Extension(name, sources,
64 include_dirs=include_dirs)
89 include_dirs=include_dirs,
90 depends=depends,
91 extra_compile_args=["-DZSTD_LEGACY_SUPPORT=1"] if support_legacy else [])
@@ -1,465 +1,536 b''
1 1 import hashlib
2 2 import io
3 3 import struct
4 4 import sys
5 5
6 6 try:
7 7 import unittest2 as unittest
8 8 except ImportError:
9 9 import unittest
10 10
11 11 import zstd
12 12
13 13 from .common import OpCountingBytesIO
14 14
15 15
16 16 if sys.version_info[0] >= 3:
17 17 next = lambda it: it.__next__()
18 18 else:
19 19 next = lambda it: it.next()
20 20
21 21
22 22 class TestCompressor(unittest.TestCase):
23 23 def test_level_bounds(self):
24 24 with self.assertRaises(ValueError):
25 25 zstd.ZstdCompressor(level=0)
26 26
27 27 with self.assertRaises(ValueError):
28 28 zstd.ZstdCompressor(level=23)
29 29
30 30
31 31 class TestCompressor_compress(unittest.TestCase):
32 32 def test_compress_empty(self):
33 33 cctx = zstd.ZstdCompressor(level=1)
34 34 cctx.compress(b'')
35 35
36 36 cctx = zstd.ZstdCompressor(level=22)
37 37 cctx.compress(b'')
38 38
39 39 def test_compress_empty(self):
40 40 cctx = zstd.ZstdCompressor(level=1)
41 41 self.assertEqual(cctx.compress(b''),
42 42 b'\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00')
43 43
44 # TODO should be temporary until https://github.com/facebook/zstd/issues/506
45 # is fixed.
46 cctx = zstd.ZstdCompressor(write_content_size=True)
47 with self.assertRaises(ValueError):
48 cctx.compress(b'')
49
50 cctx.compress(b'', allow_empty=True)
51
44 52 def test_compress_large(self):
45 53 chunks = []
46 54 for i in range(255):
47 55 chunks.append(struct.Struct('>B').pack(i) * 16384)
48 56
49 57 cctx = zstd.ZstdCompressor(level=3)
50 58 result = cctx.compress(b''.join(chunks))
51 59 self.assertEqual(len(result), 999)
52 60 self.assertEqual(result[0:4], b'\x28\xb5\x2f\xfd')
53 61
54 62 def test_write_checksum(self):
55 63 cctx = zstd.ZstdCompressor(level=1)
56 64 no_checksum = cctx.compress(b'foobar')
57 65 cctx = zstd.ZstdCompressor(level=1, write_checksum=True)
58 66 with_checksum = cctx.compress(b'foobar')
59 67
60 68 self.assertEqual(len(with_checksum), len(no_checksum) + 4)
61 69
62 70 def test_write_content_size(self):
63 71 cctx = zstd.ZstdCompressor(level=1)
64 72 no_size = cctx.compress(b'foobar' * 256)
65 73 cctx = zstd.ZstdCompressor(level=1, write_content_size=True)
66 74 with_size = cctx.compress(b'foobar' * 256)
67 75
68 76 self.assertEqual(len(with_size), len(no_size) + 1)
69 77
70 78 def test_no_dict_id(self):
71 79 samples = []
72 80 for i in range(128):
73 81 samples.append(b'foo' * 64)
74 82 samples.append(b'bar' * 64)
75 83 samples.append(b'foobar' * 64)
76 84
77 85 d = zstd.train_dictionary(1024, samples)
78 86
79 87 cctx = zstd.ZstdCompressor(level=1, dict_data=d)
80 88 with_dict_id = cctx.compress(b'foobarfoobar')
81 89
82 90 cctx = zstd.ZstdCompressor(level=1, dict_data=d, write_dict_id=False)
83 91 no_dict_id = cctx.compress(b'foobarfoobar')
84 92
85 93 self.assertEqual(len(with_dict_id), len(no_dict_id) + 4)
86 94
87 95 def test_compress_dict_multiple(self):
88 96 samples = []
89 97 for i in range(128):
90 98 samples.append(b'foo' * 64)
91 99 samples.append(b'bar' * 64)
92 100 samples.append(b'foobar' * 64)
93 101
94 102 d = zstd.train_dictionary(8192, samples)
95 103
96 104 cctx = zstd.ZstdCompressor(level=1, dict_data=d)
97 105
98 106 for i in range(32):
99 107 cctx.compress(b'foo bar foobar foo bar foobar')
100 108
101 109
102 110 class TestCompressor_compressobj(unittest.TestCase):
103 111 def test_compressobj_empty(self):
104 112 cctx = zstd.ZstdCompressor(level=1)
105 113 cobj = cctx.compressobj()
106 114 self.assertEqual(cobj.compress(b''), b'')
107 115 self.assertEqual(cobj.flush(),
108 116 b'\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00')
109 117
110 118 def test_compressobj_large(self):
111 119 chunks = []
112 120 for i in range(255):
113 121 chunks.append(struct.Struct('>B').pack(i) * 16384)
114 122
115 123 cctx = zstd.ZstdCompressor(level=3)
116 124 cobj = cctx.compressobj()
117 125
118 126 result = cobj.compress(b''.join(chunks)) + cobj.flush()
119 127 self.assertEqual(len(result), 999)
120 128 self.assertEqual(result[0:4], b'\x28\xb5\x2f\xfd')
121 129
122 130 def test_write_checksum(self):
123 131 cctx = zstd.ZstdCompressor(level=1)
124 132 cobj = cctx.compressobj()
125 133 no_checksum = cobj.compress(b'foobar') + cobj.flush()
126 134 cctx = zstd.ZstdCompressor(level=1, write_checksum=True)
127 135 cobj = cctx.compressobj()
128 136 with_checksum = cobj.compress(b'foobar') + cobj.flush()
129 137
130 138 self.assertEqual(len(with_checksum), len(no_checksum) + 4)
131 139
132 140 def test_write_content_size(self):
133 141 cctx = zstd.ZstdCompressor(level=1)
134 142 cobj = cctx.compressobj(size=len(b'foobar' * 256))
135 143 no_size = cobj.compress(b'foobar' * 256) + cobj.flush()
136 144 cctx = zstd.ZstdCompressor(level=1, write_content_size=True)
137 145 cobj = cctx.compressobj(size=len(b'foobar' * 256))
138 146 with_size = cobj.compress(b'foobar' * 256) + cobj.flush()
139 147
140 148 self.assertEqual(len(with_size), len(no_size) + 1)
141 149
142 def test_compress_after_flush(self):
150 def test_compress_after_finished(self):
143 151 cctx = zstd.ZstdCompressor()
144 152 cobj = cctx.compressobj()
145 153
146 154 cobj.compress(b'foo')
147 155 cobj.flush()
148 156
149 with self.assertRaisesRegexp(zstd.ZstdError, 'cannot call compress\(\) after flush'):
157 with self.assertRaisesRegexp(zstd.ZstdError, 'cannot call compress\(\) after compressor'):
150 158 cobj.compress(b'foo')
151 159
152 with self.assertRaisesRegexp(zstd.ZstdError, 'flush\(\) already called'):
160 with self.assertRaisesRegexp(zstd.ZstdError, 'compressor object already finished'):
153 161 cobj.flush()
154 162
163 def test_flush_block_repeated(self):
164 cctx = zstd.ZstdCompressor(level=1)
165 cobj = cctx.compressobj()
166
167 self.assertEqual(cobj.compress(b'foo'), b'')
168 self.assertEqual(cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK),
169 b'\x28\xb5\x2f\xfd\x00\x48\x18\x00\x00foo')
170 self.assertEqual(cobj.compress(b'bar'), b'')
171 # 3 byte header plus content.
172 self.assertEqual(cobj.flush(), b'\x19\x00\x00bar')
173
174 def test_flush_empty_block(self):
175 cctx = zstd.ZstdCompressor(write_checksum=True)
176 cobj = cctx.compressobj()
177
178 cobj.compress(b'foobar')
179 cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK)
180 # No-op if no block is active (this is internal to zstd).
181 self.assertEqual(cobj.flush(zstd.COMPRESSOBJ_FLUSH_BLOCK), b'')
182
183 trailing = cobj.flush()
184 # 3 bytes block header + 4 bytes frame checksum
185 self.assertEqual(len(trailing), 7)
186 header = trailing[0:3]
187 self.assertEqual(header, b'\x01\x00\x00')
188
155 189
156 190 class TestCompressor_copy_stream(unittest.TestCase):
157 191 def test_no_read(self):
158 192 source = object()
159 193 dest = io.BytesIO()
160 194
161 195 cctx = zstd.ZstdCompressor()
162 196 with self.assertRaises(ValueError):
163 197 cctx.copy_stream(source, dest)
164 198
165 199 def test_no_write(self):
166 200 source = io.BytesIO()
167 201 dest = object()
168 202
169 203 cctx = zstd.ZstdCompressor()
170 204 with self.assertRaises(ValueError):
171 205 cctx.copy_stream(source, dest)
172 206
173 207 def test_empty(self):
174 208 source = io.BytesIO()
175 209 dest = io.BytesIO()
176 210
177 211 cctx = zstd.ZstdCompressor(level=1)
178 212 r, w = cctx.copy_stream(source, dest)
179 213 self.assertEqual(int(r), 0)
180 214 self.assertEqual(w, 9)
181 215
182 216 self.assertEqual(dest.getvalue(),
183 217 b'\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00')
184 218
185 219 def test_large_data(self):
186 220 source = io.BytesIO()
187 221 for i in range(255):
188 222 source.write(struct.Struct('>B').pack(i) * 16384)
189 223 source.seek(0)
190 224
191 225 dest = io.BytesIO()
192 226 cctx = zstd.ZstdCompressor()
193 227 r, w = cctx.copy_stream(source, dest)
194 228
195 229 self.assertEqual(r, 255 * 16384)
196 230 self.assertEqual(w, 999)
197 231
198 232 def test_write_checksum(self):
199 233 source = io.BytesIO(b'foobar')
200 234 no_checksum = io.BytesIO()
201 235
202 236 cctx = zstd.ZstdCompressor(level=1)
203 237 cctx.copy_stream(source, no_checksum)
204 238
205 239 source.seek(0)
206 240 with_checksum = io.BytesIO()
207 241 cctx = zstd.ZstdCompressor(level=1, write_checksum=True)
208 242 cctx.copy_stream(source, with_checksum)
209 243
210 244 self.assertEqual(len(with_checksum.getvalue()),
211 245 len(no_checksum.getvalue()) + 4)
212 246
213 247 def test_write_content_size(self):
214 248 source = io.BytesIO(b'foobar' * 256)
215 249 no_size = io.BytesIO()
216 250
217 251 cctx = zstd.ZstdCompressor(level=1)
218 252 cctx.copy_stream(source, no_size)
219 253
220 254 source.seek(0)
221 255 with_size = io.BytesIO()
222 256 cctx = zstd.ZstdCompressor(level=1, write_content_size=True)
223 257 cctx.copy_stream(source, with_size)
224 258
225 259 # Source content size is unknown, so no content size written.
226 260 self.assertEqual(len(with_size.getvalue()),
227 261 len(no_size.getvalue()))
228 262
229 263 source.seek(0)
230 264 with_size = io.BytesIO()
231 265 cctx.copy_stream(source, with_size, size=len(source.getvalue()))
232 266
233 267 # We specified source size, so content size header is present.
234 268 self.assertEqual(len(with_size.getvalue()),
235 269 len(no_size.getvalue()) + 1)
236 270
237 271 def test_read_write_size(self):
238 272 source = OpCountingBytesIO(b'foobarfoobar')
239 273 dest = OpCountingBytesIO()
240 274 cctx = zstd.ZstdCompressor()
241 275 r, w = cctx.copy_stream(source, dest, read_size=1, write_size=1)
242 276
243 277 self.assertEqual(r, len(source.getvalue()))
244 278 self.assertEqual(w, 21)
245 279 self.assertEqual(source._read_count, len(source.getvalue()) + 1)
246 280 self.assertEqual(dest._write_count, len(dest.getvalue()))
247 281
248 282
249 283 def compress(data, level):
250 284 buffer = io.BytesIO()
251 285 cctx = zstd.ZstdCompressor(level=level)
252 286 with cctx.write_to(buffer) as compressor:
253 287 compressor.write(data)
254 288 return buffer.getvalue()
255 289
256 290
257 291 class TestCompressor_write_to(unittest.TestCase):
258 292 def test_empty(self):
259 293 self.assertEqual(compress(b'', 1),
260 294 b'\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00')
261 295
262 296 def test_multiple_compress(self):
263 297 buffer = io.BytesIO()
264 298 cctx = zstd.ZstdCompressor(level=5)
265 299 with cctx.write_to(buffer) as compressor:
266 300 compressor.write(b'foo')
267 301 compressor.write(b'bar')
268 302 compressor.write(b'x' * 8192)
269 303
270 304 result = buffer.getvalue()
271 305 self.assertEqual(result,
272 306 b'\x28\xb5\x2f\xfd\x00\x50\x75\x00\x00\x38\x66\x6f'
273 307 b'\x6f\x62\x61\x72\x78\x01\x00\xfc\xdf\x03\x23')
274 308
275 309 def test_dictionary(self):
276 310 samples = []
277 311 for i in range(128):
278 312 samples.append(b'foo' * 64)
279 313 samples.append(b'bar' * 64)
280 314 samples.append(b'foobar' * 64)
281 315
282 316 d = zstd.train_dictionary(8192, samples)
283 317
284 318 buffer = io.BytesIO()
285 319 cctx = zstd.ZstdCompressor(level=9, dict_data=d)
286 320 with cctx.write_to(buffer) as compressor:
287 321 compressor.write(b'foo')
288 322 compressor.write(b'bar')
289 323 compressor.write(b'foo' * 16384)
290 324
291 325 compressed = buffer.getvalue()
292 326 h = hashlib.sha1(compressed).hexdigest()
293 327 self.assertEqual(h, '1c5bcd25181bcd8c1a73ea8773323e0056129f92')
294 328
295 329 def test_compression_params(self):
296 330 params = zstd.CompressionParameters(20, 6, 12, 5, 4, 10, zstd.STRATEGY_FAST)
297 331
298 332 buffer = io.BytesIO()
299 333 cctx = zstd.ZstdCompressor(compression_params=params)
300 334 with cctx.write_to(buffer) as compressor:
301 335 compressor.write(b'foo')
302 336 compressor.write(b'bar')
303 337 compressor.write(b'foobar' * 16384)
304 338
305 339 compressed = buffer.getvalue()
306 340 h = hashlib.sha1(compressed).hexdigest()
307 341 self.assertEqual(h, '1ae31f270ed7de14235221a604b31ecd517ebd99')
308 342
309 343 def test_write_checksum(self):
310 344 no_checksum = io.BytesIO()
311 345 cctx = zstd.ZstdCompressor(level=1)
312 346 with cctx.write_to(no_checksum) as compressor:
313 347 compressor.write(b'foobar')
314 348
315 349 with_checksum = io.BytesIO()
316 350 cctx = zstd.ZstdCompressor(level=1, write_checksum=True)
317 351 with cctx.write_to(with_checksum) as compressor:
318 352 compressor.write(b'foobar')
319 353
320 354 self.assertEqual(len(with_checksum.getvalue()),
321 355 len(no_checksum.getvalue()) + 4)
322 356
323 357 def test_write_content_size(self):
324 358 no_size = io.BytesIO()
325 359 cctx = zstd.ZstdCompressor(level=1)
326 360 with cctx.write_to(no_size) as compressor:
327 361 compressor.write(b'foobar' * 256)
328 362
329 363 with_size = io.BytesIO()
330 364 cctx = zstd.ZstdCompressor(level=1, write_content_size=True)
331 365 with cctx.write_to(with_size) as compressor:
332 366 compressor.write(b'foobar' * 256)
333 367
334 368 # Source size is not known in streaming mode, so header not
335 369 # written.
336 370 self.assertEqual(len(with_size.getvalue()),
337 371 len(no_size.getvalue()))
338 372
339 373 # Declaring size will write the header.
340 374 with_size = io.BytesIO()
341 375 with cctx.write_to(with_size, size=len(b'foobar' * 256)) as compressor:
342 376 compressor.write(b'foobar' * 256)
343 377
344 378 self.assertEqual(len(with_size.getvalue()),
345 379 len(no_size.getvalue()) + 1)
346 380
347 381 def test_no_dict_id(self):
348 382 samples = []
349 383 for i in range(128):
350 384 samples.append(b'foo' * 64)
351 385 samples.append(b'bar' * 64)
352 386 samples.append(b'foobar' * 64)
353 387
354 388 d = zstd.train_dictionary(1024, samples)
355 389
356 390 with_dict_id = io.BytesIO()
357 391 cctx = zstd.ZstdCompressor(level=1, dict_data=d)
358 392 with cctx.write_to(with_dict_id) as compressor:
359 393 compressor.write(b'foobarfoobar')
360 394
361 395 cctx = zstd.ZstdCompressor(level=1, dict_data=d, write_dict_id=False)
362 396 no_dict_id = io.BytesIO()
363 397 with cctx.write_to(no_dict_id) as compressor:
364 398 compressor.write(b'foobarfoobar')
365 399
366 400 self.assertEqual(len(with_dict_id.getvalue()),
367 401 len(no_dict_id.getvalue()) + 4)
368 402
369 403 def test_memory_size(self):
370 404 cctx = zstd.ZstdCompressor(level=3)
371 405 buffer = io.BytesIO()
372 406 with cctx.write_to(buffer) as compressor:
373 407 size = compressor.memory_size()
374 408
375 409 self.assertGreater(size, 100000)
376 410
377 411 def test_write_size(self):
378 412 cctx = zstd.ZstdCompressor(level=3)
379 413 dest = OpCountingBytesIO()
380 414 with cctx.write_to(dest, write_size=1) as compressor:
381 415 compressor.write(b'foo')
382 416 compressor.write(b'bar')
383 417 compressor.write(b'foobar')
384 418
385 419 self.assertEqual(len(dest.getvalue()), dest._write_count)
386 420
421 def test_flush_repeated(self):
422 cctx = zstd.ZstdCompressor(level=3)
423 dest = OpCountingBytesIO()
424 with cctx.write_to(dest) as compressor:
425 compressor.write(b'foo')
426 self.assertEqual(dest._write_count, 0)
427 compressor.flush()
428 self.assertEqual(dest._write_count, 1)
429 compressor.write(b'bar')
430 self.assertEqual(dest._write_count, 1)
431 compressor.flush()
432 self.assertEqual(dest._write_count, 2)
433 compressor.write(b'baz')
434
435 self.assertEqual(dest._write_count, 3)
436
437 def test_flush_empty_block(self):
438 cctx = zstd.ZstdCompressor(level=3, write_checksum=True)
439 dest = OpCountingBytesIO()
440 with cctx.write_to(dest) as compressor:
441 compressor.write(b'foobar' * 8192)
442 count = dest._write_count
443 offset = dest.tell()
444 compressor.flush()
445 self.assertGreater(dest._write_count, count)
446 self.assertGreater(dest.tell(), offset)
447 offset = dest.tell()
448 # Ending the write here should cause an empty block to be written
449 # to denote end of frame.
450
451 trailing = dest.getvalue()[offset:]
452 # 3 bytes block header + 4 bytes frame checksum
453 self.assertEqual(len(trailing), 7)
454
455 header = trailing[0:3]
456 self.assertEqual(header, b'\x01\x00\x00')
457
387 458
388 459 class TestCompressor_read_from(unittest.TestCase):
389 460 def test_type_validation(self):
390 461 cctx = zstd.ZstdCompressor()
391 462
392 463 # Object with read() works.
393 464 cctx.read_from(io.BytesIO())
394 465
395 466 # Buffer protocol works.
396 467 cctx.read_from(b'foobar')
397 468
398 469 with self.assertRaisesRegexp(ValueError, 'must pass an object with a read'):
399 470 cctx.read_from(True)
400 471
401 472 def test_read_empty(self):
402 473 cctx = zstd.ZstdCompressor(level=1)
403 474
404 475 source = io.BytesIO()
405 476 it = cctx.read_from(source)
406 477 chunks = list(it)
407 478 self.assertEqual(len(chunks), 1)
408 479 compressed = b''.join(chunks)
409 480 self.assertEqual(compressed, b'\x28\xb5\x2f\xfd\x00\x48\x01\x00\x00')
410 481
411 482 # And again with the buffer protocol.
412 483 it = cctx.read_from(b'')
413 484 chunks = list(it)
414 485 self.assertEqual(len(chunks), 1)
415 486 compressed2 = b''.join(chunks)
416 487 self.assertEqual(compressed2, compressed)
417 488
418 489 def test_read_large(self):
419 490 cctx = zstd.ZstdCompressor(level=1)
420 491
421 492 source = io.BytesIO()
422 493 source.write(b'f' * zstd.COMPRESSION_RECOMMENDED_INPUT_SIZE)
423 494 source.write(b'o')
424 495 source.seek(0)
425 496
426 497 # Creating an iterator should not perform any compression until
427 498 # first read.
428 499 it = cctx.read_from(source, size=len(source.getvalue()))
429 500 self.assertEqual(source.tell(), 0)
430 501
431 502 # We should have exactly 2 output chunks.
432 503 chunks = []
433 504 chunk = next(it)
434 505 self.assertIsNotNone(chunk)
435 506 self.assertEqual(source.tell(), zstd.COMPRESSION_RECOMMENDED_INPUT_SIZE)
436 507 chunks.append(chunk)
437 508 chunk = next(it)
438 509 self.assertIsNotNone(chunk)
439 510 chunks.append(chunk)
440 511
441 512 self.assertEqual(source.tell(), len(source.getvalue()))
442 513
443 514 with self.assertRaises(StopIteration):
444 515 next(it)
445 516
446 517 # And again for good measure.
447 518 with self.assertRaises(StopIteration):
448 519 next(it)
449 520
450 521 # We should get the same output as the one-shot compression mechanism.
451 522 self.assertEqual(b''.join(chunks), cctx.compress(source.getvalue()))
452 523
453 524 # Now check the buffer protocol.
454 525 it = cctx.read_from(source.getvalue())
455 526 chunks = list(it)
456 527 self.assertEqual(len(chunks), 2)
457 528 self.assertEqual(b''.join(chunks), cctx.compress(source.getvalue()))
458 529
459 530 def test_read_write_size(self):
460 531 source = OpCountingBytesIO(b'foobarfoobar')
461 532 cctx = zstd.ZstdCompressor(level=3)
462 533 for chunk in cctx.read_from(source, read_size=1, write_size=1):
463 534 self.assertEqual(len(chunk), 1)
464 535
465 536 self.assertEqual(source._read_count, len(source.getvalue()) + 1)
@@ -1,48 +1,48 b''
1 1 from __future__ import unicode_literals
2 2
3 3 try:
4 4 import unittest2 as unittest
5 5 except ImportError:
6 6 import unittest
7 7
8 8 import zstd
9 9
10 10 class TestModuleAttributes(unittest.TestCase):
11 11 def test_version(self):
12 self.assertEqual(zstd.ZSTD_VERSION, (1, 1, 1))
12 self.assertEqual(zstd.ZSTD_VERSION, (1, 1, 2))
13 13
14 14 def test_constants(self):
15 15 self.assertEqual(zstd.MAX_COMPRESSION_LEVEL, 22)
16 16 self.assertEqual(zstd.FRAME_HEADER, b'\x28\xb5\x2f\xfd')
17 17
18 18 def test_hasattr(self):
19 19 attrs = (
20 20 'COMPRESSION_RECOMMENDED_INPUT_SIZE',
21 21 'COMPRESSION_RECOMMENDED_OUTPUT_SIZE',
22 22 'DECOMPRESSION_RECOMMENDED_INPUT_SIZE',
23 23 'DECOMPRESSION_RECOMMENDED_OUTPUT_SIZE',
24 24 'MAGIC_NUMBER',
25 25 'WINDOWLOG_MIN',
26 26 'WINDOWLOG_MAX',
27 27 'CHAINLOG_MIN',
28 28 'CHAINLOG_MAX',
29 29 'HASHLOG_MIN',
30 30 'HASHLOG_MAX',
31 31 'HASHLOG3_MAX',
32 32 'SEARCHLOG_MIN',
33 33 'SEARCHLOG_MAX',
34 34 'SEARCHLENGTH_MIN',
35 35 'SEARCHLENGTH_MAX',
36 36 'TARGETLENGTH_MIN',
37 37 'TARGETLENGTH_MAX',
38 38 'STRATEGY_FAST',
39 39 'STRATEGY_DFAST',
40 40 'STRATEGY_GREEDY',
41 41 'STRATEGY_LAZY',
42 42 'STRATEGY_LAZY2',
43 43 'STRATEGY_BTLAZY2',
44 44 'STRATEGY_BTOPT',
45 45 )
46 46
47 47 for a in attrs:
48 48 self.assertTrue(hasattr(zstd, a))
@@ -1,112 +1,136 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Gregory Szorc
3 3 * All rights reserved.
4 4 *
5 5 * This software may be modified and distributed under the terms
6 6 * of the BSD license. See the LICENSE file for details.
7 7 */
8 8
9 9 /* A Python C extension for Zstandard. */
10 10
11 11 #include "python-zstandard.h"
12 12
13 13 PyObject *ZstdError;
14 14
15 15 PyDoc_STRVAR(estimate_compression_context_size__doc__,
16 16 "estimate_compression_context_size(compression_parameters)\n"
17 17 "\n"
18 18 "Give the amount of memory allocated for a compression context given a\n"
19 19 "CompressionParameters instance");
20 20
21 21 PyDoc_STRVAR(estimate_decompression_context_size__doc__,
22 22 "estimate_decompression_context_size()\n"
23 23 "\n"
24 24 "Estimate the amount of memory allocated to a decompression context.\n"
25 25 );
26 26
27 27 static PyObject* estimate_decompression_context_size(PyObject* self) {
28 28 return PyLong_FromSize_t(ZSTD_estimateDCtxSize());
29 29 }
30 30
31 31 PyDoc_STRVAR(get_compression_parameters__doc__,
32 32 "get_compression_parameters(compression_level[, source_size[, dict_size]])\n"
33 33 "\n"
34 34 "Obtains a ``CompressionParameters`` instance from a compression level and\n"
35 35 "optional input size and dictionary size");
36 36
37 37 PyDoc_STRVAR(train_dictionary__doc__,
38 38 "train_dictionary(dict_size, samples)\n"
39 39 "\n"
40 40 "Train a dictionary from sample data.\n"
41 41 "\n"
42 42 "A compression dictionary of size ``dict_size`` will be created from the\n"
43 43 "iterable of samples provided by ``samples``.\n"
44 44 "\n"
45 45 "The raw dictionary content will be returned\n");
46 46
47 47 static char zstd_doc[] = "Interface to zstandard";
48 48
49 49 static PyMethodDef zstd_methods[] = {
50 50 { "estimate_compression_context_size", (PyCFunction)estimate_compression_context_size,
51 51 METH_VARARGS, estimate_compression_context_size__doc__ },
52 52 { "estimate_decompression_context_size", (PyCFunction)estimate_decompression_context_size,
53 53 METH_NOARGS, estimate_decompression_context_size__doc__ },
54 54 { "get_compression_parameters", (PyCFunction)get_compression_parameters,
55 55 METH_VARARGS, get_compression_parameters__doc__ },
56 56 { "train_dictionary", (PyCFunction)train_dictionary,
57 57 METH_VARARGS | METH_KEYWORDS, train_dictionary__doc__ },
58 58 { NULL, NULL }
59 59 };
60 60
61 61 void compressobj_module_init(PyObject* mod);
62 62 void compressor_module_init(PyObject* mod);
63 63 void compressionparams_module_init(PyObject* mod);
64 64 void constants_module_init(PyObject* mod);
65 65 void dictparams_module_init(PyObject* mod);
66 66 void compressiondict_module_init(PyObject* mod);
67 67 void compressionwriter_module_init(PyObject* mod);
68 68 void compressoriterator_module_init(PyObject* mod);
69 69 void decompressor_module_init(PyObject* mod);
70 70 void decompressobj_module_init(PyObject* mod);
71 71 void decompressionwriter_module_init(PyObject* mod);
72 72 void decompressoriterator_module_init(PyObject* mod);
73 73
74 74 void zstd_module_init(PyObject* m) {
75 /* python-zstandard relies on unstable zstd C API features. This means
76 that changes in zstd may break expectations in python-zstandard.
77
78 python-zstandard is distributed with a copy of the zstd sources.
79 python-zstandard is only guaranteed to work with the bundled version
80 of zstd.
81
82 However, downstream redistributors or packagers may unbundle zstd
83 from python-zstandard. This can result in a mismatch between zstd
84 versions and API semantics. This essentially "voids the warranty"
85 of python-zstandard and may cause undefined behavior.
86
87 We detect this mismatch here and refuse to load the module if this
88 scenario is detected.
89 */
90 if (ZSTD_VERSION_NUMBER != 10102 || ZSTD_versionNumber() != 10102) {
91 PyErr_SetString(PyExc_ImportError, "zstd C API mismatch; Python bindings not compiled against expected zstd version");
92 return;
93 }
94
75 95 compressionparams_module_init(m);
76 96 dictparams_module_init(m);
77 97 compressiondict_module_init(m);
78 98 compressobj_module_init(m);
79 99 compressor_module_init(m);
80 100 compressionwriter_module_init(m);
81 101 compressoriterator_module_init(m);
82 102 constants_module_init(m);
83 103 decompressor_module_init(m);
84 104 decompressobj_module_init(m);
85 105 decompressionwriter_module_init(m);
86 106 decompressoriterator_module_init(m);
87 107 }
88 108
89 109 #if PY_MAJOR_VERSION >= 3
90 110 static struct PyModuleDef zstd_module = {
91 111 PyModuleDef_HEAD_INIT,
92 112 "zstd",
93 113 zstd_doc,
94 114 -1,
95 115 zstd_methods
96 116 };
97 117
98 118 PyMODINIT_FUNC PyInit_zstd(void) {
99 119 PyObject *m = PyModule_Create(&zstd_module);
100 120 if (m) {
101 121 zstd_module_init(m);
122 if (PyErr_Occurred()) {
123 Py_DECREF(m);
124 m = NULL;
125 }
102 126 }
103 127 return m;
104 128 }
105 129 #else
106 130 PyMODINIT_FUNC initzstd(void) {
107 131 PyObject *m = Py_InitModule3("zstd", zstd_methods, zstd_doc);
108 132 if (m) {
109 133 zstd_module_init(m);
110 134 }
111 135 }
112 136 #endif
@@ -1,414 +1,414 b''
1 1 /* ******************************************************************
2 2 bitstream
3 3 Part of FSE library
4 4 header file (to include)
5 5 Copyright (C) 2013-2016, Yann Collet.
6 6
7 7 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
8 8
9 9 Redistribution and use in source and binary forms, with or without
10 10 modification, are permitted provided that the following conditions are
11 11 met:
12 12
13 13 * Redistributions of source code must retain the above copyright
14 14 notice, this list of conditions and the following disclaimer.
15 15 * Redistributions in binary form must reproduce the above
16 16 copyright notice, this list of conditions and the following disclaimer
17 17 in the documentation and/or other materials provided with the
18 18 distribution.
19 19
20 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 31
32 32 You can contact the author at :
33 33 - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
34 34 ****************************************************************** */
35 35 #ifndef BITSTREAM_H_MODULE
36 36 #define BITSTREAM_H_MODULE
37 37
38 38 #if defined (__cplusplus)
39 39 extern "C" {
40 40 #endif
41 41
42 42
43 43 /*
44 44 * This API consists of small unitary functions, which must be inlined for best performance.
45 45 * Since link-time-optimization is not available for all compilers,
46 46 * these functions are defined into a .h to be included.
47 47 */
48 48
49 49 /*-****************************************
50 50 * Dependencies
51 51 ******************************************/
52 52 #include "mem.h" /* unaligned access routines */
53 53 #include "error_private.h" /* error codes and messages */
54 54
55 55
56 56 /*=========================================
57 57 * Target specific
58 58 =========================================*/
59 59 #if defined(__BMI__) && defined(__GNUC__)
60 60 # include <immintrin.h> /* support for bextr (experimental) */
61 61 #endif
62 62
63 63
64 64 /*-******************************************
65 65 * bitStream encoding API (write forward)
66 66 ********************************************/
67 67 /* bitStream can mix input from multiple sources.
68 68 * A critical property of these streams is that they encode and decode in **reverse** direction.
69 69 * So the first bit sequence you add will be the last to be read, like a LIFO stack.
70 70 */
71 71 typedef struct
72 72 {
73 73 size_t bitContainer;
74 74 int bitPos;
75 75 char* startPtr;
76 76 char* ptr;
77 77 char* endPtr;
78 78 } BIT_CStream_t;
79 79
80 80 MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t dstCapacity);
81 81 MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
82 82 MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
83 83 MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
84 84
85 85 /* Start with initCStream, providing the size of buffer to write into.
86 86 * bitStream will never write outside of this buffer.
87 87 * `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be an error code.
88 88 *
89 89 * bits are first added to a local register.
90 90 * Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems.
91 91 * Writing data into memory is an explicit operation, performed by the flushBits function.
92 92 * Hence keep track how many bits are potentially stored into local register to avoid register overflow.
93 93 * After a flushBits, a maximum of 7 bits might still be stored into local register.
94 94 *
95 95 * Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers.
96 96 *
97 97 * Last operation is to close the bitStream.
98 98 * The function returns the final size of CStream in bytes.
99 99 * If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
100 100 */
101 101
102 102
103 103 /*-********************************************
104 104 * bitStream decoding API (read backward)
105 105 **********************************************/
106 106 typedef struct
107 107 {
108 108 size_t bitContainer;
109 109 unsigned bitsConsumed;
110 110 const char* ptr;
111 111 const char* start;
112 112 } BIT_DStream_t;
113 113
114 114 typedef enum { BIT_DStream_unfinished = 0,
115 115 BIT_DStream_endOfBuffer = 1,
116 116 BIT_DStream_completed = 2,
117 117 BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of BIT_reloadDStream() */
118 118 /* 1,2,4,8 would be better for bitmap combinations, but slows down performance a bit ... :( */
119 119
120 120 MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize);
121 121 MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
122 122 MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
123 123 MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
124 124
125 125
126 126 /* Start by invoking BIT_initDStream().
127 127 * A chunk of the bitStream is then stored into a local register.
128 128 * Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
129 129 * You can then retrieve bitFields stored into the local register, **in reverse order**.
130 130 * Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
131 131 * A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its result is BIT_DStream_unfinished.
132 132 * Otherwise, it can be less than that, so proceed accordingly.
133 133 * Checking if DStream has reached its end can be performed with BIT_endOfDStream().
134 134 */
135 135
136 136
137 137 /*-****************************************
138 138 * unsafe API
139 139 ******************************************/
140 140 MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
141 141 /* faster, but works only if value is "clean", meaning all high bits above nbBits are 0 */
142 142
143 143 MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
144 144 /* unsafe version; does not check buffer overflow */
145 145
146 146 MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
147 147 /* faster, but works only if nbBits >= 1 */
148 148
149 149
150 150
151 151 /*-**************************************************************
152 152 * Internal functions
153 153 ****************************************************************/
154 154 MEM_STATIC unsigned BIT_highbit32 (register U32 val)
155 155 {
156 156 # if defined(_MSC_VER) /* Visual */
157 157 unsigned long r=0;
158 158 _BitScanReverse ( &r, val );
159 159 return (unsigned) r;
160 160 # elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
161 161 return 31 - __builtin_clz (val);
162 162 # else /* Software version */
163 163 static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
164 164 U32 v = val;
165 165 v |= v >> 1;
166 166 v |= v >> 2;
167 167 v |= v >> 4;
168 168 v |= v >> 8;
169 169 v |= v >> 16;
170 170 return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
171 171 # endif
172 172 }
173 173
174 174 /*===== Local Constants =====*/
175 175 static const unsigned BIT_mask[] = { 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF }; /* up to 26 bits */
176 176
177 177
178 178 /*-**************************************************************
179 179 * bitStream encoding
180 180 ****************************************************************/
181 181 /*! BIT_initCStream() :
182 182 * `dstCapacity` must be > sizeof(void*)
183 183 * @return : 0 if success,
184 184 otherwise an error code (can be tested using ERR_isError() ) */
185 185 MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* startPtr, size_t dstCapacity)
186 186 {
187 187 bitC->bitContainer = 0;
188 188 bitC->bitPos = 0;
189 189 bitC->startPtr = (char*)startPtr;
190 190 bitC->ptr = bitC->startPtr;
191 191 bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->ptr);
192 192 if (dstCapacity <= sizeof(bitC->ptr)) return ERROR(dstSize_tooSmall);
193 193 return 0;
194 194 }
195 195
196 196 /*! BIT_addBits() :
197 197 can add up to 26 bits into `bitC`.
198 198 Does not check for register overflow ! */
199 199 MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits)
200 200 {
201 201 bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
202 202 bitC->bitPos += nbBits;
203 203 }
204 204
205 205 /*! BIT_addBitsFast() :
206 206 * works only if `value` is _clean_, meaning all high bits above nbBits are 0 */
207 207 MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits)
208 208 {
209 209 bitC->bitContainer |= value << bitC->bitPos;
210 210 bitC->bitPos += nbBits;
211 211 }
212 212
213 213 /*! BIT_flushBitsFast() :
214 214 * unsafe version; does not check buffer overflow */
215 215 MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
216 216 {
217 217 size_t const nbBytes = bitC->bitPos >> 3;
218 218 MEM_writeLEST(bitC->ptr, bitC->bitContainer);
219 219 bitC->ptr += nbBytes;
220 220 bitC->bitPos &= 7;
221 221 bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
222 222 }
223 223
224 224 /*! BIT_flushBits() :
225 225 * safe version; check for buffer overflow, and prevents it.
226 226 * note : does not signal buffer overflow. This will be revealed later on using BIT_closeCStream() */
227 227 MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
228 228 {
229 229 size_t const nbBytes = bitC->bitPos >> 3;
230 230 MEM_writeLEST(bitC->ptr, bitC->bitContainer);
231 231 bitC->ptr += nbBytes;
232 232 if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
233 233 bitC->bitPos &= 7;
234 234 bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */
235 235 }
236 236
237 237 /*! BIT_closeCStream() :
238 238 * @return : size of CStream, in bytes,
239 239 or 0 if it could not fit into dstBuffer */
240 240 MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
241 241 {
242 242 BIT_addBitsFast(bitC, 1, 1); /* endMark */
243 243 BIT_flushBits(bitC);
244 244
245 245 if (bitC->ptr >= bitC->endPtr) return 0; /* doesn't fit within authorized budget : cancel */
246 246
247 247 return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
248 248 }
249 249
250 250
251 251 /*-********************************************************
252 252 * bitStream decoding
253 253 **********************************************************/
254 254 /*! BIT_initDStream() :
255 255 * Initialize a BIT_DStream_t.
256 256 * `bitD` : a pointer to an already allocated BIT_DStream_t structure.
257 257 * `srcSize` must be the *exact* size of the bitStream, in bytes.
258 258 * @return : size of stream (== srcSize) or an errorCode if a problem is detected
259 259 */
260 260 MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize)
261 261 {
262 262 if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
263 263
264 264 if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
265 265 bitD->start = (const char*)srcBuffer;
266 266 bitD->ptr = (const char*)srcBuffer + srcSize - sizeof(bitD->bitContainer);
267 267 bitD->bitContainer = MEM_readLEST(bitD->ptr);
268 268 { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
269 bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
269 bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures bitsConsumed is always set */
270 270 if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
271 271 } else {
272 272 bitD->start = (const char*)srcBuffer;
273 273 bitD->ptr = bitD->start;
274 274 bitD->bitContainer = *(const BYTE*)(bitD->start);
275 275 switch(srcSize)
276 276 {
277 277 case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) << (sizeof(bitD->bitContainer)*8 - 16);
278 278 case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) << (sizeof(bitD->bitContainer)*8 - 24);
279 279 case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) << (sizeof(bitD->bitContainer)*8 - 32);
280 280 case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) << 24;
281 281 case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) << 16;
282 282 case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) << 8;
283 283 default:;
284 284 }
285 285 { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
286 286 bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
287 287 if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
288 288 bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
289 289 }
290 290
291 291 return srcSize;
292 292 }
293 293
294 294 MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
295 295 {
296 296 return bitContainer >> start;
297 297 }
298 298
299 299 MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const nbBits)
300 300 {
301 #if defined(__BMI__) && defined(__GNUC__) /* experimental */
301 #if defined(__BMI__) && defined(__GNUC__) && __GNUC__*1000+__GNUC_MINOR__ >= 4008 /* experimental */
302 302 # if defined(__x86_64__)
303 303 if (sizeof(bitContainer)==8)
304 304 return _bextr_u64(bitContainer, start, nbBits);
305 305 else
306 306 # endif
307 307 return _bextr_u32(bitContainer, start, nbBits);
308 308 #else
309 309 return (bitContainer >> start) & BIT_mask[nbBits];
310 310 #endif
311 311 }
312 312
313 313 MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
314 314 {
315 315 return bitContainer & BIT_mask[nbBits];
316 316 }
317 317
318 318 /*! BIT_lookBits() :
319 319 * Provides next n bits from local register.
320 320 * local register is not modified.
321 321 * On 32-bits, maxNbBits==24.
322 322 * On 64-bits, maxNbBits==56.
323 323 * @return : value extracted
324 324 */
325 325 MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
326 326 {
327 327 #if defined(__BMI__) && defined(__GNUC__) /* experimental; fails if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8 */
328 328 return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) - bitD->bitsConsumed - nbBits, nbBits);
329 329 #else
330 330 U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
331 331 return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask);
332 332 #endif
333 333 }
334 334
335 335 /*! BIT_lookBitsFast() :
336 336 * unsafe version; only works only if nbBits >= 1 */
337 337 MEM_STATIC size_t BIT_lookBitsFast(const BIT_DStream_t* bitD, U32 nbBits)
338 338 {
339 339 U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1;
340 340 return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask);
341 341 }
342 342
343 343 MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits)
344 344 {
345 345 bitD->bitsConsumed += nbBits;
346 346 }
347 347
348 348 /*! BIT_readBits() :
349 349 * Read (consume) next n bits from local register and update.
350 350 * Pay attention to not read more than nbBits contained into local register.
351 351 * @return : extracted value.
352 352 */
353 353 MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits)
354 354 {
355 355 size_t const value = BIT_lookBits(bitD, nbBits);
356 356 BIT_skipBits(bitD, nbBits);
357 357 return value;
358 358 }
359 359
360 360 /*! BIT_readBitsFast() :
361 361 * unsafe version; only works only if nbBits >= 1 */
362 362 MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits)
363 363 {
364 364 size_t const value = BIT_lookBitsFast(bitD, nbBits);
365 365 BIT_skipBits(bitD, nbBits);
366 366 return value;
367 367 }
368 368
369 369 /*! BIT_reloadDStream() :
370 * Refill `BIT_DStream_t` from src buffer previously defined (see BIT_initDStream() ).
370 * Refill `bitD` from buffer previously set in BIT_initDStream() .
371 371 * This function is safe, it guarantees it will not read beyond src buffer.
372 372 * @return : status of `BIT_DStream_t` internal register.
373 if status == unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */
373 if status == BIT_DStream_unfinished, internal register is filled with >= (sizeof(bitD->bitContainer)*8 - 7) bits */
374 374 MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD)
375 375 {
376 376 if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should not happen => corruption detected */
377 377 return BIT_DStream_overflow;
378 378
379 379 if (bitD->ptr >= bitD->start + sizeof(bitD->bitContainer)) {
380 380 bitD->ptr -= bitD->bitsConsumed >> 3;
381 381 bitD->bitsConsumed &= 7;
382 382 bitD->bitContainer = MEM_readLEST(bitD->ptr);
383 383 return BIT_DStream_unfinished;
384 384 }
385 385 if (bitD->ptr == bitD->start) {
386 386 if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer;
387 387 return BIT_DStream_completed;
388 388 }
389 389 { U32 nbBytes = bitD->bitsConsumed >> 3;
390 390 BIT_DStream_status result = BIT_DStream_unfinished;
391 391 if (bitD->ptr - nbBytes < bitD->start) {
392 392 nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */
393 393 result = BIT_DStream_endOfBuffer;
394 394 }
395 395 bitD->ptr -= nbBytes;
396 396 bitD->bitsConsumed -= nbBytes*8;
397 397 bitD->bitContainer = MEM_readLEST(bitD->ptr); /* reminder : srcSize > sizeof(bitD) */
398 398 return result;
399 399 }
400 400 }
401 401
402 402 /*! BIT_endOfDStream() :
403 403 * @return Tells if DStream has exactly reached its end (all bits consumed).
404 404 */
405 405 MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream)
406 406 {
407 407 return ((DStream->ptr == DStream->start) && (DStream->bitsConsumed == sizeof(DStream->bitContainer)*8));
408 408 }
409 409
410 410 #if defined (__cplusplus)
411 411 }
412 412 #endif
413 413
414 414 #endif /* BITSTREAM_H_MODULE */
@@ -1,225 +1,227 b''
1 1 /*
2 2 Common functions of New Generation Entropy library
3 3 Copyright (C) 2016, Yann Collet.
4 4
5 5 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6 6
7 7 Redistribution and use in source and binary forms, with or without
8 8 modification, are permitted provided that the following conditions are
9 9 met:
10 10
11 11 * Redistributions of source code must retain the above copyright
12 12 notice, this list of conditions and the following disclaimer.
13 13 * Redistributions in binary form must reproduce the above
14 14 copyright notice, this list of conditions and the following disclaimer
15 15 in the documentation and/or other materials provided with the
16 16 distribution.
17 17
18 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 30 You can contact the author at :
31 31 - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
32 32 - Public forum : https://groups.google.com/forum/#!forum/lz4c
33 33 *************************************************************************** */
34 34
35 35 /* *************************************
36 36 * Dependencies
37 37 ***************************************/
38 38 #include "mem.h"
39 39 #include "error_private.h" /* ERR_*, ERROR */
40 40 #define FSE_STATIC_LINKING_ONLY /* FSE_MIN_TABLELOG */
41 41 #include "fse.h"
42 42 #define HUF_STATIC_LINKING_ONLY /* HUF_TABLELOG_ABSOLUTEMAX */
43 43 #include "huf.h"
44 44
45 45
46 46 /*-****************************************
47 47 * FSE Error Management
48 48 ******************************************/
49 49 unsigned FSE_isError(size_t code) { return ERR_isError(code); }
50 50
51 51 const char* FSE_getErrorName(size_t code) { return ERR_getErrorName(code); }
52 52
53 53
54 54 /* **************************************************************
55 55 * HUF Error Management
56 56 ****************************************************************/
57 57 unsigned HUF_isError(size_t code) { return ERR_isError(code); }
58 58
59 59 const char* HUF_getErrorName(size_t code) { return ERR_getErrorName(code); }
60 60
61 61
62 62 /*-**************************************************************
63 63 * FSE NCount encoding-decoding
64 64 ****************************************************************/
65 65 static short FSE_abs(short a) { return (short)(a<0 ? -a : a); }
66 66
67 67 size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* tableLogPtr,
68 68 const void* headerBuffer, size_t hbSize)
69 69 {
70 70 const BYTE* const istart = (const BYTE*) headerBuffer;
71 71 const BYTE* const iend = istart + hbSize;
72 72 const BYTE* ip = istart;
73 73 int nbBits;
74 74 int remaining;
75 75 int threshold;
76 76 U32 bitStream;
77 77 int bitCount;
78 78 unsigned charnum = 0;
79 79 int previous0 = 0;
80 80
81 81 if (hbSize < 4) return ERROR(srcSize_wrong);
82 82 bitStream = MEM_readLE32(ip);
83 83 nbBits = (bitStream & 0xF) + FSE_MIN_TABLELOG; /* extract tableLog */
84 84 if (nbBits > FSE_TABLELOG_ABSOLUTE_MAX) return ERROR(tableLog_tooLarge);
85 85 bitStream >>= 4;
86 86 bitCount = 4;
87 87 *tableLogPtr = nbBits;
88 88 remaining = (1<<nbBits)+1;
89 89 threshold = 1<<nbBits;
90 90 nbBits++;
91 91
92 92 while ((remaining>1) & (charnum<=*maxSVPtr)) {
93 93 if (previous0) {
94 94 unsigned n0 = charnum;
95 95 while ((bitStream & 0xFFFF) == 0xFFFF) {
96 96 n0 += 24;
97 97 if (ip < iend-5) {
98 98 ip += 2;
99 99 bitStream = MEM_readLE32(ip) >> bitCount;
100 100 } else {
101 101 bitStream >>= 16;
102 102 bitCount += 16;
103 103 } }
104 104 while ((bitStream & 3) == 3) {
105 105 n0 += 3;
106 106 bitStream >>= 2;
107 107 bitCount += 2;
108 108 }
109 109 n0 += bitStream & 3;
110 110 bitCount += 2;
111 111 if (n0 > *maxSVPtr) return ERROR(maxSymbolValue_tooSmall);
112 112 while (charnum < n0) normalizedCounter[charnum++] = 0;
113 113 if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
114 114 ip += bitCount>>3;
115 115 bitCount &= 7;
116 116 bitStream = MEM_readLE32(ip) >> bitCount;
117 117 } else {
118 118 bitStream >>= 2;
119 119 } }
120 120 { short const max = (short)((2*threshold-1)-remaining);
121 121 short count;
122 122
123 123 if ((bitStream & (threshold-1)) < (U32)max) {
124 124 count = (short)(bitStream & (threshold-1));
125 125 bitCount += nbBits-1;
126 126 } else {
127 127 count = (short)(bitStream & (2*threshold-1));
128 128 if (count >= threshold) count -= max;
129 129 bitCount += nbBits;
130 130 }
131 131
132 132 count--; /* extra accuracy */
133 133 remaining -= FSE_abs(count);
134 134 normalizedCounter[charnum++] = count;
135 135 previous0 = !count;
136 136 while (remaining < threshold) {
137 137 nbBits--;
138 138 threshold >>= 1;
139 139 }
140 140
141 141 if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
142 142 ip += bitCount>>3;
143 143 bitCount &= 7;
144 144 } else {
145 145 bitCount -= (int)(8 * (iend - 4 - ip));
146 146 ip = iend - 4;
147 147 }
148 148 bitStream = MEM_readLE32(ip) >> (bitCount & 31);
149 149 } } /* while ((remaining>1) & (charnum<=*maxSVPtr)) */
150 150 if (remaining != 1) return ERROR(corruption_detected);
151 151 if (bitCount > 32) return ERROR(corruption_detected);
152 152 *maxSVPtr = charnum-1;
153 153
154 154 ip += (bitCount+7)>>3;
155 155 return ip-istart;
156 156 }
157 157
158 158
159 159 /*! HUF_readStats() :
160 160 Read compact Huffman tree, saved by HUF_writeCTable().
161 161 `huffWeight` is destination buffer.
162 `rankStats` is assumed to be a table of at least HUF_TABLELOG_MAX U32.
162 163 @return : size read from `src` , or an error Code .
163 164 Note : Needed by HUF_readCTable() and HUF_readDTableX?() .
164 165 */
165 166 size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
166 167 U32* nbSymbolsPtr, U32* tableLogPtr,
167 168 const void* src, size_t srcSize)
168 169 {
169 170 U32 weightTotal;
170 171 const BYTE* ip = (const BYTE*) src;
171 172 size_t iSize;
172 173 size_t oSize;
173 174
174 175 if (!srcSize) return ERROR(srcSize_wrong);
175 176 iSize = ip[0];
176 177 /* memset(huffWeight, 0, hwSize); *//* is not necessary, even though some analyzer complain ... */
177 178
178 179 if (iSize >= 128) { /* special header */
179 180 oSize = iSize - 127;
180 181 iSize = ((oSize+1)/2);
181 182 if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
182 183 if (oSize >= hwSize) return ERROR(corruption_detected);
183 184 ip += 1;
184 185 { U32 n;
185 186 for (n=0; n<oSize; n+=2) {
186 187 huffWeight[n] = ip[n/2] >> 4;
187 188 huffWeight[n+1] = ip[n/2] & 15;
188 189 } } }
189 190 else { /* header compressed with FSE (normal case) */
191 FSE_DTable fseWorkspace[FSE_DTABLE_SIZE_U32(6)]; /* 6 is max possible tableLog for HUF header (maybe even 5, to be tested) */
190 192 if (iSize+1 > srcSize) return ERROR(srcSize_wrong);
191 oSize = FSE_decompress(huffWeight, hwSize-1, ip+1, iSize); /* max (hwSize-1) values decoded, as last one is implied */
193 oSize = FSE_decompress_wksp(huffWeight, hwSize-1, ip+1, iSize, fseWorkspace, 6); /* max (hwSize-1) values decoded, as last one is implied */
192 194 if (FSE_isError(oSize)) return oSize;
193 195 }
194 196
195 197 /* collect weight stats */
196 memset(rankStats, 0, (HUF_TABLELOG_ABSOLUTEMAX + 1) * sizeof(U32));
198 memset(rankStats, 0, (HUF_TABLELOG_MAX + 1) * sizeof(U32));
197 199 weightTotal = 0;
198 200 { U32 n; for (n=0; n<oSize; n++) {
199 if (huffWeight[n] >= HUF_TABLELOG_ABSOLUTEMAX) return ERROR(corruption_detected);
201 if (huffWeight[n] >= HUF_TABLELOG_MAX) return ERROR(corruption_detected);
200 202 rankStats[huffWeight[n]]++;
201 203 weightTotal += (1 << huffWeight[n]) >> 1;
202 204 } }
203 205 if (weightTotal == 0) return ERROR(corruption_detected);
204 206
205 207 /* get last non-null symbol weight (implied, total must be 2^n) */
206 208 { U32 const tableLog = BIT_highbit32(weightTotal) + 1;
207 if (tableLog > HUF_TABLELOG_ABSOLUTEMAX) return ERROR(corruption_detected);
209 if (tableLog > HUF_TABLELOG_MAX) return ERROR(corruption_detected);
208 210 *tableLogPtr = tableLog;
209 211 /* determine last weight */
210 212 { U32 const total = 1 << tableLog;
211 213 U32 const rest = total - weightTotal;
212 214 U32 const verif = 1 << BIT_highbit32(rest);
213 215 U32 const lastWeight = BIT_highbit32(rest) + 1;
214 216 if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */
215 217 huffWeight[oSize] = (BYTE)lastWeight;
216 218 rankStats[lastWeight]++;
217 219 } }
218 220
219 221 /* check tree construction validity */
220 222 if ((rankStats[1] < 2) || (rankStats[1] & 1)) return ERROR(corruption_detected); /* by construction : at least 2 elts of rank 1, must be even */
221 223
222 224 /* results */
223 225 *nbSymbolsPtr = (U32)(oSize+1);
224 226 return iSize+1;
225 227 }
@@ -1,634 +1,668 b''
1 1 /* ******************************************************************
2 2 FSE : Finite State Entropy codec
3 3 Public Prototypes declaration
4 4 Copyright (C) 2013-2016, Yann Collet.
5 5
6 6 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
7 7
8 8 Redistribution and use in source and binary forms, with or without
9 9 modification, are permitted provided that the following conditions are
10 10 met:
11 11
12 12 * Redistributions of source code must retain the above copyright
13 13 notice, this list of conditions and the following disclaimer.
14 14 * Redistributions in binary form must reproduce the above
15 15 copyright notice, this list of conditions and the following disclaimer
16 16 in the documentation and/or other materials provided with the
17 17 distribution.
18 18
19 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 23 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 25 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 27 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 30
31 31 You can contact the author at :
32 32 - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
33 33 ****************************************************************** */
34 34 #ifndef FSE_H
35 35 #define FSE_H
36 36
37 37 #if defined (__cplusplus)
38 38 extern "C" {
39 39 #endif
40 40
41 41
42 42 /*-*****************************************
43 43 * Dependencies
44 44 ******************************************/
45 45 #include <stddef.h> /* size_t, ptrdiff_t */
46 46
47 47
48 48 /*-****************************************
49 49 * FSE simple functions
50 50 ******************************************/
51 51 /*! FSE_compress() :
52 52 Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'.
53 53 'dst' buffer must be already allocated. Compression runs faster is dstCapacity >= FSE_compressBound(srcSize).
54 54 @return : size of compressed data (<= dstCapacity).
55 55 Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
56 56 if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression instead.
57 57 if FSE_isError(return), compression failed (more details using FSE_getErrorName())
58 58 */
59 59 size_t FSE_compress(void* dst, size_t dstCapacity,
60 60 const void* src, size_t srcSize);
61 61
62 62 /*! FSE_decompress():
63 63 Decompress FSE data from buffer 'cSrc', of size 'cSrcSize',
64 64 into already allocated destination buffer 'dst', of size 'dstCapacity'.
65 65 @return : size of regenerated data (<= maxDstSize),
66 66 or an error code, which can be tested using FSE_isError() .
67 67
68 68 ** Important ** : FSE_decompress() does not decompress non-compressible nor RLE data !!!
69 69 Why ? : making this distinction requires a header.
70 70 Header management is intentionally delegated to the user layer, which can better manage special cases.
71 71 */
72 72 size_t FSE_decompress(void* dst, size_t dstCapacity,
73 73 const void* cSrc, size_t cSrcSize);
74 74
75 75
76 76 /*-*****************************************
77 77 * Tool functions
78 78 ******************************************/
79 79 size_t FSE_compressBound(size_t size); /* maximum compressed size */
80 80
81 81 /* Error Management */
82 82 unsigned FSE_isError(size_t code); /* tells if a return value is an error code */
83 83 const char* FSE_getErrorName(size_t code); /* provides error code string (useful for debugging) */
84 84
85 85
86 86 /*-*****************************************
87 87 * FSE advanced functions
88 88 ******************************************/
89 89 /*! FSE_compress2() :
90 90 Same as FSE_compress(), but allows the selection of 'maxSymbolValue' and 'tableLog'
91 91 Both parameters can be defined as '0' to mean : use default value
92 92 @return : size of compressed data
93 93 Special values : if return == 0, srcData is not compressible => Nothing is stored within cSrc !!!
94 94 if return == 1, srcData is a single byte symbol * srcSize times. Use RLE compression.
95 95 if FSE_isError(return), it's an error code.
96 96 */
97 97 size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
98 98
99 99
100 100 /*-*****************************************
101 101 * FSE detailed API
102 102 ******************************************/
103 103 /*!
104 104 FSE_compress() does the following:
105 105 1. count symbol occurrence from source[] into table count[]
106 106 2. normalize counters so that sum(count[]) == Power_of_2 (2^tableLog)
107 107 3. save normalized counters to memory buffer using writeNCount()
108 108 4. build encoding table 'CTable' from normalized counters
109 109 5. encode the data stream using encoding table 'CTable'
110 110
111 111 FSE_decompress() does the following:
112 112 1. read normalized counters with readNCount()
113 113 2. build decoding table 'DTable' from normalized counters
114 114 3. decode the data stream using decoding table 'DTable'
115 115
116 116 The following API allows targeting specific sub-functions for advanced tasks.
117 117 For example, it's possible to compress several blocks using the same 'CTable',
118 118 or to save and provide normalized distribution using external method.
119 119 */
120 120
121 121 /* *** COMPRESSION *** */
122 122
123 123 /*! FSE_count():
124 124 Provides the precise count of each byte within a table 'count'.
125 125 'count' is a table of unsigned int, of minimum size (*maxSymbolValuePtr+1).
126 126 *maxSymbolValuePtr will be updated if detected smaller than initial value.
127 127 @return : the count of the most frequent symbol (which is not identified).
128 128 if return == srcSize, there is only one symbol.
129 129 Can also return an error code, which can be tested with FSE_isError(). */
130 130 size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
131 131
132 132 /*! FSE_optimalTableLog():
133 133 dynamically downsize 'tableLog' when conditions are met.
134 134 It saves CPU time, by using smaller tables, while preserving or even improving compression ratio.
135 135 @return : recommended tableLog (necessarily <= 'maxTableLog') */
136 136 unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
137 137
138 138 /*! FSE_normalizeCount():
139 139 normalize counts so that sum(count[]) == Power_of_2 (2^tableLog)
140 140 'normalizedCounter' is a table of short, of minimum size (maxSymbolValue+1).
141 141 @return : tableLog,
142 142 or an errorCode, which can be tested using FSE_isError() */
143 143 size_t FSE_normalizeCount(short* normalizedCounter, unsigned tableLog, const unsigned* count, size_t srcSize, unsigned maxSymbolValue);
144 144
145 145 /*! FSE_NCountWriteBound():
146 146 Provides the maximum possible size of an FSE normalized table, given 'maxSymbolValue' and 'tableLog'.
147 147 Typically useful for allocation purpose. */
148 148 size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog);
149 149
150 150 /*! FSE_writeNCount():
151 151 Compactly save 'normalizedCounter' into 'buffer'.
152 152 @return : size of the compressed table,
153 153 or an errorCode, which can be tested using FSE_isError(). */
154 154 size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
155 155
156 156
157 157 /*! Constructor and Destructor of FSE_CTable.
158 158 Note that FSE_CTable size depends on 'tableLog' and 'maxSymbolValue' */
159 159 typedef unsigned FSE_CTable; /* don't allocate that. It's only meant to be more restrictive than void* */
160 160 FSE_CTable* FSE_createCTable (unsigned tableLog, unsigned maxSymbolValue);
161 161 void FSE_freeCTable (FSE_CTable* ct);
162 162
163 163 /*! FSE_buildCTable():
164 164 Builds `ct`, which must be already allocated, using FSE_createCTable().
165 165 @return : 0, or an errorCode, which can be tested using FSE_isError() */
166 166 size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
167 167
168 168 /*! FSE_compress_usingCTable():
169 169 Compress `src` using `ct` into `dst` which must be already allocated.
170 170 @return : size of compressed data (<= `dstCapacity`),
171 171 or 0 if compressed data could not fit into `dst`,
172 172 or an errorCode, which can be tested using FSE_isError() */
173 173 size_t FSE_compress_usingCTable (void* dst, size_t dstCapacity, const void* src, size_t srcSize, const FSE_CTable* ct);
174 174
175 175 /*!
176 176 Tutorial :
177 177 ----------
178 178 The first step is to count all symbols. FSE_count() does this job very fast.
179 179 Result will be saved into 'count', a table of unsigned int, which must be already allocated, and have 'maxSymbolValuePtr[0]+1' cells.
180 180 'src' is a table of bytes of size 'srcSize'. All values within 'src' MUST be <= maxSymbolValuePtr[0]
181 181 maxSymbolValuePtr[0] will be updated, with its real value (necessarily <= original value)
182 182 FSE_count() will return the number of occurrence of the most frequent symbol.
183 183 This can be used to know if there is a single symbol within 'src', and to quickly evaluate its compressibility.
184 184 If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
185 185
186 186 The next step is to normalize the frequencies.
187 187 FSE_normalizeCount() will ensure that sum of frequencies is == 2 ^'tableLog'.
188 188 It also guarantees a minimum of 1 to any Symbol with frequency >= 1.
189 189 You can use 'tableLog'==0 to mean "use default tableLog value".
190 190 If you are unsure of which tableLog value to use, you can ask FSE_optimalTableLog(),
191 191 which will provide the optimal valid tableLog given sourceSize, maxSymbolValue, and a user-defined maximum (0 means "default").
192 192
193 193 The result of FSE_normalizeCount() will be saved into a table,
194 194 called 'normalizedCounter', which is a table of signed short.
195 195 'normalizedCounter' must be already allocated, and have at least 'maxSymbolValue+1' cells.
196 196 The return value is tableLog if everything proceeded as expected.
197 197 It is 0 if there is a single symbol within distribution.
198 198 If there is an error (ex: invalid tableLog value), the function will return an ErrorCode (which can be tested using FSE_isError()).
199 199
200 200 'normalizedCounter' can be saved in a compact manner to a memory area using FSE_writeNCount().
201 201 'buffer' must be already allocated.
202 202 For guaranteed success, buffer size must be at least FSE_headerBound().
203 203 The result of the function is the number of bytes written into 'buffer'.
204 204 If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError(); ex : buffer size too small).
205 205
206 206 'normalizedCounter' can then be used to create the compression table 'CTable'.
207 207 The space required by 'CTable' must be already allocated, using FSE_createCTable().
208 208 You can then use FSE_buildCTable() to fill 'CTable'.
209 209 If there is an error, both functions will return an ErrorCode (which can be tested using FSE_isError()).
210 210
211 211 'CTable' can then be used to compress 'src', with FSE_compress_usingCTable().
212 212 Similar to FSE_count(), the convention is that 'src' is assumed to be a table of char of size 'srcSize'
213 213 The function returns the size of compressed data (without header), necessarily <= `dstCapacity`.
214 214 If it returns '0', compressed data could not fit into 'dst'.
215 215 If there is an error, the function will return an ErrorCode (which can be tested using FSE_isError()).
216 216 */
217 217
218 218
219 219 /* *** DECOMPRESSION *** */
220 220
221 221 /*! FSE_readNCount():
222 222 Read compactly saved 'normalizedCounter' from 'rBuffer'.
223 223 @return : size read from 'rBuffer',
224 224 or an errorCode, which can be tested using FSE_isError().
225 225 maxSymbolValuePtr[0] and tableLogPtr[0] will also be updated with their respective values */
226 226 size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSymbolValuePtr, unsigned* tableLogPtr, const void* rBuffer, size_t rBuffSize);
227 227
228 228 /*! Constructor and Destructor of FSE_DTable.
229 229 Note that its size depends on 'tableLog' */
230 230 typedef unsigned FSE_DTable; /* don't allocate that. It's just a way to be more restrictive than void* */
231 231 FSE_DTable* FSE_createDTable(unsigned tableLog);
232 232 void FSE_freeDTable(FSE_DTable* dt);
233 233
234 234 /*! FSE_buildDTable():
235 235 Builds 'dt', which must be already allocated, using FSE_createDTable().
236 236 return : 0, or an errorCode, which can be tested using FSE_isError() */
237 237 size_t FSE_buildDTable (FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog);
238 238
239 239 /*! FSE_decompress_usingDTable():
240 240 Decompress compressed source `cSrc` of size `cSrcSize` using `dt`
241 241 into `dst` which must be already allocated.
242 242 @return : size of regenerated data (necessarily <= `dstCapacity`),
243 243 or an errorCode, which can be tested using FSE_isError() */
244 244 size_t FSE_decompress_usingDTable(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, const FSE_DTable* dt);
245 245
246 246 /*!
247 247 Tutorial :
248 248 ----------
249 249 (Note : these functions only decompress FSE-compressed blocks.
250 250 If block is uncompressed, use memcpy() instead
251 251 If block is a single repeated byte, use memset() instead )
252 252
253 253 The first step is to obtain the normalized frequencies of symbols.
254 254 This can be performed by FSE_readNCount() if it was saved using FSE_writeNCount().
255 255 'normalizedCounter' must be already allocated, and have at least 'maxSymbolValuePtr[0]+1' cells of signed short.
256 256 In practice, that means it's necessary to know 'maxSymbolValue' beforehand,
257 257 or size the table to handle worst case situations (typically 256).
258 258 FSE_readNCount() will provide 'tableLog' and 'maxSymbolValue'.
259 259 The result of FSE_readNCount() is the number of bytes read from 'rBuffer'.
260 260 Note that 'rBufferSize' must be at least 4 bytes, even if useful information is less than that.
261 261 If there is an error, the function will return an error code, which can be tested using FSE_isError().
262 262
263 263 The next step is to build the decompression tables 'FSE_DTable' from 'normalizedCounter'.
264 264 This is performed by the function FSE_buildDTable().
265 265 The space required by 'FSE_DTable' must be already allocated using FSE_createDTable().
266 266 If there is an error, the function will return an error code, which can be tested using FSE_isError().
267 267
268 268 `FSE_DTable` can then be used to decompress `cSrc`, with FSE_decompress_usingDTable().
269 269 `cSrcSize` must be strictly correct, otherwise decompression will fail.
270 270 FSE_decompress_usingDTable() result will tell how many bytes were regenerated (<=`dstCapacity`).
271 271 If there is an error, the function will return an error code, which can be tested using FSE_isError(). (ex: dst buffer too small)
272 272 */
273 273
274 274
275 275 #ifdef FSE_STATIC_LINKING_ONLY
276 276
277 277 /* *** Dependency *** */
278 278 #include "bitstream.h"
279 279
280 280
281 281 /* *****************************************
282 282 * Static allocation
283 283 *******************************************/
284 284 /* FSE buffer bounds */
285 285 #define FSE_NCOUNTBOUND 512
286 286 #define FSE_BLOCKBOUND(size) (size + (size>>7))
287 287 #define FSE_COMPRESSBOUND(size) (FSE_NCOUNTBOUND + FSE_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
288 288
289 /* It is possible to statically allocate FSE CTable/DTable as a table of unsigned using below macros */
289 /* It is possible to statically allocate FSE CTable/DTable as a table of FSE_CTable/FSE_DTable using below macros */
290 290 #define FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) (1 + (1<<(maxTableLog-1)) + ((maxSymbolValue+1)*2))
291 291 #define FSE_DTABLE_SIZE_U32(maxTableLog) (1 + (1<<maxTableLog))
292 292
293 293
294 294 /* *****************************************
295 295 * FSE advanced API
296 296 *******************************************/
297 /* FSE_count_wksp() :
298 * Same as FSE_count(), but using an externally provided scratch buffer.
299 * `workSpace` size must be table of >= `1024` unsigned
300 */
301 size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
302 const void* source, size_t sourceSize, unsigned* workSpace);
303
304 /** FSE_countFast() :
305 * same as FSE_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr
306 */
297 307 size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
298 /**< same as FSE_count(), but blindly trusts that all byte values within src are <= *maxSymbolValuePtr */
308
309 /* FSE_countFast_wksp() :
310 * Same as FSE_countFast(), but using an externally provided scratch buffer.
311 * `workSpace` must be a table of minimum `1024` unsigned
312 */
313 size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize, unsigned* workSpace);
314
315 /*! FSE_count_simple
316 * Same as FSE_countFast(), but does not use any additional memory (not even on stack).
317 * This function is unsafe, and will segfault if any value within `src` is `> *maxSymbolValuePtr` (presuming it's also the size of `count`).
318 */
319 size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr, const void* src, size_t srcSize);
320
321
299 322
300 323 unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus);
301 324 /**< same as FSE_optimalTableLog(), which used `minus==2` */
302 325
326 /* FSE_compress_wksp() :
327 * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
328 * FSE_WKSP_SIZE_U32() provides the minimum size required for `workSpace` as a table of FSE_CTable.
329 */
330 #define FSE_WKSP_SIZE_U32(maxTableLog, maxSymbolValue) ( FSE_CTABLE_SIZE_U32(maxTableLog, maxSymbolValue) + (1<<((maxTableLog>2)?(maxTableLog-2):0)) )
331 size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
332
303 333 size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits);
304 /**< build a fake FSE_CTable, designed to not compress an input, where each symbol uses nbBits */
334 /**< build a fake FSE_CTable, designed for a flat distribution, where each symbol uses nbBits */
305 335
306 336 size_t FSE_buildCTable_rle (FSE_CTable* ct, unsigned char symbolValue);
307 337 /**< build a fake FSE_CTable, designed to compress always the same symbolValue */
308 338
339 /* FSE_buildCTable_wksp() :
340 * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
341 * `wkspSize` must be >= `(1<<tableLog)`.
342 */
343 size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize);
344
309 345 size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits);
310 /**< build a fake FSE_DTable, designed to read an uncompressed bitstream where each symbol uses nbBits */
346 /**< build a fake FSE_DTable, designed to read a flat distribution where each symbol uses nbBits */
311 347
312 348 size_t FSE_buildDTable_rle (FSE_DTable* dt, unsigned char symbolValue);
313 349 /**< build a fake FSE_DTable, designed to always generate the same symbolValue */
314 350
351 size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog);
352 /**< same as FSE_decompress(), using an externally allocated `workSpace` produced with `FSE_DTABLE_SIZE_U32(maxLog)` */
353
315 354
316 355 /* *****************************************
317 356 * FSE symbol compression API
318 357 *******************************************/
319 358 /*!
320 359 This API consists of small unitary functions, which highly benefit from being inlined.
321 You will want to enable link-time-optimization to ensure these functions are properly inlined in your binary.
322 Visual seems to do it automatically.
323 For gcc or clang, you'll need to add -flto flag at compilation and linking stages.
324 If none of these solutions is applicable, include "fse.c" directly.
360 Hence their body are included in next section.
325 361 */
326 typedef struct
327 {
362 typedef struct {
328 363 ptrdiff_t value;
329 364 const void* stateTable;
330 365 const void* symbolTT;
331 366 unsigned stateLog;
332 367 } FSE_CState_t;
333 368
334 369 static void FSE_initCState(FSE_CState_t* CStatePtr, const FSE_CTable* ct);
335 370
336 371 static void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* CStatePtr, unsigned symbol);
337 372
338 373 static void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* CStatePtr);
339 374
340 375 /**<
341 376 These functions are inner components of FSE_compress_usingCTable().
342 377 They allow the creation of custom streams, mixing multiple tables and bit sources.
343 378
344 379 A key property to keep in mind is that encoding and decoding are done **in reverse direction**.
345 380 So the first symbol you will encode is the last you will decode, like a LIFO stack.
346 381
347 382 You will need a few variables to track your CStream. They are :
348 383
349 384 FSE_CTable ct; // Provided by FSE_buildCTable()
350 385 BIT_CStream_t bitStream; // bitStream tracking structure
351 386 FSE_CState_t state; // State tracking structure (can have several)
352 387
353 388
354 389 The first thing to do is to init bitStream and state.
355 390 size_t errorCode = BIT_initCStream(&bitStream, dstBuffer, maxDstSize);
356 391 FSE_initCState(&state, ct);
357 392
358 393 Note that BIT_initCStream() can produce an error code, so its result should be tested, using FSE_isError();
359 394 You can then encode your input data, byte after byte.
360 395 FSE_encodeSymbol() outputs a maximum of 'tableLog' bits at a time.
361 396 Remember decoding will be done in reverse direction.
362 397 FSE_encodeByte(&bitStream, &state, symbol);
363 398
364 399 At any time, you can also add any bit sequence.
365 400 Note : maximum allowed nbBits is 25, for compatibility with 32-bits decoders
366 401 BIT_addBits(&bitStream, bitField, nbBits);
367 402
368 403 The above methods don't commit data to memory, they just store it into local register, for speed.
369 404 Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t).
370 405 Writing data to memory is a manual operation, performed by the flushBits function.
371 406 BIT_flushBits(&bitStream);
372 407
373 408 Your last FSE encoding operation shall be to flush your last state value(s).
374 409 FSE_flushState(&bitStream, &state);
375 410
376 411 Finally, you must close the bitStream.
377 412 The function returns the size of CStream in bytes.
378 413 If data couldn't fit into dstBuffer, it will return a 0 ( == not compressible)
379 414 If there is an error, it returns an errorCode (which can be tested using FSE_isError()).
380 415 size_t size = BIT_closeCStream(&bitStream);
381 416 */
382 417
383 418
384 419 /* *****************************************
385 420 * FSE symbol decompression API
386 421 *******************************************/
387 typedef struct
388 {
422 typedef struct {
389 423 size_t state;
390 424 const void* table; /* precise table may vary, depending on U16 */
391 425 } FSE_DState_t;
392 426
393 427
394 428 static void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt);
395 429
396 430 static unsigned char FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
397 431
398 432 static unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr);
399 433
400 434 /**<
401 435 Let's now decompose FSE_decompress_usingDTable() into its unitary components.
402 436 You will decode FSE-encoded symbols from the bitStream,
403 437 and also any other bitFields you put in, **in reverse order**.
404 438
405 439 You will need a few variables to track your bitStream. They are :
406 440
407 441 BIT_DStream_t DStream; // Stream context
408 442 FSE_DState_t DState; // State context. Multiple ones are possible
409 443 FSE_DTable* DTablePtr; // Decoding table, provided by FSE_buildDTable()
410 444
411 445 The first thing to do is to init the bitStream.
412 446 errorCode = BIT_initDStream(&DStream, srcBuffer, srcSize);
413 447
414 448 You should then retrieve your initial state(s)
415 449 (in reverse flushing order if you have several ones) :
416 450 errorCode = FSE_initDState(&DState, &DStream, DTablePtr);
417 451
418 452 You can then decode your data, symbol after symbol.
419 453 For information the maximum number of bits read by FSE_decodeSymbol() is 'tableLog'.
420 454 Keep in mind that symbols are decoded in reverse order, like a LIFO stack (last in, first out).
421 455 unsigned char symbol = FSE_decodeSymbol(&DState, &DStream);
422 456
423 457 You can retrieve any bitfield you eventually stored into the bitStream (in reverse order)
424 458 Note : maximum allowed nbBits is 25, for 32-bits compatibility
425 459 size_t bitField = BIT_readBits(&DStream, nbBits);
426 460
427 461 All above operations only read from local register (which size depends on size_t).
428 462 Refueling the register from memory is manually performed by the reload method.
429 463 endSignal = FSE_reloadDStream(&DStream);
430 464
431 465 BIT_reloadDStream() result tells if there is still some more data to read from DStream.
432 466 BIT_DStream_unfinished : there is still some data left into the DStream.
433 467 BIT_DStream_endOfBuffer : Dstream reached end of buffer. Its container may no longer be completely filled.
434 468 BIT_DStream_completed : Dstream reached its exact end, corresponding in general to decompression completed.
435 469 BIT_DStream_tooFar : Dstream went too far. Decompression result is corrupted.
436 470
437 471 When reaching end of buffer (BIT_DStream_endOfBuffer), progress slowly, notably if you decode multiple symbols per loop,
438 472 to properly detect the exact end of stream.
439 473 After each decoded symbol, check if DStream is fully consumed using this simple test :
440 474 BIT_reloadDStream(&DStream) >= BIT_DStream_completed
441 475
442 476 When it's done, verify decompression is fully completed, by checking both DStream and the relevant states.
443 477 Checking if DStream has reached its end is performed by :
444 478 BIT_endOfDStream(&DStream);
445 479 Check also the states. There might be some symbols left there, if some high probability ones (>50%) are possible.
446 480 FSE_endOfDState(&DState);
447 481 */
448 482
449 483
450 484 /* *****************************************
451 485 * FSE unsafe API
452 486 *******************************************/
453 487 static unsigned char FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD);
454 488 /* faster, but works only if nbBits is always >= 1 (otherwise, result will be corrupted) */
455 489
456 490
457 491 /* *****************************************
458 492 * Implementation of inlined functions
459 493 *******************************************/
460 494 typedef struct {
461 495 int deltaFindState;
462 496 U32 deltaNbBits;
463 497 } FSE_symbolCompressionTransform; /* total 8 bytes */
464 498
465 499 MEM_STATIC void FSE_initCState(FSE_CState_t* statePtr, const FSE_CTable* ct)
466 500 {
467 501 const void* ptr = ct;
468 502 const U16* u16ptr = (const U16*) ptr;
469 503 const U32 tableLog = MEM_read16(ptr);
470 504 statePtr->value = (ptrdiff_t)1<<tableLog;
471 505 statePtr->stateTable = u16ptr+2;
472 506 statePtr->symbolTT = ((const U32*)ct + 1 + (tableLog ? (1<<(tableLog-1)) : 1));
473 507 statePtr->stateLog = tableLog;
474 508 }
475 509
476 510
477 511 /*! FSE_initCState2() :
478 512 * Same as FSE_initCState(), but the first symbol to include (which will be the last to be read)
479 513 * uses the smallest state value possible, saving the cost of this symbol */
480 514 MEM_STATIC void FSE_initCState2(FSE_CState_t* statePtr, const FSE_CTable* ct, U32 symbol)
481 515 {
482 516 FSE_initCState(statePtr, ct);
483 517 { const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
484 518 const U16* stateTable = (const U16*)(statePtr->stateTable);
485 519 U32 nbBitsOut = (U32)((symbolTT.deltaNbBits + (1<<15)) >> 16);
486 520 statePtr->value = (nbBitsOut << 16) - symbolTT.deltaNbBits;
487 521 statePtr->value = stateTable[(statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
488 522 }
489 523 }
490 524
491 525 MEM_STATIC void FSE_encodeSymbol(BIT_CStream_t* bitC, FSE_CState_t* statePtr, U32 symbol)
492 526 {
493 527 const FSE_symbolCompressionTransform symbolTT = ((const FSE_symbolCompressionTransform*)(statePtr->symbolTT))[symbol];
494 528 const U16* const stateTable = (const U16*)(statePtr->stateTable);
495 529 U32 nbBitsOut = (U32)((statePtr->value + symbolTT.deltaNbBits) >> 16);
496 530 BIT_addBits(bitC, statePtr->value, nbBitsOut);
497 531 statePtr->value = stateTable[ (statePtr->value >> nbBitsOut) + symbolTT.deltaFindState];
498 532 }
499 533
500 534 MEM_STATIC void FSE_flushCState(BIT_CStream_t* bitC, const FSE_CState_t* statePtr)
501 535 {
502 536 BIT_addBits(bitC, statePtr->value, statePtr->stateLog);
503 537 BIT_flushBits(bitC);
504 538 }
505 539
506 540
507 541 /* ====== Decompression ====== */
508 542
509 543 typedef struct {
510 544 U16 tableLog;
511 545 U16 fastMode;
512 546 } FSE_DTableHeader; /* sizeof U32 */
513 547
514 548 typedef struct
515 549 {
516 550 unsigned short newState;
517 551 unsigned char symbol;
518 552 unsigned char nbBits;
519 553 } FSE_decode_t; /* size == U32 */
520 554
521 555 MEM_STATIC void FSE_initDState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD, const FSE_DTable* dt)
522 556 {
523 557 const void* ptr = dt;
524 558 const FSE_DTableHeader* const DTableH = (const FSE_DTableHeader*)ptr;
525 559 DStatePtr->state = BIT_readBits(bitD, DTableH->tableLog);
526 560 BIT_reloadDStream(bitD);
527 561 DStatePtr->table = dt + 1;
528 562 }
529 563
530 564 MEM_STATIC BYTE FSE_peekSymbol(const FSE_DState_t* DStatePtr)
531 565 {
532 566 FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
533 567 return DInfo.symbol;
534 568 }
535 569
536 570 MEM_STATIC void FSE_updateState(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
537 571 {
538 572 FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
539 573 U32 const nbBits = DInfo.nbBits;
540 574 size_t const lowBits = BIT_readBits(bitD, nbBits);
541 575 DStatePtr->state = DInfo.newState + lowBits;
542 576 }
543 577
544 578 MEM_STATIC BYTE FSE_decodeSymbol(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
545 579 {
546 580 FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
547 581 U32 const nbBits = DInfo.nbBits;
548 582 BYTE const symbol = DInfo.symbol;
549 583 size_t const lowBits = BIT_readBits(bitD, nbBits);
550 584
551 585 DStatePtr->state = DInfo.newState + lowBits;
552 586 return symbol;
553 587 }
554 588
555 589 /*! FSE_decodeSymbolFast() :
556 590 unsafe, only works if no symbol has a probability > 50% */
557 591 MEM_STATIC BYTE FSE_decodeSymbolFast(FSE_DState_t* DStatePtr, BIT_DStream_t* bitD)
558 592 {
559 593 FSE_decode_t const DInfo = ((const FSE_decode_t*)(DStatePtr->table))[DStatePtr->state];
560 594 U32 const nbBits = DInfo.nbBits;
561 595 BYTE const symbol = DInfo.symbol;
562 596 size_t const lowBits = BIT_readBitsFast(bitD, nbBits);
563 597
564 598 DStatePtr->state = DInfo.newState + lowBits;
565 599 return symbol;
566 600 }
567 601
568 602 MEM_STATIC unsigned FSE_endOfDState(const FSE_DState_t* DStatePtr)
569 603 {
570 604 return DStatePtr->state == 0;
571 605 }
572 606
573 607
574 608
575 609 #ifndef FSE_COMMONDEFS_ONLY
576 610
577 611 /* **************************************************************
578 612 * Tuning parameters
579 613 ****************************************************************/
580 614 /*!MEMORY_USAGE :
581 615 * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
582 616 * Increasing memory usage improves compression ratio
583 617 * Reduced memory usage can improve speed, due to cache effect
584 618 * Recommended max value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */
585 619 #ifndef FSE_MAX_MEMORY_USAGE
586 620 # define FSE_MAX_MEMORY_USAGE 14
587 621 #endif
588 622 #ifndef FSE_DEFAULT_MEMORY_USAGE
589 623 # define FSE_DEFAULT_MEMORY_USAGE 13
590 624 #endif
591 625
592 626 /*!FSE_MAX_SYMBOL_VALUE :
593 627 * Maximum symbol value authorized.
594 628 * Required for proper stack allocation */
595 629 #ifndef FSE_MAX_SYMBOL_VALUE
596 630 # define FSE_MAX_SYMBOL_VALUE 255
597 631 #endif
598 632
599 633 /* **************************************************************
600 634 * template functions type & suffix
601 635 ****************************************************************/
602 636 #define FSE_FUNCTION_TYPE BYTE
603 637 #define FSE_FUNCTION_EXTENSION
604 638 #define FSE_DECODE_TYPE FSE_decode_t
605 639
606 640
607 641 #endif /* !FSE_COMMONDEFS_ONLY */
608 642
609 643
610 644 /* ***************************************************************
611 645 * Constants
612 646 *****************************************************************/
613 647 #define FSE_MAX_TABLELOG (FSE_MAX_MEMORY_USAGE-2)
614 648 #define FSE_MAX_TABLESIZE (1U<<FSE_MAX_TABLELOG)
615 649 #define FSE_MAXTABLESIZE_MASK (FSE_MAX_TABLESIZE-1)
616 650 #define FSE_DEFAULT_TABLELOG (FSE_DEFAULT_MEMORY_USAGE-2)
617 651 #define FSE_MIN_TABLELOG 5
618 652
619 653 #define FSE_TABLELOG_ABSOLUTE_MAX 15
620 654 #if FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX
621 655 # error "FSE_MAX_TABLELOG > FSE_TABLELOG_ABSOLUTE_MAX is not supported"
622 656 #endif
623 657
624 658 #define FSE_TABLESTEP(tableSize) ((tableSize>>1) + (tableSize>>3) + 3)
625 659
626 660
627 661 #endif /* FSE_STATIC_LINKING_ONLY */
628 662
629 663
630 664 #if defined (__cplusplus)
631 665 }
632 666 #endif
633 667
634 668 #endif /* FSE_H */
@@ -1,329 +1,329 b''
1 1 /* ******************************************************************
2 2 FSE : Finite State Entropy decoder
3 3 Copyright (C) 2013-2015, Yann Collet.
4 4
5 5 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6 6
7 7 Redistribution and use in source and binary forms, with or without
8 8 modification, are permitted provided that the following conditions are
9 9 met:
10 10
11 11 * Redistributions of source code must retain the above copyright
12 12 notice, this list of conditions and the following disclaimer.
13 13 * Redistributions in binary form must reproduce the above
14 14 copyright notice, this list of conditions and the following disclaimer
15 15 in the documentation and/or other materials provided with the
16 16 distribution.
17 17
18 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 30 You can contact the author at :
31 31 - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
32 32 - Public forum : https://groups.google.com/forum/#!forum/lz4c
33 33 ****************************************************************** */
34 34
35 35
36 36 /* **************************************************************
37 37 * Compiler specifics
38 38 ****************************************************************/
39 39 #ifdef _MSC_VER /* Visual Studio */
40 40 # define FORCE_INLINE static __forceinline
41 41 # include <intrin.h> /* For Visual 2005 */
42 42 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
43 43 # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */
44 44 #else
45 45 # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
46 46 # ifdef __GNUC__
47 47 # define FORCE_INLINE static inline __attribute__((always_inline))
48 48 # else
49 49 # define FORCE_INLINE static inline
50 50 # endif
51 51 # else
52 52 # define FORCE_INLINE static
53 53 # endif /* __STDC_VERSION__ */
54 54 #endif
55 55
56 56
57 57 /* **************************************************************
58 58 * Includes
59 59 ****************************************************************/
60 60 #include <stdlib.h> /* malloc, free, qsort */
61 61 #include <string.h> /* memcpy, memset */
62 62 #include <stdio.h> /* printf (debug) */
63 63 #include "bitstream.h"
64 64 #define FSE_STATIC_LINKING_ONLY
65 65 #include "fse.h"
66 66
67 67
68 68 /* **************************************************************
69 69 * Error Management
70 70 ****************************************************************/
71 71 #define FSE_isError ERR_isError
72 72 #define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
73 73
74 74 /* check and forward error code */
75 75 #define CHECK_F(f) { size_t const e = f; if (FSE_isError(e)) return e; }
76 76
77 77
78 78 /* **************************************************************
79 * Complex types
80 ****************************************************************/
81 typedef U32 DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
82
83
84 /* **************************************************************
85 79 * Templates
86 80 ****************************************************************/
87 81 /*
88 82 designed to be included
89 83 for type-specific functions (template emulation in C)
90 84 Objective is to write these functions only once, for improved maintenance
91 85 */
92 86
93 87 /* safety checks */
94 88 #ifndef FSE_FUNCTION_EXTENSION
95 89 # error "FSE_FUNCTION_EXTENSION must be defined"
96 90 #endif
97 91 #ifndef FSE_FUNCTION_TYPE
98 92 # error "FSE_FUNCTION_TYPE must be defined"
99 93 #endif
100 94
101 95 /* Function names */
102 96 #define FSE_CAT(X,Y) X##Y
103 97 #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
104 98 #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
105 99
106 100
107 101 /* Function templates */
108 102 FSE_DTable* FSE_createDTable (unsigned tableLog)
109 103 {
110 104 if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
111 105 return (FSE_DTable*)malloc( FSE_DTABLE_SIZE_U32(tableLog) * sizeof (U32) );
112 106 }
113 107
114 108 void FSE_freeDTable (FSE_DTable* dt)
115 109 {
116 110 free(dt);
117 111 }
118 112
119 113 size_t FSE_buildDTable(FSE_DTable* dt, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
120 114 {
121 115 void* const tdPtr = dt+1; /* because *dt is unsigned, 32-bits aligned on 32-bits */
122 116 FSE_DECODE_TYPE* const tableDecode = (FSE_DECODE_TYPE*) (tdPtr);
123 117 U16 symbolNext[FSE_MAX_SYMBOL_VALUE+1];
124 118
125 119 U32 const maxSV1 = maxSymbolValue + 1;
126 120 U32 const tableSize = 1 << tableLog;
127 121 U32 highThreshold = tableSize-1;
128 122
129 123 /* Sanity Checks */
130 124 if (maxSymbolValue > FSE_MAX_SYMBOL_VALUE) return ERROR(maxSymbolValue_tooLarge);
131 125 if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
132 126
133 127 /* Init, lay down lowprob symbols */
134 128 { FSE_DTableHeader DTableH;
135 129 DTableH.tableLog = (U16)tableLog;
136 130 DTableH.fastMode = 1;
137 131 { S16 const largeLimit= (S16)(1 << (tableLog-1));
138 132 U32 s;
139 133 for (s=0; s<maxSV1; s++) {
140 134 if (normalizedCounter[s]==-1) {
141 135 tableDecode[highThreshold--].symbol = (FSE_FUNCTION_TYPE)s;
142 136 symbolNext[s] = 1;
143 137 } else {
144 138 if (normalizedCounter[s] >= largeLimit) DTableH.fastMode=0;
145 139 symbolNext[s] = normalizedCounter[s];
146 140 } } }
147 141 memcpy(dt, &DTableH, sizeof(DTableH));
148 142 }
149 143
150 144 /* Spread symbols */
151 145 { U32 const tableMask = tableSize-1;
152 146 U32 const step = FSE_TABLESTEP(tableSize);
153 147 U32 s, position = 0;
154 148 for (s=0; s<maxSV1; s++) {
155 149 int i;
156 150 for (i=0; i<normalizedCounter[s]; i++) {
157 151 tableDecode[position].symbol = (FSE_FUNCTION_TYPE)s;
158 152 position = (position + step) & tableMask;
159 153 while (position > highThreshold) position = (position + step) & tableMask; /* lowprob area */
160 154 } }
161 155 if (position!=0) return ERROR(GENERIC); /* position must reach all cells once, otherwise normalizedCounter is incorrect */
162 156 }
163 157
164 158 /* Build Decoding table */
165 159 { U32 u;
166 160 for (u=0; u<tableSize; u++) {
167 161 FSE_FUNCTION_TYPE const symbol = (FSE_FUNCTION_TYPE)(tableDecode[u].symbol);
168 162 U16 nextState = symbolNext[symbol]++;
169 163 tableDecode[u].nbBits = (BYTE) (tableLog - BIT_highbit32 ((U32)nextState) );
170 164 tableDecode[u].newState = (U16) ( (nextState << tableDecode[u].nbBits) - tableSize);
171 165 } }
172 166
173 167 return 0;
174 168 }
175 169
176 170
177 171 #ifndef FSE_COMMONDEFS_ONLY
178 172
179 173 /*-*******************************************************
180 174 * Decompression (Byte symbols)
181 175 *********************************************************/
182 176 size_t FSE_buildDTable_rle (FSE_DTable* dt, BYTE symbolValue)
183 177 {
184 178 void* ptr = dt;
185 179 FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
186 180 void* dPtr = dt + 1;
187 181 FSE_decode_t* const cell = (FSE_decode_t*)dPtr;
188 182
189 183 DTableH->tableLog = 0;
190 184 DTableH->fastMode = 0;
191 185
192 186 cell->newState = 0;
193 187 cell->symbol = symbolValue;
194 188 cell->nbBits = 0;
195 189
196 190 return 0;
197 191 }
198 192
199 193
200 194 size_t FSE_buildDTable_raw (FSE_DTable* dt, unsigned nbBits)
201 195 {
202 196 void* ptr = dt;
203 197 FSE_DTableHeader* const DTableH = (FSE_DTableHeader*)ptr;
204 198 void* dPtr = dt + 1;
205 199 FSE_decode_t* const dinfo = (FSE_decode_t*)dPtr;
206 200 const unsigned tableSize = 1 << nbBits;
207 201 const unsigned tableMask = tableSize - 1;
208 202 const unsigned maxSV1 = tableMask+1;
209 203 unsigned s;
210 204
211 205 /* Sanity checks */
212 206 if (nbBits < 1) return ERROR(GENERIC); /* min size */
213 207
214 208 /* Build Decoding Table */
215 209 DTableH->tableLog = (U16)nbBits;
216 210 DTableH->fastMode = 1;
217 211 for (s=0; s<maxSV1; s++) {
218 212 dinfo[s].newState = 0;
219 213 dinfo[s].symbol = (BYTE)s;
220 214 dinfo[s].nbBits = (BYTE)nbBits;
221 215 }
222 216
223 217 return 0;
224 218 }
225 219
226 220 FORCE_INLINE size_t FSE_decompress_usingDTable_generic(
227 221 void* dst, size_t maxDstSize,
228 222 const void* cSrc, size_t cSrcSize,
229 223 const FSE_DTable* dt, const unsigned fast)
230 224 {
231 225 BYTE* const ostart = (BYTE*) dst;
232 226 BYTE* op = ostart;
233 227 BYTE* const omax = op + maxDstSize;
234 228 BYTE* const olimit = omax-3;
235 229
236 230 BIT_DStream_t bitD;
237 231 FSE_DState_t state1;
238 232 FSE_DState_t state2;
239 233
240 234 /* Init */
241 235 CHECK_F(BIT_initDStream(&bitD, cSrc, cSrcSize));
242 236
243 237 FSE_initDState(&state1, &bitD, dt);
244 238 FSE_initDState(&state2, &bitD, dt);
245 239
246 240 #define FSE_GETSYMBOL(statePtr) fast ? FSE_decodeSymbolFast(statePtr, &bitD) : FSE_decodeSymbol(statePtr, &bitD)
247 241
248 242 /* 4 symbols per loop */
249 243 for ( ; (BIT_reloadDStream(&bitD)==BIT_DStream_unfinished) & (op<olimit) ; op+=4) {
250 244 op[0] = FSE_GETSYMBOL(&state1);
251 245
252 246 if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
253 247 BIT_reloadDStream(&bitD);
254 248
255 249 op[1] = FSE_GETSYMBOL(&state2);
256 250
257 251 if (FSE_MAX_TABLELOG*4+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
258 252 { if (BIT_reloadDStream(&bitD) > BIT_DStream_unfinished) { op+=2; break; } }
259 253
260 254 op[2] = FSE_GETSYMBOL(&state1);
261 255
262 256 if (FSE_MAX_TABLELOG*2+7 > sizeof(bitD.bitContainer)*8) /* This test must be static */
263 257 BIT_reloadDStream(&bitD);
264 258
265 259 op[3] = FSE_GETSYMBOL(&state2);
266 260 }
267 261
268 262 /* tail */
269 263 /* note : BIT_reloadDStream(&bitD) >= FSE_DStream_partiallyFilled; Ends at exactly BIT_DStream_completed */
270 264 while (1) {
271 265 if (op>(omax-2)) return ERROR(dstSize_tooSmall);
272 266 *op++ = FSE_GETSYMBOL(&state1);
273 267 if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
274 268 *op++ = FSE_GETSYMBOL(&state2);
275 269 break;
276 270 }
277 271
278 272 if (op>(omax-2)) return ERROR(dstSize_tooSmall);
279 273 *op++ = FSE_GETSYMBOL(&state2);
280 274 if (BIT_reloadDStream(&bitD)==BIT_DStream_overflow) {
281 275 *op++ = FSE_GETSYMBOL(&state1);
282 276 break;
283 277 } }
284 278
285 279 return op-ostart;
286 280 }
287 281
288 282
289 283 size_t FSE_decompress_usingDTable(void* dst, size_t originalSize,
290 284 const void* cSrc, size_t cSrcSize,
291 285 const FSE_DTable* dt)
292 286 {
293 287 const void* ptr = dt;
294 288 const FSE_DTableHeader* DTableH = (const FSE_DTableHeader*)ptr;
295 289 const U32 fastMode = DTableH->fastMode;
296 290
297 291 /* select fast mode (static) */
298 292 if (fastMode) return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 1);
299 293 return FSE_decompress_usingDTable_generic(dst, originalSize, cSrc, cSrcSize, dt, 0);
300 294 }
301 295
302 296
303 size_t FSE_decompress(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize)
297 size_t FSE_decompress_wksp(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize, FSE_DTable* workSpace, unsigned maxLog)
304 298 {
305 299 const BYTE* const istart = (const BYTE*)cSrc;
306 300 const BYTE* ip = istart;
307 301 short counting[FSE_MAX_SYMBOL_VALUE+1];
308 DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */
309 302 unsigned tableLog;
310 303 unsigned maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
311 304
312 if (cSrcSize<2) return ERROR(srcSize_wrong); /* too small input size */
305 /* normal FSE decoding mode */
306 size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
307 if (FSE_isError(NCountLength)) return NCountLength;
308 //if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size; supposed to be already checked in NCountLength, only remaining case : NCountLength==cSrcSize */
309 if (tableLog > maxLog) return ERROR(tableLog_tooLarge);
310 ip += NCountLength;
311 cSrcSize -= NCountLength;
312
313 CHECK_F( FSE_buildDTable (workSpace, counting, maxSymbolValue, tableLog) );
313 314
314 /* normal FSE decoding mode */
315 { size_t const NCountLength = FSE_readNCount (counting, &maxSymbolValue, &tableLog, istart, cSrcSize);
316 if (FSE_isError(NCountLength)) return NCountLength;
317 if (NCountLength >= cSrcSize) return ERROR(srcSize_wrong); /* too small input size */
318 ip += NCountLength;
319 cSrcSize -= NCountLength;
320 }
315 return FSE_decompress_usingDTable (dst, dstCapacity, ip, cSrcSize, workSpace); /* always return, even if it is an error code */
316 }
317
321 318
322 CHECK_F( FSE_buildDTable (dt, counting, maxSymbolValue, tableLog) );
319 typedef FSE_DTable DTable_max_t[FSE_DTABLE_SIZE_U32(FSE_MAX_TABLELOG)];
323 320
324 return FSE_decompress_usingDTable (dst, maxDstSize, ip, cSrcSize, dt); /* always return, even if it is an error code */
321 size_t FSE_decompress(void* dst, size_t dstCapacity, const void* cSrc, size_t cSrcSize)
322 {
323 DTable_max_t dt; /* Static analyzer seems unable to understand this table will be properly initialized later */
324 return FSE_decompress_wksp(dst, dstCapacity, cSrc, cSrcSize, dt, FSE_MAX_TABLELOG);
325 325 }
326 326
327 327
328 328
329 329 #endif /* FSE_COMMONDEFS_ONLY */
@@ -1,228 +1,238 b''
1 1 /* ******************************************************************
2 2 Huffman coder, part of New Generation Entropy library
3 3 header file
4 4 Copyright (C) 2013-2016, Yann Collet.
5 5
6 6 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
7 7
8 8 Redistribution and use in source and binary forms, with or without
9 9 modification, are permitted provided that the following conditions are
10 10 met:
11 11
12 12 * Redistributions of source code must retain the above copyright
13 13 notice, this list of conditions and the following disclaimer.
14 14 * Redistributions in binary form must reproduce the above
15 15 copyright notice, this list of conditions and the following disclaimer
16 16 in the documentation and/or other materials provided with the
17 17 distribution.
18 18
19 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 23 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 25 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 27 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 30
31 31 You can contact the author at :
32 32 - Source repository : https://github.com/Cyan4973/FiniteStateEntropy
33 33 ****************************************************************** */
34 34 #ifndef HUF_H_298734234
35 35 #define HUF_H_298734234
36 36
37 37 #if defined (__cplusplus)
38 38 extern "C" {
39 39 #endif
40 40
41 41
42 42 /* *** Dependencies *** */
43 43 #include <stddef.h> /* size_t */
44 44
45 45
46 46 /* *** simple functions *** */
47 47 /**
48 48 HUF_compress() :
49 49 Compress content from buffer 'src', of size 'srcSize', into buffer 'dst'.
50 50 'dst' buffer must be already allocated.
51 51 Compression runs faster if `dstCapacity` >= HUF_compressBound(srcSize).
52 52 `srcSize` must be <= `HUF_BLOCKSIZE_MAX` == 128 KB.
53 53 @return : size of compressed data (<= `dstCapacity`).
54 54 Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!!
55 55 if return == 1, srcData is a single repeated byte symbol (RLE compression).
56 56 if HUF_isError(return), compression failed (more details using HUF_getErrorName())
57 57 */
58 58 size_t HUF_compress(void* dst, size_t dstCapacity,
59 59 const void* src, size_t srcSize);
60 60
61 61 /**
62 62 HUF_decompress() :
63 63 Decompress HUF data from buffer 'cSrc', of size 'cSrcSize',
64 64 into already allocated buffer 'dst', of minimum size 'dstSize'.
65 `dstSize` : **must** be the ***exact*** size of original (uncompressed) data.
65 `originalSize` : **must** be the ***exact*** size of original (uncompressed) data.
66 66 Note : in contrast with FSE, HUF_decompress can regenerate
67 67 RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data,
68 68 because it knows size to regenerate.
69 @return : size of regenerated data (== dstSize),
69 @return : size of regenerated data (== originalSize),
70 70 or an error code, which can be tested using HUF_isError()
71 71 */
72 size_t HUF_decompress(void* dst, size_t dstSize,
72 size_t HUF_decompress(void* dst, size_t originalSize,
73 73 const void* cSrc, size_t cSrcSize);
74 74
75 75
76 /* ****************************************
77 * Tool functions
78 ******************************************/
79 #define HUF_BLOCKSIZE_MAX (128 * 1024)
76 /* *** Tool functions *** */
77 #define HUF_BLOCKSIZE_MAX (128 * 1024) /**< maximum input size for a single block compressed with HUF_compress */
80 78 size_t HUF_compressBound(size_t size); /**< maximum compressed size (worst case) */
81 79
82 80 /* Error Management */
83 81 unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */
84 82 const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */
85 83
86 84
87 /* *** Advanced function *** */
85 /* *** Advanced function *** */
88 86
89 87 /** HUF_compress2() :
90 * Same as HUF_compress(), but offers direct control over `maxSymbolValue` and `tableLog` */
88 * Same as HUF_compress(), but offers direct control over `maxSymbolValue` and `tableLog` .
89 * `tableLog` must be `<= HUF_TABLELOG_MAX` . */
91 90 size_t HUF_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
92 91
92 /** HUF_compress4X_wksp() :
93 * Same as HUF_compress2(), but uses externally allocated `workSpace`, which must be a table of >= 1024 unsigned */
94 size_t HUF_compress4X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least 1024 unsigned */
95
96
93 97
94 98 #ifdef HUF_STATIC_LINKING_ONLY
95 99
96 100 /* *** Dependencies *** */
97 101 #include "mem.h" /* U32 */
98 102
99 103
100 104 /* *** Constants *** */
101 #define HUF_TABLELOG_ABSOLUTEMAX 16 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
105 #define HUF_TABLELOG_ABSOLUTEMAX 15 /* absolute limit of HUF_MAX_TABLELOG. Beyond that value, code does not work */
102 106 #define HUF_TABLELOG_MAX 12 /* max configured tableLog (for static allocation); can be modified up to HUF_ABSOLUTEMAX_TABLELOG */
103 107 #define HUF_TABLELOG_DEFAULT 11 /* tableLog by default, when not specified */
104 108 #define HUF_SYMBOLVALUE_MAX 255
105 109 #if (HUF_TABLELOG_MAX > HUF_TABLELOG_ABSOLUTEMAX)
106 110 # error "HUF_TABLELOG_MAX is too large !"
107 111 #endif
108 112
109 113
110 114 /* ****************************************
111 115 * Static allocation
112 116 ******************************************/
113 117 /* HUF buffer bounds */
114 118 #define HUF_CTABLEBOUND 129
115 119 #define HUF_BLOCKBOUND(size) (size + (size>>8) + 8) /* only true if incompressible pre-filtered with fast heuristic */
116 120 #define HUF_COMPRESSBOUND(size) (HUF_CTABLEBOUND + HUF_BLOCKBOUND(size)) /* Macro version, useful for static allocation */
117 121
118 122 /* static allocation of HUF's Compression Table */
119 123 #define HUF_CREATE_STATIC_CTABLE(name, maxSymbolValue) \
120 124 U32 name##hb[maxSymbolValue+1]; \
121 125 void* name##hv = &(name##hb); \
122 126 HUF_CElt* name = (HUF_CElt*)(name##hv) /* no final ; */
123 127
124 128 /* static allocation of HUF's DTable */
125 129 typedef U32 HUF_DTable;
126 130 #define HUF_DTABLE_SIZE(maxTableLog) (1 + (1<<(maxTableLog)))
127 131 #define HUF_CREATE_STATIC_DTABLEX2(DTable, maxTableLog) \
128 HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1)*0x1000001) }
132 HUF_DTable DTable[HUF_DTABLE_SIZE((maxTableLog)-1)] = { ((U32)((maxTableLog)-1) * 0x01000001) }
129 133 #define HUF_CREATE_STATIC_DTABLEX4(DTable, maxTableLog) \
130 HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog)*0x1000001) }
134 HUF_DTable DTable[HUF_DTABLE_SIZE(maxTableLog)] = { ((U32)(maxTableLog) * 0x01000001) }
131 135
132 136
133 137 /* ****************************************
134 138 * Advanced decompression functions
135 139 ******************************************/
136 140 size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
137 141 size_t HUF_decompress4X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
138 142
139 143 size_t HUF_decompress4X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< decodes RLE and uncompressed */
140 144 size_t HUF_decompress4X_hufOnly(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< considers RLE and uncompressed as errors */
141 145 size_t HUF_decompress4X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
142 146 size_t HUF_decompress4X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
143 147
144 size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
145 size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
146 size_t HUF_decompress1X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
147
148 148
149 149 /* ****************************************
150 150 * HUF detailed API
151 151 ******************************************/
152 152 /*!
153 153 HUF_compress() does the following:
154 154 1. count symbol occurrence from source[] into table count[] using FSE_count()
155 155 2. (optional) refine tableLog using HUF_optimalTableLog()
156 156 3. build Huffman table from count using HUF_buildCTable()
157 157 4. save Huffman table to memory buffer using HUF_writeCTable()
158 158 5. encode the data stream using HUF_compress4X_usingCTable()
159 159
160 160 The following API allows targeting specific sub-functions for advanced tasks.
161 161 For example, it's possible to compress several blocks using the same 'CTable',
162 162 or to save and regenerate 'CTable' using external methods.
163 163 */
164 164 /* FSE_count() : find it within "fse.h" */
165 165 unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue);
166 166 typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */
167 167 size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits);
168 168 size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog);
169 169 size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
170 170
171 171
172 /** HUF_buildCTable_wksp() :
173 * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
174 * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
175 */
176 size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize);
177
172 178 /*! HUF_readStats() :
173 179 Read compact Huffman tree, saved by HUF_writeCTable().
174 180 `huffWeight` is destination buffer.
175 181 @return : size read from `src` , or an error Code .
176 182 Note : Needed by HUF_readCTable() and HUF_readDTableXn() . */
177 183 size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats,
178 184 U32* nbSymbolsPtr, U32* tableLogPtr,
179 185 const void* src, size_t srcSize);
180 186
181 187 /** HUF_readCTable() :
182 188 * Loading a CTable saved with HUF_writeCTable() */
183 189 size_t HUF_readCTable (HUF_CElt* CTable, unsigned maxSymbolValue, const void* src, size_t srcSize);
184 190
185 191
186 192 /*
187 193 HUF_decompress() does the following:
188 194 1. select the decompression algorithm (X2, X4) based on pre-computed heuristics
189 195 2. build Huffman table from save, using HUF_readDTableXn()
190 196 3. decode 1 or 4 segments in parallel using HUF_decompressSXn_usingDTable
191 197 */
192 198
193 199 /** HUF_selectDecoder() :
194 200 * Tells which decoder is likely to decode faster,
195 201 * based on a set of pre-determined metrics.
196 202 * @return : 0==HUF_decompress4X2, 1==HUF_decompress4X4 .
197 203 * Assumption : 0 < cSrcSize < dstSize <= 128 KB */
198 204 U32 HUF_selectDecoder (size_t dstSize, size_t cSrcSize);
199 205
200 206 size_t HUF_readDTableX2 (HUF_DTable* DTable, const void* src, size_t srcSize);
201 207 size_t HUF_readDTableX4 (HUF_DTable* DTable, const void* src, size_t srcSize);
202 208
203 209 size_t HUF_decompress4X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
204 210 size_t HUF_decompress4X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
205 211 size_t HUF_decompress4X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
206 212
207 213
208 214 /* single stream variants */
209 215
210 216 size_t HUF_compress1X (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog);
217 size_t HUF_compress1X_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize); /**< `workSpace` must be a table of at least 1024 unsigned */
211 218 size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable);
212 219
213 220 size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
214 221 size_t HUF_decompress1X4 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* double-symbol decoder */
215 222
216 size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
223 size_t HUF_decompress1X_DCtx (HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize);
224 size_t HUF_decompress1X2_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< single-symbol decoder */
225 size_t HUF_decompress1X4_DCtx(HUF_DTable* dctx, void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /**< double-symbols decoder */
226
227 size_t HUF_decompress1X_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable); /**< automatic selection of sing or double symbol decoder, based on DTable */
217 228 size_t HUF_decompress1X2_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
218 229 size_t HUF_decompress1X4_usingDTable(void* dst, size_t maxDstSize, const void* cSrc, size_t cSrcSize, const HUF_DTable* DTable);
219 230
220
221 231 #endif /* HUF_STATIC_LINKING_ONLY */
222 232
223 233
224 234 #if defined (__cplusplus)
225 235 }
226 236 #endif
227 237
228 238 #endif /* HUF_H_298734234 */
@@ -1,370 +1,372 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 3 * All rights reserved.
4 4 *
5 5 * This source code is licensed under the BSD-style license found in the
6 6 * LICENSE file in the root directory of this source tree. An additional grant
7 7 * of patent rights can be found in the PATENTS file in the same directory.
8 8 */
9 9
10 10 #ifndef MEM_H_MODULE
11 11 #define MEM_H_MODULE
12 12
13 13 #if defined (__cplusplus)
14 14 extern "C" {
15 15 #endif
16 16
17 17 /*-****************************************
18 18 * Dependencies
19 19 ******************************************/
20 20 #include <stddef.h> /* size_t, ptrdiff_t */
21 21 #include <string.h> /* memcpy */
22 22
23 23
24 24 /*-****************************************
25 25 * Compiler specifics
26 26 ******************************************/
27 27 #if defined(_MSC_VER) /* Visual Studio */
28 28 # include <stdlib.h> /* _byteswap_ulong */
29 29 # include <intrin.h> /* _byteswap_* */
30 30 #endif
31 31 #if defined(__GNUC__)
32 32 # define MEM_STATIC static __inline __attribute__((unused))
33 33 #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
34 34 # define MEM_STATIC static inline
35 35 #elif defined(_MSC_VER)
36 36 # define MEM_STATIC static __inline
37 37 #else
38 38 # define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */
39 39 #endif
40 40
41 41 /* code only tested on 32 and 64 bits systems */
42 42 #define MEM_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(int)(!!(c)) }; }
43 43 MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); }
44 44
45 45
46 46 /*-**************************************************************
47 47 * Basic Types
48 48 *****************************************************************/
49 49 #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )
50 50 # include <stdint.h>
51 51 typedef uint8_t BYTE;
52 52 typedef uint16_t U16;
53 53 typedef int16_t S16;
54 54 typedef uint32_t U32;
55 55 typedef int32_t S32;
56 56 typedef uint64_t U64;
57 57 typedef int64_t S64;
58 typedef intptr_t iPtrDiff;
58 59 #else
59 typedef unsigned char BYTE;
60 typedef unsigned char BYTE;
60 61 typedef unsigned short U16;
61 62 typedef signed short S16;
62 63 typedef unsigned int U32;
63 64 typedef signed int S32;
64 65 typedef unsigned long long U64;
65 66 typedef signed long long S64;
67 typedef ptrdiff_t iPtrDiff;
66 68 #endif
67 69
68 70
69 71 /*-**************************************************************
70 72 * Memory I/O
71 73 *****************************************************************/
72 74 /* MEM_FORCE_MEMORY_ACCESS :
73 75 * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.
74 76 * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.
75 77 * The below switch allow to select different access method for improved performance.
76 78 * Method 0 (default) : use `memcpy()`. Safe and portable.
77 79 * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).
78 80 * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.
79 81 * Method 2 : direct access. This method is portable but violate C standard.
80 82 * It can generate buggy code on targets depending on alignment.
81 83 * In some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)
82 84 * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.
83 85 * Prefer these methods in priority order (0 > 1 > 2)
84 86 */
85 87 #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
86 88 # if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )
87 89 # define MEM_FORCE_MEMORY_ACCESS 2
88 90 # elif defined(__INTEL_COMPILER) /*|| defined(_MSC_VER)*/ || \
89 91 (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) ))
90 92 # define MEM_FORCE_MEMORY_ACCESS 1
91 93 # endif
92 94 #endif
93 95
94 96 MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; }
95 97 MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; }
96 98
97 99 MEM_STATIC unsigned MEM_isLittleEndian(void)
98 100 {
99 101 const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
100 102 return one.c[0];
101 103 }
102 104
103 105 #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2)
104 106
105 107 /* violates C standard, by lying on structure alignment.
106 108 Only use if no other choice to achieve best performance on target platform */
107 109 MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; }
108 110 MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; }
109 111 MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; }
110 112 MEM_STATIC U64 MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; }
111 113
112 114 MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }
113 115 MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }
114 116 MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; }
115 117
116 118 #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1)
117 119
118 120 /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */
119 121 /* currently only defined for gcc and icc */
120 122 #if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32))
121 123 __pragma( pack(push, 1) )
122 124 typedef union { U16 u16; U32 u32; U64 u64; size_t st; } unalign;
123 125 __pragma( pack(pop) )
124 126 #else
125 127 typedef union { U16 u16; U32 u32; U64 u64; size_t st; } __attribute__((packed)) unalign;
126 128 #endif
127 129
128 130 MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign*)ptr)->u16; }
129 131 MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }
130 132 MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign*)ptr)->u64; }
131 133 MEM_STATIC U64 MEM_readST(const void* ptr) { return ((const unalign*)ptr)->st; }
132 134
133 135 MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; }
134 136 MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; }
135 137 MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign*)memPtr)->u64 = value; }
136 138
137 139 #else
138 140
139 141 /* default method, safe and standard.
140 142 can sometimes prove slower */
141 143
142 144 MEM_STATIC U16 MEM_read16(const void* memPtr)
143 145 {
144 146 U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
145 147 }
146 148
147 149 MEM_STATIC U32 MEM_read32(const void* memPtr)
148 150 {
149 151 U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
150 152 }
151 153
152 154 MEM_STATIC U64 MEM_read64(const void* memPtr)
153 155 {
154 156 U64 val; memcpy(&val, memPtr, sizeof(val)); return val;
155 157 }
156 158
157 159 MEM_STATIC size_t MEM_readST(const void* memPtr)
158 160 {
159 161 size_t val; memcpy(&val, memPtr, sizeof(val)); return val;
160 162 }
161 163
162 164 MEM_STATIC void MEM_write16(void* memPtr, U16 value)
163 165 {
164 166 memcpy(memPtr, &value, sizeof(value));
165 167 }
166 168
167 169 MEM_STATIC void MEM_write32(void* memPtr, U32 value)
168 170 {
169 171 memcpy(memPtr, &value, sizeof(value));
170 172 }
171 173
172 174 MEM_STATIC void MEM_write64(void* memPtr, U64 value)
173 175 {
174 176 memcpy(memPtr, &value, sizeof(value));
175 177 }
176 178
177 179 #endif /* MEM_FORCE_MEMORY_ACCESS */
178 180
179 181 MEM_STATIC U32 MEM_swap32(U32 in)
180 182 {
181 183 #if defined(_MSC_VER) /* Visual Studio */
182 184 return _byteswap_ulong(in);
183 185 #elif defined (__GNUC__)
184 186 return __builtin_bswap32(in);
185 187 #else
186 188 return ((in << 24) & 0xff000000 ) |
187 189 ((in << 8) & 0x00ff0000 ) |
188 190 ((in >> 8) & 0x0000ff00 ) |
189 191 ((in >> 24) & 0x000000ff );
190 192 #endif
191 193 }
192 194
193 195 MEM_STATIC U64 MEM_swap64(U64 in)
194 196 {
195 197 #if defined(_MSC_VER) /* Visual Studio */
196 198 return _byteswap_uint64(in);
197 199 #elif defined (__GNUC__)
198 200 return __builtin_bswap64(in);
199 201 #else
200 202 return ((in << 56) & 0xff00000000000000ULL) |
201 203 ((in << 40) & 0x00ff000000000000ULL) |
202 204 ((in << 24) & 0x0000ff0000000000ULL) |
203 205 ((in << 8) & 0x000000ff00000000ULL) |
204 206 ((in >> 8) & 0x00000000ff000000ULL) |
205 207 ((in >> 24) & 0x0000000000ff0000ULL) |
206 208 ((in >> 40) & 0x000000000000ff00ULL) |
207 209 ((in >> 56) & 0x00000000000000ffULL);
208 210 #endif
209 211 }
210 212
211 213 MEM_STATIC size_t MEM_swapST(size_t in)
212 214 {
213 215 if (MEM_32bits())
214 216 return (size_t)MEM_swap32((U32)in);
215 217 else
216 218 return (size_t)MEM_swap64((U64)in);
217 219 }
218 220
219 221 /*=== Little endian r/w ===*/
220 222
221 223 MEM_STATIC U16 MEM_readLE16(const void* memPtr)
222 224 {
223 225 if (MEM_isLittleEndian())
224 226 return MEM_read16(memPtr);
225 227 else {
226 228 const BYTE* p = (const BYTE*)memPtr;
227 229 return (U16)(p[0] + (p[1]<<8));
228 230 }
229 231 }
230 232
231 233 MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val)
232 234 {
233 235 if (MEM_isLittleEndian()) {
234 236 MEM_write16(memPtr, val);
235 237 } else {
236 238 BYTE* p = (BYTE*)memPtr;
237 239 p[0] = (BYTE)val;
238 240 p[1] = (BYTE)(val>>8);
239 241 }
240 242 }
241 243
242 244 MEM_STATIC U32 MEM_readLE24(const void* memPtr)
243 245 {
244 246 return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16);
245 247 }
246 248
247 249 MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val)
248 250 {
249 251 MEM_writeLE16(memPtr, (U16)val);
250 252 ((BYTE*)memPtr)[2] = (BYTE)(val>>16);
251 253 }
252 254
253 255 MEM_STATIC U32 MEM_readLE32(const void* memPtr)
254 256 {
255 257 if (MEM_isLittleEndian())
256 258 return MEM_read32(memPtr);
257 259 else
258 260 return MEM_swap32(MEM_read32(memPtr));
259 261 }
260 262
261 263 MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32)
262 264 {
263 265 if (MEM_isLittleEndian())
264 266 MEM_write32(memPtr, val32);
265 267 else
266 268 MEM_write32(memPtr, MEM_swap32(val32));
267 269 }
268 270
269 271 MEM_STATIC U64 MEM_readLE64(const void* memPtr)
270 272 {
271 273 if (MEM_isLittleEndian())
272 274 return MEM_read64(memPtr);
273 275 else
274 276 return MEM_swap64(MEM_read64(memPtr));
275 277 }
276 278
277 279 MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64)
278 280 {
279 281 if (MEM_isLittleEndian())
280 282 MEM_write64(memPtr, val64);
281 283 else
282 284 MEM_write64(memPtr, MEM_swap64(val64));
283 285 }
284 286
285 287 MEM_STATIC size_t MEM_readLEST(const void* memPtr)
286 288 {
287 289 if (MEM_32bits())
288 290 return (size_t)MEM_readLE32(memPtr);
289 291 else
290 292 return (size_t)MEM_readLE64(memPtr);
291 293 }
292 294
293 295 MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val)
294 296 {
295 297 if (MEM_32bits())
296 298 MEM_writeLE32(memPtr, (U32)val);
297 299 else
298 300 MEM_writeLE64(memPtr, (U64)val);
299 301 }
300 302
301 303 /*=== Big endian r/w ===*/
302 304
303 305 MEM_STATIC U32 MEM_readBE32(const void* memPtr)
304 306 {
305 307 if (MEM_isLittleEndian())
306 308 return MEM_swap32(MEM_read32(memPtr));
307 309 else
308 310 return MEM_read32(memPtr);
309 311 }
310 312
311 313 MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32)
312 314 {
313 315 if (MEM_isLittleEndian())
314 316 MEM_write32(memPtr, MEM_swap32(val32));
315 317 else
316 318 MEM_write32(memPtr, val32);
317 319 }
318 320
319 321 MEM_STATIC U64 MEM_readBE64(const void* memPtr)
320 322 {
321 323 if (MEM_isLittleEndian())
322 324 return MEM_swap64(MEM_read64(memPtr));
323 325 else
324 326 return MEM_read64(memPtr);
325 327 }
326 328
327 329 MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64)
328 330 {
329 331 if (MEM_isLittleEndian())
330 332 MEM_write64(memPtr, MEM_swap64(val64));
331 333 else
332 334 MEM_write64(memPtr, val64);
333 335 }
334 336
335 337 MEM_STATIC size_t MEM_readBEST(const void* memPtr)
336 338 {
337 339 if (MEM_32bits())
338 340 return (size_t)MEM_readBE32(memPtr);
339 341 else
340 342 return (size_t)MEM_readBE64(memPtr);
341 343 }
342 344
343 345 MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val)
344 346 {
345 347 if (MEM_32bits())
346 348 MEM_writeBE32(memPtr, (U32)val);
347 349 else
348 350 MEM_writeBE64(memPtr, (U64)val);
349 351 }
350 352
351 353
352 354 /* function safe only for comparisons */
353 355 MEM_STATIC U32 MEM_readMINMATCH(const void* memPtr, U32 length)
354 356 {
355 357 switch (length)
356 358 {
357 359 default :
358 360 case 4 : return MEM_read32(memPtr);
359 361 case 3 : if (MEM_isLittleEndian())
360 362 return MEM_read32(memPtr)<<8;
361 363 else
362 364 return MEM_read32(memPtr)>>8;
363 365 }
364 366 }
365 367
366 368 #if defined (__cplusplus)
367 369 }
368 370 #endif
369 371
370 372 #endif /* MEM_H_MODULE */
@@ -1,83 +1,77 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 3 * All rights reserved.
4 4 *
5 5 * This source code is licensed under the BSD-style license found in the
6 6 * LICENSE file in the root directory of this source tree. An additional grant
7 7 * of patent rights can be found in the PATENTS file in the same directory.
8 8 */
9 9
10 10
11 11
12 12 /*-*************************************
13 13 * Dependencies
14 14 ***************************************/
15 15 #include <stdlib.h> /* malloc */
16 16 #include "error_private.h"
17 17 #define ZSTD_STATIC_LINKING_ONLY
18 18 #include "zstd.h" /* declaration of ZSTD_isError, ZSTD_getErrorName, ZSTD_getErrorCode, ZSTD_getErrorString, ZSTD_versionNumber */
19 #include "zbuff.h" /* declaration of ZBUFF_isError, ZBUFF_getErrorName */
20 19
21 20
22 21 /*-****************************************
23 22 * Version
24 23 ******************************************/
25 24 unsigned ZSTD_versionNumber (void) { return ZSTD_VERSION_NUMBER; }
26 25
27 26
28 27 /*-****************************************
29 28 * ZSTD Error Management
30 29 ******************************************/
31 30 /*! ZSTD_isError() :
32 31 * tells if a return value is an error code */
33 32 unsigned ZSTD_isError(size_t code) { return ERR_isError(code); }
34 33
35 34 /*! ZSTD_getErrorName() :
36 35 * provides error code string from function result (useful for debugging) */
37 36 const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); }
38 37
39 38 /*! ZSTD_getError() :
40 39 * convert a `size_t` function result into a proper ZSTD_errorCode enum */
41 40 ZSTD_ErrorCode ZSTD_getErrorCode(size_t code) { return ERR_getErrorCode(code); }
42 41
43 42 /*! ZSTD_getErrorString() :
44 43 * provides error code string from enum */
45 44 const char* ZSTD_getErrorString(ZSTD_ErrorCode code) { return ERR_getErrorName(code); }
46 45
47
48 /* **************************************************************
49 * ZBUFF Error Management
50 ****************************************************************/
46 /* --- ZBUFF Error Management (deprecated) --- */
51 47 unsigned ZBUFF_isError(size_t errorCode) { return ERR_isError(errorCode); }
52
53 48 const char* ZBUFF_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
54 49
55 50
56
57 51 /*=**************************************************************
58 52 * Custom allocator
59 53 ****************************************************************/
60 54 /* default uses stdlib */
61 55 void* ZSTD_defaultAllocFunction(void* opaque, size_t size)
62 56 {
63 57 void* address = malloc(size);
64 58 (void)opaque;
65 59 return address;
66 60 }
67 61
68 62 void ZSTD_defaultFreeFunction(void* opaque, void* address)
69 63 {
70 64 (void)opaque;
71 65 free(address);
72 66 }
73 67
74 68 void* ZSTD_malloc(size_t size, ZSTD_customMem customMem)
75 69 {
76 70 return customMem.customAlloc(customMem.opaque, size);
77 71 }
78 72
79 73 void ZSTD_free(void* ptr, ZSTD_customMem customMem)
80 74 {
81 75 if (ptr!=NULL)
82 76 customMem.customFree(customMem.opaque, ptr);
83 77 }
@@ -1,267 +1,270 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 3 * All rights reserved.
4 4 *
5 5 * This source code is licensed under the BSD-style license found in the
6 6 * LICENSE file in the root directory of this source tree. An additional grant
7 7 * of patent rights can be found in the PATENTS file in the same directory.
8 8 */
9 9
10 10 #ifndef ZSTD_CCOMMON_H_MODULE
11 11 #define ZSTD_CCOMMON_H_MODULE
12 12
13 13 /*-*******************************************************
14 14 * Compiler specifics
15 15 *********************************************************/
16 16 #ifdef _MSC_VER /* Visual Studio */
17 17 # define FORCE_INLINE static __forceinline
18 18 # include <intrin.h> /* For Visual 2005 */
19 19 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
20 20 # pragma warning(disable : 4324) /* disable: C4324: padded structure */
21 21 # pragma warning(disable : 4100) /* disable: C4100: unreferenced formal parameter */
22 22 #else
23 23 # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
24 24 # ifdef __GNUC__
25 25 # define FORCE_INLINE static inline __attribute__((always_inline))
26 26 # else
27 27 # define FORCE_INLINE static inline
28 28 # endif
29 29 # else
30 30 # define FORCE_INLINE static
31 31 # endif /* __STDC_VERSION__ */
32 32 #endif
33 33
34 34 #ifdef _MSC_VER
35 35 # define FORCE_NOINLINE static __declspec(noinline)
36 36 #else
37 37 # ifdef __GNUC__
38 38 # define FORCE_NOINLINE static __attribute__((__noinline__))
39 39 # else
40 40 # define FORCE_NOINLINE static
41 41 # endif
42 42 #endif
43 43
44 44
45 45 /*-*************************************
46 46 * Dependencies
47 47 ***************************************/
48 48 #include "mem.h"
49 49 #include "error_private.h"
50 50 #define ZSTD_STATIC_LINKING_ONLY
51 51 #include "zstd.h"
52 52
53 53
54 54 /*-*************************************
55 55 * shared macros
56 56 ***************************************/
57 57 #define MIN(a,b) ((a)<(b) ? (a) : (b))
58 58 #define MAX(a,b) ((a)>(b) ? (a) : (b))
59 59 #define CHECK_F(f) { size_t const errcod = f; if (ERR_isError(errcod)) return errcod; } /* check and Forward error code */
60 60 #define CHECK_E(f, e) { size_t const errcod = f; if (ERR_isError(errcod)) return ERROR(e); } /* check and send Error code */
61 61
62 62
63 63 /*-*************************************
64 64 * Common constants
65 65 ***************************************/
66 66 #define ZSTD_OPT_NUM (1<<12)
67 67 #define ZSTD_DICT_MAGIC 0xEC30A437 /* v0.7+ */
68 68
69 69 #define ZSTD_REP_NUM 3 /* number of repcodes */
70 70 #define ZSTD_REP_CHECK (ZSTD_REP_NUM) /* number of repcodes to check by the optimal parser */
71 71 #define ZSTD_REP_MOVE (ZSTD_REP_NUM-1)
72 72 #define ZSTD_REP_MOVE_OPT (ZSTD_REP_NUM)
73 73 static const U32 repStartValue[ZSTD_REP_NUM] = { 1, 4, 8 };
74 74
75 75 #define KB *(1 <<10)
76 76 #define MB *(1 <<20)
77 77 #define GB *(1U<<30)
78 78
79 79 #define BIT7 128
80 80 #define BIT6 64
81 81 #define BIT5 32
82 82 #define BIT4 16
83 83 #define BIT1 2
84 84 #define BIT0 1
85 85
86 86 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 10
87 87 static const size_t ZSTD_fcs_fieldSize[4] = { 0, 2, 4, 8 };
88 88 static const size_t ZSTD_did_fieldSize[4] = { 0, 1, 2, 4 };
89 89
90 90 #define ZSTD_BLOCKHEADERSIZE 3 /* C standard doesn't allow `static const` variable to be init using another `static const` variable */
91 91 static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE;
92 92 typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
93 93
94 94 #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */
95 95 #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */
96 96
97 97 #define HufLog 12
98 98 typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e;
99 99
100 100 #define LONGNBSEQ 0x7F00
101 101
102 102 #define MINMATCH 3
103 103 #define EQUAL_READ32 4
104 104
105 105 #define Litbits 8
106 106 #define MaxLit ((1<<Litbits) - 1)
107 107 #define MaxML 52
108 108 #define MaxLL 35
109 109 #define MaxOff 28
110 110 #define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */
111 111 #define MLFSELog 9
112 112 #define LLFSELog 9
113 113 #define OffFSELog 8
114 114
115 115 static const U32 LL_bits[MaxLL+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 116 1, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 9,10,11,12,
117 117 13,14,15,16 };
118 118 static const S16 LL_defaultNorm[MaxLL+1] = { 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
119 119 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
120 120 -1,-1,-1,-1 };
121 121 #define LL_DEFAULTNORMLOG 6 /* for static allocation */
122 122 static const U32 LL_defaultNormLog = LL_DEFAULTNORMLOG;
123 123
124 124 static const U32 ML_bits[MaxML+1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125 125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126 126 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 7, 8, 9,10,11,
127 127 12,13,14,15,16 };
128 128 static const S16 ML_defaultNorm[MaxML+1] = { 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
129 129 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
130 130 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,
131 131 -1,-1,-1,-1,-1 };
132 132 #define ML_DEFAULTNORMLOG 6 /* for static allocation */
133 133 static const U32 ML_defaultNormLog = ML_DEFAULTNORMLOG;
134 134
135 135 static const S16 OF_defaultNorm[MaxOff+1] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
136 136 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 };
137 137 #define OF_DEFAULTNORMLOG 5 /* for static allocation */
138 138 static const U32 OF_defaultNormLog = OF_DEFAULTNORMLOG;
139 139
140 140
141 141 /*-*******************************************
142 142 * Shared functions to include for inlining
143 143 *********************************************/
144 144 static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); }
145 145 #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
146 146
147 147 /*! ZSTD_wildcopy() :
148 148 * custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */
149 149 #define WILDCOPY_OVERLENGTH 8
150 MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, size_t length)
150 MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length)
151 151 {
152 152 const BYTE* ip = (const BYTE*)src;
153 153 BYTE* op = (BYTE*)dst;
154 154 BYTE* const oend = op + length;
155 155 do
156 156 COPY8(op, ip)
157 157 while (op < oend);
158 158 }
159 159
160 160 MEM_STATIC void ZSTD_wildcopy_e(void* dst, const void* src, void* dstEnd) /* should be faster for decoding, but strangely, not verified on all platform */
161 161 {
162 162 const BYTE* ip = (const BYTE*)src;
163 163 BYTE* op = (BYTE*)dst;
164 164 BYTE* const oend = (BYTE*)dstEnd;
165 165 do
166 166 COPY8(op, ip)
167 167 while (op < oend);
168 168 }
169 169
170 170
171 171 /*-*******************************************
172 172 * Private interfaces
173 173 *********************************************/
174 174 typedef struct ZSTD_stats_s ZSTD_stats_t;
175 175
176 176 typedef struct {
177 177 U32 off;
178 178 U32 len;
179 179 } ZSTD_match_t;
180 180
181 181 typedef struct {
182 182 U32 price;
183 183 U32 off;
184 184 U32 mlen;
185 185 U32 litlen;
186 186 U32 rep[ZSTD_REP_NUM];
187 187 } ZSTD_optimal_t;
188 188
189 189
190 190 typedef struct seqDef_s {
191 191 U32 offset;
192 192 U16 litLength;
193 193 U16 matchLength;
194 194 } seqDef;
195 195
196 196
197 197 typedef struct {
198 198 seqDef* sequencesStart;
199 199 seqDef* sequences;
200 200 BYTE* litStart;
201 201 BYTE* lit;
202 202 BYTE* llCode;
203 203 BYTE* mlCode;
204 204 BYTE* ofCode;
205 205 U32 longLengthID; /* 0 == no longLength; 1 == Lit.longLength; 2 == Match.longLength; */
206 206 U32 longLengthPos;
207 207 /* opt */
208 208 ZSTD_optimal_t* priceTable;
209 209 ZSTD_match_t* matchTable;
210 210 U32* matchLengthFreq;
211 211 U32* litLengthFreq;
212 212 U32* litFreq;
213 213 U32* offCodeFreq;
214 214 U32 matchLengthSum;
215 215 U32 matchSum;
216 216 U32 litLengthSum;
217 217 U32 litSum;
218 218 U32 offCodeSum;
219 219 U32 log2matchLengthSum;
220 220 U32 log2matchSum;
221 221 U32 log2litLengthSum;
222 222 U32 log2litSum;
223 223 U32 log2offCodeSum;
224 224 U32 factor;
225 U32 staticPrices;
225 226 U32 cachedPrice;
226 227 U32 cachedLitLength;
227 228 const BYTE* cachedLiterals;
228 229 } seqStore_t;
229 230
230 231 const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx);
231 232 void ZSTD_seqToCodes(const seqStore_t* seqStorePtr);
232 233 int ZSTD_isSkipFrame(ZSTD_DCtx* dctx);
233 234
234 235 /* custom memory allocation functions */
235 236 void* ZSTD_defaultAllocFunction(void* opaque, size_t size);
236 237 void ZSTD_defaultFreeFunction(void* opaque, void* address);
238 #ifndef ZSTD_DLL_IMPORT
237 239 static const ZSTD_customMem defaultCustomMem = { ZSTD_defaultAllocFunction, ZSTD_defaultFreeFunction, NULL };
240 #endif
238 241 void* ZSTD_malloc(size_t size, ZSTD_customMem customMem);
239 242 void ZSTD_free(void* ptr, ZSTD_customMem customMem);
240 243
241 244
242 245 /*====== common function ======*/
243 246
244 247 MEM_STATIC U32 ZSTD_highbit32(U32 val)
245 248 {
246 249 # if defined(_MSC_VER) /* Visual */
247 250 unsigned long r=0;
248 251 _BitScanReverse(&r, val);
249 252 return (unsigned)r;
250 253 # elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
251 254 return 31 - __builtin_clz(val);
252 255 # else /* Software version */
253 256 static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
254 257 U32 v = val;
255 258 int r;
256 259 v |= v >> 1;
257 260 v |= v >> 2;
258 261 v |= v >> 4;
259 262 v |= v >> 8;
260 263 v |= v >> 16;
261 264 r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
262 265 return r;
263 266 # endif
264 267 }
265 268
266 269
267 270 #endif /* ZSTD_CCOMMON_H_MODULE */
@@ -1,810 +1,850 b''
1 1 /* ******************************************************************
2 2 FSE : Finite State Entropy encoder
3 3 Copyright (C) 2013-2015, Yann Collet.
4 4
5 5 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6 6
7 7 Redistribution and use in source and binary forms, with or without
8 8 modification, are permitted provided that the following conditions are
9 9 met:
10 10
11 11 * Redistributions of source code must retain the above copyright
12 12 notice, this list of conditions and the following disclaimer.
13 13 * Redistributions in binary form must reproduce the above
14 14 copyright notice, this list of conditions and the following disclaimer
15 15 in the documentation and/or other materials provided with the
16 16 distribution.
17 17
18 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 30 You can contact the author at :
31 31 - FSE source repository : https://github.com/Cyan4973/FiniteStateEntropy
32 32 - Public forum : https://groups.google.com/forum/#!forum/lz4c
33 33 ****************************************************************** */
34 34
35 35 /* **************************************************************
36 36 * Compiler specifics
37 37 ****************************************************************/
38 38 #ifdef _MSC_VER /* Visual Studio */
39 39 # define FORCE_INLINE static __forceinline
40 40 # include <intrin.h> /* For Visual 2005 */
41 41 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
42 42 # pragma warning(disable : 4214) /* disable: C4214: non-int bitfields */
43 43 #else
44 44 # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
45 45 # ifdef __GNUC__
46 46 # define FORCE_INLINE static inline __attribute__((always_inline))
47 47 # else
48 48 # define FORCE_INLINE static inline
49 49 # endif
50 50 # else
51 51 # define FORCE_INLINE static
52 52 # endif /* __STDC_VERSION__ */
53 53 #endif
54 54
55 55
56 56 /* **************************************************************
57 57 * Includes
58 58 ****************************************************************/
59 59 #include <stdlib.h> /* malloc, free, qsort */
60 60 #include <string.h> /* memcpy, memset */
61 61 #include <stdio.h> /* printf (debug) */
62 62 #include "bitstream.h"
63 63 #define FSE_STATIC_LINKING_ONLY
64 64 #include "fse.h"
65 65
66 66
67 67 /* **************************************************************
68 68 * Error Management
69 69 ****************************************************************/
70 70 #define FSE_STATIC_ASSERT(c) { enum { FSE_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
71 71
72 72
73 73 /* **************************************************************
74 * Complex types
75 ****************************************************************/
76 typedef U32 CTable_max_t[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
77
78
79 /* **************************************************************
80 74 * Templates
81 75 ****************************************************************/
82 76 /*
83 77 designed to be included
84 78 for type-specific functions (template emulation in C)
85 79 Objective is to write these functions only once, for improved maintenance
86 80 */
87 81
88 82 /* safety checks */
89 83 #ifndef FSE_FUNCTION_EXTENSION
90 84 # error "FSE_FUNCTION_EXTENSION must be defined"
91 85 #endif
92 86 #ifndef FSE_FUNCTION_TYPE
93 87 # error "FSE_FUNCTION_TYPE must be defined"
94 88 #endif
95 89
96 90 /* Function names */
97 91 #define FSE_CAT(X,Y) X##Y
98 92 #define FSE_FUNCTION_NAME(X,Y) FSE_CAT(X,Y)
99 93 #define FSE_TYPE_NAME(X,Y) FSE_CAT(X,Y)
100 94
101 95
102 96 /* Function templates */
103 size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
97
98 /* FSE_buildCTable_wksp() :
99 * Same as FSE_buildCTable(), but using an externally allocated scratch buffer (`workSpace`).
100 * wkspSize should be sized to handle worst case situation, which is `1<<max_tableLog * sizeof(FSE_FUNCTION_TYPE)`
101 * workSpace must also be properly aligned with FSE_FUNCTION_TYPE requirements
102 */
103 size_t FSE_buildCTable_wksp(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
104 104 {
105 105 U32 const tableSize = 1 << tableLog;
106 106 U32 const tableMask = tableSize - 1;
107 107 void* const ptr = ct;
108 108 U16* const tableU16 = ( (U16*) ptr) + 2;
109 109 void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableLog ? tableSize>>1 : 1) ;
110 110 FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
111 111 U32 const step = FSE_TABLESTEP(tableSize);
112 112 U32 cumul[FSE_MAX_SYMBOL_VALUE+2];
113 113
114 FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */
114 FSE_FUNCTION_TYPE* const tableSymbol = (FSE_FUNCTION_TYPE*)workSpace;
115 115 U32 highThreshold = tableSize-1;
116 116
117 117 /* CTable header */
118 if (((size_t)1 << tableLog) * sizeof(FSE_FUNCTION_TYPE) > wkspSize) return ERROR(tableLog_tooLarge);
118 119 tableU16[-2] = (U16) tableLog;
119 120 tableU16[-1] = (U16) maxSymbolValue;
120 121
121 122 /* For explanations on how to distribute symbol values over the table :
122 123 * http://fastcompression.blogspot.fr/2014/02/fse-distributing-symbol-values.html */
123 124
124 125 /* symbol start positions */
125 126 { U32 u;
126 127 cumul[0] = 0;
127 128 for (u=1; u<=maxSymbolValue+1; u++) {
128 129 if (normalizedCounter[u-1]==-1) { /* Low proba symbol */
129 130 cumul[u] = cumul[u-1] + 1;
130 131 tableSymbol[highThreshold--] = (FSE_FUNCTION_TYPE)(u-1);
131 132 } else {
132 133 cumul[u] = cumul[u-1] + normalizedCounter[u-1];
133 134 } }
134 135 cumul[maxSymbolValue+1] = tableSize+1;
135 136 }
136 137
137 138 /* Spread symbols */
138 139 { U32 position = 0;
139 140 U32 symbol;
140 141 for (symbol=0; symbol<=maxSymbolValue; symbol++) {
141 142 int nbOccurences;
142 143 for (nbOccurences=0; nbOccurences<normalizedCounter[symbol]; nbOccurences++) {
143 144 tableSymbol[position] = (FSE_FUNCTION_TYPE)symbol;
144 145 position = (position + step) & tableMask;
145 146 while (position > highThreshold) position = (position + step) & tableMask; /* Low proba area */
146 147 } }
147 148
148 149 if (position!=0) return ERROR(GENERIC); /* Must have gone through all positions */
149 150 }
150 151
151 152 /* Build table */
152 153 { U32 u; for (u=0; u<tableSize; u++) {
153 154 FSE_FUNCTION_TYPE s = tableSymbol[u]; /* note : static analyzer may not understand tableSymbol is properly initialized */
154 155 tableU16[cumul[s]++] = (U16) (tableSize+u); /* TableU16 : sorted by symbol order; gives next state value */
155 156 } }
156 157
157 158 /* Build Symbol Transformation Table */
158 159 { unsigned total = 0;
159 160 unsigned s;
160 161 for (s=0; s<=maxSymbolValue; s++) {
161 162 switch (normalizedCounter[s])
162 163 {
163 164 case 0: break;
164 165
165 166 case -1:
166 167 case 1:
167 168 symbolTT[s].deltaNbBits = (tableLog << 16) - (1<<tableLog);
168 169 symbolTT[s].deltaFindState = total - 1;
169 170 total ++;
170 171 break;
171 172 default :
172 173 {
173 174 U32 const maxBitsOut = tableLog - BIT_highbit32 (normalizedCounter[s]-1);
174 175 U32 const minStatePlus = normalizedCounter[s] << maxBitsOut;
175 176 symbolTT[s].deltaNbBits = (maxBitsOut << 16) - minStatePlus;
176 177 symbolTT[s].deltaFindState = total - normalizedCounter[s];
177 178 total += normalizedCounter[s];
178 179 } } } }
179 180
180 181 return 0;
181 182 }
182 183
183 184
185 size_t FSE_buildCTable(FSE_CTable* ct, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
186 {
187 FSE_FUNCTION_TYPE tableSymbol[FSE_MAX_TABLESIZE]; /* memset() is not necessary, even if static analyzer complain about it */
188 return FSE_buildCTable_wksp(ct, normalizedCounter, maxSymbolValue, tableLog, tableSymbol, sizeof(tableSymbol));
189 }
190
191
184 192
185 193 #ifndef FSE_COMMONDEFS_ONLY
186 194
187 195 /*-**************************************************************
188 196 * FSE NCount encoding-decoding
189 197 ****************************************************************/
190 198 size_t FSE_NCountWriteBound(unsigned maxSymbolValue, unsigned tableLog)
191 199 {
192 size_t maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3;
200 size_t const maxHeaderSize = (((maxSymbolValue+1) * tableLog) >> 3) + 3;
193 201 return maxSymbolValue ? maxHeaderSize : FSE_NCOUNTBOUND; /* maxSymbolValue==0 ? use default */
194 202 }
195 203
196 204 static short FSE_abs(short a) { return (short)(a<0 ? -a : a); }
197 205
198 206 static size_t FSE_writeNCount_generic (void* header, size_t headerBufferSize,
199 207 const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog,
200 208 unsigned writeIsSafe)
201 209 {
202 210 BYTE* const ostart = (BYTE*) header;
203 211 BYTE* out = ostart;
204 212 BYTE* const oend = ostart + headerBufferSize;
205 213 int nbBits;
206 214 const int tableSize = 1 << tableLog;
207 215 int remaining;
208 216 int threshold;
209 217 U32 bitStream;
210 218 int bitCount;
211 219 unsigned charnum = 0;
212 220 int previous0 = 0;
213 221
214 222 bitStream = 0;
215 223 bitCount = 0;
216 224 /* Table Size */
217 225 bitStream += (tableLog-FSE_MIN_TABLELOG) << bitCount;
218 226 bitCount += 4;
219 227
220 228 /* Init */
221 229 remaining = tableSize+1; /* +1 for extra accuracy */
222 230 threshold = tableSize;
223 231 nbBits = tableLog+1;
224 232
225 233 while (remaining>1) { /* stops at 1 */
226 234 if (previous0) {
227 235 unsigned start = charnum;
228 236 while (!normalizedCounter[charnum]) charnum++;
229 237 while (charnum >= start+24) {
230 238 start+=24;
231 239 bitStream += 0xFFFFU << bitCount;
232 240 if ((!writeIsSafe) && (out > oend-2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
233 241 out[0] = (BYTE) bitStream;
234 242 out[1] = (BYTE)(bitStream>>8);
235 243 out+=2;
236 244 bitStream>>=16;
237 245 }
238 246 while (charnum >= start+3) {
239 247 start+=3;
240 248 bitStream += 3 << bitCount;
241 249 bitCount += 2;
242 250 }
243 251 bitStream += (charnum-start) << bitCount;
244 252 bitCount += 2;
245 253 if (bitCount>16) {
246 254 if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
247 255 out[0] = (BYTE)bitStream;
248 256 out[1] = (BYTE)(bitStream>>8);
249 257 out += 2;
250 258 bitStream >>= 16;
251 259 bitCount -= 16;
252 260 } }
253 261 { short count = normalizedCounter[charnum++];
254 262 const short max = (short)((2*threshold-1)-remaining);
255 263 remaining -= FSE_abs(count);
256 264 if (remaining<1) return ERROR(GENERIC);
257 265 count++; /* +1 for extra accuracy */
258 266 if (count>=threshold) count += max; /* [0..max[ [max..threshold[ (...) [threshold+max 2*threshold[ */
259 267 bitStream += count << bitCount;
260 268 bitCount += nbBits;
261 269 bitCount -= (count<max);
262 270 previous0 = (count==1);
263 271 while (remaining<threshold) nbBits--, threshold>>=1;
264 272 }
265 273 if (bitCount>16) {
266 274 if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
267 275 out[0] = (BYTE)bitStream;
268 276 out[1] = (BYTE)(bitStream>>8);
269 277 out += 2;
270 278 bitStream >>= 16;
271 279 bitCount -= 16;
272 280 } }
273 281
274 282 /* flush remaining bitStream */
275 283 if ((!writeIsSafe) && (out > oend - 2)) return ERROR(dstSize_tooSmall); /* Buffer overflow */
276 284 out[0] = (BYTE)bitStream;
277 285 out[1] = (BYTE)(bitStream>>8);
278 286 out+= (bitCount+7) /8;
279 287
280 288 if (charnum > maxSymbolValue + 1) return ERROR(GENERIC);
281 289
282 290 return (out-ostart);
283 291 }
284 292
285 293
286 294 size_t FSE_writeNCount (void* buffer, size_t bufferSize, const short* normalizedCounter, unsigned maxSymbolValue, unsigned tableLog)
287 295 {
288 296 if (tableLog > FSE_MAX_TABLELOG) return ERROR(GENERIC); /* Unsupported */
289 297 if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported */
290 298
291 299 if (bufferSize < FSE_NCountWriteBound(maxSymbolValue, tableLog))
292 300 return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 0);
293 301
294 302 return FSE_writeNCount_generic(buffer, bufferSize, normalizedCounter, maxSymbolValue, tableLog, 1);
295 303 }
296 304
297 305
298 306
299 307 /*-**************************************************************
300 308 * Counting histogram
301 309 ****************************************************************/
302 310 /*! FSE_count_simple
303 This function just counts byte values within `src`,
304 and store the histogram into table `count`.
305 This function is unsafe : it doesn't check that all values within `src` can fit into `count`.
311 This function counts byte values within `src`, and store the histogram into table `count`.
312 It doesn't use any additional memory.
313 But this function is unsafe : it doesn't check that all values within `src` can fit into `count`.
306 314 For this reason, prefer using a table `count` with 256 elements.
307 315 @return : count of most numerous element
308 316 */
309 static size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
310 const void* src, size_t srcSize)
317 size_t FSE_count_simple(unsigned* count, unsigned* maxSymbolValuePtr,
318 const void* src, size_t srcSize)
311 319 {
312 320 const BYTE* ip = (const BYTE*)src;
313 321 const BYTE* const end = ip + srcSize;
314 322 unsigned maxSymbolValue = *maxSymbolValuePtr;
315 323 unsigned max=0;
316 324
317
318 325 memset(count, 0, (maxSymbolValue+1)*sizeof(*count));
319 326 if (srcSize==0) { *maxSymbolValuePtr = 0; return 0; }
320 327
321 328 while (ip<end) count[*ip++]++;
322 329
323 330 while (!count[maxSymbolValue]) maxSymbolValue--;
324 331 *maxSymbolValuePtr = maxSymbolValue;
325 332
326 333 { U32 s; for (s=0; s<=maxSymbolValue; s++) if (count[s] > max) max = count[s]; }
327 334
328 335 return (size_t)max;
329 336 }
330 337
331 338
332 static size_t FSE_count_parallel(unsigned* count, unsigned* maxSymbolValuePtr,
339 /* FSE_count_parallel_wksp() :
340 * Same as FSE_count_parallel(), but using an externally provided scratch buffer.
341 * `workSpace` size must be a minimum of `1024 * sizeof(unsigned)`` */
342 static size_t FSE_count_parallel_wksp(
343 unsigned* count, unsigned* maxSymbolValuePtr,
333 344 const void* source, size_t sourceSize,
334 unsigned checkMax)
345 unsigned checkMax, unsigned* const workSpace)
335 346 {
336 347 const BYTE* ip = (const BYTE*)source;
337 348 const BYTE* const iend = ip+sourceSize;
338 349 unsigned maxSymbolValue = *maxSymbolValuePtr;
339 350 unsigned max=0;
340
351 U32* const Counting1 = workSpace;
352 U32* const Counting2 = Counting1 + 256;
353 U32* const Counting3 = Counting2 + 256;
354 U32* const Counting4 = Counting3 + 256;
341 355
342 U32 Counting1[256] = { 0 };
343 U32 Counting2[256] = { 0 };
344 U32 Counting3[256] = { 0 };
345 U32 Counting4[256] = { 0 };
356 memset(Counting1, 0, 4*256*sizeof(unsigned));
346 357
347 358 /* safety checks */
348 359 if (!sourceSize) {
349 360 memset(count, 0, maxSymbolValue + 1);
350 361 *maxSymbolValuePtr = 0;
351 362 return 0;
352 363 }
353 364 if (!maxSymbolValue) maxSymbolValue = 255; /* 0 == default */
354 365
355 366 /* by stripes of 16 bytes */
356 367 { U32 cached = MEM_read32(ip); ip += 4;
357 368 while (ip < iend-15) {
358 369 U32 c = cached; cached = MEM_read32(ip); ip += 4;
359 370 Counting1[(BYTE) c ]++;
360 371 Counting2[(BYTE)(c>>8) ]++;
361 372 Counting3[(BYTE)(c>>16)]++;
362 373 Counting4[ c>>24 ]++;
363 374 c = cached; cached = MEM_read32(ip); ip += 4;
364 375 Counting1[(BYTE) c ]++;
365 376 Counting2[(BYTE)(c>>8) ]++;
366 377 Counting3[(BYTE)(c>>16)]++;
367 378 Counting4[ c>>24 ]++;
368 379 c = cached; cached = MEM_read32(ip); ip += 4;
369 380 Counting1[(BYTE) c ]++;
370 381 Counting2[(BYTE)(c>>8) ]++;
371 382 Counting3[(BYTE)(c>>16)]++;
372 383 Counting4[ c>>24 ]++;
373 384 c = cached; cached = MEM_read32(ip); ip += 4;
374 385 Counting1[(BYTE) c ]++;
375 386 Counting2[(BYTE)(c>>8) ]++;
376 387 Counting3[(BYTE)(c>>16)]++;
377 388 Counting4[ c>>24 ]++;
378 389 }
379 390 ip-=4;
380 391 }
381 392
382 393 /* finish last symbols */
383 394 while (ip<iend) Counting1[*ip++]++;
384 395
385 396 if (checkMax) { /* verify stats will fit into destination table */
386 397 U32 s; for (s=255; s>maxSymbolValue; s--) {
387 398 Counting1[s] += Counting2[s] + Counting3[s] + Counting4[s];
388 399 if (Counting1[s]) return ERROR(maxSymbolValue_tooSmall);
389 400 } }
390 401
391 { U32 s; for (s=0; s<=maxSymbolValue; s++) {
392 count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
393 if (count[s] > max) max = count[s];
394 }}
402 { U32 s; for (s=0; s<=maxSymbolValue; s++) {
403 count[s] = Counting1[s] + Counting2[s] + Counting3[s] + Counting4[s];
404 if (count[s] > max) max = count[s];
405 } }
395 406
396 407 while (!count[maxSymbolValue]) maxSymbolValue--;
397 408 *maxSymbolValuePtr = maxSymbolValue;
398 409 return (size_t)max;
399 410 }
400 411
412 /* FSE_countFast_wksp() :
413 * Same as FSE_countFast(), but using an externally provided scratch buffer.
414 * `workSpace` size must be table of >= `1024` unsigned */
415 size_t FSE_countFast_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
416 const void* source, size_t sourceSize, unsigned* workSpace)
417 {
418 if (sourceSize < 1500) return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
419 return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 0, workSpace);
420 }
421
401 422 /* fast variant (unsafe : won't check if src contains values beyond count[] limit) */
402 423 size_t FSE_countFast(unsigned* count, unsigned* maxSymbolValuePtr,
403 424 const void* source, size_t sourceSize)
404 425 {
405 if (sourceSize < 1500) return FSE_count_simple(count, maxSymbolValuePtr, source, sourceSize);
406 return FSE_count_parallel(count, maxSymbolValuePtr, source, sourceSize, 0);
426 unsigned tmpCounters[1024];
427 return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, tmpCounters);
428 }
429
430 /* FSE_count_wksp() :
431 * Same as FSE_count(), but using an externally provided scratch buffer.
432 * `workSpace` size must be table of >= `1024` unsigned */
433 size_t FSE_count_wksp(unsigned* count, unsigned* maxSymbolValuePtr,
434 const void* source, size_t sourceSize, unsigned* workSpace)
435 {
436 if (*maxSymbolValuePtr < 255)
437 return FSE_count_parallel_wksp(count, maxSymbolValuePtr, source, sourceSize, 1, workSpace);
438 *maxSymbolValuePtr = 255;
439 return FSE_countFast_wksp(count, maxSymbolValuePtr, source, sourceSize, workSpace);
407 440 }
408 441
409 442 size_t FSE_count(unsigned* count, unsigned* maxSymbolValuePtr,
410 const void* source, size_t sourceSize)
443 const void* src, size_t srcSize)
411 444 {
412 if (*maxSymbolValuePtr <255)
413 return FSE_count_parallel(count, maxSymbolValuePtr, source, sourceSize, 1);
414 *maxSymbolValuePtr = 255;
415 return FSE_countFast(count, maxSymbolValuePtr, source, sourceSize);
445 unsigned tmpCounters[1024];
446 return FSE_count_wksp(count, maxSymbolValuePtr, src, srcSize, tmpCounters);
416 447 }
417 448
418 449
419 450
420 451 /*-**************************************************************
421 452 * FSE Compression Code
422 453 ****************************************************************/
423 454 /*! FSE_sizeof_CTable() :
424 455 FSE_CTable is a variable size structure which contains :
425 456 `U16 tableLog;`
426 457 `U16 maxSymbolValue;`
427 458 `U16 nextStateNumber[1 << tableLog];` // This size is variable
428 459 `FSE_symbolCompressionTransform symbolTT[maxSymbolValue+1];` // This size is variable
429 460 Allocation is manual (C standard does not support variable-size structures).
430 461 */
431
432 462 size_t FSE_sizeof_CTable (unsigned maxSymbolValue, unsigned tableLog)
433 463 {
434 size_t size;
435 FSE_STATIC_ASSERT((size_t)FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)*4 >= sizeof(CTable_max_t)); /* A compilation error here means FSE_CTABLE_SIZE_U32 is not large enough */
436 if (tableLog > FSE_MAX_TABLELOG) return ERROR(GENERIC);
437 size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
438 return size;
464 if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
465 return FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
439 466 }
440 467
441 468 FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)
442 469 {
443 470 size_t size;
444 471 if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
445 472 size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
446 473 return (FSE_CTable*)malloc(size);
447 474 }
448 475
449 476 void FSE_freeCTable (FSE_CTable* ct) { free(ct); }
450 477
451 478 /* provides the minimum logSize to safely represent a distribution */
452 479 static unsigned FSE_minTableLog(size_t srcSize, unsigned maxSymbolValue)
453 480 {
454 481 U32 minBitsSrc = BIT_highbit32((U32)(srcSize - 1)) + 1;
455 482 U32 minBitsSymbols = BIT_highbit32(maxSymbolValue) + 2;
456 483 U32 minBits = minBitsSrc < minBitsSymbols ? minBitsSrc : minBitsSymbols;
457 484 return minBits;
458 485 }
459 486
460 487 unsigned FSE_optimalTableLog_internal(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue, unsigned minus)
461 488 {
462 489 U32 maxBitsSrc = BIT_highbit32((U32)(srcSize - 1)) - minus;
463 490 U32 tableLog = maxTableLog;
464 491 U32 minBits = FSE_minTableLog(srcSize, maxSymbolValue);
465 492 if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
466 493 if (maxBitsSrc < tableLog) tableLog = maxBitsSrc; /* Accuracy can be reduced */
467 494 if (minBits > tableLog) tableLog = minBits; /* Need a minimum to safely represent all symbol values */
468 495 if (tableLog < FSE_MIN_TABLELOG) tableLog = FSE_MIN_TABLELOG;
469 496 if (tableLog > FSE_MAX_TABLELOG) tableLog = FSE_MAX_TABLELOG;
470 497 return tableLog;
471 498 }
472 499
473 500 unsigned FSE_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
474 501 {
475 502 return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 2);
476 503 }
477 504
478 505
479 506 /* Secondary normalization method.
480 507 To be used when primary method fails. */
481 508
482 509 static size_t FSE_normalizeM2(short* norm, U32 tableLog, const unsigned* count, size_t total, U32 maxSymbolValue)
483 510 {
484 511 U32 s;
485 512 U32 distributed = 0;
486 513 U32 ToDistribute;
487 514
488 515 /* Init */
489 U32 lowThreshold = (U32)(total >> tableLog);
516 U32 const lowThreshold = (U32)(total >> tableLog);
490 517 U32 lowOne = (U32)((total * 3) >> (tableLog + 1));
491 518
492 519 for (s=0; s<=maxSymbolValue; s++) {
493 520 if (count[s] == 0) {
494 521 norm[s]=0;
495 522 continue;
496 523 }
497 524 if (count[s] <= lowThreshold) {
498 525 norm[s] = -1;
499 526 distributed++;
500 527 total -= count[s];
501 528 continue;
502 529 }
503 530 if (count[s] <= lowOne) {
504 531 norm[s] = 1;
505 532 distributed++;
506 533 total -= count[s];
507 534 continue;
508 535 }
509 536 norm[s]=-2;
510 537 }
511 538 ToDistribute = (1 << tableLog) - distributed;
512 539
513 540 if ((total / ToDistribute) > lowOne) {
514 541 /* risk of rounding to zero */
515 542 lowOne = (U32)((total * 3) / (ToDistribute * 2));
516 543 for (s=0; s<=maxSymbolValue; s++) {
517 544 if ((norm[s] == -2) && (count[s] <= lowOne)) {
518 545 norm[s] = 1;
519 546 distributed++;
520 547 total -= count[s];
521 548 continue;
522 549 } }
523 550 ToDistribute = (1 << tableLog) - distributed;
524 551 }
525 552
526 553 if (distributed == maxSymbolValue+1) {
527 554 /* all values are pretty poor;
528 555 probably incompressible data (should have already been detected);
529 556 find max, then give all remaining points to max */
530 557 U32 maxV = 0, maxC = 0;
531 558 for (s=0; s<=maxSymbolValue; s++)
532 559 if (count[s] > maxC) maxV=s, maxC=count[s];
533 560 norm[maxV] += (short)ToDistribute;
534 561 return 0;
535 562 }
536 563
537 {
538 U64 const vStepLog = 62 - tableLog;
564 { U64 const vStepLog = 62 - tableLog;
539 565 U64 const mid = (1ULL << (vStepLog-1)) - 1;
540 566 U64 const rStep = ((((U64)1<<vStepLog) * ToDistribute) + mid) / total; /* scale on remaining */
541 567 U64 tmpTotal = mid;
542 568 for (s=0; s<=maxSymbolValue; s++) {
543 569 if (norm[s]==-2) {
544 U64 end = tmpTotal + (count[s] * rStep);
545 U32 sStart = (U32)(tmpTotal >> vStepLog);
546 U32 sEnd = (U32)(end >> vStepLog);
547 U32 weight = sEnd - sStart;
570 U64 const end = tmpTotal + (count[s] * rStep);
571 U32 const sStart = (U32)(tmpTotal >> vStepLog);
572 U32 const sEnd = (U32)(end >> vStepLog);
573 U32 const weight = sEnd - sStart;
548 574 if (weight < 1)
549 575 return ERROR(GENERIC);
550 576 norm[s] = (short)weight;
551 577 tmpTotal = end;
552 578 } } }
553 579
554 580 return 0;
555 581 }
556 582
557 583
558 584 size_t FSE_normalizeCount (short* normalizedCounter, unsigned tableLog,
559 585 const unsigned* count, size_t total,
560 586 unsigned maxSymbolValue)
561 587 {
562 588 /* Sanity checks */
563 589 if (tableLog==0) tableLog = FSE_DEFAULT_TABLELOG;
564 590 if (tableLog < FSE_MIN_TABLELOG) return ERROR(GENERIC); /* Unsupported size */
565 591 if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge); /* Unsupported size */
566 592 if (tableLog < FSE_minTableLog(total, maxSymbolValue)) return ERROR(GENERIC); /* Too small tableLog, compression potentially impossible */
567 593
568 594 { U32 const rtbTable[] = { 0, 473195, 504333, 520860, 550000, 700000, 750000, 830000 };
569
570 595 U64 const scale = 62 - tableLog;
571 596 U64 const step = ((U64)1<<62) / total; /* <== here, one division ! */
572 597 U64 const vStep = 1ULL<<(scale-20);
573 598 int stillToDistribute = 1<<tableLog;
574 599 unsigned s;
575 600 unsigned largest=0;
576 601 short largestP=0;
577 602 U32 lowThreshold = (U32)(total >> tableLog);
578 603
579 604 for (s=0; s<=maxSymbolValue; s++) {
580 605 if (count[s] == total) return 0; /* rle special case */
581 606 if (count[s] == 0) { normalizedCounter[s]=0; continue; }
582 607 if (count[s] <= lowThreshold) {
583 608 normalizedCounter[s] = -1;
584 609 stillToDistribute--;
585 610 } else {
586 611 short proba = (short)((count[s]*step) >> scale);
587 612 if (proba<8) {
588 613 U64 restToBeat = vStep * rtbTable[proba];
589 614 proba += (count[s]*step) - ((U64)proba<<scale) > restToBeat;
590 615 }
591 616 if (proba > largestP) largestP=proba, largest=s;
592 617 normalizedCounter[s] = proba;
593 618 stillToDistribute -= proba;
594 619 } }
595 620 if (-stillToDistribute >= (normalizedCounter[largest] >> 1)) {
596 621 /* corner case, need another normalization method */
597 size_t errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
622 size_t const errorCode = FSE_normalizeM2(normalizedCounter, tableLog, count, total, maxSymbolValue);
598 623 if (FSE_isError(errorCode)) return errorCode;
599 624 }
600 625 else normalizedCounter[largest] += (short)stillToDistribute;
601 626 }
602 627
603 628 #if 0
604 629 { /* Print Table (debug) */
605 630 U32 s;
606 631 U32 nTotal = 0;
607 632 for (s=0; s<=maxSymbolValue; s++)
608 633 printf("%3i: %4i \n", s, normalizedCounter[s]);
609 634 for (s=0; s<=maxSymbolValue; s++)
610 635 nTotal += abs(normalizedCounter[s]);
611 636 if (nTotal != (1U<<tableLog))
612 637 printf("Warning !!! Total == %u != %u !!!", nTotal, 1U<<tableLog);
613 638 getchar();
614 639 }
615 640 #endif
616 641
617 642 return tableLog;
618 643 }
619 644
620 645
621 646 /* fake FSE_CTable, for raw (uncompressed) input */
622 647 size_t FSE_buildCTable_raw (FSE_CTable* ct, unsigned nbBits)
623 648 {
624 649 const unsigned tableSize = 1 << nbBits;
625 650 const unsigned tableMask = tableSize - 1;
626 651 const unsigned maxSymbolValue = tableMask;
627 652 void* const ptr = ct;
628 653 U16* const tableU16 = ( (U16*) ptr) + 2;
629 654 void* const FSCT = ((U32*)ptr) + 1 /* header */ + (tableSize>>1); /* assumption : tableLog >= 1 */
630 655 FSE_symbolCompressionTransform* const symbolTT = (FSE_symbolCompressionTransform*) (FSCT);
631 656 unsigned s;
632 657
633 658 /* Sanity checks */
634 659 if (nbBits < 1) return ERROR(GENERIC); /* min size */
635 660
636 661 /* header */
637 662 tableU16[-2] = (U16) nbBits;
638 663 tableU16[-1] = (U16) maxSymbolValue;
639 664
640 665 /* Build table */
641 666 for (s=0; s<tableSize; s++)
642 667 tableU16[s] = (U16)(tableSize + s);
643 668
644 669 /* Build Symbol Transformation Table */
645 670 { const U32 deltaNbBits = (nbBits << 16) - (1 << nbBits);
646
647 671 for (s=0; s<=maxSymbolValue; s++) {
648 672 symbolTT[s].deltaNbBits = deltaNbBits;
649 673 symbolTT[s].deltaFindState = s-1;
650 674 } }
651 675
652
653 676 return 0;
654 677 }
655 678
656 /* fake FSE_CTable, for rle (100% always same symbol) input */
679 /* fake FSE_CTable, for rle input (always same symbol) */
657 680 size_t FSE_buildCTable_rle (FSE_CTable* ct, BYTE symbolValue)
658 681 {
659 682 void* ptr = ct;
660 683 U16* tableU16 = ( (U16*) ptr) + 2;
661 684 void* FSCTptr = (U32*)ptr + 2;
662 685 FSE_symbolCompressionTransform* symbolTT = (FSE_symbolCompressionTransform*) FSCTptr;
663 686
664 687 /* header */
665 688 tableU16[-2] = (U16) 0;
666 689 tableU16[-1] = (U16) symbolValue;
667 690
668 691 /* Build table */
669 692 tableU16[0] = 0;
670 693 tableU16[1] = 0; /* just in case */
671 694
672 695 /* Build Symbol Transformation Table */
673 696 symbolTT[symbolValue].deltaNbBits = 0;
674 697 symbolTT[symbolValue].deltaFindState = 0;
675 698
676 699 return 0;
677 700 }
678 701
679 702
680 703 static size_t FSE_compress_usingCTable_generic (void* dst, size_t dstSize,
681 704 const void* src, size_t srcSize,
682 705 const FSE_CTable* ct, const unsigned fast)
683 706 {
684 707 const BYTE* const istart = (const BYTE*) src;
685 708 const BYTE* const iend = istart + srcSize;
686 709 const BYTE* ip=iend;
687 710
688
689 711 BIT_CStream_t bitC;
690 712 FSE_CState_t CState1, CState2;
691 713
692 714 /* init */
693 715 if (srcSize <= 2) return 0;
694 { size_t const errorCode = BIT_initCStream(&bitC, dst, dstSize);
695 if (FSE_isError(errorCode)) return 0; }
716 { size_t const initError = BIT_initCStream(&bitC, dst, dstSize);
717 if (FSE_isError(initError)) return 0; /* not enough space available to write a bitstream */ }
696 718
697 719 #define FSE_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
698 720
699 721 if (srcSize & 1) {
700 722 FSE_initCState2(&CState1, ct, *--ip);
701 723 FSE_initCState2(&CState2, ct, *--ip);
702 724 FSE_encodeSymbol(&bitC, &CState1, *--ip);
703 725 FSE_FLUSHBITS(&bitC);
704 726 } else {
705 727 FSE_initCState2(&CState2, ct, *--ip);
706 728 FSE_initCState2(&CState1, ct, *--ip);
707 729 }
708 730
709 731 /* join to mod 4 */
710 732 srcSize -= 2;
711 733 if ((sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) && (srcSize & 2)) { /* test bit 2 */
712 734 FSE_encodeSymbol(&bitC, &CState2, *--ip);
713 735 FSE_encodeSymbol(&bitC, &CState1, *--ip);
714 736 FSE_FLUSHBITS(&bitC);
715 737 }
716 738
717 739 /* 2 or 4 encoding per loop */
718 for ( ; ip>istart ; ) {
740 while ( ip>istart ) {
719 741
720 742 FSE_encodeSymbol(&bitC, &CState2, *--ip);
721 743
722 744 if (sizeof(bitC.bitContainer)*8 < FSE_MAX_TABLELOG*2+7 ) /* this test must be static */
723 745 FSE_FLUSHBITS(&bitC);
724 746
725 747 FSE_encodeSymbol(&bitC, &CState1, *--ip);
726 748
727 749 if (sizeof(bitC.bitContainer)*8 > FSE_MAX_TABLELOG*4+7 ) { /* this test must be static */
728 750 FSE_encodeSymbol(&bitC, &CState2, *--ip);
729 751 FSE_encodeSymbol(&bitC, &CState1, *--ip);
730 752 }
731 753
732 754 FSE_FLUSHBITS(&bitC);
733 755 }
734 756
735 757 FSE_flushCState(&bitC, &CState2);
736 758 FSE_flushCState(&bitC, &CState1);
737 759 return BIT_closeCStream(&bitC);
738 760 }
739 761
740 762 size_t FSE_compress_usingCTable (void* dst, size_t dstSize,
741 763 const void* src, size_t srcSize,
742 764 const FSE_CTable* ct)
743 765 {
744 const unsigned fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
766 unsigned const fast = (dstSize >= FSE_BLOCKBOUND(srcSize));
745 767
746 768 if (fast)
747 769 return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 1);
748 770 else
749 771 return FSE_compress_usingCTable_generic(dst, dstSize, src, srcSize, ct, 0);
750 772 }
751 773
752 774
753 775 size_t FSE_compressBound(size_t size) { return FSE_COMPRESSBOUND(size); }
754 776
755 size_t FSE_compress2 (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)
777 #define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return f
778 #define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
779
780 /* FSE_compress_wksp() :
781 * Same as FSE_compress2(), but using an externally allocated scratch buffer (`workSpace`).
782 * `wkspSize` size must be `(1<<tableLog)`.
783 */
784 size_t FSE_compress_wksp (void* dst, size_t dstSize, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog, void* workSpace, size_t wkspSize)
756 785 {
757 const BYTE* const istart = (const BYTE*) src;
758 const BYTE* ip = istart;
759
760 786 BYTE* const ostart = (BYTE*) dst;
761 787 BYTE* op = ostart;
762 788 BYTE* const oend = ostart + dstSize;
763 789
764 790 U32 count[FSE_MAX_SYMBOL_VALUE+1];
765 791 S16 norm[FSE_MAX_SYMBOL_VALUE+1];
766 CTable_max_t ct;
767 size_t errorCode;
792 FSE_CTable* CTable = (FSE_CTable*)workSpace;
793 size_t const CTableSize = FSE_CTABLE_SIZE_U32(tableLog, maxSymbolValue);
794 void* scratchBuffer = (void*)(CTable + CTableSize);
795 size_t const scratchBufferSize = wkspSize - (CTableSize * sizeof(FSE_CTable));
768 796
769 797 /* init conditions */
770 if (srcSize <= 1) return 0; /* Uncompressible */
798 if (wkspSize < FSE_WKSP_SIZE_U32(tableLog, maxSymbolValue)) return ERROR(tableLog_tooLarge);
799 if (srcSize <= 1) return 0; /* Not compressible */
771 800 if (!maxSymbolValue) maxSymbolValue = FSE_MAX_SYMBOL_VALUE;
772 801 if (!tableLog) tableLog = FSE_DEFAULT_TABLELOG;
773 802
774 803 /* Scan input and build symbol stats */
775 errorCode = FSE_count (count, &maxSymbolValue, ip, srcSize);
776 if (FSE_isError(errorCode)) return errorCode;
777 if (errorCode == srcSize) return 1;
778 if (errorCode == 1) return 0; /* each symbol only present once */
779 if (errorCode < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */
804 { CHECK_V_F(maxCount, FSE_count(count, &maxSymbolValue, src, srcSize) );
805 if (maxCount == srcSize) return 1; /* only a single symbol in src : rle */
806 if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
807 if (maxCount < (srcSize >> 7)) return 0; /* Heuristic : not compressible enough */
808 }
780 809
781 810 tableLog = FSE_optimalTableLog(tableLog, srcSize, maxSymbolValue);
782 errorCode = FSE_normalizeCount (norm, tableLog, count, srcSize, maxSymbolValue);
783 if (FSE_isError(errorCode)) return errorCode;
811 CHECK_F( FSE_normalizeCount(norm, tableLog, count, srcSize, maxSymbolValue) );
784 812
785 813 /* Write table description header */
786 errorCode = FSE_writeNCount (op, oend-op, norm, maxSymbolValue, tableLog);
787 if (FSE_isError(errorCode)) return errorCode;
788 op += errorCode;
814 { CHECK_V_F(nc_err, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
815 op += nc_err;
816 }
789 817
790 818 /* Compress */
791 errorCode = FSE_buildCTable (ct, norm, maxSymbolValue, tableLog);
792 if (FSE_isError(errorCode)) return errorCode;
793 errorCode = FSE_compress_usingCTable(op, oend - op, ip, srcSize, ct);
794 if (errorCode == 0) return 0; /* not enough space for compressed data */
795 op += errorCode;
819 CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, scratchBufferSize) );
820 { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, src, srcSize, CTable) );
821 if (cSize == 0) return 0; /* not enough space for compressed data */
822 op += cSize;
823 }
796 824
797 825 /* check compressibility */
798 if ( (size_t)(op-ostart) >= srcSize-1 )
799 return 0;
826 if ( (size_t)(op-ostart) >= srcSize-1 ) return 0;
800 827
801 828 return op-ostart;
802 829 }
803 830
804 size_t FSE_compress (void* dst, size_t dstSize, const void* src, size_t srcSize)
831 typedef struct {
832 FSE_CTable CTable_max[FSE_CTABLE_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)];
833 BYTE scratchBuffer[1 << FSE_MAX_TABLELOG];
834 } fseWkspMax_t;
835
836 size_t FSE_compress2 (void* dst, size_t dstCapacity, const void* src, size_t srcSize, unsigned maxSymbolValue, unsigned tableLog)
805 837 {
806 return FSE_compress2(dst, dstSize, src, (U32)srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);
838 fseWkspMax_t scratchBuffer;
839 FSE_STATIC_ASSERT(sizeof(scratchBuffer) >= FSE_WKSP_SIZE_U32(FSE_MAX_TABLELOG, FSE_MAX_SYMBOL_VALUE)); /* compilation failures here means scratchBuffer is not large enough */
840 if (tableLog > FSE_MAX_TABLELOG) return ERROR(tableLog_tooLarge);
841 return FSE_compress_wksp(dst, dstCapacity, src, srcSize, maxSymbolValue, tableLog, &scratchBuffer, sizeof(scratchBuffer));
842 }
843
844 size_t FSE_compress (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
845 {
846 return FSE_compress2(dst, dstCapacity, src, srcSize, FSE_MAX_SYMBOL_VALUE, FSE_DEFAULT_TABLELOG);
807 847 }
808 848
809 849
810 850 #endif /* FSE_COMMONDEFS_ONLY */
@@ -1,533 +1,609 b''
1 1 /* ******************************************************************
2 2 Huffman encoder, part of New Generation Entropy library
3 3 Copyright (C) 2013-2016, Yann Collet.
4 4
5 5 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6 6
7 7 Redistribution and use in source and binary forms, with or without
8 8 modification, are permitted provided that the following conditions are
9 9 met:
10 10
11 11 * Redistributions of source code must retain the above copyright
12 12 notice, this list of conditions and the following disclaimer.
13 13 * Redistributions in binary form must reproduce the above
14 14 copyright notice, this list of conditions and the following disclaimer
15 15 in the documentation and/or other materials provided with the
16 16 distribution.
17 17
18 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 30 You can contact the author at :
31 31 - FSE+HUF source repository : https://github.com/Cyan4973/FiniteStateEntropy
32 32 - Public forum : https://groups.google.com/forum/#!forum/lz4c
33 33 ****************************************************************** */
34 34
35 35 /* **************************************************************
36 36 * Compiler specifics
37 37 ****************************************************************/
38 38 #ifdef _MSC_VER /* Visual Studio */
39 39 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
40 40 #endif
41 41
42 42
43 43 /* **************************************************************
44 44 * Includes
45 45 ****************************************************************/
46 46 #include <string.h> /* memcpy, memset */
47 47 #include <stdio.h> /* printf (debug) */
48 48 #include "bitstream.h"
49 49 #define FSE_STATIC_LINKING_ONLY /* FSE_optimalTableLog_internal */
50 50 #include "fse.h" /* header compression */
51 51 #define HUF_STATIC_LINKING_ONLY
52 52 #include "huf.h"
53 53
54 54
55 55 /* **************************************************************
56 56 * Error Management
57 57 ****************************************************************/
58 58 #define HUF_STATIC_ASSERT(c) { enum { HUF_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
59 #define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return f
60 #define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
59 61
60 62
61 63 /* **************************************************************
62 64 * Utils
63 65 ****************************************************************/
64 66 unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue)
65 67 {
66 68 return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1);
67 69 }
68 70
69 71
70 72 /* *******************************************************
71 73 * HUF : Huffman block compression
72 74 *********************************************************/
75 /* HUF_compressWeights() :
76 * Same as FSE_compress(), but dedicated to huff0's weights compression.
77 * The use case needs much less stack memory.
78 * Note : all elements within weightTable are supposed to be <= HUF_TABLELOG_MAX.
79 */
80 #define MAX_FSE_TABLELOG_FOR_HUFF_HEADER 6
81 size_t HUF_compressWeights (void* dst, size_t dstSize, const void* weightTable, size_t wtSize)
82 {
83 BYTE* const ostart = (BYTE*) dst;
84 BYTE* op = ostart;
85 BYTE* const oend = ostart + dstSize;
86
87 U32 maxSymbolValue = HUF_TABLELOG_MAX;
88 U32 tableLog = MAX_FSE_TABLELOG_FOR_HUFF_HEADER;
89
90 FSE_CTable CTable[FSE_CTABLE_SIZE_U32(MAX_FSE_TABLELOG_FOR_HUFF_HEADER, HUF_TABLELOG_MAX)];
91 BYTE scratchBuffer[1<<MAX_FSE_TABLELOG_FOR_HUFF_HEADER];
92
93 U32 count[HUF_TABLELOG_MAX+1];
94 S16 norm[HUF_TABLELOG_MAX+1];
95
96 /* init conditions */
97 if (wtSize <= 1) return 0; /* Not compressible */
98
99 /* Scan input and build symbol stats */
100 { CHECK_V_F(maxCount, FSE_count_simple(count, &maxSymbolValue, weightTable, wtSize) );
101 if (maxCount == wtSize) return 1; /* only a single symbol in src : rle */
102 if (maxCount == 1) return 0; /* each symbol present maximum once => not compressible */
103 }
104
105 tableLog = FSE_optimalTableLog(tableLog, wtSize, maxSymbolValue);
106 CHECK_F( FSE_normalizeCount(norm, tableLog, count, wtSize, maxSymbolValue) );
107
108 /* Write table description header */
109 { CHECK_V_F(hSize, FSE_writeNCount(op, oend-op, norm, maxSymbolValue, tableLog) );
110 op += hSize;
111 }
112
113 /* Compress */
114 CHECK_F( FSE_buildCTable_wksp(CTable, norm, maxSymbolValue, tableLog, scratchBuffer, sizeof(scratchBuffer)) );
115 { CHECK_V_F(cSize, FSE_compress_usingCTable(op, oend - op, weightTable, wtSize, CTable) );
116 if (cSize == 0) return 0; /* not enough space for compressed data */
117 op += cSize;
118 }
119
120 return op-ostart;
121 }
122
123
73 124 struct HUF_CElt_s {
74 125 U16 val;
75 126 BYTE nbBits;
76 127 }; /* typedef'd to HUF_CElt within "huf.h" */
77 128
78 typedef struct nodeElt_s {
79 U32 count;
80 U16 parent;
81 BYTE byte;
82 BYTE nbBits;
83 } nodeElt;
84
85 129 /*! HUF_writeCTable() :
86 130 `CTable` : huffman tree to save, using huf representation.
87 131 @return : size of saved CTable */
88 132 size_t HUF_writeCTable (void* dst, size_t maxDstSize,
89 133 const HUF_CElt* CTable, U32 maxSymbolValue, U32 huffLog)
90 134 {
91 BYTE bitsToWeight[HUF_TABLELOG_MAX + 1];
135 BYTE bitsToWeight[HUF_TABLELOG_MAX + 1]; /* precomputed conversion table */
92 136 BYTE huffWeight[HUF_SYMBOLVALUE_MAX];
93 137 BYTE* op = (BYTE*)dst;
94 138 U32 n;
95 139
96 140 /* check conditions */
97 if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(GENERIC);
141 if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(maxSymbolValue_tooLarge);
98 142
99 143 /* convert to weight */
100 144 bitsToWeight[0] = 0;
101 145 for (n=1; n<huffLog+1; n++)
102 146 bitsToWeight[n] = (BYTE)(huffLog + 1 - n);
103 147 for (n=0; n<maxSymbolValue; n++)
104 148 huffWeight[n] = bitsToWeight[CTable[n].nbBits];
105 149
106 { size_t const size = FSE_compress(op+1, maxDstSize-1, huffWeight, maxSymbolValue);
107 if (FSE_isError(size)) return size;
108 if ((size>1) & (size < maxSymbolValue/2)) { /* FSE compressed */
109 op[0] = (BYTE)size;
110 return size+1;
111 }
112 }
150 /* attempt weights compression by FSE */
151 { CHECK_V_F(hSize, HUF_compressWeights(op+1, maxDstSize-1, huffWeight, maxSymbolValue) );
152 if ((hSize>1) & (hSize < maxSymbolValue/2)) { /* FSE compressed */
153 op[0] = (BYTE)hSize;
154 return hSize+1;
155 } }
113 156
114 /* raw values */
115 if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen */
157 /* write raw values as 4-bits (max : 15) */
158 if (maxSymbolValue > (256-128)) return ERROR(GENERIC); /* should not happen : likely means source cannot be compressed */
116 159 if (((maxSymbolValue+1)/2) + 1 > maxDstSize) return ERROR(dstSize_tooSmall); /* not enough space within dst buffer */
117 160 op[0] = (BYTE)(128 /*special case*/ + (maxSymbolValue-1));
118 huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause issue in final combination */
161 huffWeight[maxSymbolValue] = 0; /* to be sure it doesn't cause msan issue in final combination */
119 162 for (n=0; n<maxSymbolValue; n+=2)
120 163 op[(n/2)+1] = (BYTE)((huffWeight[n] << 4) + huffWeight[n+1]);
121 164 return ((maxSymbolValue+1)/2) + 1;
122
123 165 }
124 166
125 167
126 168 size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, size_t srcSize)
127 169 {
128 BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1];
170 BYTE huffWeight[HUF_SYMBOLVALUE_MAX + 1]; /* init not required, even though some static analyzer may complain */
129 171 U32 rankVal[HUF_TABLELOG_ABSOLUTEMAX + 1]; /* large enough for values from 0 to 16 */
130 172 U32 tableLog = 0;
131 size_t readSize;
132 173 U32 nbSymbols = 0;
133 /*memset(huffWeight, 0, sizeof(huffWeight));*/ /* is not necessary, even though some analyzer complain ... */
134 174
135 175 /* get symbol weights */
136 readSize = HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize);
137 if (HUF_isError(readSize)) return readSize;
176 CHECK_V_F(readSize, HUF_readStats(huffWeight, HUF_SYMBOLVALUE_MAX+1, rankVal, &nbSymbols, &tableLog, src, srcSize));
138 177
139 178 /* check result */
140 179 if (tableLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
141 180 if (nbSymbols > maxSymbolValue+1) return ERROR(maxSymbolValue_tooSmall);
142 181
143 182 /* Prepare base value per rank */
144 183 { U32 n, nextRankStart = 0;
145 184 for (n=1; n<=tableLog; n++) {
146 185 U32 current = nextRankStart;
147 186 nextRankStart += (rankVal[n] << (n-1));
148 187 rankVal[n] = current;
149 188 } }
150 189
151 190 /* fill nbBits */
152 191 { U32 n; for (n=0; n<nbSymbols; n++) {
153 192 const U32 w = huffWeight[n];
154 193 CTable[n].nbBits = (BYTE)(tableLog + 1 - w);
155 194 } }
156 195
157 196 /* fill val */
158 197 { U16 nbPerRank[HUF_TABLELOG_MAX+2] = {0}; /* support w=0=>n=tableLog+1 */
159 198 U16 valPerRank[HUF_TABLELOG_MAX+2] = {0};
160 199 { U32 n; for (n=0; n<nbSymbols; n++) nbPerRank[CTable[n].nbBits]++; }
161 200 /* determine stating value per rank */
162 201 valPerRank[tableLog+1] = 0; /* for w==0 */
163 202 { U16 min = 0;
164 203 U32 n; for (n=tableLog; n>0; n--) { /* start at n=tablelog <-> w=1 */
165 204 valPerRank[n] = min; /* get starting value within each rank */
166 205 min += nbPerRank[n];
167 206 min >>= 1;
168 207 } }
169 208 /* assign value within rank, symbol order */
170 209 { U32 n; for (n=0; n<=maxSymbolValue; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; }
171 210 }
172 211
173 212 return readSize;
174 213 }
175 214
176 215
216 typedef struct nodeElt_s {
217 U32 count;
218 U16 parent;
219 BYTE byte;
220 BYTE nbBits;
221 } nodeElt;
222
177 223 static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits)
178 224 {
179 225 const U32 largestBits = huffNode[lastNonNull].nbBits;
180 226 if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */
181 227
182 228 /* there are several too large elements (at least >= 2) */
183 229 { int totalCost = 0;
184 230 const U32 baseCost = 1 << (largestBits - maxNbBits);
185 231 U32 n = lastNonNull;
186 232
187 233 while (huffNode[n].nbBits > maxNbBits) {
188 234 totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits));
189 235 huffNode[n].nbBits = (BYTE)maxNbBits;
190 236 n --;
191 237 } /* n stops at huffNode[n].nbBits <= maxNbBits */
192 238 while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */
193 239
194 240 /* renorm totalCost */
195 241 totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */
196 242
197 243 /* repay normalized cost */
198 244 { U32 const noSymbol = 0xF0F0F0F0;
199 245 U32 rankLast[HUF_TABLELOG_MAX+2];
200 246 int pos;
201 247
202 248 /* Get pos of last (smallest) symbol per rank */
203 249 memset(rankLast, 0xF0, sizeof(rankLast));
204 250 { U32 currentNbBits = maxNbBits;
205 251 for (pos=n ; pos >= 0; pos--) {
206 252 if (huffNode[pos].nbBits >= currentNbBits) continue;
207 253 currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */
208 254 rankLast[maxNbBits-currentNbBits] = pos;
209 255 } }
210 256
211 257 while (totalCost > 0) {
212 258 U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1;
213 259 for ( ; nBitsToDecrease > 1; nBitsToDecrease--) {
214 260 U32 highPos = rankLast[nBitsToDecrease];
215 261 U32 lowPos = rankLast[nBitsToDecrease-1];
216 262 if (highPos == noSymbol) continue;
217 263 if (lowPos == noSymbol) break;
218 264 { U32 const highTotal = huffNode[highPos].count;
219 265 U32 const lowTotal = 2 * huffNode[lowPos].count;
220 266 if (highTotal <= lowTotal) break;
221 267 } }
222 268 /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */
223 269 while ((nBitsToDecrease<=HUF_TABLELOG_MAX) && (rankLast[nBitsToDecrease] == noSymbol)) /* HUF_MAX_TABLELOG test just to please gcc 5+; but it should not be necessary */
224 270 nBitsToDecrease ++;
225 271 totalCost -= 1 << (nBitsToDecrease-1);
226 272 if (rankLast[nBitsToDecrease-1] == noSymbol)
227 273 rankLast[nBitsToDecrease-1] = rankLast[nBitsToDecrease]; /* this rank is no longer empty */
228 274 huffNode[rankLast[nBitsToDecrease]].nbBits ++;
229 275 if (rankLast[nBitsToDecrease] == 0) /* special case, reached largest symbol */
230 276 rankLast[nBitsToDecrease] = noSymbol;
231 277 else {
232 278 rankLast[nBitsToDecrease]--;
233 279 if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease)
234 280 rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */
235 281 } } /* while (totalCost > 0) */
236 282
237 283 while (totalCost < 0) { /* Sometimes, cost correction overshoot */
238 284 if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */
239 285 while (huffNode[n].nbBits == maxNbBits) n--;
240 286 huffNode[n+1].nbBits--;
241 287 rankLast[1] = n+1;
242 288 totalCost++;
243 289 continue;
244 290 }
245 291 huffNode[ rankLast[1] + 1 ].nbBits--;
246 292 rankLast[1]++;
247 293 totalCost ++;
248 294 } } } /* there are several too large elements (at least >= 2) */
249 295
250 296 return maxNbBits;
251 297 }
252 298
253 299
254 300 typedef struct {
255 301 U32 base;
256 302 U32 current;
257 303 } rankPos;
258 304
259 305 static void HUF_sort(nodeElt* huffNode, const U32* count, U32 maxSymbolValue)
260 306 {
261 307 rankPos rank[32];
262 308 U32 n;
263 309
264 310 memset(rank, 0, sizeof(rank));
265 311 for (n=0; n<=maxSymbolValue; n++) {
266 312 U32 r = BIT_highbit32(count[n] + 1);
267 313 rank[r].base ++;
268 314 }
269 315 for (n=30; n>0; n--) rank[n-1].base += rank[n].base;
270 316 for (n=0; n<32; n++) rank[n].current = rank[n].base;
271 317 for (n=0; n<=maxSymbolValue; n++) {
272 318 U32 const c = count[n];
273 319 U32 const r = BIT_highbit32(c+1) + 1;
274 320 U32 pos = rank[r].current++;
275 321 while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) huffNode[pos]=huffNode[pos-1], pos--;
276 322 huffNode[pos].count = c;
277 323 huffNode[pos].byte = (BYTE)n;
278 324 }
279 325 }
280 326
281 327
328 /** HUF_buildCTable_wksp() :
329 * Same as HUF_buildCTable(), but using externally allocated scratch buffer.
330 * `workSpace` must be aligned on 4-bytes boundaries, and be at least as large as a table of 1024 unsigned.
331 */
282 332 #define STARTNODE (HUF_SYMBOLVALUE_MAX+1)
283 size_t HUF_buildCTable (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits)
333 typedef nodeElt huffNodeTable[2*HUF_SYMBOLVALUE_MAX+1 +1];
334 size_t HUF_buildCTable_wksp (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize)
284 335 {
285 nodeElt huffNode0[2*HUF_SYMBOLVALUE_MAX+1 +1];
286 nodeElt* huffNode = huffNode0 + 1;
336 nodeElt* const huffNode0 = (nodeElt*)workSpace;
337 nodeElt* const huffNode = huffNode0+1;
287 338 U32 n, nonNullRank;
288 339 int lowS, lowN;
289 340 U16 nodeNb = STARTNODE;
290 341 U32 nodeRoot;
291 342
292 343 /* safety checks */
344 if (wkspSize < sizeof(huffNodeTable)) return ERROR(GENERIC); /* workSpace is not large enough */
293 345 if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT;
294 346 if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) return ERROR(GENERIC);
295 memset(huffNode0, 0, sizeof(huffNode0));
347 memset(huffNode0, 0, sizeof(huffNodeTable));
296 348
297 349 /* sort, decreasing order */
298 350 HUF_sort(huffNode, count, maxSymbolValue);
299 351
300 352 /* init for parents */
301 353 nonNullRank = maxSymbolValue;
302 354 while(huffNode[nonNullRank].count == 0) nonNullRank--;
303 355 lowS = nonNullRank; nodeRoot = nodeNb + lowS - 1; lowN = nodeNb;
304 356 huffNode[nodeNb].count = huffNode[lowS].count + huffNode[lowS-1].count;
305 357 huffNode[lowS].parent = huffNode[lowS-1].parent = nodeNb;
306 358 nodeNb++; lowS-=2;
307 359 for (n=nodeNb; n<=nodeRoot; n++) huffNode[n].count = (U32)(1U<<30);
308 huffNode0[0].count = (U32)(1U<<31);
360 huffNode0[0].count = (U32)(1U<<31); /* fake entry, strong barrier */
309 361
310 362 /* create parents */
311 363 while (nodeNb <= nodeRoot) {
312 364 U32 n1 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
313 365 U32 n2 = (huffNode[lowS].count < huffNode[lowN].count) ? lowS-- : lowN++;
314 366 huffNode[nodeNb].count = huffNode[n1].count + huffNode[n2].count;
315 367 huffNode[n1].parent = huffNode[n2].parent = nodeNb;
316 368 nodeNb++;
317 369 }
318 370
319 371 /* distribute weights (unlimited tree height) */
320 372 huffNode[nodeRoot].nbBits = 0;
321 373 for (n=nodeRoot-1; n>=STARTNODE; n--)
322 374 huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
323 375 for (n=0; n<=nonNullRank; n++)
324 376 huffNode[n].nbBits = huffNode[ huffNode[n].parent ].nbBits + 1;
325 377
326 378 /* enforce maxTableLog */
327 379 maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits);
328 380
329 381 /* fill result into tree (val, nbBits) */
330 382 { U16 nbPerRank[HUF_TABLELOG_MAX+1] = {0};
331 383 U16 valPerRank[HUF_TABLELOG_MAX+1] = {0};
332 384 if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */
333 385 for (n=0; n<=nonNullRank; n++)
334 386 nbPerRank[huffNode[n].nbBits]++;
335 387 /* determine stating value per rank */
336 388 { U16 min = 0;
337 389 for (n=maxNbBits; n>0; n--) {
338 390 valPerRank[n] = min; /* get starting value within each rank */
339 391 min += nbPerRank[n];
340 392 min >>= 1;
341 393 } }
342 394 for (n=0; n<=maxSymbolValue; n++)
343 395 tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */
344 396 for (n=0; n<=maxSymbolValue; n++)
345 397 tree[n].val = valPerRank[tree[n].nbBits]++; /* assign value within rank, symbol order */
346 398 }
347 399
348 400 return maxNbBits;
349 401 }
350 402
403 /** HUF_buildCTable() :
404 * Note : count is used before tree is written, so they can safely overlap
405 */
406 size_t HUF_buildCTable (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U32 maxNbBits)
407 {
408 huffNodeTable nodeTable;
409 return HUF_buildCTable_wksp(tree, count, maxSymbolValue, maxNbBits, nodeTable, sizeof(nodeTable));
410 }
411
351 412 static void HUF_encodeSymbol(BIT_CStream_t* bitCPtr, U32 symbol, const HUF_CElt* CTable)
352 413 {
353 414 BIT_addBitsFast(bitCPtr, CTable[symbol].val, CTable[symbol].nbBits);
354 415 }
355 416
356 417 size_t HUF_compressBound(size_t size) { return HUF_COMPRESSBOUND(size); }
357 418
358 419 #define HUF_FLUSHBITS(s) (fast ? BIT_flushBitsFast(s) : BIT_flushBits(s))
359 420
360 421 #define HUF_FLUSHBITS_1(stream) \
361 422 if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*2+7) HUF_FLUSHBITS(stream)
362 423
363 424 #define HUF_FLUSHBITS_2(stream) \
364 425 if (sizeof((stream)->bitContainer)*8 < HUF_TABLELOG_MAX*4+7) HUF_FLUSHBITS(stream)
365 426
366 427 size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
367 428 {
368 429 const BYTE* ip = (const BYTE*) src;
369 430 BYTE* const ostart = (BYTE*)dst;
370 431 BYTE* const oend = ostart + dstSize;
371 432 BYTE* op = ostart;
372 433 size_t n;
373 434 const unsigned fast = (dstSize >= HUF_BLOCKBOUND(srcSize));
374 435 BIT_CStream_t bitC;
375 436
376 437 /* init */
377 438 if (dstSize < 8) return 0; /* not enough space to compress */
378 { size_t const errorCode = BIT_initCStream(&bitC, op, oend-op);
379 if (HUF_isError(errorCode)) return 0; }
439 { size_t const initErr = BIT_initCStream(&bitC, op, oend-op);
440 if (HUF_isError(initErr)) return 0; }
380 441
381 442 n = srcSize & ~3; /* join to mod 4 */
382 443 switch (srcSize & 3)
383 444 {
384 445 case 3 : HUF_encodeSymbol(&bitC, ip[n+ 2], CTable);
385 446 HUF_FLUSHBITS_2(&bitC);
386 447 case 2 : HUF_encodeSymbol(&bitC, ip[n+ 1], CTable);
387 448 HUF_FLUSHBITS_1(&bitC);
388 449 case 1 : HUF_encodeSymbol(&bitC, ip[n+ 0], CTable);
389 450 HUF_FLUSHBITS(&bitC);
390 451 case 0 :
391 452 default: ;
392 453 }
393 454
394 455 for (; n>0; n-=4) { /* note : n&3==0 at this stage */
395 456 HUF_encodeSymbol(&bitC, ip[n- 1], CTable);
396 457 HUF_FLUSHBITS_1(&bitC);
397 458 HUF_encodeSymbol(&bitC, ip[n- 2], CTable);
398 459 HUF_FLUSHBITS_2(&bitC);
399 460 HUF_encodeSymbol(&bitC, ip[n- 3], CTable);
400 461 HUF_FLUSHBITS_1(&bitC);
401 462 HUF_encodeSymbol(&bitC, ip[n- 4], CTable);
402 463 HUF_FLUSHBITS(&bitC);
403 464 }
404 465
405 466 return BIT_closeCStream(&bitC);
406 467 }
407 468
408 469
409 470 size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable)
410 471 {
411 472 size_t const segmentSize = (srcSize+3)/4; /* first 3 segments */
412 473 const BYTE* ip = (const BYTE*) src;
413 474 const BYTE* const iend = ip + srcSize;
414 475 BYTE* const ostart = (BYTE*) dst;
415 476 BYTE* const oend = ostart + dstSize;
416 477 BYTE* op = ostart;
417 478
418 479 if (dstSize < 6 + 1 + 1 + 1 + 8) return 0; /* minimum space to compress successfully */
419 480 if (srcSize < 12) return 0; /* no saving possible : too small input */
420 481 op += 6; /* jumpTable */
421 482
422 { size_t const cSize = HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable);
423 if (HUF_isError(cSize)) return cSize;
483 { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
424 484 if (cSize==0) return 0;
425 485 MEM_writeLE16(ostart, (U16)cSize);
426 486 op += cSize;
427 487 }
428 488
429 489 ip += segmentSize;
430 { size_t const cSize = HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable);
431 if (HUF_isError(cSize)) return cSize;
490 { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
432 491 if (cSize==0) return 0;
433 492 MEM_writeLE16(ostart+2, (U16)cSize);
434 493 op += cSize;
435 494 }
436 495
437 496 ip += segmentSize;
438 { size_t const cSize = HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable);
439 if (HUF_isError(cSize)) return cSize;
497 { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, segmentSize, CTable) );
440 498 if (cSize==0) return 0;
441 499 MEM_writeLE16(ostart+4, (U16)cSize);
442 500 op += cSize;
443 501 }
444 502
445 503 ip += segmentSize;
446 { size_t const cSize = HUF_compress1X_usingCTable(op, oend-op, ip, iend-ip, CTable);
447 if (HUF_isError(cSize)) return cSize;
504 { CHECK_V_F(cSize, HUF_compress1X_usingCTable(op, oend-op, ip, iend-ip, CTable) );
448 505 if (cSize==0) return 0;
449 506 op += cSize;
450 507 }
451 508
452 509 return op-ostart;
453 510 }
454 511
455 512
513 /* `workSpace` must a table of at least 1024 unsigned */
456 514 static size_t HUF_compress_internal (
457 515 void* dst, size_t dstSize,
458 516 const void* src, size_t srcSize,
459 517 unsigned maxSymbolValue, unsigned huffLog,
460 unsigned singleStream)
518 unsigned singleStream,
519 void* workSpace, size_t wkspSize)
461 520 {
462 521 BYTE* const ostart = (BYTE*)dst;
463 522 BYTE* const oend = ostart + dstSize;
464 523 BYTE* op = ostart;
465 524
466 U32 count[HUF_SYMBOLVALUE_MAX+1];
467 HUF_CElt CTable[HUF_SYMBOLVALUE_MAX+1];
525 union {
526 U32 count[HUF_SYMBOLVALUE_MAX+1];
527 HUF_CElt CTable[HUF_SYMBOLVALUE_MAX+1];
528 } table; /* `count` can overlap with `CTable`; saves 1 KB */
468 529
469 530 /* checks & inits */
531 if (wkspSize < sizeof(huffNodeTable)) return ERROR(GENERIC);
470 532 if (!srcSize) return 0; /* Uncompressed (note : 1 means rle, so first byte must be correct) */
471 533 if (!dstSize) return 0; /* cannot fit within dst budget */
472 534 if (srcSize > HUF_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); /* current block size limit */
473 535 if (huffLog > HUF_TABLELOG_MAX) return ERROR(tableLog_tooLarge);
474 536 if (!maxSymbolValue) maxSymbolValue = HUF_SYMBOLVALUE_MAX;
475 537 if (!huffLog) huffLog = HUF_TABLELOG_DEFAULT;
476 538
477 539 /* Scan input and build symbol stats */
478 { size_t const largest = FSE_count (count, &maxSymbolValue, (const BYTE*)src, srcSize);
479 if (HUF_isError(largest)) return largest;
540 { CHECK_V_F(largest, FSE_count_wksp (table.count, &maxSymbolValue, (const BYTE*)src, srcSize, (U32*)workSpace) );
480 541 if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
481 542 if (largest <= (srcSize >> 7)+1) return 0; /* Fast heuristic : not compressible enough */
482 543 }
483 544
484 545 /* Build Huffman Tree */
485 546 huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue);
486 { size_t const maxBits = HUF_buildCTable (CTable, count, maxSymbolValue, huffLog);
487 if (HUF_isError(maxBits)) return maxBits;
547 { CHECK_V_F(maxBits, HUF_buildCTable_wksp (table.CTable, table.count, maxSymbolValue, huffLog, workSpace, wkspSize) );
488 548 huffLog = (U32)maxBits;
489 549 }
490 550
491 551 /* Write table description header */
492 { size_t const hSize = HUF_writeCTable (op, dstSize, CTable, maxSymbolValue, huffLog);
493 if (HUF_isError(hSize)) return hSize;
552 { CHECK_V_F(hSize, HUF_writeCTable (op, dstSize, table.CTable, maxSymbolValue, huffLog) );
494 553 if (hSize + 12 >= srcSize) return 0; /* not useful to try compression */
495 554 op += hSize;
496 555 }
497 556
498 557 /* Compress */
499 558 { size_t const cSize = (singleStream) ?
500 HUF_compress1X_usingCTable(op, oend - op, src, srcSize, CTable) : /* single segment */
501 HUF_compress4X_usingCTable(op, oend - op, src, srcSize, CTable);
559 HUF_compress1X_usingCTable(op, oend - op, src, srcSize, table.CTable) : /* single segment */
560 HUF_compress4X_usingCTable(op, oend - op, src, srcSize, table.CTable);
502 561 if (HUF_isError(cSize)) return cSize;
503 562 if (cSize==0) return 0; /* uncompressible */
504 563 op += cSize;
505 564 }
506 565
507 566 /* check compressibility */
508 567 if ((size_t)(op-ostart) >= srcSize-1)
509 568 return 0;
510 569
511 570 return op-ostart;
512 571 }
513 572
514 573
574 size_t HUF_compress1X_wksp (void* dst, size_t dstSize,
575 const void* src, size_t srcSize,
576 unsigned maxSymbolValue, unsigned huffLog,
577 void* workSpace, size_t wkspSize)
578 {
579 return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1 /* single stream */, workSpace, wkspSize);
580 }
581
515 582 size_t HUF_compress1X (void* dst, size_t dstSize,
516 583 const void* src, size_t srcSize,
517 584 unsigned maxSymbolValue, unsigned huffLog)
518 585 {
519 return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1);
586 unsigned workSpace[1024];
587 return HUF_compress1X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
588 }
589
590 size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
591 const void* src, size_t srcSize,
592 unsigned maxSymbolValue, unsigned huffLog,
593 void* workSpace, size_t wkspSize)
594 {
595 return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0 /* 4 streams */, workSpace, wkspSize);
520 596 }
521 597
522 598 size_t HUF_compress2 (void* dst, size_t dstSize,
523 599 const void* src, size_t srcSize,
524 600 unsigned maxSymbolValue, unsigned huffLog)
525 601 {
526 return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 0);
602 unsigned workSpace[1024];
603 return HUF_compress4X_wksp(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, workSpace, sizeof(workSpace));
527 604 }
528 605
529
530 606 size_t HUF_compress (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
531 607 {
532 608 return HUF_compress2(dst, maxDstSize, src, (U32)srcSize, 255, HUF_TABLELOG_DEFAULT);
533 609 }
@@ -1,3264 +1,3291 b''
1 1 /**
2 2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 3 * All rights reserved.
4 4 *
5 5 * This source code is licensed under the BSD-style license found in the
6 6 * LICENSE file in the root directory of this source tree. An additional grant
7 7 * of patent rights can be found in the PATENTS file in the same directory.
8 8 */
9 9
10 10
11 11 /*-*************************************
12 12 * Dependencies
13 13 ***************************************/
14 14 #include <string.h> /* memset */
15 15 #include "mem.h"
16 16 #define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
17 17 #include "xxhash.h" /* XXH_reset, update, digest */
18 18 #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
19 19 #include "fse.h"
20 20 #define HUF_STATIC_LINKING_ONLY
21 21 #include "huf.h"
22 22 #include "zstd_internal.h" /* includes zstd.h */
23 23
24 24
25 25 /*-*************************************
26 26 * Constants
27 27 ***************************************/
28 28 static const U32 g_searchStrength = 8; /* control skip over incompressible data */
29 29 #define HASH_READ_SIZE 8
30 30 typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
31 31
32 32
33 33 /*-*************************************
34 34 * Helper functions
35 35 ***************************************/
36 #define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
36 37 size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
37 38
38 39
39 40 /*-*************************************
40 41 * Sequence storage
41 42 ***************************************/
42 43 static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
43 44 {
44 45 ssPtr->lit = ssPtr->litStart;
45 46 ssPtr->sequences = ssPtr->sequencesStart;
46 47 ssPtr->longLengthID = 0;
47 48 }
48 49
49 50
50 51 /*-*************************************
51 52 * Context memory management
52 53 ***************************************/
53 54 struct ZSTD_CCtx_s
54 55 {
55 56 const BYTE* nextSrc; /* next block here to continue on current prefix */
56 57 const BYTE* base; /* All regular indexes relative to this position */
57 58 const BYTE* dictBase; /* extDict indexes relative to this position */
58 59 U32 dictLimit; /* below that point, need extDict */
59 60 U32 lowLimit; /* below that point, no more data */
60 61 U32 nextToUpdate; /* index from which to continue dictionary update */
61 62 U32 nextToUpdate3; /* index from which to continue dictionary update */
62 63 U32 hashLog3; /* dispatch table : larger == faster, more memory */
63 64 U32 loadedDictEnd;
64 65 ZSTD_compressionStage_e stage;
65 66 U32 rep[ZSTD_REP_NUM];
66 67 U32 savedRep[ZSTD_REP_NUM];
67 68 U32 dictID;
68 69 ZSTD_parameters params;
69 70 void* workSpace;
70 71 size_t workSpaceSize;
71 72 size_t blockSize;
72 73 U64 frameContentSize;
73 74 XXH64_state_t xxhState;
74 75 ZSTD_customMem customMem;
75 76
76 77 seqStore_t seqStore; /* sequences storage ptrs */
77 78 U32* hashTable;
78 79 U32* hashTable3;
79 80 U32* chainTable;
80 81 HUF_CElt* hufTable;
81 82 U32 flagStaticTables;
82 83 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
83 84 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
84 85 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
86 unsigned tmpCounters[1024];
85 87 };
86 88
87 89 ZSTD_CCtx* ZSTD_createCCtx(void)
88 90 {
89 91 return ZSTD_createCCtx_advanced(defaultCustomMem);
90 92 }
91 93
92 94 ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
93 95 {
94 96 ZSTD_CCtx* cctx;
95 97
96 98 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
97 99 if (!customMem.customAlloc || !customMem.customFree) return NULL;
98 100
99 101 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
100 102 if (!cctx) return NULL;
101 103 memset(cctx, 0, sizeof(ZSTD_CCtx));
102 104 memcpy(&(cctx->customMem), &customMem, sizeof(customMem));
103 105 return cctx;
104 106 }
105 107
106 108 size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
107 109 {
108 110 if (cctx==NULL) return 0; /* support free on NULL */
109 111 ZSTD_free(cctx->workSpace, cctx->customMem);
110 112 ZSTD_free(cctx, cctx->customMem);
111 113 return 0; /* reserved as a potential error code in the future */
112 114 }
113 115
114 116 size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
115 117 {
116 118 if (cctx==NULL) return 0; /* support sizeof on NULL */
117 119 return sizeof(*cctx) + cctx->workSpaceSize;
118 120 }
119 121
120 122 const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
121 123 {
122 124 return &(ctx->seqStore);
123 125 }
124 126
125 127 static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
126 128 {
127 129 return cctx->params;
128 130 }
129 131
130 132
131 133 /** ZSTD_checkParams() :
132 134 ensure param values remain within authorized range.
133 135 @return : 0, or an error code if one value is beyond authorized range */
134 136 size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
135 137 {
136 138 # define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
137 139 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
138 140 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
139 141 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
140 142 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
141 143 { U32 const searchLengthMin = ((cParams.strategy == ZSTD_fast) | (cParams.strategy == ZSTD_greedy)) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN;
142 144 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
143 145 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
144 146 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
145 147 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported);
146 148 return 0;
147 149 }
148 150
149 151
152 /** ZSTD_cycleLog() :
153 * condition for correct operation : hashLog > 1 */
154 static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
155 {
156 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
157 return hashLog - btScale;
158 }
159
150 160 /** ZSTD_adjustCParams() :
151 161 optimize `cPar` for a given input (`srcSize` and `dictSize`).
152 162 mostly downsizing to reduce memory consumption and initialization.
153 163 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
154 164 but if both are 0, no optimization can be done.
155 165 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
156 166 ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
157 167 {
158 168 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
159 169
160 170 /* resize params, to use less memory when necessary */
161 171 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
162 172 U64 const rSize = srcSize + dictSize + minSrcSize;
163 173 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
164 174 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
165 175 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
166 176 } }
167 177 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
168 { U32 const btPlus = (cPar.strategy == ZSTD_btlazy2) | (cPar.strategy == ZSTD_btopt) | (cPar.strategy == ZSTD_btopt2);
169 U32 const maxChainLog = cPar.windowLog+btPlus;
170 if (cPar.chainLog > maxChainLog) cPar.chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */
178 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
179 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
180 }
171 181
172 182 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
173 183
174 184 return cPar;
175 185 }
176 186
177 187
178 188 size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
179 189 {
180 190 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
181 191 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
182 192 size_t const maxNbSeq = blockSize / divider;
183 193 size_t const tokenSpace = blockSize + 11*maxNbSeq;
184 194
185 195 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
186 196 size_t const hSize = ((size_t)1) << cParams.hashLog;
187 197 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
188 198 size_t const h3Size = ((size_t)1) << hashLog3;
189 199 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
190 200
191 201 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
192 202 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
193 203 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
194 204 + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
195 205
196 206 return sizeof(ZSTD_CCtx) + neededSpace;
197 207 }
198 208
199 209
200 210 static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
201 211 {
202 212 return (param1.cParams.hashLog == param2.cParams.hashLog)
203 213 & (param1.cParams.chainLog == param2.cParams.chainLog)
204 214 & (param1.cParams.strategy == param2.cParams.strategy)
205 215 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
206 216 }
207 217
208 218 /*! ZSTD_continueCCtx() :
209 219 reuse CCtx without reset (note : requires no dictionary) */
210 220 static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
211 221 {
212 222 U32 const end = (U32)(cctx->nextSrc - cctx->base);
213 223 cctx->params = params;
214 224 cctx->frameContentSize = frameContentSize;
215 225 cctx->lowLimit = end;
216 226 cctx->dictLimit = end;
217 227 cctx->nextToUpdate = end+1;
218 228 cctx->stage = ZSTDcs_init;
219 229 cctx->dictID = 0;
220 230 cctx->loadedDictEnd = 0;
221 231 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
222 232 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
223 233 XXH64_reset(&cctx->xxhState, 0);
224 234 return 0;
225 235 }
226 236
227 237 typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
228 238
229 239 /*! ZSTD_resetCCtx_advanced() :
230 240 note : 'params' must be validated */
231 241 static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
232 242 ZSTD_parameters params, U64 frameContentSize,
233 243 ZSTD_compResetPolicy_e const crp)
234 244 {
235 245 if (crp == ZSTDcrp_continue)
236 246 if (ZSTD_equivalentParams(params, zc->params))
237 247 return ZSTD_continueCCtx(zc, params, frameContentSize);
238 248
239 249 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
240 250 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
241 251 size_t const maxNbSeq = blockSize / divider;
242 252 size_t const tokenSpace = blockSize + 11*maxNbSeq;
243 253 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
244 254 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
245 255 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
246 256 size_t const h3Size = ((size_t)1) << hashLog3;
247 257 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
248 258 void* ptr;
249 259
250 260 /* Check if workSpace is large enough, alloc a new one if needed */
251 261 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
252 262 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
253 263 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
254 264 + (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
255 265 if (zc->workSpaceSize < neededSpace) {
256 266 ZSTD_free(zc->workSpace, zc->customMem);
257 267 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
258 268 if (zc->workSpace == NULL) return ERROR(memory_allocation);
259 269 zc->workSpaceSize = neededSpace;
260 270 } }
261 271
262 272 if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
263 273 XXH64_reset(&zc->xxhState, 0);
264 274 zc->hashLog3 = hashLog3;
265 275 zc->hashTable = (U32*)(zc->workSpace);
266 276 zc->chainTable = zc->hashTable + hSize;
267 277 zc->hashTable3 = zc->chainTable + chainSize;
268 278 ptr = zc->hashTable3 + h3Size;
269 279 zc->hufTable = (HUF_CElt*)ptr;
270 280 zc->flagStaticTables = 0;
271 281 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
272 282
273 283 zc->nextToUpdate = 1;
274 284 zc->nextSrc = NULL;
275 285 zc->base = NULL;
276 286 zc->dictBase = NULL;
277 287 zc->dictLimit = 0;
278 288 zc->lowLimit = 0;
279 289 zc->params = params;
280 290 zc->blockSize = blockSize;
281 291 zc->frameContentSize = frameContentSize;
282 292 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
283 293
284 294 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
285 295 zc->seqStore.litFreq = (U32*)ptr;
286 296 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
287 297 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
288 298 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
289 299 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
290 300 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
291 301 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
292 302 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
293 303 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
294 304 zc->seqStore.litLengthSum = 0;
295 305 }
296 306 zc->seqStore.sequencesStart = (seqDef*)ptr;
297 307 ptr = zc->seqStore.sequencesStart + maxNbSeq;
298 308 zc->seqStore.llCode = (BYTE*) ptr;
299 309 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
300 310 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
301 311 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
302 312
303 313 zc->stage = ZSTDcs_init;
304 314 zc->dictID = 0;
305 315 zc->loadedDictEnd = 0;
306 316
307 317 return 0;
308 318 }
309 319 }
310 320
311 321
312 322 /*! ZSTD_copyCCtx() :
313 323 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
314 324 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
315 325 * @return : 0, or an error code */
316 326 size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
317 327 {
318 328 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
319 329
320 330 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
321 331 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, pledgedSrcSize, ZSTDcrp_noMemset);
322 332
323 333 /* copy tables */
324 334 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
325 335 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
326 336 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
327 337 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
328 338 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
329 339 }
330 340
331 341 /* copy dictionary offsets */
332 342 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
333 343 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
334 344 dstCCtx->nextSrc = srcCCtx->nextSrc;
335 345 dstCCtx->base = srcCCtx->base;
336 346 dstCCtx->dictBase = srcCCtx->dictBase;
337 347 dstCCtx->dictLimit = srcCCtx->dictLimit;
338 348 dstCCtx->lowLimit = srcCCtx->lowLimit;
339 349 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
340 350 dstCCtx->dictID = srcCCtx->dictID;
341 351
342 352 /* copy entropy tables */
343 353 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
344 354 if (srcCCtx->flagStaticTables) {
345 355 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
346 356 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
347 357 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
348 358 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
349 359 }
350 360
351 361 return 0;
352 362 }
353 363
354 364
355 365 /*! ZSTD_reduceTable() :
356 366 * reduce table indexes by `reducerValue` */
357 367 static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
358 368 {
359 369 U32 u;
360 370 for (u=0 ; u < size ; u++) {
361 371 if (table[u] < reducerValue) table[u] = 0;
362 372 else table[u] -= reducerValue;
363 373 }
364 374 }
365 375
366 376 /*! ZSTD_reduceIndex() :
367 377 * rescale all indexes to avoid future overflow (indexes are U32) */
368 378 static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
369 379 {
370 380 { U32 const hSize = 1 << zc->params.cParams.hashLog;
371 381 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
372 382
373 383 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
374 384 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
375 385
376 386 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
377 387 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
378 388 }
379 389
380 390
381 391 /*-*******************************************************
382 392 * Block entropic compression
383 393 *********************************************************/
384 394
385 395 /* See doc/zstd_compression_format.md for detailed format description */
386 396
387 397 size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
388 398 {
389 399 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
390 400 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
391 401 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
392 402 return ZSTD_blockHeaderSize+srcSize;
393 403 }
394 404
395 405
396 406 static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
397 407 {
398 408 BYTE* const ostart = (BYTE* const)dst;
399 409 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
400 410
401 411 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
402 412
403 413 switch(flSize)
404 414 {
405 415 case 1: /* 2 - 1 - 5 */
406 416 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
407 417 break;
408 418 case 2: /* 2 - 2 - 12 */
409 419 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
410 420 break;
411 421 default: /*note : should not be necessary : flSize is within {1,2,3} */
412 422 case 3: /* 2 - 2 - 20 */
413 423 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
414 424 break;
415 425 }
416 426
417 427 memcpy(ostart + flSize, src, srcSize);
418 428 return srcSize + flSize;
419 429 }
420 430
421 431 static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
422 432 {
423 433 BYTE* const ostart = (BYTE* const)dst;
424 434 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
425 435
426 436 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
427 437
428 438 switch(flSize)
429 439 {
430 440 case 1: /* 2 - 1 - 5 */
431 441 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
432 442 break;
433 443 case 2: /* 2 - 2 - 12 */
434 444 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
435 445 break;
436 446 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
437 447 case 3: /* 2 - 2 - 20 */
438 448 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
439 449 break;
440 450 }
441 451
442 452 ostart[flSize] = *(const BYTE*)src;
443 453 return flSize+1;
444 454 }
445 455
446 456
447 457 static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
448 458
449 459 static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
450 460 void* dst, size_t dstCapacity,
451 461 const void* src, size_t srcSize)
452 462 {
453 463 size_t const minGain = ZSTD_minGain(srcSize);
454 464 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
455 465 BYTE* const ostart = (BYTE*)dst;
456 466 U32 singleStream = srcSize < 256;
457 467 symbolEncodingType_e hType = set_compressed;
458 468 size_t cLitSize;
459 469
460 470
461 471 /* small ? don't even attempt compression (speed opt) */
462 472 # define LITERAL_NOENTROPY 63
463 473 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
464 474 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
465 475 }
466 476
467 477 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
468 478 if (zc->flagStaticTables && (lhSize==3)) {
469 479 hType = set_repeat;
470 480 singleStream = 1;
471 481 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
472 482 } else {
473 cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11)
474 : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11);
483 cLitSize = singleStream ? HUF_compress1X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters))
484 : HUF_compress4X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters));
475 485 }
476 486
477 487 if ((cLitSize==0) | (cLitSize >= srcSize - minGain))
478 488 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
479 489 if (cLitSize==1)
480 490 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
481 491
482 492 /* Build header */
483 493 switch(lhSize)
484 494 {
485 495 case 3: /* 2 - 2 - 10 - 10 */
486 496 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
487 497 MEM_writeLE24(ostart, lhc);
488 498 break;
489 499 }
490 500 case 4: /* 2 - 2 - 14 - 14 */
491 501 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
492 502 MEM_writeLE32(ostart, lhc);
493 503 break;
494 504 }
495 505 default: /* should not be necessary, lhSize is only {3,4,5} */
496 506 case 5: /* 2 - 2 - 18 - 18 */
497 507 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
498 508 MEM_writeLE32(ostart, lhc);
499 509 ostart[4] = (BYTE)(cLitSize >> 10);
500 510 break;
501 511 }
502 512 }
503 513 return lhSize+cLitSize;
504 514 }
505 515
506 516 static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
507 517 8, 9, 10, 11, 12, 13, 14, 15,
508 518 16, 16, 17, 17, 18, 18, 19, 19,
509 519 20, 20, 20, 20, 21, 21, 21, 21,
510 520 22, 22, 22, 22, 22, 22, 22, 22,
511 521 23, 23, 23, 23, 23, 23, 23, 23,
512 522 24, 24, 24, 24, 24, 24, 24, 24,
513 523 24, 24, 24, 24, 24, 24, 24, 24 };
514 524
515 525 static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
516 526 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
517 527 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
518 528 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
519 529 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
520 530 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
521 531 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
522 532 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
523 533
524 534
525 535 void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
526 536 {
527 537 BYTE const LL_deltaCode = 19;
528 538 BYTE const ML_deltaCode = 36;
529 539 const seqDef* const sequences = seqStorePtr->sequencesStart;
530 540 BYTE* const llCodeTable = seqStorePtr->llCode;
531 541 BYTE* const ofCodeTable = seqStorePtr->ofCode;
532 542 BYTE* const mlCodeTable = seqStorePtr->mlCode;
533 543 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
534 544 U32 u;
535 545 for (u=0; u<nbSeq; u++) {
536 546 U32 const llv = sequences[u].litLength;
537 547 U32 const mlv = sequences[u].matchLength;
538 548 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
539 549 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
540 550 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
541 551 }
542 552 if (seqStorePtr->longLengthID==1)
543 553 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
544 554 if (seqStorePtr->longLengthID==2)
545 555 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
546 556 }
547 557
548 558
549 559 size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
550 560 void* dst, size_t dstCapacity,
551 561 size_t srcSize)
552 562 {
553 563 const seqStore_t* seqStorePtr = &(zc->seqStore);
554 564 U32 count[MaxSeq+1];
555 565 S16 norm[MaxSeq+1];
556 566 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
557 567 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
558 568 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
559 569 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
560 570 const seqDef* const sequences = seqStorePtr->sequencesStart;
561 571 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
562 572 const BYTE* const llCodeTable = seqStorePtr->llCode;
563 573 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
564 574 BYTE* const ostart = (BYTE*)dst;
565 575 BYTE* const oend = ostart + dstCapacity;
566 576 BYTE* op = ostart;
567 577 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
568 578 BYTE* seqHead;
579 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
569 580
570 581 /* Compress literals */
571 582 { const BYTE* const literals = seqStorePtr->litStart;
572 583 size_t const litSize = seqStorePtr->lit - literals;
573 584 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
574 585 if (ZSTD_isError(cSize)) return cSize;
575 586 op += cSize;
576 587 }
577 588
578 589 /* Sequences Header */
579 590 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
580 591 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
581 592 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
582 593 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
583 594 if (nbSeq==0) goto _check_compressibility;
584 595
585 596 /* seqHead : flags for FSE encoding type */
586 597 seqHead = op++;
587 598
588 599 #define MIN_SEQ_FOR_DYNAMIC_FSE 64
589 600 #define MAX_SEQ_FOR_STATIC_FSE 1000
590 601
591 602 /* convert length/distances into codes */
592 603 ZSTD_seqToCodes(seqStorePtr);
593 604
594 605 /* CTable for Literal Lengths */
595 606 { U32 max = MaxLL;
596 size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
607 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters);
597 608 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
598 609 *op++ = llCodeTable[0];
599 610 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
600 611 LLtype = set_rle;
601 612 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
602 613 LLtype = set_repeat;
603 614 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
604 FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
615 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
605 616 LLtype = set_basic;
606 617 } else {
607 618 size_t nbSeq_1 = nbSeq;
608 619 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
609 620 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
610 621 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
611 622 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
612 623 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
613 624 op += NCountSize; }
614 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
625 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
615 626 LLtype = set_compressed;
616 627 } }
617 628
618 629 /* CTable for Offsets */
619 630 { U32 max = MaxOff;
620 size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
631 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters);
621 632 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
622 633 *op++ = ofCodeTable[0];
623 634 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
624 635 Offtype = set_rle;
625 636 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
626 637 Offtype = set_repeat;
627 638 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
628 FSE_buildCTable(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog);
639 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
629 640 Offtype = set_basic;
630 641 } else {
631 642 size_t nbSeq_1 = nbSeq;
632 643 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
633 644 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
634 645 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
635 646 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
636 647 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
637 648 op += NCountSize; }
638 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
649 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
639 650 Offtype = set_compressed;
640 651 } }
641 652
642 653 /* CTable for MatchLengths */
643 654 { U32 max = MaxML;
644 size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
655 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters);
645 656 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
646 657 *op++ = *mlCodeTable;
647 658 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
648 659 MLtype = set_rle;
649 660 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
650 661 MLtype = set_repeat;
651 662 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
652 FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
663 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
653 664 MLtype = set_basic;
654 665 } else {
655 666 size_t nbSeq_1 = nbSeq;
656 667 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
657 668 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
658 669 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
659 670 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
660 671 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
661 672 op += NCountSize; }
662 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
673 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
663 674 MLtype = set_compressed;
664 675 } }
665 676
666 677 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
667 678 zc->flagStaticTables = 0;
668 679
669 680 /* Encoding Sequences */
670 681 { BIT_CStream_t blockStream;
671 682 FSE_CState_t stateMatchLength;
672 683 FSE_CState_t stateOffsetBits;
673 684 FSE_CState_t stateLitLength;
674 685
675 686 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
676 687
677 688 /* first symbols */
678 689 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
679 690 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
680 691 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
681 692 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
682 693 if (MEM_32bits()) BIT_flushBits(&blockStream);
683 694 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
684 695 if (MEM_32bits()) BIT_flushBits(&blockStream);
685 696 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
686 697 BIT_flushBits(&blockStream);
687 698
688 699 { size_t n;
689 700 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
690 701 BYTE const llCode = llCodeTable[n];
691 702 BYTE const ofCode = ofCodeTable[n];
692 703 BYTE const mlCode = mlCodeTable[n];
693 704 U32 const llBits = LL_bits[llCode];
694 705 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
695 706 U32 const mlBits = ML_bits[mlCode];
696 707 /* (7)*/ /* (7)*/
697 708 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
698 709 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
699 710 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
700 711 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
701 712 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
702 713 BIT_flushBits(&blockStream); /* (7)*/
703 714 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
704 715 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
705 716 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
706 717 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
707 718 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
708 719 BIT_flushBits(&blockStream); /* (7)*/
709 720 } }
710 721
711 722 FSE_flushCState(&blockStream, &stateMatchLength);
712 723 FSE_flushCState(&blockStream, &stateOffsetBits);
713 724 FSE_flushCState(&blockStream, &stateLitLength);
714 725
715 726 { size_t const streamSize = BIT_closeCStream(&blockStream);
716 727 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
717 728 op += streamSize;
718 729 } }
719 730
720 731 /* check compressibility */
721 732 _check_compressibility:
722 733 { size_t const minGain = ZSTD_minGain(srcSize);
723 734 size_t const maxCSize = srcSize - minGain;
724 735 if ((size_t)(op-ostart) >= maxCSize) return 0; }
725 736
726 737 /* confirm repcodes */
727 738 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->savedRep[i]; }
728 739
729 740 return op - ostart;
730 741 }
731 742
732 743
733 744 /*! ZSTD_storeSeq() :
734 745 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
735 746 `offsetCode` : distance to match, or 0 == repCode.
736 747 `matchCode` : matchLength - MINMATCH
737 748 */
738 749 MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
739 750 {
740 751 #if 0 /* for debug */
741 752 static const BYTE* g_start = NULL;
742 const U32 pos = (U32)(literals - g_start);
743 if (g_start==NULL) g_start = literals;
753 const U32 pos = (U32)((const BYTE*)literals - g_start);
754 if (g_start==NULL) g_start = (const BYTE*)literals;
744 755 //if ((pos > 1) && (pos < 50000))
745 756 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
746 757 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
747 758 #endif
748 759 /* copy Literals */
749 760 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
750 761 seqStorePtr->lit += litLength;
751 762
752 763 /* literal Length */
753 764 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
754 765 seqStorePtr->sequences[0].litLength = (U16)litLength;
755 766
756 767 /* match offset */
757 768 seqStorePtr->sequences[0].offset = offsetCode + 1;
758 769
759 770 /* match Length */
760 771 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
761 772 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
762 773
763 774 seqStorePtr->sequences++;
764 775 }
765 776
766 777
767 778 /*-*************************************
768 779 * Match length counter
769 780 ***************************************/
770 781 static unsigned ZSTD_NbCommonBytes (register size_t val)
771 782 {
772 783 if (MEM_isLittleEndian()) {
773 784 if (MEM_64bits()) {
774 785 # if defined(_MSC_VER) && defined(_WIN64)
775 786 unsigned long r = 0;
776 787 _BitScanForward64( &r, (U64)val );
777 788 return (unsigned)(r>>3);
778 789 # elif defined(__GNUC__) && (__GNUC__ >= 3)
779 790 return (__builtin_ctzll((U64)val) >> 3);
780 791 # else
781 792 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
782 793 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
783 794 # endif
784 795 } else { /* 32 bits */
785 796 # if defined(_MSC_VER)
786 797 unsigned long r=0;
787 798 _BitScanForward( &r, (U32)val );
788 799 return (unsigned)(r>>3);
789 800 # elif defined(__GNUC__) && (__GNUC__ >= 3)
790 801 return (__builtin_ctz((U32)val) >> 3);
791 802 # else
792 803 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
793 804 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
794 805 # endif
795 806 }
796 807 } else { /* Big Endian CPU */
797 808 if (MEM_64bits()) {
798 809 # if defined(_MSC_VER) && defined(_WIN64)
799 810 unsigned long r = 0;
800 811 _BitScanReverse64( &r, val );
801 812 return (unsigned)(r>>3);
802 813 # elif defined(__GNUC__) && (__GNUC__ >= 3)
803 814 return (__builtin_clzll(val) >> 3);
804 815 # else
805 816 unsigned r;
806 817 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
807 818 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
808 819 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
809 820 r += (!val);
810 821 return r;
811 822 # endif
812 823 } else { /* 32 bits */
813 824 # if defined(_MSC_VER)
814 825 unsigned long r = 0;
815 826 _BitScanReverse( &r, (unsigned long)val );
816 827 return (unsigned)(r>>3);
817 828 # elif defined(__GNUC__) && (__GNUC__ >= 3)
818 829 return (__builtin_clz((U32)val) >> 3);
819 830 # else
820 831 unsigned r;
821 832 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
822 833 r += (!val);
823 834 return r;
824 835 # endif
825 836 } }
826 837 }
827 838
828 839
829 840 static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
830 841 {
831 842 const BYTE* const pStart = pIn;
832 843 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
833 844
834 845 while (pIn < pInLoopLimit) {
835 846 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
836 847 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
837 848 pIn += ZSTD_NbCommonBytes(diff);
838 849 return (size_t)(pIn - pStart);
839 850 }
840 851 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
841 852 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
842 853 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
843 854 return (size_t)(pIn - pStart);
844 855 }
845 856
846 857 /** ZSTD_count_2segments() :
847 858 * can count match length with `ip` & `match` in 2 different segments.
848 859 * convention : on reaching mEnd, match count continue starting from iStart
849 860 */
850 861 static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
851 862 {
852 863 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
853 864 size_t const matchLength = ZSTD_count(ip, match, vEnd);
854 865 if (match + matchLength != mEnd) return matchLength;
855 866 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
856 867 }
857 868
858 869
859 870 /*-*************************************
860 871 * Hashes
861 872 ***************************************/
862 873 static const U32 prime3bytes = 506832829U;
863 874 static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
864 875 MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
865 876
866 877 static const U32 prime4bytes = 2654435761U;
867 878 static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
868 879 static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
869 880
870 881 static const U64 prime5bytes = 889523592379ULL;
871 882 static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
872 883 static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
873 884
874 885 static const U64 prime6bytes = 227718039650203ULL;
875 886 static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
876 887 static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
877 888
878 889 static const U64 prime7bytes = 58295818150454627ULL;
879 890 static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
880 891 static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
881 892
882 893 static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
883 894 static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
884 895 static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
885 896
886 897 static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
887 898 {
888 899 switch(mls)
889 900 {
890 901 default:
891 902 case 4: return ZSTD_hash4Ptr(p, hBits);
892 903 case 5: return ZSTD_hash5Ptr(p, hBits);
893 904 case 6: return ZSTD_hash6Ptr(p, hBits);
894 905 case 7: return ZSTD_hash7Ptr(p, hBits);
895 906 case 8: return ZSTD_hash8Ptr(p, hBits);
896 907 }
897 908 }
898 909
899 910
900 911 /*-*************************************
901 912 * Fast Scan
902 913 ***************************************/
903 914 static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
904 915 {
905 916 U32* const hashTable = zc->hashTable;
906 917 U32 const hBits = zc->params.cParams.hashLog;
907 918 const BYTE* const base = zc->base;
908 919 const BYTE* ip = base + zc->nextToUpdate;
909 920 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
910 921 const size_t fastHashFillStep = 3;
911 922
912 923 while(ip <= iend) {
913 924 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
914 925 ip += fastHashFillStep;
915 926 }
916 927 }
917 928
918 929
919 930 FORCE_INLINE
920 931 void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
921 932 const void* src, size_t srcSize,
922 933 const U32 mls)
923 934 {
924 935 U32* const hashTable = cctx->hashTable;
925 936 U32 const hBits = cctx->params.cParams.hashLog;
926 937 seqStore_t* seqStorePtr = &(cctx->seqStore);
927 938 const BYTE* const base = cctx->base;
928 939 const BYTE* const istart = (const BYTE*)src;
929 940 const BYTE* ip = istart;
930 941 const BYTE* anchor = istart;
931 942 const U32 lowestIndex = cctx->dictLimit;
932 943 const BYTE* const lowest = base + lowestIndex;
933 944 const BYTE* const iend = istart + srcSize;
934 945 const BYTE* const ilimit = iend - HASH_READ_SIZE;
935 946 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
936 947 U32 offsetSaved = 0;
937 948
938 949 /* init */
939 950 ip += (ip==lowest);
940 951 { U32 const maxRep = (U32)(ip-lowest);
941 952 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
942 953 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
943 954 }
944 955
945 956 /* Main Search Loop */
946 957 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
947 958 size_t mLength;
948 959 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
949 960 U32 const current = (U32)(ip-base);
950 961 U32 const matchIndex = hashTable[h];
951 962 const BYTE* match = base + matchIndex;
952 963 hashTable[h] = current; /* update hash table */
953 964
954 965 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
955 966 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
956 967 ip++;
957 968 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
958 969 } else {
959 970 U32 offset;
960 971 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
961 972 ip += ((ip-anchor) >> g_searchStrength) + 1;
962 973 continue;
963 974 }
964 975 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
965 976 offset = (U32)(ip-match);
966 977 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
967 978 offset_2 = offset_1;
968 979 offset_1 = offset;
969 980
970 981 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
971 982 }
972 983
973 984 /* match found */
974 985 ip += mLength;
975 986 anchor = ip;
976 987
977 988 if (ip <= ilimit) {
978 989 /* Fill Table */
979 990 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */
980 991 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
981 992 /* check immediate repcode */
982 993 while ( (ip <= ilimit)
983 994 && ( (offset_2>0)
984 995 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
985 996 /* store sequence */
986 997 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
987 998 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
988 999 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
989 1000 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
990 1001 ip += rLength;
991 1002 anchor = ip;
992 1003 continue; /* faster when present ... (?) */
993 1004 } } }
994 1005
995 1006 /* save reps for next block */
996 1007 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
997 1008 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
998 1009
999 1010 /* Last Literals */
1000 1011 { size_t const lastLLSize = iend - anchor;
1001 1012 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1002 1013 seqStorePtr->lit += lastLLSize;
1003 1014 }
1004 1015 }
1005 1016
1006 1017
1007 1018 static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
1008 1019 const void* src, size_t srcSize)
1009 1020 {
1010 1021 const U32 mls = ctx->params.cParams.searchLength;
1011 1022 switch(mls)
1012 1023 {
1013 1024 default:
1014 1025 case 4 :
1015 1026 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
1016 1027 case 5 :
1017 1028 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
1018 1029 case 6 :
1019 1030 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
1020 1031 case 7 :
1021 1032 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
1022 1033 }
1023 1034 }
1024 1035
1025 1036
1026 1037 static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
1027 1038 const void* src, size_t srcSize,
1028 1039 const U32 mls)
1029 1040 {
1030 1041 U32* hashTable = ctx->hashTable;
1031 1042 const U32 hBits = ctx->params.cParams.hashLog;
1032 1043 seqStore_t* seqStorePtr = &(ctx->seqStore);
1033 1044 const BYTE* const base = ctx->base;
1034 1045 const BYTE* const dictBase = ctx->dictBase;
1035 1046 const BYTE* const istart = (const BYTE*)src;
1036 1047 const BYTE* ip = istart;
1037 1048 const BYTE* anchor = istart;
1038 1049 const U32 lowestIndex = ctx->lowLimit;
1039 1050 const BYTE* const dictStart = dictBase + lowestIndex;
1040 1051 const U32 dictLimit = ctx->dictLimit;
1041 1052 const BYTE* const lowPrefixPtr = base + dictLimit;
1042 1053 const BYTE* const dictEnd = dictBase + dictLimit;
1043 1054 const BYTE* const iend = istart + srcSize;
1044 1055 const BYTE* const ilimit = iend - 8;
1045 1056 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1046 1057
1047 1058 /* Search Loop */
1048 1059 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1049 1060 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
1050 1061 const U32 matchIndex = hashTable[h];
1051 1062 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1052 1063 const BYTE* match = matchBase + matchIndex;
1053 1064 const U32 current = (U32)(ip-base);
1054 1065 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1055 1066 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1056 1067 const BYTE* repMatch = repBase + repIndex;
1057 1068 size_t mLength;
1058 1069 hashTable[h] = current; /* update hash table */
1059 1070
1060 1071 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1061 1072 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1062 1073 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1063 1074 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
1064 1075 ip++;
1065 1076 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1066 1077 } else {
1067 1078 if ( (matchIndex < lowestIndex) ||
1068 1079 (MEM_read32(match) != MEM_read32(ip)) ) {
1069 1080 ip += ((ip-anchor) >> g_searchStrength) + 1;
1070 1081 continue;
1071 1082 }
1072 1083 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1073 1084 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1074 1085 U32 offset;
1075 1086 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1076 1087 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1077 1088 offset = current - matchIndex;
1078 1089 offset_2 = offset_1;
1079 1090 offset_1 = offset;
1080 1091 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1081 1092 } }
1082 1093
1083 1094 /* found a match : store it */
1084 1095 ip += mLength;
1085 1096 anchor = ip;
1086 1097
1087 1098 if (ip <= ilimit) {
1088 1099 /* Fill Table */
1089 1100 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
1090 1101 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1091 1102 /* check immediate repcode */
1092 1103 while (ip <= ilimit) {
1093 1104 U32 const current2 = (U32)(ip-base);
1094 1105 U32 const repIndex2 = current2 - offset_2;
1095 1106 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1096 1107 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1097 1108 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1098 1109 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1099 1110 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1100 1111 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1101 1112 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1102 1113 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
1103 1114 ip += repLength2;
1104 1115 anchor = ip;
1105 1116 continue;
1106 1117 }
1107 1118 break;
1108 1119 } } }
1109 1120
1110 1121 /* save reps for next block */
1111 1122 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1112 1123
1113 1124 /* Last Literals */
1114 1125 { size_t const lastLLSize = iend - anchor;
1115 1126 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1116 1127 seqStorePtr->lit += lastLLSize;
1117 1128 }
1118 1129 }
1119 1130
1120 1131
1121 1132 static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
1122 1133 const void* src, size_t srcSize)
1123 1134 {
1124 1135 U32 const mls = ctx->params.cParams.searchLength;
1125 1136 switch(mls)
1126 1137 {
1127 1138 default:
1128 1139 case 4 :
1129 1140 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
1130 1141 case 5 :
1131 1142 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
1132 1143 case 6 :
1133 1144 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
1134 1145 case 7 :
1135 1146 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
1136 1147 }
1137 1148 }
1138 1149
1139 1150
1140 1151 /*-*************************************
1141 1152 * Double Fast
1142 1153 ***************************************/
1143 1154 static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1144 1155 {
1145 1156 U32* const hashLarge = cctx->hashTable;
1146 1157 U32 const hBitsL = cctx->params.cParams.hashLog;
1147 1158 U32* const hashSmall = cctx->chainTable;
1148 1159 U32 const hBitsS = cctx->params.cParams.chainLog;
1149 1160 const BYTE* const base = cctx->base;
1150 1161 const BYTE* ip = base + cctx->nextToUpdate;
1151 1162 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
1152 1163 const size_t fastHashFillStep = 3;
1153 1164
1154 1165 while(ip <= iend) {
1155 1166 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1156 1167 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1157 1168 ip += fastHashFillStep;
1158 1169 }
1159 1170 }
1160 1171
1161 1172
1162 1173 FORCE_INLINE
1163 1174 void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1164 1175 const void* src, size_t srcSize,
1165 1176 const U32 mls)
1166 1177 {
1167 1178 U32* const hashLong = cctx->hashTable;
1168 1179 const U32 hBitsL = cctx->params.cParams.hashLog;
1169 1180 U32* const hashSmall = cctx->chainTable;
1170 1181 const U32 hBitsS = cctx->params.cParams.chainLog;
1171 1182 seqStore_t* seqStorePtr = &(cctx->seqStore);
1172 1183 const BYTE* const base = cctx->base;
1173 1184 const BYTE* const istart = (const BYTE*)src;
1174 1185 const BYTE* ip = istart;
1175 1186 const BYTE* anchor = istart;
1176 1187 const U32 lowestIndex = cctx->dictLimit;
1177 1188 const BYTE* const lowest = base + lowestIndex;
1178 1189 const BYTE* const iend = istart + srcSize;
1179 1190 const BYTE* const ilimit = iend - HASH_READ_SIZE;
1180 1191 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1181 1192 U32 offsetSaved = 0;
1182 1193
1183 1194 /* init */
1184 1195 ip += (ip==lowest);
1185 1196 { U32 const maxRep = (U32)(ip-lowest);
1186 1197 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1187 1198 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1188 1199 }
1189 1200
1190 1201 /* Main Search Loop */
1191 1202 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1192 1203 size_t mLength;
1193 1204 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1194 1205 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1195 1206 U32 const current = (U32)(ip-base);
1196 1207 U32 const matchIndexL = hashLong[h2];
1197 1208 U32 const matchIndexS = hashSmall[h];
1198 1209 const BYTE* matchLong = base + matchIndexL;
1199 1210 const BYTE* match = base + matchIndexS;
1200 1211 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1201 1212
1202 1213 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1203 1214 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1204 1215 ip++;
1205 1216 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1206 1217 } else {
1207 1218 U32 offset;
1208 1219 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1209 1220 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
1210 1221 offset = (U32)(ip-matchLong);
1211 1222 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1212 1223 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
1213 1224 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1214 1225 U32 const matchIndex3 = hashLong[h3];
1215 1226 const BYTE* match3 = base + matchIndex3;
1216 1227 hashLong[h3] = current + 1;
1217 1228 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1218 1229 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1219 1230 ip++;
1220 1231 offset = (U32)(ip-match3);
1221 1232 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1222 1233 } else {
1223 1234 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1224 1235 offset = (U32)(ip-match);
1225 1236 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1226 1237 }
1227 1238 } else {
1228 1239 ip += ((ip-anchor) >> g_searchStrength) + 1;
1229 1240 continue;
1230 1241 }
1231 1242
1232 1243 offset_2 = offset_1;
1233 1244 offset_1 = offset;
1234 1245
1235 1246 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1236 1247 }
1237 1248
1238 1249 /* match found */
1239 1250 ip += mLength;
1240 1251 anchor = ip;
1241 1252
1242 1253 if (ip <= ilimit) {
1243 1254 /* Fill Table */
1244 1255 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1245 1256 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1246 1257 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1247 1258 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1248 1259
1249 1260 /* check immediate repcode */
1250 1261 while ( (ip <= ilimit)
1251 1262 && ( (offset_2>0)
1252 1263 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1253 1264 /* store sequence */
1254 1265 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
1255 1266 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
1256 1267 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1257 1268 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1258 1269 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1259 1270 ip += rLength;
1260 1271 anchor = ip;
1261 1272 continue; /* faster when present ... (?) */
1262 1273 } } }
1263 1274
1264 1275 /* save reps for next block */
1265 1276 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1266 1277 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
1267 1278
1268 1279 /* Last Literals */
1269 1280 { size_t const lastLLSize = iend - anchor;
1270 1281 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1271 1282 seqStorePtr->lit += lastLLSize;
1272 1283 }
1273 1284 }
1274 1285
1275 1286
1276 1287 static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1277 1288 {
1278 1289 const U32 mls = ctx->params.cParams.searchLength;
1279 1290 switch(mls)
1280 1291 {
1281 1292 default:
1282 1293 case 4 :
1283 1294 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1284 1295 case 5 :
1285 1296 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1286 1297 case 6 :
1287 1298 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1288 1299 case 7 :
1289 1300 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1290 1301 }
1291 1302 }
1292 1303
1293 1304
1294 1305 static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1295 1306 const void* src, size_t srcSize,
1296 1307 const U32 mls)
1297 1308 {
1298 1309 U32* const hashLong = ctx->hashTable;
1299 1310 U32 const hBitsL = ctx->params.cParams.hashLog;
1300 1311 U32* const hashSmall = ctx->chainTable;
1301 1312 U32 const hBitsS = ctx->params.cParams.chainLog;
1302 1313 seqStore_t* seqStorePtr = &(ctx->seqStore);
1303 1314 const BYTE* const base = ctx->base;
1304 1315 const BYTE* const dictBase = ctx->dictBase;
1305 1316 const BYTE* const istart = (const BYTE*)src;
1306 1317 const BYTE* ip = istart;
1307 1318 const BYTE* anchor = istart;
1308 1319 const U32 lowestIndex = ctx->lowLimit;
1309 1320 const BYTE* const dictStart = dictBase + lowestIndex;
1310 1321 const U32 dictLimit = ctx->dictLimit;
1311 1322 const BYTE* const lowPrefixPtr = base + dictLimit;
1312 1323 const BYTE* const dictEnd = dictBase + dictLimit;
1313 1324 const BYTE* const iend = istart + srcSize;
1314 1325 const BYTE* const ilimit = iend - 8;
1315 1326 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1316 1327
1317 1328 /* Search Loop */
1318 1329 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1319 1330 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1320 1331 const U32 matchIndex = hashSmall[hSmall];
1321 1332 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1322 1333 const BYTE* match = matchBase + matchIndex;
1323 1334
1324 1335 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1325 1336 const U32 matchLongIndex = hashLong[hLong];
1326 1337 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1327 1338 const BYTE* matchLong = matchLongBase + matchLongIndex;
1328 1339
1329 1340 const U32 current = (U32)(ip-base);
1330 1341 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1331 1342 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1332 1343 const BYTE* repMatch = repBase + repIndex;
1333 1344 size_t mLength;
1334 1345 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1335 1346
1336 1347 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1337 1348 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1338 1349 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1339 1350 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1340 1351 ip++;
1341 1352 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1342 1353 } else {
1343 1354 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1344 1355 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1345 1356 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1346 1357 U32 offset;
1347 1358 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1348 1359 offset = current - matchLongIndex;
1349 1360 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1350 1361 offset_2 = offset_1;
1351 1362 offset_1 = offset;
1352 1363 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1353 1364
1354 1365 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
1355 1366 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1356 1367 U32 const matchIndex3 = hashLong[h3];
1357 1368 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1358 1369 const BYTE* match3 = match3Base + matchIndex3;
1359 1370 U32 offset;
1360 1371 hashLong[h3] = current + 1;
1361 1372 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1362 1373 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1363 1374 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1364 1375 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1365 1376 ip++;
1366 1377 offset = current+1 - matchIndex3;
1367 1378 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1368 1379 } else {
1369 1380 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1370 1381 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1371 1382 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1372 1383 offset = current - matchIndex;
1373 1384 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1374 1385 }
1375 1386 offset_2 = offset_1;
1376 1387 offset_1 = offset;
1377 1388 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1378 1389
1379 1390 } else {
1380 1391 ip += ((ip-anchor) >> g_searchStrength) + 1;
1381 1392 continue;
1382 1393 } }
1383 1394
1384 1395 /* found a match : store it */
1385 1396 ip += mLength;
1386 1397 anchor = ip;
1387 1398
1388 1399 if (ip <= ilimit) {
1389 1400 /* Fill Table */
1390 1401 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1391 1402 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1392 1403 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1393 1404 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1394 1405 /* check immediate repcode */
1395 1406 while (ip <= ilimit) {
1396 1407 U32 const current2 = (U32)(ip-base);
1397 1408 U32 const repIndex2 = current2 - offset_2;
1398 1409 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1399 1410 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1400 1411 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1401 1412 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1402 1413 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1403 1414 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1404 1415 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1405 1416 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1406 1417 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1407 1418 ip += repLength2;
1408 1419 anchor = ip;
1409 1420 continue;
1410 1421 }
1411 1422 break;
1412 1423 } } }
1413 1424
1414 1425 /* save reps for next block */
1415 1426 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1416 1427
1417 1428 /* Last Literals */
1418 1429 { size_t const lastLLSize = iend - anchor;
1419 1430 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1420 1431 seqStorePtr->lit += lastLLSize;
1421 1432 }
1422 1433 }
1423 1434
1424 1435
1425 1436 static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1426 1437 const void* src, size_t srcSize)
1427 1438 {
1428 1439 U32 const mls = ctx->params.cParams.searchLength;
1429 1440 switch(mls)
1430 1441 {
1431 1442 default:
1432 1443 case 4 :
1433 1444 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1434 1445 case 5 :
1435 1446 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1436 1447 case 6 :
1437 1448 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1438 1449 case 7 :
1439 1450 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1440 1451 }
1441 1452 }
1442 1453
1443 1454
1444 1455 /*-*************************************
1445 1456 * Binary Tree search
1446 1457 ***************************************/
1447 1458 /** ZSTD_insertBt1() : add one or multiple positions to tree.
1448 1459 * ip : assumed <= iend-8 .
1449 1460 * @return : nb of positions added */
1450 1461 static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1451 1462 U32 extDict)
1452 1463 {
1453 1464 U32* const hashTable = zc->hashTable;
1454 1465 U32 const hashLog = zc->params.cParams.hashLog;
1455 1466 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1456 1467 U32* const bt = zc->chainTable;
1457 1468 U32 const btLog = zc->params.cParams.chainLog - 1;
1458 1469 U32 const btMask = (1 << btLog) - 1;
1459 1470 U32 matchIndex = hashTable[h];
1460 1471 size_t commonLengthSmaller=0, commonLengthLarger=0;
1461 1472 const BYTE* const base = zc->base;
1462 1473 const BYTE* const dictBase = zc->dictBase;
1463 1474 const U32 dictLimit = zc->dictLimit;
1464 1475 const BYTE* const dictEnd = dictBase + dictLimit;
1465 1476 const BYTE* const prefixStart = base + dictLimit;
1466 1477 const BYTE* match;
1467 1478 const U32 current = (U32)(ip-base);
1468 1479 const U32 btLow = btMask >= current ? 0 : current - btMask;
1469 1480 U32* smallerPtr = bt + 2*(current&btMask);
1470 1481 U32* largerPtr = smallerPtr + 1;
1471 1482 U32 dummy32; /* to be nullified at the end */
1472 1483 U32 const windowLow = zc->lowLimit;
1473 1484 U32 matchEndIdx = current+8;
1474 1485 size_t bestLength = 8;
1475 1486 #ifdef ZSTD_C_PREDICT
1476 1487 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1477 1488 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1478 1489 predictedSmall += (predictedSmall>0);
1479 1490 predictedLarge += (predictedLarge>0);
1480 1491 #endif /* ZSTD_C_PREDICT */
1481 1492
1482 1493 hashTable[h] = current; /* Update Hash Table */
1483 1494
1484 1495 while (nbCompares-- && (matchIndex > windowLow)) {
1485 U32* nextPtr = bt + 2*(matchIndex & btMask);
1496 U32* const nextPtr = bt + 2*(matchIndex & btMask);
1486 1497 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1498
1487 1499 #ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
1488 1500 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
1489 1501 if (matchIndex == predictedSmall) {
1490 1502 /* no need to check length, result known */
1491 1503 *smallerPtr = matchIndex;
1492 1504 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1493 1505 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1494 1506 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1495 1507 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
1496 1508 continue;
1497 1509 }
1498 1510 if (matchIndex == predictedLarge) {
1499 1511 *largerPtr = matchIndex;
1500 1512 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1501 1513 largerPtr = nextPtr;
1502 1514 matchIndex = nextPtr[0];
1503 1515 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
1504 1516 continue;
1505 1517 }
1506 1518 #endif
1507 1519 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
1508 1520 match = base + matchIndex;
1509 1521 if (match[matchLength] == ip[matchLength])
1510 1522 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1511 1523 } else {
1512 1524 match = dictBase + matchIndex;
1513 1525 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1514 1526 if (matchIndex+matchLength >= dictLimit)
1515 1527 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1516 1528 }
1517 1529
1518 1530 if (matchLength > bestLength) {
1519 1531 bestLength = matchLength;
1520 1532 if (matchLength > matchEndIdx - matchIndex)
1521 1533 matchEndIdx = matchIndex + (U32)matchLength;
1522 1534 }
1523 1535
1524 1536 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1525 1537 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
1526 1538
1527 1539 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
1528 1540 /* match is smaller than current */
1529 1541 *smallerPtr = matchIndex; /* update smaller idx */
1530 1542 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1531 1543 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1532 1544 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1533 1545 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1534 1546 } else {
1535 1547 /* match is larger than current */
1536 1548 *largerPtr = matchIndex;
1537 1549 commonLengthLarger = matchLength;
1538 1550 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1539 1551 largerPtr = nextPtr;
1540 1552 matchIndex = nextPtr[0];
1541 1553 } }
1542 1554
1543 1555 *smallerPtr = *largerPtr = 0;
1544 1556 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
1545 1557 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1546 1558 return 1;
1547 1559 }
1548 1560
1549 1561
1550 1562 static size_t ZSTD_insertBtAndFindBestMatch (
1551 1563 ZSTD_CCtx* zc,
1552 1564 const BYTE* const ip, const BYTE* const iend,
1553 1565 size_t* offsetPtr,
1554 1566 U32 nbCompares, const U32 mls,
1555 1567 U32 extDict)
1556 1568 {
1557 1569 U32* const hashTable = zc->hashTable;
1558 1570 U32 const hashLog = zc->params.cParams.hashLog;
1559 1571 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1560 1572 U32* const bt = zc->chainTable;
1561 1573 U32 const btLog = zc->params.cParams.chainLog - 1;
1562 1574 U32 const btMask = (1 << btLog) - 1;
1563 1575 U32 matchIndex = hashTable[h];
1564 1576 size_t commonLengthSmaller=0, commonLengthLarger=0;
1565 1577 const BYTE* const base = zc->base;
1566 1578 const BYTE* const dictBase = zc->dictBase;
1567 1579 const U32 dictLimit = zc->dictLimit;
1568 1580 const BYTE* const dictEnd = dictBase + dictLimit;
1569 1581 const BYTE* const prefixStart = base + dictLimit;
1570 1582 const U32 current = (U32)(ip-base);
1571 1583 const U32 btLow = btMask >= current ? 0 : current - btMask;
1572 1584 const U32 windowLow = zc->lowLimit;
1573 1585 U32* smallerPtr = bt + 2*(current&btMask);
1574 1586 U32* largerPtr = bt + 2*(current&btMask) + 1;
1575 1587 U32 matchEndIdx = current+8;
1576 1588 U32 dummy32; /* to be nullified at the end */
1577 1589 size_t bestLength = 0;
1578 1590
1579 1591 hashTable[h] = current; /* Update Hash Table */
1580 1592
1581 1593 while (nbCompares-- && (matchIndex > windowLow)) {
1582 U32* nextPtr = bt + 2*(matchIndex & btMask);
1594 U32* const nextPtr = bt + 2*(matchIndex & btMask);
1583 1595 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1584 1596 const BYTE* match;
1585 1597
1586 1598 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
1587 1599 match = base + matchIndex;
1588 1600 if (match[matchLength] == ip[matchLength])
1589 1601 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1590 1602 } else {
1591 1603 match = dictBase + matchIndex;
1592 1604 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1593 1605 if (matchIndex+matchLength >= dictLimit)
1594 1606 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1595 1607 }
1596 1608
1597 1609 if (matchLength > bestLength) {
1598 1610 if (matchLength > matchEndIdx - matchIndex)
1599 1611 matchEndIdx = matchIndex + (U32)matchLength;
1600 1612 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
1601 1613 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
1602 1614 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1603 1615 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1604 1616 }
1605 1617
1606 1618 if (match[matchLength] < ip[matchLength]) {
1607 1619 /* match is smaller than current */
1608 1620 *smallerPtr = matchIndex; /* update smaller idx */
1609 1621 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1610 1622 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1611 1623 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1612 1624 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1613 1625 } else {
1614 1626 /* match is larger than current */
1615 1627 *largerPtr = matchIndex;
1616 1628 commonLengthLarger = matchLength;
1617 1629 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1618 1630 largerPtr = nextPtr;
1619 1631 matchIndex = nextPtr[0];
1620 1632 } }
1621 1633
1622 1634 *smallerPtr = *largerPtr = 0;
1623 1635
1624 1636 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
1625 1637 return bestLength;
1626 1638 }
1627 1639
1628 1640
1629 1641 static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1630 1642 {
1631 1643 const BYTE* const base = zc->base;
1632 1644 const U32 target = (U32)(ip - base);
1633 1645 U32 idx = zc->nextToUpdate;
1634 1646
1635 1647 while(idx < target)
1636 1648 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
1637 1649 }
1638 1650
1639 1651 /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
1640 1652 static size_t ZSTD_BtFindBestMatch (
1641 1653 ZSTD_CCtx* zc,
1642 1654 const BYTE* const ip, const BYTE* const iLimit,
1643 1655 size_t* offsetPtr,
1644 1656 const U32 maxNbAttempts, const U32 mls)
1645 1657 {
1646 1658 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1647 1659 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1648 1660 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1649 1661 }
1650 1662
1651 1663
1652 1664 static size_t ZSTD_BtFindBestMatch_selectMLS (
1653 1665 ZSTD_CCtx* zc, /* Index table will be updated */
1654 1666 const BYTE* ip, const BYTE* const iLimit,
1655 1667 size_t* offsetPtr,
1656 1668 const U32 maxNbAttempts, const U32 matchLengthSearch)
1657 1669 {
1658 1670 switch(matchLengthSearch)
1659 1671 {
1660 1672 default :
1661 1673 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1662 1674 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1663 1675 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1664 1676 }
1665 1677 }
1666 1678
1667 1679
1668 1680 static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1669 1681 {
1670 1682 const BYTE* const base = zc->base;
1671 1683 const U32 target = (U32)(ip - base);
1672 1684 U32 idx = zc->nextToUpdate;
1673 1685
1674 1686 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1675 1687 }
1676 1688
1677 1689
1678 1690 /** Tree updater, providing best match */
1679 1691 static size_t ZSTD_BtFindBestMatch_extDict (
1680 1692 ZSTD_CCtx* zc,
1681 1693 const BYTE* const ip, const BYTE* const iLimit,
1682 1694 size_t* offsetPtr,
1683 1695 const U32 maxNbAttempts, const U32 mls)
1684 1696 {
1685 1697 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1686 1698 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
1687 1699 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
1688 1700 }
1689 1701
1690 1702
1691 1703 static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1692 1704 ZSTD_CCtx* zc, /* Index table will be updated */
1693 1705 const BYTE* ip, const BYTE* const iLimit,
1694 1706 size_t* offsetPtr,
1695 1707 const U32 maxNbAttempts, const U32 matchLengthSearch)
1696 1708 {
1697 1709 switch(matchLengthSearch)
1698 1710 {
1699 1711 default :
1700 1712 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1701 1713 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1702 1714 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1703 1715 }
1704 1716 }
1705 1717
1706 1718
1707 1719
1708 1720 /* *********************************
1709 1721 * Hash Chain
1710 1722 ***********************************/
1711 1723 #define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1712 1724
1713 1725 /* Update chains up to ip (excluded)
1714 1726 Assumption : always within prefix (ie. not within extDict) */
1715 1727 FORCE_INLINE
1716 1728 U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1717 1729 {
1718 1730 U32* const hashTable = zc->hashTable;
1719 1731 const U32 hashLog = zc->params.cParams.hashLog;
1720 1732 U32* const chainTable = zc->chainTable;
1721 1733 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1722 1734 const BYTE* const base = zc->base;
1723 1735 const U32 target = (U32)(ip - base);
1724 1736 U32 idx = zc->nextToUpdate;
1725 1737
1726 1738 while(idx < target) { /* catch up */
1727 1739 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1728 1740 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1729 1741 hashTable[h] = idx;
1730 1742 idx++;
1731 1743 }
1732 1744
1733 1745 zc->nextToUpdate = target;
1734 1746 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1735 1747 }
1736 1748
1737 1749
1738 1750
1739 1751 FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1740 1752 size_t ZSTD_HcFindBestMatch_generic (
1741 1753 ZSTD_CCtx* zc, /* Index table will be updated */
1742 1754 const BYTE* const ip, const BYTE* const iLimit,
1743 1755 size_t* offsetPtr,
1744 1756 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1745 1757 {
1746 1758 U32* const chainTable = zc->chainTable;
1747 1759 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1748 1760 const U32 chainMask = chainSize-1;
1749 1761 const BYTE* const base = zc->base;
1750 1762 const BYTE* const dictBase = zc->dictBase;
1751 1763 const U32 dictLimit = zc->dictLimit;
1752 1764 const BYTE* const prefixStart = base + dictLimit;
1753 1765 const BYTE* const dictEnd = dictBase + dictLimit;
1754 1766 const U32 lowLimit = zc->lowLimit;
1755 1767 const U32 current = (U32)(ip-base);
1756 1768 const U32 minChain = current > chainSize ? current - chainSize : 0;
1757 1769 int nbAttempts=maxNbAttempts;
1758 1770 size_t ml=EQUAL_READ32-1;
1759 1771
1760 1772 /* HC4 match finder */
1761 1773 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1762 1774
1763 1775 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
1764 1776 const BYTE* match;
1765 1777 size_t currentMl=0;
1766 1778 if ((!extDict) || matchIndex >= dictLimit) {
1767 1779 match = base + matchIndex;
1768 1780 if (match[ml] == ip[ml]) /* potentially better */
1769 1781 currentMl = ZSTD_count(ip, match, iLimit);
1770 1782 } else {
1771 1783 match = dictBase + matchIndex;
1772 1784 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1773 1785 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1774 1786 }
1775 1787
1776 1788 /* save best solution */
1777 1789 if (currentMl > ml) { ml = currentMl; *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
1778 1790
1779 1791 if (matchIndex <= minChain) break;
1780 1792 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1781 1793 }
1782 1794
1783 1795 return ml;
1784 1796 }
1785 1797
1786 1798
1787 1799 FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1788 1800 ZSTD_CCtx* zc,
1789 1801 const BYTE* ip, const BYTE* const iLimit,
1790 1802 size_t* offsetPtr,
1791 1803 const U32 maxNbAttempts, const U32 matchLengthSearch)
1792 1804 {
1793 1805 switch(matchLengthSearch)
1794 1806 {
1795 1807 default :
1796 1808 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1797 1809 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1798 1810 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1799 1811 }
1800 1812 }
1801 1813
1802 1814
1803 1815 FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1804 1816 ZSTD_CCtx* zc,
1805 1817 const BYTE* ip, const BYTE* const iLimit,
1806 1818 size_t* offsetPtr,
1807 1819 const U32 maxNbAttempts, const U32 matchLengthSearch)
1808 1820 {
1809 1821 switch(matchLengthSearch)
1810 1822 {
1811 1823 default :
1812 1824 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1813 1825 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1814 1826 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1815 1827 }
1816 1828 }
1817 1829
1818 1830
1819 1831 /* *******************************
1820 1832 * Common parser - lazy strategy
1821 1833 *********************************/
1822 1834 FORCE_INLINE
1823 1835 void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1824 1836 const void* src, size_t srcSize,
1825 1837 const U32 searchMethod, const U32 depth)
1826 1838 {
1827 1839 seqStore_t* seqStorePtr = &(ctx->seqStore);
1828 1840 const BYTE* const istart = (const BYTE*)src;
1829 1841 const BYTE* ip = istart;
1830 1842 const BYTE* anchor = istart;
1831 1843 const BYTE* const iend = istart + srcSize;
1832 1844 const BYTE* const ilimit = iend - 8;
1833 1845 const BYTE* const base = ctx->base + ctx->dictLimit;
1834 1846
1835 1847 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1836 1848 U32 const mls = ctx->params.cParams.searchLength;
1837 1849
1838 1850 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1839 1851 size_t* offsetPtr,
1840 1852 U32 maxNbAttempts, U32 matchLengthSearch);
1841 1853 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
1842 1854 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
1843 1855
1844 1856 /* init */
1845 1857 ip += (ip==base);
1846 1858 ctx->nextToUpdate3 = ctx->nextToUpdate;
1847 1859 { U32 const maxRep = (U32)(ip-base);
1848 1860 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1849 1861 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1850 1862 }
1851 1863
1852 1864 /* Match Loop */
1853 1865 while (ip < ilimit) {
1854 1866 size_t matchLength=0;
1855 1867 size_t offset=0;
1856 1868 const BYTE* start=ip+1;
1857 1869
1858 1870 /* check repCode */
1859 1871 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
1860 1872 /* repcode : we take it */
1861 1873 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
1862 1874 if (depth==0) goto _storeSequence;
1863 1875 }
1864 1876
1865 1877 /* first search (depth 0) */
1866 1878 { size_t offsetFound = 99999999;
1867 1879 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1868 1880 if (ml2 > matchLength)
1869 1881 matchLength = ml2, start = ip, offset=offsetFound;
1870 1882 }
1871 1883
1872 1884 if (matchLength < EQUAL_READ32) {
1873 1885 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1874 1886 continue;
1875 1887 }
1876 1888
1877 1889 /* let's try to find a better solution */
1878 1890 if (depth>=1)
1879 1891 while (ip<ilimit) {
1880 1892 ip ++;
1881 1893 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1882 1894 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
1883 1895 int const gain2 = (int)(mlRep * 3);
1884 1896 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
1885 1897 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1886 1898 matchLength = mlRep, offset = 0, start = ip;
1887 1899 }
1888 1900 { size_t offset2=99999999;
1889 1901 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1890 1902 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1891 1903 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
1892 1904 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1893 1905 matchLength = ml2, offset = offset2, start = ip;
1894 1906 continue; /* search a better one */
1895 1907 } }
1896 1908
1897 1909 /* let's find an even better one */
1898 1910 if ((depth==2) && (ip<ilimit)) {
1899 1911 ip ++;
1900 1912 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1901 1913 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
1902 1914 int const gain2 = (int)(ml2 * 4);
1903 1915 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
1904 1916 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1905 1917 matchLength = ml2, offset = 0, start = ip;
1906 1918 }
1907 1919 { size_t offset2=99999999;
1908 1920 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1909 1921 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1910 1922 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
1911 1923 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1912 1924 matchLength = ml2, offset = offset2, start = ip;
1913 1925 continue;
1914 1926 } } }
1915 1927 break; /* nothing found : store previous solution */
1916 1928 }
1917 1929
1918 1930 /* catch up */
1919 1931 if (offset) {
1920 1932 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1921 1933 { start--; matchLength++; }
1922 1934 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
1923 1935 }
1924 1936
1925 1937 /* store sequence */
1926 1938 _storeSequence:
1927 1939 { size_t const litLength = start - anchor;
1928 1940 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
1929 1941 anchor = ip = start + matchLength;
1930 1942 }
1931 1943
1932 1944 /* check immediate repcode */
1933 1945 while ( (ip <= ilimit)
1934 1946 && ((offset_2>0)
1935 1947 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1936 1948 /* store sequence */
1937 1949 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1938 1950 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
1939 1951 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1940 1952 ip += matchLength;
1941 1953 anchor = ip;
1942 1954 continue; /* faster when present ... (?) */
1943 1955 } }
1944 1956
1945 1957 /* Save reps for next block */
1946 1958 ctx->savedRep[0] = offset_1 ? offset_1 : savedOffset;
1947 1959 ctx->savedRep[1] = offset_2 ? offset_2 : savedOffset;
1948 1960
1949 1961 /* Last Literals */
1950 1962 { size_t const lastLLSize = iend - anchor;
1951 1963 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1952 1964 seqStorePtr->lit += lastLLSize;
1953 1965 }
1954 1966 }
1955 1967
1956 1968
1957 1969 static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1958 1970 {
1959 1971 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1960 1972 }
1961 1973
1962 1974 static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1963 1975 {
1964 1976 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
1965 1977 }
1966 1978
1967 1979 static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1968 1980 {
1969 1981 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
1970 1982 }
1971 1983
1972 1984 static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1973 1985 {
1974 1986 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
1975 1987 }
1976 1988
1977 1989
1978 1990 FORCE_INLINE
1979 1991 void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1980 1992 const void* src, size_t srcSize,
1981 1993 const U32 searchMethod, const U32 depth)
1982 1994 {
1983 1995 seqStore_t* seqStorePtr = &(ctx->seqStore);
1984 1996 const BYTE* const istart = (const BYTE*)src;
1985 1997 const BYTE* ip = istart;
1986 1998 const BYTE* anchor = istart;
1987 1999 const BYTE* const iend = istart + srcSize;
1988 2000 const BYTE* const ilimit = iend - 8;
1989 2001 const BYTE* const base = ctx->base;
1990 2002 const U32 dictLimit = ctx->dictLimit;
1991 2003 const U32 lowestIndex = ctx->lowLimit;
1992 2004 const BYTE* const prefixStart = base + dictLimit;
1993 2005 const BYTE* const dictBase = ctx->dictBase;
1994 2006 const BYTE* const dictEnd = dictBase + dictLimit;
1995 2007 const BYTE* const dictStart = dictBase + ctx->lowLimit;
1996 2008
1997 2009 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
1998 2010 const U32 mls = ctx->params.cParams.searchLength;
1999 2011
2000 2012 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2001 2013 size_t* offsetPtr,
2002 2014 U32 maxNbAttempts, U32 matchLengthSearch);
2003 2015 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2004 2016
2005 2017 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
2006 2018
2007 2019 /* init */
2008 2020 ctx->nextToUpdate3 = ctx->nextToUpdate;
2009 2021 ip += (ip == prefixStart);
2010 2022
2011 2023 /* Match Loop */
2012 2024 while (ip < ilimit) {
2013 2025 size_t matchLength=0;
2014 2026 size_t offset=0;
2015 2027 const BYTE* start=ip+1;
2016 2028 U32 current = (U32)(ip-base);
2017 2029
2018 2030 /* check repCode */
2019 2031 { const U32 repIndex = (U32)(current+1 - offset_1);
2020 2032 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2021 2033 const BYTE* const repMatch = repBase + repIndex;
2022 2034 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2023 2035 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
2024 2036 /* repcode detected we should take it */
2025 2037 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2026 2038 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2027 2039 if (depth==0) goto _storeSequence;
2028 2040 } }
2029 2041
2030 2042 /* first search (depth 0) */
2031 2043 { size_t offsetFound = 99999999;
2032 2044 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
2033 2045 if (ml2 > matchLength)
2034 2046 matchLength = ml2, start = ip, offset=offsetFound;
2035 2047 }
2036 2048
2037 2049 if (matchLength < EQUAL_READ32) {
2038 2050 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2039 2051 continue;
2040 2052 }
2041 2053
2042 2054 /* let's try to find a better solution */
2043 2055 if (depth>=1)
2044 2056 while (ip<ilimit) {
2045 2057 ip ++;
2046 2058 current++;
2047 2059 /* check repCode */
2048 2060 if (offset) {
2049 2061 const U32 repIndex = (U32)(current - offset_1);
2050 2062 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2051 2063 const BYTE* const repMatch = repBase + repIndex;
2052 2064 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2053 2065 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2054 2066 /* repcode detected */
2055 2067 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2056 2068 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2057 2069 int const gain2 = (int)(repLength * 3);
2058 2070 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
2059 2071 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2060 2072 matchLength = repLength, offset = 0, start = ip;
2061 2073 } }
2062 2074
2063 2075 /* search match, depth 1 */
2064 2076 { size_t offset2=99999999;
2065 2077 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
2066 2078 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2067 2079 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
2068 2080 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2069 2081 matchLength = ml2, offset = offset2, start = ip;
2070 2082 continue; /* search a better one */
2071 2083 } }
2072 2084
2073 2085 /* let's find an even better one */
2074 2086 if ((depth==2) && (ip<ilimit)) {
2075 2087 ip ++;
2076 2088 current++;
2077 2089 /* check repCode */
2078 2090 if (offset) {
2079 2091 const U32 repIndex = (U32)(current - offset_1);
2080 2092 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2081 2093 const BYTE* const repMatch = repBase + repIndex;
2082 2094 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2083 2095 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2084 2096 /* repcode detected */
2085 2097 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2086 2098 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2087 2099 int gain2 = (int)(repLength * 4);
2088 2100 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
2089 2101 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2090 2102 matchLength = repLength, offset = 0, start = ip;
2091 2103 } }
2092 2104
2093 2105 /* search match, depth 2 */
2094 2106 { size_t offset2=99999999;
2095 2107 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
2096 2108 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2097 2109 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
2098 2110 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2099 2111 matchLength = ml2, offset = offset2, start = ip;
2100 2112 continue;
2101 2113 } } }
2102 2114 break; /* nothing found : store previous solution */
2103 2115 }
2104 2116
2105 2117 /* catch up */
2106 2118 if (offset) {
2107 2119 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
2108 2120 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2109 2121 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
2110 2122 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
2111 2123 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
2112 2124 }
2113 2125
2114 2126 /* store sequence */
2115 2127 _storeSequence:
2116 2128 { size_t const litLength = start - anchor;
2117 2129 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
2118 2130 anchor = ip = start + matchLength;
2119 2131 }
2120 2132
2121 2133 /* check immediate repcode */
2122 2134 while (ip <= ilimit) {
2123 2135 const U32 repIndex = (U32)((ip-base) - offset_2);
2124 2136 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2125 2137 const BYTE* const repMatch = repBase + repIndex;
2126 2138 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2127 2139 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2128 2140 /* repcode detected we should take it */
2129 2141 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2130 2142 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2131 2143 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
2132 2144 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2133 2145 ip += matchLength;
2134 2146 anchor = ip;
2135 2147 continue; /* faster when present ... (?) */
2136 2148 }
2137 2149 break;
2138 2150 } }
2139 2151
2140 2152 /* Save reps for next block */
2141 2153 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
2142 2154
2143 2155 /* Last Literals */
2144 2156 { size_t const lastLLSize = iend - anchor;
2145 2157 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2146 2158 seqStorePtr->lit += lastLLSize;
2147 2159 }
2148 2160 }
2149 2161
2150 2162
2151 2163 void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2152 2164 {
2153 2165 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
2154 2166 }
2155 2167
2156 2168 static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2157 2169 {
2158 2170 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
2159 2171 }
2160 2172
2161 2173 static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2162 2174 {
2163 2175 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
2164 2176 }
2165 2177
2166 2178 static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2167 2179 {
2168 2180 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
2169 2181 }
2170 2182
2171 2183
2172 2184 /* The optimal parser */
2173 2185 #include "zstd_opt.h"
2174 2186
2175 2187 static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2176 2188 {
2177 2189 #ifdef ZSTD_OPT_H_91842398743
2178 2190 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2179 2191 #else
2180 2192 (void)ctx; (void)src; (void)srcSize;
2181 2193 return;
2182 2194 #endif
2183 2195 }
2184 2196
2185 2197 static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2186 2198 {
2187 2199 #ifdef ZSTD_OPT_H_91842398743
2188 2200 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
2189 2201 #else
2190 2202 (void)ctx; (void)src; (void)srcSize;
2191 2203 return;
2192 2204 #endif
2193 2205 }
2194 2206
2195 2207 static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2196 2208 {
2197 2209 #ifdef ZSTD_OPT_H_91842398743
2198 2210 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2199 2211 #else
2200 2212 (void)ctx; (void)src; (void)srcSize;
2201 2213 return;
2202 2214 #endif
2203 2215 }
2204 2216
2205 2217 static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2206 2218 {
2207 2219 #ifdef ZSTD_OPT_H_91842398743
2208 2220 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
2209 2221 #else
2210 2222 (void)ctx; (void)src; (void)srcSize;
2211 2223 return;
2212 2224 #endif
2213 2225 }
2214 2226
2215 2227
2216 2228 typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
2217 2229
2218 2230 static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
2219 2231 {
2220 2232 static const ZSTD_blockCompressor blockCompressor[2][8] = {
2221 2233 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
2222 2234 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btopt2_extDict }
2223 2235 };
2224 2236
2225 2237 return blockCompressor[extDict][(U32)strat];
2226 2238 }
2227 2239
2228 2240
2229 2241 static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2230 2242 {
2231 2243 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
2232 2244 const BYTE* const base = zc->base;
2233 2245 const BYTE* const istart = (const BYTE*)src;
2234 2246 const U32 current = (U32)(istart-base);
2235 2247 if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
2236 2248 ZSTD_resetSeqStore(&(zc->seqStore));
2237 2249 if (current > zc->nextToUpdate + 384)
2238 2250 zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384)); /* update tree not updated after finding very long rep matches */
2239 2251 blockCompressor(zc, src, srcSize);
2240 2252 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
2241 2253 }
2242 2254
2243 2255
2244 2256 /*! ZSTD_compress_generic() :
2245 2257 * Compress a chunk of data into one or multiple blocks.
2246 2258 * All blocks will be terminated, all input will be consumed.
2247 2259 * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2248 2260 * Frame is supposed already started (header already produced)
2249 2261 * @return : compressed size, or an error code
2250 2262 */
2251 2263 static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2252 2264 void* dst, size_t dstCapacity,
2253 2265 const void* src, size_t srcSize,
2254 2266 U32 lastFrameChunk)
2255 2267 {
2256 2268 size_t blockSize = cctx->blockSize;
2257 2269 size_t remaining = srcSize;
2258 2270 const BYTE* ip = (const BYTE*)src;
2259 2271 BYTE* const ostart = (BYTE*)dst;
2260 2272 BYTE* op = ostart;
2261 2273 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
2262 2274
2263 2275 if (cctx->params.fParams.checksumFlag && srcSize)
2264 2276 XXH64_update(&cctx->xxhState, src, srcSize);
2265 2277
2266 2278 while (remaining) {
2267 2279 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
2268 2280 size_t cSize;
2269 2281
2270 2282 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
2271 2283 if (remaining < blockSize) blockSize = remaining;
2272 2284
2273 2285 /* preemptive overflow correction */
2274 if (cctx->lowLimit > (1<<30)) {
2275 U32 const btplus = (cctx->params.cParams.strategy == ZSTD_btlazy2) | (cctx->params.cParams.strategy == ZSTD_btopt) | (cctx->params.cParams.strategy == ZSTD_btopt2);
2276 U32 const chainMask = (1 << (cctx->params.cParams.chainLog - btplus)) - 1;
2277 U32 const supLog = MAX(cctx->params.cParams.chainLog, 17 /* blockSize */);
2278 U32 const newLowLimit = (cctx->lowLimit & chainMask) + (1 << supLog); /* preserve position % chainSize, ensure current-repcode doesn't underflow */
2279 U32 const correction = cctx->lowLimit - newLowLimit;
2286 if (cctx->lowLimit > (2U<<30)) {
2287 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
2288 U32 const current = (U32)(ip - cctx->base);
2289 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
2290 U32 const correction = current - newCurrent;
2291 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
2280 2292 ZSTD_reduceIndex(cctx, correction);
2281 2293 cctx->base += correction;
2282 2294 cctx->dictBase += correction;
2283 cctx->lowLimit = newLowLimit;
2295 cctx->lowLimit -= correction;
2284 2296 cctx->dictLimit -= correction;
2285 2297 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2286 2298 else cctx->nextToUpdate -= correction;
2287 2299 }
2288 2300
2289 2301 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
2290 2302 /* enforce maxDist */
2291 2303 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2292 2304 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2293 2305 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
2294 2306 }
2295 2307
2296 2308 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
2297 2309 if (ZSTD_isError(cSize)) return cSize;
2298 2310
2299 2311 if (cSize == 0) { /* block is not compressible */
2300 2312 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2301 2313 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2302 2314 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2303 2315 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2304 2316 cSize = ZSTD_blockHeaderSize+blockSize;
2305 2317 } else {
2306 2318 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
2307 2319 MEM_writeLE24(op, cBlockHeader24);
2308 2320 cSize += ZSTD_blockHeaderSize;
2309 2321 }
2310 2322
2311 2323 remaining -= blockSize;
2312 2324 dstCapacity -= cSize;
2313 2325 ip += blockSize;
2314 2326 op += cSize;
2315 2327 }
2316 2328
2317 2329 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
2318 2330 return op-ostart;
2319 2331 }
2320 2332
2321 2333
2322 2334 static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2323 2335 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
2324 2336 { BYTE* const op = (BYTE*)dst;
2325 2337 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2326 2338 U32 const checksumFlag = params.fParams.checksumFlag>0;
2327 2339 U32 const windowSize = 1U << params.cParams.windowLog;
2328 2340 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize > (pledgedSrcSize-1));
2329 2341 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2330 2342 U32 const fcsCode = params.fParams.contentSizeFlag ?
2331 2343 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2332 2344 0;
2333 2345 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
2334 2346 size_t pos;
2335 2347
2336 2348 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
2337 2349
2338 2350 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
2339 2351 op[4] = frameHeaderDecriptionByte; pos=5;
2340 2352 if (!singleSegment) op[pos++] = windowLogByte;
2341 2353 switch(dictIDSizeCode)
2342 2354 {
2343 2355 default: /* impossible */
2344 2356 case 0 : break;
2345 2357 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
2346 2358 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
2347 2359 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2348 2360 }
2349 2361 switch(fcsCode)
2350 2362 {
2351 2363 default: /* impossible */
2352 2364 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
2353 2365 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2354 2366 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
2355 2367 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
2356 2368 }
2357 2369 return pos;
2358 2370 }
2359 2371
2360 2372
2361 2373 static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
2362 2374 void* dst, size_t dstCapacity,
2363 2375 const void* src, size_t srcSize,
2364 2376 U32 frame, U32 lastFrameChunk)
2365 2377 {
2366 2378 const BYTE* const ip = (const BYTE*) src;
2367 2379 size_t fhSize = 0;
2368 2380
2369 2381 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
2370 2382
2371 2383 if (frame && (cctx->stage==ZSTDcs_init)) {
2372 2384 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
2373 2385 if (ZSTD_isError(fhSize)) return fhSize;
2374 2386 dstCapacity -= fhSize;
2375 2387 dst = (char*)dst + fhSize;
2376 2388 cctx->stage = ZSTDcs_ongoing;
2377 2389 }
2378 2390
2379 2391 /* Check if blocks follow each other */
2380 2392 if (src != cctx->nextSrc) {
2381 2393 /* not contiguous */
2382 2394 ptrdiff_t const delta = cctx->nextSrc - ip;
2383 2395 cctx->lowLimit = cctx->dictLimit;
2384 2396 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2385 2397 cctx->dictBase = cctx->base;
2386 2398 cctx->base -= delta;
2387 2399 cctx->nextToUpdate = cctx->dictLimit;
2388 2400 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
2389 2401 }
2390 2402
2391 2403 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2392 2404 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2393 2405 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2394 2406 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2395 2407 cctx->lowLimit = lowLimitMax;
2396 2408 }
2397 2409
2398 2410 cctx->nextSrc = ip + srcSize;
2399 2411
2400 2412 { size_t const cSize = frame ?
2401 2413 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2402 2414 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
2403 2415 if (ZSTD_isError(cSize)) return cSize;
2404 2416 return cSize + fhSize;
2405 2417 }
2406 2418 }
2407 2419
2408 2420
2409 2421 size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
2410 2422 void* dst, size_t dstCapacity,
2411 2423 const void* src, size_t srcSize)
2412 2424 {
2413 2425 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
2414 2426 }
2415 2427
2416 2428
2417 2429 size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
2418 2430 {
2419 2431 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2420 2432 }
2421 2433
2422 2434 size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2423 2435 {
2424 2436 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
2425 2437 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
2426 2438 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
2427 2439 }
2428 2440
2429 2441
2430 2442 static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2431 2443 {
2432 2444 const BYTE* const ip = (const BYTE*) src;
2433 2445 const BYTE* const iend = ip + srcSize;
2434 2446
2435 2447 /* input becomes current prefix */
2436 2448 zc->lowLimit = zc->dictLimit;
2437 2449 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2438 2450 zc->dictBase = zc->base;
2439 2451 zc->base += ip - zc->nextSrc;
2440 2452 zc->nextToUpdate = zc->dictLimit;
2441 2453 zc->loadedDictEnd = (U32)(iend - zc->base);
2442 2454
2443 2455 zc->nextSrc = iend;
2444 2456 if (srcSize <= HASH_READ_SIZE) return 0;
2445 2457
2446 2458 switch(zc->params.cParams.strategy)
2447 2459 {
2448 2460 case ZSTD_fast:
2449 2461 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
2450 2462 break;
2451 2463
2452 2464 case ZSTD_dfast:
2453 2465 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2454 2466 break;
2455 2467
2456 2468 case ZSTD_greedy:
2457 2469 case ZSTD_lazy:
2458 2470 case ZSTD_lazy2:
2459 2471 ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
2460 2472 break;
2461 2473
2462 2474 case ZSTD_btlazy2:
2463 2475 case ZSTD_btopt:
2464 2476 case ZSTD_btopt2:
2465 2477 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
2466 2478 break;
2467 2479
2468 2480 default:
2469 2481 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2470 2482 }
2471 2483
2472 2484 zc->nextToUpdate = zc->loadedDictEnd;
2473 2485 return 0;
2474 2486 }
2475 2487
2476 2488
2477 2489 /* Dictionaries that assign zero probability to symbols that show up causes problems
2478 2490 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2479 2491 that we may encounter during compression.
2480 2492 NOTE: This behavior is not standard and could be improved in the future. */
2481 2493 static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2482 2494 U32 s;
2483 2495 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2484 2496 for (s = 0; s <= maxSymbolValue; ++s) {
2485 2497 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2486 2498 }
2487 2499 return 0;
2488 2500 }
2489 2501
2490 2502
2491 2503 /* Dictionary format :
2492 2504 Magic == ZSTD_DICT_MAGIC (4 bytes)
2493 2505 HUF_writeCTable(256)
2494 2506 FSE_writeNCount(off)
2495 2507 FSE_writeNCount(ml)
2496 2508 FSE_writeNCount(ll)
2497 2509 RepOffsets
2498 2510 Dictionary content
2499 2511 */
2500 2512 /*! ZSTD_loadDictEntropyStats() :
2501 2513 @return : size read from dictionary
2502 2514 note : magic number supposed already checked */
2503 2515 static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
2504 2516 {
2505 2517 const BYTE* dictPtr = (const BYTE*)dict;
2506 2518 const BYTE* const dictEnd = dictPtr + dictSize;
2507 2519 short offcodeNCount[MaxOff+1];
2508 2520 unsigned offcodeMaxValue = MaxOff;
2521 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
2509 2522
2510 2523 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
2511 2524 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
2512 2525 dictPtr += hufHeaderSize;
2513 2526 }
2514 2527
2515 2528 { unsigned offcodeLog;
2516 2529 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
2517 2530 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2518 2531 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
2519 2532 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
2520 CHECK_E (FSE_buildCTable(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog), dictionary_corrupted);
2533 CHECK_E (FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
2521 2534 dictPtr += offcodeHeaderSize;
2522 2535 }
2523 2536
2524 2537 { short matchlengthNCount[MaxML+1];
2525 2538 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
2526 2539 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
2527 2540 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2528 2541 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
2529 2542 /* Every match length code must have non-zero probability */
2530 2543 CHECK_F (ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
2531 CHECK_E (FSE_buildCTable(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog), dictionary_corrupted);
2544 CHECK_E (FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
2532 2545 dictPtr += matchlengthHeaderSize;
2533 2546 }
2534 2547
2535 2548 { short litlengthNCount[MaxLL+1];
2536 2549 unsigned litlengthMaxValue = MaxLL, litlengthLog;
2537 2550 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
2538 2551 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2539 2552 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
2540 2553 /* Every literal length code must have non-zero probability */
2541 2554 CHECK_F (ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
2542 CHECK_E(FSE_buildCTable(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog), dictionary_corrupted);
2555 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
2543 2556 dictPtr += litlengthHeaderSize;
2544 2557 }
2545 2558
2546 2559 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
2547 2560 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2548 2561 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2549 2562 cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);
2550 2563 dictPtr += 12;
2551 2564
2552 2565 { U32 offcodeMax = MaxOff;
2553 2566 if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) {
2554 2567 U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */
2555 2568 /* Calculate minimum offset code required to represent maxOffset */
2556 2569 offcodeMax = ZSTD_highbit32(maxOffset);
2557 2570 }
2558 2571 /* Every possible supported offset <= dictContentSize + 128 KB must be representable */
2559 2572 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
2560 2573 }
2561 2574
2562 2575 cctx->flagStaticTables = 1;
2563 2576 return dictPtr - (const BYTE*)dict;
2564 2577 }
2565 2578
2566 2579 /** ZSTD_compress_insertDictionary() :
2567 2580 * @return : 0, or an error code */
2568 2581 static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2569 2582 {
2570 2583 if ((dict==NULL) || (dictSize<=8)) return 0;
2571 2584
2572 2585 /* default : dict is pure content */
2573 2586 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
2574 2587 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
2575 2588
2576 2589 /* known magic number : dict is parsed for entropy stats and content */
2577 2590 { size_t const loadError = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8);
2578 2591 size_t const eSize = loadError + 8;
2579 2592 if (ZSTD_isError(loadError)) return loadError;
2580 2593 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2581 2594 }
2582 2595 }
2583 2596
2584 2597
2585 2598 /*! ZSTD_compressBegin_internal() :
2586 2599 * @return : 0, or an error code */
2587 2600 static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
2588 2601 const void* dict, size_t dictSize,
2589 2602 ZSTD_parameters params, U64 pledgedSrcSize)
2590 2603 {
2591 2604 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
2592 2605 CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp));
2593 2606 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
2594 2607 }
2595 2608
2596 2609
2597 2610 /*! ZSTD_compressBegin_advanced() :
2598 2611 * @return : 0, or an error code */
2599 2612 size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
2600 2613 const void* dict, size_t dictSize,
2601 2614 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2602 2615 {
2603 2616 /* compression parameters verification and optimization */
2604 2617 CHECK_F(ZSTD_checkCParams(params.cParams));
2605 2618 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
2606 2619 }
2607 2620
2608 2621
2609 2622 size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
2610 2623 {
2611 2624 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
2612 2625 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
2613 2626 }
2614 2627
2615 2628
2616 2629 size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
2617 2630 {
2618 2631 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
2619 2632 }
2620 2633
2621 2634
2622 2635 /*! ZSTD_writeEpilogue() :
2623 2636 * Ends a frame.
2624 2637 * @return : nb of bytes written into dst (or an error code) */
2625 2638 static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
2626 2639 {
2627 2640 BYTE* const ostart = (BYTE*)dst;
2628 2641 BYTE* op = ostart;
2629 2642 size_t fhSize = 0;
2630 2643
2631 2644 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
2632 2645
2633 2646 /* special case : empty frame */
2634 2647 if (cctx->stage == ZSTDcs_init) {
2635 2648 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
2636 2649 if (ZSTD_isError(fhSize)) return fhSize;
2637 2650 dstCapacity -= fhSize;
2638 2651 op += fhSize;
2639 2652 cctx->stage = ZSTDcs_ongoing;
2640 2653 }
2641 2654
2642 2655 if (cctx->stage != ZSTDcs_ending) {
2643 2656 /* write one last empty block, make it the "last" block */
2644 2657 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2645 2658 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2646 2659 MEM_writeLE32(op, cBlockHeader24);
2647 2660 op += ZSTD_blockHeaderSize;
2648 2661 dstCapacity -= ZSTD_blockHeaderSize;
2649 2662 }
2650 2663
2651 2664 if (cctx->params.fParams.checksumFlag) {
2652 2665 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2653 2666 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2654 2667 MEM_writeLE32(op, checksum);
2655 2668 op += 4;
2656 2669 }
2657 2670
2658 2671 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
2659 2672 return op-ostart;
2660 2673 }
2661 2674
2662 2675
2663 2676 size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2664 2677 void* dst, size_t dstCapacity,
2665 2678 const void* src, size_t srcSize)
2666 2679 {
2667 2680 size_t endResult;
2668 2681 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
2669 2682 if (ZSTD_isError(cSize)) return cSize;
2670 2683 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2671 2684 if (ZSTD_isError(endResult)) return endResult;
2672 2685 return cSize + endResult;
2673 2686 }
2674 2687
2675 2688
2676 2689 static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
2677 2690 void* dst, size_t dstCapacity,
2678 2691 const void* src, size_t srcSize,
2679 2692 const void* dict,size_t dictSize,
2680 2693 ZSTD_parameters params)
2681 2694 {
2682 2695 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
2683 2696 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
2684 2697 }
2685 2698
2686 2699 size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2687 2700 void* dst, size_t dstCapacity,
2688 2701 const void* src, size_t srcSize,
2689 2702 const void* dict,size_t dictSize,
2690 2703 ZSTD_parameters params)
2691 2704 {
2692 2705 CHECK_F(ZSTD_checkCParams(params.cParams));
2693 2706 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2694 2707 }
2695 2708
2696 2709 size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel)
2697 2710 {
2698 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dictSize);
2711 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
2699 2712 params.fParams.contentSizeFlag = 1;
2700 2713 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2701 2714 }
2702 2715
2703 2716 size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
2704 2717 {
2705 2718 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
2706 2719 }
2707 2720
2708 2721 size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
2709 2722 {
2710 2723 size_t result;
2711 2724 ZSTD_CCtx ctxBody;
2712 2725 memset(&ctxBody, 0, sizeof(ctxBody));
2713 2726 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
2714 2727 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
2715 2728 ZSTD_free(ctxBody.workSpace, defaultCustomMem); /* can't free ctxBody itself, as it's on stack; free only heap content */
2716 2729 return result;
2717 2730 }
2718 2731
2719 2732
2720 2733 /* ===== Dictionary API ===== */
2721 2734
2722 2735 struct ZSTD_CDict_s {
2723 2736 void* dictContent;
2724 2737 size_t dictContentSize;
2725 2738 ZSTD_CCtx* refContext;
2726 2739 }; /* typedef'd tp ZSTD_CDict within "zstd.h" */
2727 2740
2728 2741 size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2729 2742 {
2730 2743 if (cdict==NULL) return 0; /* support sizeof on NULL */
2731 2744 return ZSTD_sizeof_CCtx(cdict->refContext) + cdict->dictContentSize;
2732 2745 }
2733 2746
2734 2747 ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_parameters params, ZSTD_customMem customMem)
2735 2748 {
2736 2749 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2737 2750 if (!customMem.customAlloc || !customMem.customFree) return NULL;
2738 2751
2739 2752 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
2740 2753 void* const dictContent = ZSTD_malloc(dictSize, customMem);
2741 2754 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2742 2755
2743 2756 if (!dictContent || !cdict || !cctx) {
2744 2757 ZSTD_free(dictContent, customMem);
2745 2758 ZSTD_free(cdict, customMem);
2746 2759 ZSTD_free(cctx, customMem);
2747 2760 return NULL;
2748 2761 }
2749 2762
2750 2763 if (dictSize) {
2751 2764 memcpy(dictContent, dict, dictSize);
2752 2765 }
2753 2766 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, dictContent, dictSize, params, 0);
2754 2767 if (ZSTD_isError(errorCode)) {
2755 2768 ZSTD_free(dictContent, customMem);
2756 2769 ZSTD_free(cdict, customMem);
2757 2770 ZSTD_free(cctx, customMem);
2758 2771 return NULL;
2759 2772 } }
2760 2773
2761 2774 cdict->dictContent = dictContent;
2762 2775 cdict->dictContentSize = dictSize;
2763 2776 cdict->refContext = cctx;
2764 2777 return cdict;
2765 2778 }
2766 2779 }
2767 2780
2768 2781 ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2769 2782 {
2770 2783 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2771 2784 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2772 2785 params.fParams.contentSizeFlag = 1;
2773 2786 return ZSTD_createCDict_advanced(dict, dictSize, params, allocator);
2774 2787 }
2775 2788
2776 2789 size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2777 2790 {
2778 2791 if (cdict==NULL) return 0; /* support free on NULL */
2779 2792 { ZSTD_customMem const cMem = cdict->refContext->customMem;
2780 2793 ZSTD_freeCCtx(cdict->refContext);
2781 2794 ZSTD_free(cdict->dictContent, cMem);
2782 2795 ZSTD_free(cdict, cMem);
2783 2796 return 0;
2784 2797 }
2785 2798 }
2786 2799
2787 2800 static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
2788 2801 return ZSTD_getParamsFromCCtx(cdict->refContext);
2789 2802 }
2790 2803
2791 2804 size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, U64 pledgedSrcSize)
2792 2805 {
2793 2806 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
2794 2807 else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, pledgedSrcSize));
2795 2808 return 0;
2796 2809 }
2797 2810
2798 2811 /*! ZSTD_compress_usingCDict() :
2799 2812 * Compression using a digested Dictionary.
2800 2813 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2801 2814 * Note that compression level is decided during dictionary creation */
2802 2815 size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2803 2816 void* dst, size_t dstCapacity,
2804 2817 const void* src, size_t srcSize,
2805 2818 const ZSTD_CDict* cdict)
2806 2819 {
2807 2820 CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize));
2808 2821
2809 2822 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2810 2823 cctx->params.fParams.contentSizeFlag = 1;
2811 2824 cctx->frameContentSize = srcSize;
2812 2825 }
2813 2826
2814 2827 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
2815 2828 }
2816 2829
2817 2830
2818 2831
2819 2832 /* ******************************************************************
2820 2833 * Streaming
2821 2834 ********************************************************************/
2822 2835
2823 2836 typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2824 2837
2825 2838 struct ZSTD_CStream_s {
2826 2839 ZSTD_CCtx* cctx;
2827 2840 ZSTD_CDict* cdictLocal;
2828 2841 const ZSTD_CDict* cdict;
2829 2842 char* inBuff;
2830 2843 size_t inBuffSize;
2831 2844 size_t inToCompress;
2832 2845 size_t inBuffPos;
2833 2846 size_t inBuffTarget;
2834 2847 size_t blockSize;
2835 2848 char* outBuff;
2836 2849 size_t outBuffSize;
2837 2850 size_t outBuffContentSize;
2838 2851 size_t outBuffFlushedSize;
2839 2852 ZSTD_cStreamStage stage;
2840 2853 U32 checksum;
2841 2854 U32 frameEnded;
2855 U64 pledgedSrcSize;
2856 U64 inputProcessed;
2842 2857 ZSTD_parameters params;
2843 2858 ZSTD_customMem customMem;
2844 2859 }; /* typedef'd to ZSTD_CStream within "zstd.h" */
2845 2860
2846 2861 ZSTD_CStream* ZSTD_createCStream(void)
2847 2862 {
2848 2863 return ZSTD_createCStream_advanced(defaultCustomMem);
2849 2864 }
2850 2865
2851 2866 ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2852 2867 {
2853 2868 ZSTD_CStream* zcs;
2854 2869
2855 2870 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2856 2871 if (!customMem.customAlloc || !customMem.customFree) return NULL;
2857 2872
2858 2873 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
2859 2874 if (zcs==NULL) return NULL;
2860 2875 memset(zcs, 0, sizeof(ZSTD_CStream));
2861 2876 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
2862 2877 zcs->cctx = ZSTD_createCCtx_advanced(customMem);
2863 2878 if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
2864 2879 return zcs;
2865 2880 }
2866 2881
2867 2882 size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2868 2883 {
2869 2884 if (zcs==NULL) return 0; /* support free on NULL */
2870 2885 { ZSTD_customMem const cMem = zcs->customMem;
2871 2886 ZSTD_freeCCtx(zcs->cctx);
2872 2887 ZSTD_freeCDict(zcs->cdictLocal);
2873 2888 ZSTD_free(zcs->inBuff, cMem);
2874 2889 ZSTD_free(zcs->outBuff, cMem);
2875 2890 ZSTD_free(zcs, cMem);
2876 2891 return 0;
2877 2892 }
2878 2893 }
2879 2894
2880 2895
2881 2896 /*====== Initialization ======*/
2882 2897
2883 2898 size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2884 2899 size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
2885 2900
2886 2901 size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
2887 2902 {
2888 2903 if (zcs->inBuffSize==0) return ERROR(stage_wrong); /* zcs has not been init at least once */
2889 2904
2890 2905 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
2891 2906 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
2892 2907
2893 2908 zcs->inToCompress = 0;
2894 2909 zcs->inBuffPos = 0;
2895 2910 zcs->inBuffTarget = zcs->blockSize;
2896 2911 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2897 2912 zcs->stage = zcss_load;
2898 2913 zcs->frameEnded = 0;
2914 zcs->pledgedSrcSize = pledgedSrcSize;
2915 zcs->inputProcessed = 0;
2899 2916 return 0; /* ready to go */
2900 2917 }
2901 2918
2902 2919 size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2903 2920 const void* dict, size_t dictSize,
2904 2921 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2905 2922 {
2906 2923 /* allocate buffers */
2907 2924 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
2908 2925 if (zcs->inBuffSize < neededInBuffSize) {
2909 2926 zcs->inBuffSize = neededInBuffSize;
2910 2927 ZSTD_free(zcs->inBuff, zcs->customMem);
2911 2928 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
2912 2929 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
2913 2930 }
2914 2931 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
2915 2932 }
2916 2933 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
2917 2934 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
2918 2935 ZSTD_free(zcs->outBuff, zcs->customMem);
2919 2936 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
2920 2937 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
2921 2938 }
2922 2939
2923 2940 if (dict) {
2924 2941 ZSTD_freeCDict(zcs->cdictLocal);
2925 2942 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, params, zcs->customMem);
2926 2943 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
2927 2944 zcs->cdict = zcs->cdictLocal;
2928 2945 } else zcs->cdict = NULL;
2929 2946
2930 2947 zcs->checksum = params.fParams.checksumFlag > 0;
2931 2948 zcs->params = params;
2932 2949
2933 2950 return ZSTD_resetCStream(zcs, pledgedSrcSize);
2934 2951 }
2935 2952
2936 2953 /* note : cdict must outlive compression session */
2937 2954 size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
2938 2955 {
2939 2956 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
2940 2957 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);
2941 2958 zcs->cdict = cdict;
2942 2959 return initError;
2943 2960 }
2944 2961
2945 2962 size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
2946 2963 {
2947 2964 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
2948 2965 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
2949 2966 }
2950 2967
2968 size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
2969 {
2970 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
2971 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
2972 }
2973
2951 2974 size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
2952 2975 {
2953 2976 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);
2954 2977 }
2955 2978
2956 2979 size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
2957 2980 {
2958 2981 if (zcs==NULL) return 0; /* support sizeof on NULL */
2959 2982 return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;
2960 2983 }
2961 2984
2962 2985 /*====== Compression ======*/
2963 2986
2964 2987 typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
2965 2988
2966 2989 MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2967 2990 {
2968 2991 size_t const length = MIN(dstCapacity, srcSize);
2969 2992 memcpy(dst, src, length);
2970 2993 return length;
2971 2994 }
2972 2995
2973 2996 static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
2974 2997 void* dst, size_t* dstCapacityPtr,
2975 2998 const void* src, size_t* srcSizePtr,
2976 2999 ZSTD_flush_e const flush)
2977 3000 {
2978 3001 U32 someMoreWork = 1;
2979 3002 const char* const istart = (const char*)src;
2980 3003 const char* const iend = istart + *srcSizePtr;
2981 3004 const char* ip = istart;
2982 3005 char* const ostart = (char*)dst;
2983 3006 char* const oend = ostart + *dstCapacityPtr;
2984 3007 char* op = ostart;
2985 3008
2986 3009 while (someMoreWork) {
2987 3010 switch(zcs->stage)
2988 3011 {
2989 3012 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
2990 3013
2991 3014 case zcss_load:
2992 3015 /* complete inBuffer */
2993 3016 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
2994 3017 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
2995 3018 zcs->inBuffPos += loaded;
2996 3019 ip += loaded;
2997 3020 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
2998 3021 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
2999 3022 } }
3000 3023 /* compress current block (note : this stage cannot be stopped in the middle) */
3001 3024 { void* cDst;
3002 3025 size_t cSize;
3003 3026 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3004 3027 size_t oSize = oend-op;
3005 3028 if (oSize >= ZSTD_compressBound(iSize))
3006 3029 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3007 3030 else
3008 3031 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3009 3032 cSize = (flush == zsf_end) ?
3010 3033 ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3011 3034 ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
3012 3035 if (ZSTD_isError(cSize)) return cSize;
3013 3036 if (flush == zsf_end) zcs->frameEnded = 1;
3014 3037 /* prepare next block */
3015 3038 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3016 3039 if (zcs->inBuffTarget > zcs->inBuffSize)
3017 3040 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
3018 3041 zcs->inToCompress = zcs->inBuffPos;
3019 3042 if (cDst == op) { op += cSize; break; } /* no need to flush */
3020 3043 zcs->outBuffContentSize = cSize;
3021 3044 zcs->outBuffFlushedSize = 0;
3022 3045 zcs->stage = zcss_flush; /* pass-through to flush stage */
3023 3046 }
3024 3047
3025 3048 case zcss_flush:
3026 3049 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3027 3050 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3028 3051 op += flushed;
3029 3052 zcs->outBuffFlushedSize += flushed;
3030 3053 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3031 3054 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3032 3055 zcs->stage = zcss_load;
3033 3056 break;
3034 3057 }
3035 3058
3036 3059 case zcss_final:
3037 3060 someMoreWork = 0; /* do nothing */
3038 3061 break;
3039 3062
3040 3063 default:
3041 3064 return ERROR(GENERIC); /* impossible */
3042 3065 }
3043 3066 }
3044 3067
3045 3068 *srcSizePtr = ip - istart;
3046 3069 *dstCapacityPtr = op - ostart;
3070 zcs->inputProcessed += *srcSizePtr;
3047 3071 if (zcs->frameEnded) return 0;
3048 3072 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3049 3073 if (hintInSize==0) hintInSize = zcs->blockSize;
3050 3074 return hintInSize;
3051 3075 }
3052 3076 }
3053 3077
3054 3078 size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
3055 3079 {
3056 3080 size_t sizeRead = input->size - input->pos;
3057 3081 size_t sizeWritten = output->size - output->pos;
3058 3082 size_t const result = ZSTD_compressStream_generic(zcs,
3059 3083 (char*)(output->dst) + output->pos, &sizeWritten,
3060 3084 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3061 3085 input->pos += sizeRead;
3062 3086 output->pos += sizeWritten;
3063 3087 return result;
3064 3088 }
3065 3089
3066 3090
3067 3091 /*====== Finalize ======*/
3068 3092
3069 3093 /*! ZSTD_flushStream() :
3070 3094 * @return : amount of data remaining to flush */
3071 3095 size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
3072 3096 {
3073 3097 size_t srcSize = 0;
3074 3098 size_t sizeWritten = output->size - output->pos;
3075 3099 size_t const result = ZSTD_compressStream_generic(zcs,
3076 3100 (char*)(output->dst) + output->pos, &sizeWritten,
3077 3101 &srcSize, &srcSize, /* use a valid src address instead of NULL */
3078 3102 zsf_flush);
3079 3103 output->pos += sizeWritten;
3080 3104 if (ZSTD_isError(result)) return result;
3081 3105 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3082 3106 }
3083 3107
3084 3108
3085 3109 size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
3086 3110 {
3087 3111 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3088 3112 BYTE* const oend = (BYTE*)(output->dst) + output->size;
3089 3113 BYTE* op = ostart;
3090 3114
3115 if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize))
3116 return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
3117
3091 3118 if (zcs->stage != zcss_final) {
3092 3119 /* flush whatever remains */
3093 3120 size_t srcSize = 0;
3094 3121 size_t sizeWritten = output->size - output->pos;
3095 3122 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3096 3123 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3097 3124 op += sizeWritten;
3098 3125 if (remainingToFlush) {
3099 3126 output->pos += sizeWritten;
3100 3127 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3101 3128 }
3102 3129 /* create epilogue */
3103 3130 zcs->stage = zcss_final;
3104 3131 zcs->outBuffContentSize = !notEnded ? 0 :
3105 3132 ZSTD_compressEnd(zcs->cctx, zcs->outBuff, zcs->outBuffSize, NULL, 0); /* write epilogue, including final empty block, into outBuff */
3106 3133 }
3107 3134
3108 3135 /* flush epilogue */
3109 3136 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3110 3137 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3111 3138 op += flushed;
3112 3139 zcs->outBuffFlushedSize += flushed;
3113 3140 output->pos += op-ostart;
3114 3141 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3115 3142 return toFlush - flushed;
3116 3143 }
3117 3144 }
3118 3145
3119 3146
3120 3147
3121 3148 /*-===== Pre-defined compression levels =====-*/
3122 3149
3123 3150 #define ZSTD_DEFAULT_CLEVEL 1
3124 3151 #define ZSTD_MAX_CLEVEL 22
3125 3152 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
3126 3153
3127 3154 static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
3128 3155 { /* "default" */
3129 3156 /* W, C, H, S, L, TL, strat */
3130 3157 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
3131 3158 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3132 3159 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
3133 3160 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3134 3161 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
3135 3162 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3136 3163 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3137 3164 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
3138 3165 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
3139 3166 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3140 3167 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3141 3168 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3142 3169 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3143 3170 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3144 3171 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3145 3172 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3146 3173 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
3147 3174 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3148 3175 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3149 3176 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
3150 3177 { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */
3151 3178 { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */
3152 3179 { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */
3153 3180 },
3154 3181 { /* for srcSize <= 256 KB */
3155 3182 /* W, C, H, S, L, T, strat */
3156 3183 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
3157 3184 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
3158 3185 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3159 3186 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3160 3187 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3161 3188 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3162 3189 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3163 3190 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3164 3191 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3165 3192 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3166 3193 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3167 3194 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3168 3195 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3169 3196 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
3170 3197 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
3171 3198 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3172 3199 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3173 3200 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
3174 3201 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3175 3202 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
3176 3203 { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/
3177 3204 { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/
3178 3205 { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/
3179 3206 },
3180 3207 { /* for srcSize <= 128 KB */
3181 3208 /* W, C, H, S, L, T, strat */
3182 3209 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3183 3210 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3184 3211 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3185 3212 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3186 3213 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3187 3214 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3188 3215 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3189 3216 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3190 3217 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3191 3218 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3192 3219 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3193 3220 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3194 3221 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3195 3222 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
3196 3223 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3197 3224 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3198 3225 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3199 3226 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3200 3227 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3201 3228 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
3202 3229 { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/
3203 3230 { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/
3204 3231 { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/
3205 3232 },
3206 3233 { /* for srcSize <= 16 KB */
3207 3234 /* W, C, H, S, L, T, strat */
3208 3235 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
3209 3236 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
3210 3237 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3211 3238 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3212 3239 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3213 3240 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3214 3241 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3215 3242 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3216 3243 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3217 3244 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
3218 3245 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3219 3246 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3220 3247 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3221 3248 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3222 3249 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3223 3250 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3224 3251 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3225 3252 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3226 3253 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3227 3254 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
3228 3255 { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/
3229 3256 { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/
3230 3257 { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/
3231 3258 },
3232 3259 };
3233 3260
3234 3261 /*! ZSTD_getCParams() :
3235 3262 * @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3236 3263 * Size values are optional, provide 0 if not known or unused */
3237 3264 ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
3238 3265 {
3239 3266 ZSTD_compressionParameters cp;
3240 3267 size_t const addedSize = srcSize ? 0 : 500;
3241 3268 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
3242 3269 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
3243 3270 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
3244 3271 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
3245 3272 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
3246 3273 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3247 3274 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
3248 3275 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
3249 3276 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3250 3277 }
3251 3278 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
3252 3279 return cp;
3253 3280 }
3254 3281
3255 3282 /*! ZSTD_getParams() :
3256 3283 * same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
3257 3284 * All fields of `ZSTD_frameParameters` are set to default (0) */
3258 3285 ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
3259 3286 ZSTD_parameters params;
3260 3287 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3261 3288 memset(&params, 0, sizeof(params));
3262 3289 params.cParams = cParams;
3263 3290 return params;
3264 3291 }
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now