1 /*
2 Copyright (c) 2014 - 2019, Syoyo Fujita and many contributors.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the Syoyo Fujita nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 // TinyEXR contains some OpenEXR code, which is licensed under ------------
29
30 ///////////////////////////////////////////////////////////////////////////
31 //
32 // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
33 // Digital Ltd. LLC
34 //
35 // All rights reserved.
36 //
37 // Redistribution and use in source and binary forms, with or without
38 // modification, are permitted provided that the following conditions are
39 // met:
40 // * Redistributions of source code must retain the above copyright
41 // notice, this list of conditions and the following disclaimer.
42 // * Redistributions in binary form must reproduce the above
43 // copyright notice, this list of conditions and the following disclaimer
44 // in the documentation and/or other materials provided with the
45 // distribution.
46 // * Neither the name of Industrial Light & Magic nor the names of
47 // its contributors may be used to endorse or promote products derived
48 // from this software without specific prior written permission.
49 //
50 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 //
62 ///////////////////////////////////////////////////////////////////////////
63
64 // End of OpenEXR license -------------------------------------------------
65
66 #ifndef TINYEXR_H_
67 #define TINYEXR_H_
68
69 //
70 //
71 // Do this:
72 // #define TINYEXR_IMPLEMENTATION
73 // before you include this file in *one* C or C++ file to create the
74 // implementation.
75 //
76 // // i.e. it should look like this:
77 // #include ...
78 // #include ...
79 // #include ...
80 // #define TINYEXR_IMPLEMENTATION
81 // #include "tinyexr.h"
82 //
83 //
84
85 #include <stddef.h> // for size_t
86 #include <stdint.h> // guess stdint.h is available(C99)
87
88 #ifdef __cplusplus
89 extern "C" {
90 #endif
91
92 // Use embedded miniz or not to decode ZIP format pixel. Linking with zlib
93 // required if this flas is 0.
94 #ifndef TINYEXR_USE_MINIZ
95 #define TINYEXR_USE_MINIZ (1)
96 #endif
97
98 // Disable PIZ comporession when applying cpplint.
99 #ifndef TINYEXR_USE_PIZ
100 #define TINYEXR_USE_PIZ (1)
101 #endif
102
103 #ifndef TINYEXR_USE_ZFP
104 #define TINYEXR_USE_ZFP (0) // TinyEXR extension.
105 // http://computation.llnl.gov/projects/floating-point-compression
106 #endif
107
108 #define TINYEXR_SUCCESS (0)
109 #define TINYEXR_ERROR_INVALID_MAGIC_NUMBER (-1)
110 #define TINYEXR_ERROR_INVALID_EXR_VERSION (-2)
111 #define TINYEXR_ERROR_INVALID_ARGUMENT (-3)
112 #define TINYEXR_ERROR_INVALID_DATA (-4)
113 #define TINYEXR_ERROR_INVALID_FILE (-5)
114 #define TINYEXR_ERROR_INVALID_PARAMETER (-6)
115 #define TINYEXR_ERROR_CANT_OPEN_FILE (-7)
116 #define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-8)
117 #define TINYEXR_ERROR_INVALID_HEADER (-9)
118 #define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-10)
119 #define TINYEXR_ERROR_CANT_WRITE_FILE (-11)
120 #define TINYEXR_ERROR_SERIALZATION_FAILED (-12)
121
122 // @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf }
123
124 // pixel type: possible values are: UINT = 0 HALF = 1 FLOAT = 2
125 #define TINYEXR_PIXELTYPE_UINT (0)
126 #define TINYEXR_PIXELTYPE_HALF (1)
127 #define TINYEXR_PIXELTYPE_FLOAT (2)
128
129 #define TINYEXR_MAX_HEADER_ATTRIBUTES (1024)
130 #define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128)
131
132 #define TINYEXR_COMPRESSIONTYPE_NONE (0)
133 #define TINYEXR_COMPRESSIONTYPE_RLE (1)
134 #define TINYEXR_COMPRESSIONTYPE_ZIPS (2)
135 #define TINYEXR_COMPRESSIONTYPE_ZIP (3)
136 #define TINYEXR_COMPRESSIONTYPE_PIZ (4)
137 #define TINYEXR_COMPRESSIONTYPE_ZFP (128) // TinyEXR extension
138
139 #define TINYEXR_ZFP_COMPRESSIONTYPE_RATE (0)
140 #define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION (1)
141 #define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY (2)
142
143 #define TINYEXR_TILE_ONE_LEVEL (0)
144 #define TINYEXR_TILE_MIPMAP_LEVELS (1)
145 #define TINYEXR_TILE_RIPMAP_LEVELS (2)
146
147 #define TINYEXR_TILE_ROUND_DOWN (0)
148 #define TINYEXR_TILE_ROUND_UP (1)
149
150 typedef struct _EXRVersion {
151 int version; // this must be 2
152 int tiled; // tile format image
153 int long_name; // long name attribute
154 int non_image; // deep image(EXR 2.0)
155 int multipart; // multi-part(EXR 2.0)
156 } EXRVersion;
157
158 typedef struct _EXRAttribute {
159 char name[256]; // name and type are up to 255 chars long.
160 char type[256];
161 unsigned char *value; // uint8_t*
162 int size;
163 int pad0;
164 } EXRAttribute;
165
166 typedef struct _EXRChannelInfo {
167 char name[256]; // less than 255 bytes long
168 int pixel_type;
169 int x_sampling;
170 int y_sampling;
171 unsigned char p_linear;
172 unsigned char pad[3];
173 } EXRChannelInfo;
174
175 typedef struct _EXRTile {
176 int offset_x;
177 int offset_y;
178 int level_x;
179 int level_y;
180
181 int width; // actual width in a tile.
182 int height; // actual height int a tile.
183
184 unsigned char **images; // image[channels][pixels]
185 } EXRTile;
186
187 typedef struct _EXRHeader {
188 float pixel_aspect_ratio;
189 int line_order;
190 int data_window[4];
191 int display_window[4];
192 float screen_window_center[2];
193 float screen_window_width;
194
195 int chunk_count;
196
197 // Properties for tiled format(`tiledesc`).
198 int tiled;
199 int tile_size_x;
200 int tile_size_y;
201 int tile_level_mode;
202 int tile_rounding_mode;
203
204 int long_name;
205 int non_image;
206 int multipart;
207 unsigned int header_len;
208
209 // Custom attributes(exludes required attributes(e.g. `channels`,
210 // `compression`, etc)
211 int num_custom_attributes;
212 EXRAttribute *custom_attributes; // array of EXRAttribute. size =
213 // `num_custom_attributes`.
214
215 EXRChannelInfo *channels; // [num_channels]
216
217 int *pixel_types; // Loaded pixel type(TINYEXR_PIXELTYPE_*) of `images` for
218 // each channel. This is overwritten with `requested_pixel_types` when
219 // loading.
220 int num_channels;
221
222 int compression_type; // compression type(TINYEXR_COMPRESSIONTYPE_*)
223 int *requested_pixel_types; // Filled initially by
224 // ParseEXRHeaderFrom(Meomory|File), then users
225 // can edit it(only valid for HALF pixel type
226 // channel)
227
228 } EXRHeader;
229
230 typedef struct _EXRMultiPartHeader {
231 int num_headers;
232 EXRHeader *headers;
233
234 } EXRMultiPartHeader;
235
236 typedef struct _EXRImage {
237 EXRTile *tiles; // Tiled pixel data. The application must reconstruct image
238 // from tiles manually. NULL if scanline format.
239 unsigned char **images; // image[channels][pixels]. NULL if tiled format.
240
241 int width;
242 int height;
243 int num_channels;
244
245 // Properties for tile format.
246 int num_tiles;
247
248 } EXRImage;
249
250 typedef struct _EXRMultiPartImage {
251 int num_images;
252 EXRImage *images;
253
254 } EXRMultiPartImage;
255
256 typedef struct _DeepImage {
257 const char **channel_names;
258 float ***image; // image[channels][scanlines][samples]
259 int **offset_table; // offset_table[scanline][offsets]
260 int num_channels;
261 int width;
262 int height;
263 int pad0;
264 } DeepImage;
265
266 // @deprecated { to be removed. }
267 // Loads single-frame OpenEXR image. Assume EXR image contains A(single channel
268 // alpha) or RGB(A) channels.
269 // Application must free image data as returned by `out_rgba`
270 // Result image format is: float x RGBA x width x hight
271 // Returns negative value and may set error string in `err` when there's an
272 // error
273 extern int LoadEXR(float **out_rgba, int *width, int *height,
274 const char *filename, const char **err);
275
276 // @deprecated { to be removed. }
277 // Simple wrapper API for ParseEXRHeaderFromFile.
278 // checking given file is a EXR file(by just look up header)
279 // @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for
280 // others
281 extern int IsEXR(const char *filename);
282
283 // @deprecated { to be removed. }
284 // Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels.
285 // components must be 1(Grayscale), 3(RGB) or 4(RGBA).
286 // Input image format is: `float x width x height`, or `float x RGB(A) x width x
287 // hight`
288 // Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero
289 // value.
290 // Save image as fp32(FLOAT) format when `save_as_fp16` is 0.
291 // Use ZIP compression by default.
292 // Returns negative value and may set error string in `err` when there's an
293 // error
294 extern int SaveEXR(const float *data, const int width, const int height,
295 const int components, const int save_as_fp16,
296 const char *filename, const char **err);
297
298 // Initialize EXRHeader struct
299 extern void InitEXRHeader(EXRHeader *exr_header);
300
301 // Initialize EXRImage struct
302 extern void InitEXRImage(EXRImage *exr_image);
303
304 // Free's internal data of EXRHeader struct
305 extern int FreeEXRHeader(EXRHeader *exr_header);
306
307 // Free's internal data of EXRImage struct
308 extern int FreeEXRImage(EXRImage *exr_image);
309
310 // Free's error message
311 extern void FreeEXRErrorMessage(const char *msg);
312
313 // Parse EXR version header of a file.
314 extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename);
315
316 // Parse EXR version header from memory-mapped EXR data.
317 extern int ParseEXRVersionFromMemory(EXRVersion *version,
318 const unsigned char *memory, size_t size);
319
320 // Parse single-part OpenEXR header from a file and initialize `EXRHeader`.
321 // When there was an error message, Application must free `err` with
322 // FreeEXRErrorMessage()
323 extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version,
324 const char *filename, const char **err);
325
326 // Parse single-part OpenEXR header from a memory and initialize `EXRHeader`.
327 // When there was an error message, Application must free `err` with
328 // FreeEXRErrorMessage()
329 extern int ParseEXRHeaderFromMemory(EXRHeader *header,
330 const EXRVersion *version,
331 const unsigned char *memory, size_t size,
332 const char **err);
333
334 // Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*`
335 // array.
336 // When there was an error message, Application must free `err` with
337 // FreeEXRErrorMessage()
338 extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
339 int *num_headers,
340 const EXRVersion *version,
341 const char *filename,
342 const char **err);
343
344 // Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*`
345 // array
346 // When there was an error message, Application must free `err` with
347 // FreeEXRErrorMessage()
348 extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
349 int *num_headers,
350 const EXRVersion *version,
351 const unsigned char *memory,
352 size_t size, const char **err);
353
354 // Loads single-part OpenEXR image from a file.
355 // Application must setup `ParseEXRHeaderFromFile` before calling this function.
356 // Application can free EXRImage using `FreeEXRImage`
357 // Returns negative value and may set error string in `err` when there's an
358 // error
359 // When there was an error message, Application must free `err` with
360 // FreeEXRErrorMessage()
361 extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
362 const char *filename, const char **err);
363
364 // Loads single-part OpenEXR image from a memory.
365 // Application must setup `EXRHeader` with
366 // `ParseEXRHeaderFromMemory` before calling this function.
367 // Application can free EXRImage using `FreeEXRImage`
368 // Returns negative value and may set error string in `err` when there's an
369 // error
370 // When there was an error message, Application must free `err` with
371 // FreeEXRErrorMessage()
372 extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
373 const unsigned char *memory,
374 const size_t size, const char **err);
375
376 // Loads multi-part OpenEXR image from a file.
377 // Application must setup `ParseEXRMultipartHeaderFromFile` before calling this
378 // function.
379 // Application can free EXRImage using `FreeEXRImage`
380 // Returns negative value and may set error string in `err` when there's an
381 // error
382 // When there was an error message, Application must free `err` with
383 // FreeEXRErrorMessage()
384 extern int LoadEXRMultipartImageFromFile(EXRImage *images,
385 const EXRHeader **headers,
386 unsigned int num_parts,
387 const char *filename,
388 const char **err);
389
390 // Loads multi-part OpenEXR image from a memory.
391 // Application must setup `EXRHeader*` array with
392 // `ParseEXRMultipartHeaderFromMemory` before calling this function.
393 // Application can free EXRImage using `FreeEXRImage`
394 // Returns negative value and may set error string in `err` when there's an
395 // error
396 // When there was an error message, Application must free `err` with
397 // FreeEXRErrorMessage()
398 extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
399 const EXRHeader **headers,
400 unsigned int num_parts,
401 const unsigned char *memory,
402 const size_t size, const char **err);
403
404 // Saves multi-channel, single-frame OpenEXR image to a file.
405 // Returns negative value and may set error string in `err` when there's an
406 // error
407 // When there was an error message, Application must free `err` with
408 // FreeEXRErrorMessage()
409 extern int SaveEXRImageToFile(const EXRImage *image,
410 const EXRHeader *exr_header, const char *filename,
411 const char **err);
412
413 // Saves multi-channel, single-frame OpenEXR image to a memory.
414 // Image is compressed using EXRImage.compression value.
415 // Return the number of bytes if success.
416 // Return zero and will set error string in `err` when there's an
417 // error.
418 // When there was an error message, Application must free `err` with
419 // FreeEXRErrorMessage()
420 extern size_t SaveEXRImageToMemory(const EXRImage *image,
421 const EXRHeader *exr_header,
422 unsigned char **memory, const char **err);
423
424 // Loads single-frame OpenEXR deep image.
425 // Application must free memory of variables in DeepImage(image, offset_table)
426 // Returns negative value and may set error string in `err` when there's an
427 // error
428 // When there was an error message, Application must free `err` with
429 // FreeEXRErrorMessage()
430 extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
431 const char **err);
432
433 // NOT YET IMPLEMENTED:
434 // Saves single-frame OpenEXR deep image.
435 // Returns negative value and may set error string in `err` when there's an
436 // error
437 // extern int SaveDeepEXR(const DeepImage *in_image, const char *filename,
438 // const char **err);
439
440 // NOT YET IMPLEMENTED:
441 // Loads multi-part OpenEXR deep image.
442 // Application must free memory of variables in DeepImage(image, offset_table)
443 // extern int LoadMultiPartDeepEXR(DeepImage **out_image, int num_parts, const
444 // char *filename,
445 // const char **err);
446
447 // For emscripten.
448 // Loads single-frame OpenEXR image from memory. Assume EXR image contains
449 // RGB(A) channels.
450 // Returns negative value and may set error string in `err` when there's an
451 // error
452 // When there was an error message, Application must free `err` with
453 // FreeEXRErrorMessage()
454 extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
455 const unsigned char *memory, size_t size,
456 const char **err);
457
458 #ifdef __cplusplus
459 }
460 #endif
461
462 #endif // TINYEXR_H_
463
464 #ifdef TINYEXR_IMPLEMENTATION
465 #ifndef TINYEXR_IMPLEMENTATION_DEIFNED
466 #define TINYEXR_IMPLEMENTATION_DEIFNED
467
468 #include <algorithm>
469 #include <cassert>
470 #include <cstdio>
471 #include <cstdlib>
472 #include <cstring>
473 #include <sstream>
474
475 //#include <iostream> // debug
476
477 #include <limits>
478 #include <string>
479 #include <vector>
480
481 #if __cplusplus > 199711L
482 // C++11
483 #include <cstdint>
484 #endif // __cplusplus > 199711L
485
486 #ifdef _OPENMP
487 #include <omp.h>
488 #endif
489
490 #if TINYEXR_USE_MINIZ
491 #else
492 // Issue #46. Please include your own zlib-compatible API header before
493 // including `tinyexr.h`
494 //#include "zlib.h"
495 #endif
496
497 #if TINYEXR_USE_ZFP
498 #include "zfp.h"
499 #endif
500
501 namespace tinyexr {
502
503 #if __cplusplus > 199711L
504 // C++11
505 typedef uint64_t tinyexr_uint64;
506 typedef int64_t tinyexr_int64;
507 #else
508 // Although `long long` is not a standard type pre C++11, assume it is defined
509 // as a compiler's extension.
510 #ifdef __clang__
511 #pragma clang diagnostic push
512 #pragma clang diagnostic ignored "-Wc++11-long-long"
513 #endif
514 typedef unsigned long long tinyexr_uint64;
515 typedef long long tinyexr_int64;
516 #ifdef __clang__
517 #pragma clang diagnostic pop
518 #endif
519 #endif
520
521 #if TINYEXR_USE_MINIZ
522
523 namespace miniz {
524
525 #ifdef __clang__
526 #pragma clang diagnostic push
527 #pragma clang diagnostic ignored "-Wc++11-long-long"
528 #pragma clang diagnostic ignored "-Wold-style-cast"
529 #pragma clang diagnostic ignored "-Wpadded"
530 #pragma clang diagnostic ignored "-Wsign-conversion"
531 #pragma clang diagnostic ignored "-Wc++11-extensions"
532 #pragma clang diagnostic ignored "-Wconversion"
533 #pragma clang diagnostic ignored "-Wunused-function"
534 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
535 #pragma clang diagnostic ignored "-Wundef"
536
537 #if __has_warning("-Wcomma")
538 #pragma clang diagnostic ignored "-Wcomma"
539 #endif
540
541 #if __has_warning("-Wmacro-redefined")
542 #pragma clang diagnostic ignored "-Wmacro-redefined"
543 #endif
544
545 #if __has_warning("-Wcast-qual")
546 #pragma clang diagnostic ignored "-Wcast-qual"
547 #endif
548
549 #if __has_warning("-Wzero-as-null-pointer-constant")
550 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
551 #endif
552
553 #if __has_warning("-Wtautological-constant-compare")
554 #pragma clang diagnostic ignored "-Wtautological-constant-compare"
555 #endif
556
557 #if __has_warning("-Wextra-semi-stmt")
558 #pragma clang diagnostic ignored "-Wextra-semi-stmt"
559 #endif
560
561 #endif
562
563 /* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
564 reading/writing/appending, PNG writing
565 See "unlicense" statement at the end of this file.
566 Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013
567 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951:
568 http://www.ietf.org/rfc/rfc1951.txt
569
570 Most API's defined in miniz.c are optional. For example, to disable the
571 archive related functions just define
572 MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO
573 (see the list below for more macros).
574
575 * Change History
576 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major
577 release with Zip64 support (almost there!):
578 - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug
579 (thanks kahmyong.moon@hp.com) which could cause locate files to not find
580 files. This bug
581 would only have occured in earlier versions if you explicitly used this
582 flag, OR if you used mz_zip_extract_archive_file_to_heap() or
583 mz_zip_add_mem_to_archive_file_in_place()
584 (which used this flag). If you can't switch to v1.15 but want to fix
585 this bug, just remove the uses of this flag from both helper funcs (and of
586 course don't use the flag).
587 - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when
588 pUser_read_buf is not NULL and compressed size is > uncompressed size
589 - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract
590 compressed data from directory entries, to account for weird zipfiles which
591 contain zero-size compressed data on dir entries.
592 Hopefully this fix won't cause any issues on weird zip archives,
593 because it assumes the low 16-bits of zip external attributes are DOS
594 attributes (which I believe they always are in practice).
595 - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the
596 internal attributes, just the filename and external attributes
597 - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed
598 - Added cmake support for Linux builds which builds all the examples,
599 tested with clang v3.3 and gcc v4.6.
600 - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti
601 - Merged MZ_FORCEINLINE fix from hdeanclark
602 - Fix <time.h> include before config #ifdef, thanks emil.brink
603 - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping
604 (super useful for OpenGL apps), and explicit control over the compression
605 level (so you can
606 set it to 1 for real-time compression).
607 - Merged in some compiler fixes from paulharris's github repro.
608 - Retested this build under Windows (VS 2010, including static analysis),
609 tcc 0.9.26, gcc v4.6 and clang v3.3.
610 - Added example6.c, which dumps an image of the mandelbrot set to a PNG
611 file.
612 - Modified example2 to help test the
613 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more.
614 - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix
615 possible src file fclose() leak if alignment bytes+local header file write
616 faiiled
617 - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader():
618 Was pushing the wrong central dir header offset, appears harmless in this
619 release, but it became a problem in the zip64 branch
620 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE,
621 #include <time.h> (thanks fermtect).
622 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix
623 mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit.
624 - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and
625 re-ran a randomized regression test on ~500k files.
626 - Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
627 - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze
628 (static analysis) option and fixed all warnings (except for the silly
629 "Use of the comma-operator in a tested expression.." analysis warning,
630 which I purposely use to work around a MSVC compiler warning).
631 - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and
632 tested Linux executables. The codeblocks workspace is compatible with
633 Linux+Win32/x64.
634 - Added miniz_tester solution/project, which is a useful little app
635 derived from LZHAM's tester app that I use as part of the regression test.
636 - Ran miniz.c and tinfl.c through another series of regression testing on
637 ~500,000 files and archives.
638 - Modified example5.c so it purposely disables a bunch of high-level
639 functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the
640 MINIZ_NO_STDIO bug report.)
641 - Fix ftell() usage in examples so they exit with an error on files which
642 are too large (a limitation of the examples, not miniz itself).
643 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple
644 minor level_and_flags issues in the archive API's.
645 level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce
646 Dawson <bruced@valvesoftware.com> for the feedback/bug report.
647 5/28/11 v1.11 - Added statement from unlicense.org
648 5/27/11 v1.10 - Substantial compressor optimizations:
649 - Level 1 is now ~4x faster than before. The L1 compressor's throughput
650 now varies between 70-110MB/sec. on a
651 - Core i7 (actual throughput varies depending on the type of data, and x64
652 vs. x86).
653 - Improved baseline L2-L9 compression perf. Also, greatly improved
654 compression perf. issues on some file types.
655 - Refactored the compression code for better readability and
656 maintainability.
657 - Added level 10 compression level (L10 has slightly better ratio than
658 level 9, but could have a potentially large
659 drop in throughput on some files).
660 5/15/11 v1.09 - Initial stable release.
661
662 * Low-level Deflate/Inflate implementation notes:
663
664 Compression: Use the "tdefl" API's. The compressor supports raw, static,
665 and dynamic blocks, lazy or
666 greedy parsing, match length filtering, RLE-only, and Huffman-only streams.
667 It performs and compresses
668 approximately as well as zlib.
669
670 Decompression: Use the "tinfl" API's. The entire decompressor is
671 implemented as a single function
672 coroutine: see tinfl_decompress(). It supports decompression into a 32KB
673 (or larger power of 2) wrapping buffer, or into a memory
674 block large enough to hold the entire file.
675
676 The low-level tdefl/tinfl API's do not make any use of dynamic memory
677 allocation.
678
679 * zlib-style API notes:
680
681 miniz.c implements a fairly large subset of zlib. There's enough
682 functionality present for it to be a drop-in
683 zlib replacement in many apps:
684 The z_stream struct, optional memory allocation callbacks
685 deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
686 inflateInit/inflateInit2/inflate/inflateEnd
687 compress, compress2, compressBound, uncompress
688 CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly
689 routines.
690 Supports raw deflate streams or standard zlib streams with adler-32
691 checking.
692
693 Limitations:
694 The callback API's are not implemented yet. No support for gzip headers or
695 zlib static dictionaries.
696 I've tried to closely emulate zlib's various flavors of stream flushing
697 and return status codes, but
698 there are no guarantees that miniz.c pulls this off perfectly.
699
700 * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function,
701 originally written by
702 Alex Evans. Supports 1-4 bytes/pixel images.
703
704 * ZIP archive API notes:
705
706 The ZIP archive API's where designed with simplicity and efficiency in
707 mind, with just enough abstraction to
708 get the job done with minimal fuss. There are simple API's to retrieve file
709 information, read files from
710 existing archives, create new archives, append new files to existing
711 archives, or clone archive data from
712 one archive to another. It supports archives located in memory or the heap,
713 on disk (using stdio.h),
714 or you can specify custom file read/write callbacks.
715
716 - Archive reading: Just call this function to read a single file from a
717 disk archive:
718
719 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const
720 char *pArchive_name,
721 size_t *pSize, mz_uint zip_flags);
722
723 For more complex cases, use the "mz_zip_reader" functions. Upon opening an
724 archive, the entire central
725 directory is located and read as-is into memory, and subsequent file access
726 only occurs when reading individual files.
727
728 - Archives file scanning: The simple way is to use this function to scan a
729 loaded archive for a specific file:
730
731 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
732 const char *pComment, mz_uint flags);
733
734 The locate operation can optionally check file comments too, which (as one
735 example) can be used to identify
736 multiple versions of the same file in an archive. This function uses a
737 simple linear search through the central
738 directory, so it's not very fast.
739
740 Alternately, you can iterate through all the files in an archive (using
741 mz_zip_reader_get_num_files()) and
742 retrieve detailed info on each file by calling mz_zip_reader_file_stat().
743
744 - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer
745 immediately writes compressed file data
746 to disk and builds an exact image of the central directory in memory. The
747 central directory image is written
748 all at once at the end of the archive file when the archive is finalized.
749
750 The archive writer can optionally align each file's local header and file
751 data to any power of 2 alignment,
752 which can be useful when the archive will be read from optical media. Also,
753 the writer supports placing
754 arbitrary data blobs at the very beginning of ZIP archives. Archives
755 written using either feature are still
756 readable by any ZIP tool.
757
758 - Archive appending: The simple way to add a single file to an archive is
759 to call this function:
760
761 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename,
762 const char *pArchive_name,
763 const void *pBuf, size_t buf_size, const void *pComment, mz_uint16
764 comment_size, mz_uint level_and_flags);
765
766 The archive will be created if it doesn't already exist, otherwise it'll be
767 appended to.
768 Note the appending is done in-place and is not an atomic operation, so if
769 something goes wrong
770 during the operation it's possible the archive could be left without a
771 central directory (although the local
772 file headers and file data will be fine, so the archive will be
773 recoverable).
774
775 For more complex archive modification scenarios:
776 1. The safest way is to use a mz_zip_reader to read the existing archive,
777 cloning only those bits you want to
778 preserve into a new archive using using the
779 mz_zip_writer_add_from_zip_reader() function (which compiles the
780 compressed file data as-is). When you're done, delete the old archive and
781 rename the newly written archive, and
782 you're done. This is safe but requires a bunch of temporary disk space or
783 heap memory.
784
785 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using
786 mz_zip_writer_init_from_reader(),
787 append new files as needed, then finalize the archive which will write an
788 updated central directory to the
789 original archive. (This is basically what
790 mz_zip_add_mem_to_archive_file_in_place() does.) There's a
791 possibility that the archive's central directory could be lost with this
792 method if anything goes wrong, though.
793
794 - ZIP archive support limitations:
795 No zip64 or spanning support. Extraction functions can only handle
796 unencrypted, stored or deflated files.
797 Requires streams capable of seeking.
798
799 * This is a header file library, like stb_image.c. To get only a header file,
800 either cut and paste the
801 below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then
802 include miniz.c from it.
803
804 * Important: For best perf. be sure to customize the below macros for your
805 target platform:
806 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
807 #define MINIZ_LITTLE_ENDIAN 1
808 #define MINIZ_HAS_64BIT_REGISTERS 1
809
810 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before
811 including miniz.c to ensure miniz
812 uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be
813 able to process large files
814 (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).
815 */
816
817 #ifndef MINIZ_HEADER_INCLUDED
818 #define MINIZ_HEADER_INCLUDED
819
820 //#include <stdlib.h>
821
822 // Defines to completely disable specific portions of miniz.c:
823 // If all macros here are defined the only functionality remaining will be
824 // CRC-32, adler-32, tinfl, and tdefl.
825
826 // Define MINIZ_NO_STDIO to disable all usage and any functions which rely on
827 // stdio for file I/O.
828 //#define MINIZ_NO_STDIO
829
830 // If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able
831 // to get the current time, or
832 // get/set file times, and the C run-time funcs that get/set times won't be
833 // called.
834 // The current downside is the times written to your archives will be from 1979.
835 #define MINIZ_NO_TIME
836
837 // Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
838 #define MINIZ_NO_ARCHIVE_APIS
839
840 // Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive
841 // API's.
842 //#define MINIZ_NO_ARCHIVE_WRITING_APIS
843
844 // Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression
845 // API's.
846 //#define MINIZ_NO_ZLIB_APIS
847
848 // Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent
849 // conflicts against stock zlib.
850 //#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
851
852 // Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
853 // Note if MINIZ_NO_MALLOC is defined then the user must always provide custom
854 // user alloc/free/realloc
855 // callbacks to the zlib and archive API's, and a few stand-alone helper API's
856 // which don't provide custom user
857 // functions (such as tdefl_compress_mem_to_heap() and
858 // tinfl_decompress_mem_to_heap()) won't work.
859 //#define MINIZ_NO_MALLOC
860
861 #if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
862 // TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc
863 // on Linux
864 #define MINIZ_NO_TIME
865 #endif
866
867 #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
868 //#include <time.h>
869 #endif
870
871 #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
872 defined(__i386) || defined(__i486__) || defined(__i486) || \
873 defined(i386) || defined(__ia64__) || defined(__x86_64__)
874 // MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
875 #define MINIZ_X86_OR_X64_CPU 1
876 #endif
877
878 #if defined(__sparcv9)
879 // Big endian
880 #else
881 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
882 // Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
883 #define MINIZ_LITTLE_ENDIAN 1
884 #endif
885 #endif
886
887 #if MINIZ_X86_OR_X64_CPU
888 // Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
889 // integer loads and stores from unaligned addresses.
890 //#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
891 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES \
892 0 // disable to suppress compiler warnings
893 #endif
894
895 #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \
896 defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \
897 defined(__x86_64__)
898 // Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are
899 // reasonably fast (and don't involve compiler generated calls to helper
900 // functions).
901 #define MINIZ_HAS_64BIT_REGISTERS 1
902 #endif
903
904 #ifdef __cplusplus
905 extern "C" {
906 #endif
907
908 // ------------------- zlib-style API Definitions.
909
910 // For more compatibility with zlib, miniz.c uses unsigned long for some
911 // parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits!
912 typedef unsigned long mz_ulong;
913
914 // mz_free() internally uses the MZ_FREE() macro (which by default calls free()
915 // unless you've modified the MZ_MALLOC macro) to release a block allocated from
916 // the heap.
917 void mz_free(void *p);
918
919 #define MZ_ADLER32_INIT (1)
920 // mz_adler32() returns the initial adler-32 value to use when called with
921 // ptr==NULL.
922 mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
923
924 #define MZ_CRC32_INIT (0)
925 // mz_crc32() returns the initial CRC-32 value to use when called with
926 // ptr==NULL.
927 mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
928
929 // Compression strategies.
930 enum {
931 MZ_DEFAULT_STRATEGY = 0,
932 MZ_FILTERED = 1,
933 MZ_HUFFMAN_ONLY = 2,
934 MZ_RLE = 3,
935 MZ_FIXED = 4
936 };
937
938 // Method
939 #define MZ_DEFLATED 8
940
941 #ifndef MINIZ_NO_ZLIB_APIS
942
943 // Heap allocation callbacks.
944 // Note that mz_alloc_func parameter types purpsosely differ from zlib's:
945 // items/size is size_t, not unsigned long.
946 typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
947 typedef void (*mz_free_func)(void *opaque, void *address);
948 typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items,
949 size_t size);
950
951 #define MZ_VERSION "9.1.15"
952 #define MZ_VERNUM 0x91F0
953 #define MZ_VER_MAJOR 9
954 #define MZ_VER_MINOR 1
955 #define MZ_VER_REVISION 15
956 #define MZ_VER_SUBREVISION 0
957
958 // Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The
959 // other values are for advanced use (refer to the zlib docs).
960 enum {
961 MZ_NO_FLUSH = 0,
962 MZ_PARTIAL_FLUSH = 1,
963 MZ_SYNC_FLUSH = 2,
964 MZ_FULL_FLUSH = 3,
965 MZ_FINISH = 4,
966 MZ_BLOCK = 5
967 };
968
969 // Return status codes. MZ_PARAM_ERROR is non-standard.
970 enum {
971 MZ_OK = 0,
972 MZ_STREAM_END = 1,
973 MZ_NEED_DICT = 2,
974 MZ_ERRNO = -1,
975 MZ_STREAM_ERROR = -2,
976 MZ_DATA_ERROR = -3,
977 MZ_MEM_ERROR = -4,
978 MZ_BUF_ERROR = -5,
979 MZ_VERSION_ERROR = -6,
980 MZ_PARAM_ERROR = -10000
981 };
982
983 // Compression levels: 0-9 are the standard zlib-style levels, 10 is best
984 // possible compression (not zlib compatible, and may be very slow),
985 // MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
986 enum {
987 MZ_NO_COMPRESSION = 0,
988 MZ_BEST_SPEED = 1,
989 MZ_BEST_COMPRESSION = 9,
990 MZ_UBER_COMPRESSION = 10,
991 MZ_DEFAULT_LEVEL = 6,
992 MZ_DEFAULT_COMPRESSION = -1
993 };
994
995 // Window bits
996 #define MZ_DEFAULT_WINDOW_BITS 15
997
998 struct mz_internal_state;
999
1000 // Compression/decompression stream struct.
1001 typedef struct mz_stream_s {
1002 const unsigned char *next_in; // pointer to next byte to read
1003 unsigned int avail_in; // number of bytes available at next_in
1004 mz_ulong total_in; // total number of bytes consumed so far
1005
1006 unsigned char *next_out; // pointer to next byte to write
1007 unsigned int avail_out; // number of bytes that can be written to next_out
1008 mz_ulong total_out; // total number of bytes produced so far
1009
1010 char *msg; // error msg (unused)
1011 struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
1012
1013 mz_alloc_func
1014 zalloc; // optional heap allocation function (defaults to malloc)
1015 mz_free_func zfree; // optional heap free function (defaults to free)
1016 void *opaque; // heap alloc function user pointer
1017
1018 int data_type; // data_type (unused)
1019 mz_ulong adler; // adler32 of the source or uncompressed data
1020 mz_ulong reserved; // not used
1021 } mz_stream;
1022
1023 typedef mz_stream *mz_streamp;
1024
1025 // Returns the version string of miniz.c.
1026 const char *mz_version(void);
1027
1028 // mz_deflateInit() initializes a compressor with default options:
1029 // Parameters:
1030 // pStream must point to an initialized mz_stream struct.
1031 // level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
1032 // level 1 enables a specially optimized compression function that's been
1033 // optimized purely for performance, not ratio.
1034 // (This special func. is currently only enabled when
1035 // MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.)
1036 // Return values:
1037 // MZ_OK on success.
1038 // MZ_STREAM_ERROR if the stream is bogus.
1039 // MZ_PARAM_ERROR if the input parameters are bogus.
1040 // MZ_MEM_ERROR on out of memory.
1041 int mz_deflateInit(mz_streamp pStream, int level);
1042
1043 // mz_deflateInit2() is like mz_deflate(), except with more control:
1044 // Additional parameters:
1045 // method must be MZ_DEFLATED
1046 // window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with
1047 // zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no
1048 // header or footer)
1049 // mem_level must be between [1, 9] (it's checked but ignored by miniz.c)
1050 int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
1051 int mem_level, int strategy);
1052
1053 // Quickly resets a compressor without having to reallocate anything. Same as
1054 // calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2().
1055 int mz_deflateReset(mz_streamp pStream);
1056
1057 // mz_deflate() compresses the input to output, consuming as much of the input
1058 // and producing as much output as possible.
1059 // Parameters:
1060 // pStream is the stream to read from and write to. You must initialize/update
1061 // the next_in, avail_in, next_out, and avail_out members.
1062 // flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or
1063 // MZ_FINISH.
1064 // Return values:
1065 // MZ_OK on success (when flushing, or if more input is needed but not
1066 // available, and/or there's more output to be written but the output buffer
1067 // is full).
1068 // MZ_STREAM_END if all input has been consumed and all output bytes have been
1069 // written. Don't call mz_deflate() on the stream anymore.
1070 // MZ_STREAM_ERROR if the stream is bogus.
1071 // MZ_PARAM_ERROR if one of the parameters is invalid.
1072 // MZ_BUF_ERROR if no forward progress is possible because the input and/or
1073 // output buffers are empty. (Fill up the input buffer or free up some output
1074 // space and try again.)
1075 int mz_deflate(mz_streamp pStream, int flush);
1076
1077 // mz_deflateEnd() deinitializes a compressor:
1078 // Return values:
1079 // MZ_OK on success.
1080 // MZ_STREAM_ERROR if the stream is bogus.
1081 int mz_deflateEnd(mz_streamp pStream);
1082
1083 // mz_deflateBound() returns a (very) conservative upper bound on the amount of
1084 // data that could be generated by deflate(), assuming flush is set to only
1085 // MZ_NO_FLUSH or MZ_FINISH.
1086 mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
1087
1088 // Single-call compression functions mz_compress() and mz_compress2():
1089 // Returns MZ_OK on success, or one of the error codes from mz_deflate() on
1090 // failure.
1091 int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
1092 const unsigned char *pSource, mz_ulong source_len);
1093 int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
1094 const unsigned char *pSource, mz_ulong source_len, int level);
1095
1096 // mz_compressBound() returns a (very) conservative upper bound on the amount of
1097 // data that could be generated by calling mz_compress().
1098 mz_ulong mz_compressBound(mz_ulong source_len);
1099
1100 // Initializes a decompressor.
1101 int mz_inflateInit(mz_streamp pStream);
1102
1103 // mz_inflateInit2() is like mz_inflateInit() with an additional option that
1104 // controls the window size and whether or not the stream has been wrapped with
1105 // a zlib header/footer:
1106 // window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or
1107 // -MZ_DEFAULT_WINDOW_BITS (raw deflate).
1108 int mz_inflateInit2(mz_streamp pStream, int window_bits);
1109
1110 // Decompresses the input stream to the output, consuming only as much of the
1111 // input as needed, and writing as much to the output as possible.
1112 // Parameters:
1113 // pStream is the stream to read from and write to. You must initialize/update
1114 // the next_in, avail_in, next_out, and avail_out members.
1115 // flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH.
1116 // On the first call, if flush is MZ_FINISH it's assumed the input and output
1117 // buffers are both sized large enough to decompress the entire stream in a
1118 // single call (this is slightly faster).
1119 // MZ_FINISH implies that there are no more source bytes available beside
1120 // what's already in the input buffer, and that the output buffer is large
1121 // enough to hold the rest of the decompressed data.
1122 // Return values:
1123 // MZ_OK on success. Either more input is needed but not available, and/or
1124 // there's more output to be written but the output buffer is full.
1125 // MZ_STREAM_END if all needed input has been consumed and all output bytes
1126 // have been written. For zlib streams, the adler-32 of the decompressed data
1127 // has also been verified.
1128 // MZ_STREAM_ERROR if the stream is bogus.
1129 // MZ_DATA_ERROR if the deflate stream is invalid.
1130 // MZ_PARAM_ERROR if one of the parameters is invalid.
1131 // MZ_BUF_ERROR if no forward progress is possible because the input buffer is
1132 // empty but the inflater needs more input to continue, or if the output
1133 // buffer is not large enough. Call mz_inflate() again
1134 // with more input data, or with more room in the output buffer (except when
1135 // using single call decompression, described above).
1136 int mz_inflate(mz_streamp pStream, int flush);
1137
1138 // Deinitializes a decompressor.
1139 int mz_inflateEnd(mz_streamp pStream);
1140
1141 // Single-call decompression.
1142 // Returns MZ_OK on success, or one of the error codes from mz_inflate() on
1143 // failure.
1144 int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
1145 const unsigned char *pSource, mz_ulong source_len);
1146
1147 // Returns a string description of the specified error code, or NULL if the
1148 // error code is invalid.
1149 const char *mz_error(int err);
1150
1151 // Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used
1152 // as a drop-in replacement for the subset of zlib that miniz.c supports.
1153 // Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you
1154 // use zlib in the same project.
1155 #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
1156 typedef unsigned char Byte;
1157 typedef unsigned int uInt;
1158 typedef mz_ulong uLong;
1159 typedef Byte Bytef;
1160 typedef uInt uIntf;
1161 typedef char charf;
1162 typedef int intf;
1163 typedef void *voidpf;
1164 typedef uLong uLongf;
1165 typedef void *voidp;
1166 typedef void *const voidpc;
1167 #define Z_NULL 0
1168 #define Z_NO_FLUSH MZ_NO_FLUSH
1169 #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
1170 #define Z_SYNC_FLUSH MZ_SYNC_FLUSH
1171 #define Z_FULL_FLUSH MZ_FULL_FLUSH
1172 #define Z_FINISH MZ_FINISH
1173 #define Z_BLOCK MZ_BLOCK
1174 #define Z_OK MZ_OK
1175 #define Z_STREAM_END MZ_STREAM_END
1176 #define Z_NEED_DICT MZ_NEED_DICT
1177 #define Z_ERRNO MZ_ERRNO
1178 #define Z_STREAM_ERROR MZ_STREAM_ERROR
1179 #define Z_DATA_ERROR MZ_DATA_ERROR
1180 #define Z_MEM_ERROR MZ_MEM_ERROR
1181 #define Z_BUF_ERROR MZ_BUF_ERROR
1182 #define Z_VERSION_ERROR MZ_VERSION_ERROR
1183 #define Z_PARAM_ERROR MZ_PARAM_ERROR
1184 #define Z_NO_COMPRESSION MZ_NO_COMPRESSION
1185 #define Z_BEST_SPEED MZ_BEST_SPEED
1186 #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
1187 #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
1188 #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
1189 #define Z_FILTERED MZ_FILTERED
1190 #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
1191 #define Z_RLE MZ_RLE
1192 #define Z_FIXED MZ_FIXED
1193 #define Z_DEFLATED MZ_DEFLATED
1194 #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
1195 #define alloc_func mz_alloc_func
1196 #define free_func mz_free_func
1197 #define internal_state mz_internal_state
1198 #define z_stream mz_stream
1199 #define deflateInit mz_deflateInit
1200 #define deflateInit2 mz_deflateInit2
1201 #define deflateReset mz_deflateReset
1202 #define deflate mz_deflate
1203 #define deflateEnd mz_deflateEnd
1204 #define deflateBound mz_deflateBound
1205 #define compress mz_compress
1206 #define compress2 mz_compress2
1207 #define compressBound mz_compressBound
1208 #define inflateInit mz_inflateInit
1209 #define inflateInit2 mz_inflateInit2
1210 #define inflate mz_inflate
1211 #define inflateEnd mz_inflateEnd
1212 #define uncompress mz_uncompress
1213 #define crc32 mz_crc32
1214 #define adler32 mz_adler32
1215 #define MAX_WBITS 15
1216 #define MAX_MEM_LEVEL 9
1217 #define zError mz_error
1218 #define ZLIB_VERSION MZ_VERSION
1219 #define ZLIB_VERNUM MZ_VERNUM
1220 #define ZLIB_VER_MAJOR MZ_VER_MAJOR
1221 #define ZLIB_VER_MINOR MZ_VER_MINOR
1222 #define ZLIB_VER_REVISION MZ_VER_REVISION
1223 #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
1224 #define zlibVersion mz_version
1225 #define zlib_version mz_version()
1226 #endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
1227
1228 #endif // MINIZ_NO_ZLIB_APIS
1229
1230 // ------------------- Types and macros
1231
1232 typedef unsigned char mz_uint8;
1233 typedef signed short mz_int16;
1234 typedef unsigned short mz_uint16;
1235 typedef unsigned int mz_uint32;
1236 typedef unsigned int mz_uint;
1237 typedef long long mz_int64;
1238 typedef unsigned long long mz_uint64;
1239 typedef int mz_bool;
1240
1241 #define MZ_FALSE (0)
1242 #define MZ_TRUE (1)
1243
1244 // An attempt to work around MSVC's spammy "warning C4127: conditional
1245 // expression is constant" message.
1246 #ifdef _MSC_VER
1247 #define MZ_MACRO_END while (0, 0)
1248 #else
1249 #define MZ_MACRO_END while (0)
1250 #endif
1251
1252 // ------------------- ZIP archive reading/writing
1253
1254 #ifndef MINIZ_NO_ARCHIVE_APIS
1255
1256 enum {
1257 MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
1258 MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
1259 MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
1260 };
1261
1262 typedef struct {
1263 mz_uint32 m_file_index;
1264 mz_uint32 m_central_dir_ofs;
1265 mz_uint16 m_version_made_by;
1266 mz_uint16 m_version_needed;
1267 mz_uint16 m_bit_flag;
1268 mz_uint16 m_method;
1269 #ifndef MINIZ_NO_TIME
1270 time_t m_time;
1271 #endif
1272 mz_uint32 m_crc32;
1273 mz_uint64 m_comp_size;
1274 mz_uint64 m_uncomp_size;
1275 mz_uint16 m_internal_attr;
1276 mz_uint32 m_external_attr;
1277 mz_uint64 m_local_header_ofs;
1278 mz_uint32 m_comment_size;
1279 char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
1280 char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
1281 } mz_zip_archive_file_stat;
1282
1283 typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
1284 void *pBuf, size_t n);
1285 typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
1286 const void *pBuf, size_t n);
1287
1288 struct mz_zip_internal_state_tag;
1289 typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
1290
1291 typedef enum {
1292 MZ_ZIP_MODE_INVALID = 0,
1293 MZ_ZIP_MODE_READING = 1,
1294 MZ_ZIP_MODE_WRITING = 2,
1295 MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
1296 } mz_zip_mode;
1297
1298 typedef struct mz_zip_archive_tag {
1299 mz_uint64 m_archive_size;
1300 mz_uint64 m_central_directory_file_ofs;
1301 mz_uint m_total_files;
1302 mz_zip_mode m_zip_mode;
1303
1304 mz_uint m_file_offset_alignment;
1305
1306 mz_alloc_func m_pAlloc;
1307 mz_free_func m_pFree;
1308 mz_realloc_func m_pRealloc;
1309 void *m_pAlloc_opaque;
1310
1311 mz_file_read_func m_pRead;
1312 mz_file_write_func m_pWrite;
1313 void *m_pIO_opaque;
1314
1315 mz_zip_internal_state *m_pState;
1316
1317 } mz_zip_archive;
1318
1319 typedef enum {
1320 MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
1321 MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
1322 MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
1323 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
1324 } mz_zip_flags;
1325
1326 // ZIP archive reading
1327
1328 // Inits a ZIP archive reader.
1329 // These functions read and validate the archive's central directory.
1330 mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
1331 mz_uint32 flags);
1332 mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
1333 size_t size, mz_uint32 flags);
1334
1335 #ifndef MINIZ_NO_STDIO
1336 mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
1337 mz_uint32 flags);
1338 #endif
1339
1340 // Returns the total number of files in the archive.
1341 mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
1342
1343 // Returns detailed information about an archive file entry.
1344 mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
1345 mz_zip_archive_file_stat *pStat);
1346
1347 // Determines if an archive file entry is a directory entry.
1348 mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
1349 mz_uint file_index);
1350 mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
1351 mz_uint file_index);
1352
1353 // Retrieves the filename of an archive file entry.
1354 // Returns the number of bytes written to pFilename, or if filename_buf_size is
1355 // 0 this function returns the number of bytes needed to fully store the
1356 // filename.
1357 mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
1358 char *pFilename, mz_uint filename_buf_size);
1359
1360 // Attempts to locates a file in the archive's central directory.
1361 // Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
1362 // Returns -1 if the file cannot be found.
1363 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
1364 const char *pComment, mz_uint flags);
1365
1366 // Extracts a archive file to a memory buffer using no memory allocation.
1367 mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
1368 mz_uint file_index, void *pBuf,
1369 size_t buf_size, mz_uint flags,
1370 void *pUser_read_buf,
1371 size_t user_read_buf_size);
1372 mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
1373 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
1374 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
1375
1376 // Extracts a archive file to a memory buffer.
1377 mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
1378 void *pBuf, size_t buf_size,
1379 mz_uint flags);
1380 mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
1381 const char *pFilename, void *pBuf,
1382 size_t buf_size, mz_uint flags);
1383
1384 // Extracts a archive file to a dynamically allocated heap buffer.
1385 void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
1386 size_t *pSize, mz_uint flags);
1387 void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
1388 const char *pFilename, size_t *pSize,
1389 mz_uint flags);
1390
1391 // Extracts a archive file using a callback function to output the file's data.
1392 mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
1393 mz_uint file_index,
1394 mz_file_write_func pCallback,
1395 void *pOpaque, mz_uint flags);
1396 mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
1397 const char *pFilename,
1398 mz_file_write_func pCallback,
1399 void *pOpaque, mz_uint flags);
1400
1401 #ifndef MINIZ_NO_STDIO
1402 // Extracts a archive file to a disk file and sets its last accessed and
1403 // modified times.
1404 // This function only extracts files, not archive directory records.
1405 mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
1406 const char *pDst_filename, mz_uint flags);
1407 mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
1408 const char *pArchive_filename,
1409 const char *pDst_filename,
1410 mz_uint flags);
1411 #endif
1412
1413 // Ends archive reading, freeing all allocations, and closing the input archive
1414 // file if mz_zip_reader_init_file() was used.
1415 mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
1416
1417 // ZIP archive writing
1418
1419 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
1420
1421 // Inits a ZIP archive writer.
1422 mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
1423 mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
1424 size_t size_to_reserve_at_beginning,
1425 size_t initial_allocation_size);
1426
1427 #ifndef MINIZ_NO_STDIO
1428 mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
1429 mz_uint64 size_to_reserve_at_beginning);
1430 #endif
1431
1432 // Converts a ZIP archive reader object into a writer object, to allow efficient
1433 // in-place file appends to occur on an existing archive.
1434 // For archives opened using mz_zip_reader_init_file, pFilename must be the
1435 // archive's filename so it can be reopened for writing. If the file can't be
1436 // reopened, mz_zip_reader_end() will be called.
1437 // For archives opened using mz_zip_reader_init_mem, the memory block must be
1438 // growable using the realloc callback (which defaults to realloc unless you've
1439 // overridden it).
1440 // Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's
1441 // user provided m_pWrite function cannot be NULL.
1442 // Note: In-place archive modification is not recommended unless you know what
1443 // you're doing, because if execution stops or something goes wrong before
1444 // the archive is finalized the file's central directory will be hosed.
1445 mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
1446 const char *pFilename);
1447
1448 // Adds the contents of a memory buffer to an archive. These functions record
1449 // the current local time into the archive.
1450 // To add a directory entry, call this method with an archive name ending in a
1451 // forwardslash with empty buffer.
1452 // level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1453 // MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1454 // just set to MZ_DEFAULT_COMPRESSION.
1455 mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
1456 const void *pBuf, size_t buf_size,
1457 mz_uint level_and_flags);
1458 mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
1459 const char *pArchive_name, const void *pBuf,
1460 size_t buf_size, const void *pComment,
1461 mz_uint16 comment_size,
1462 mz_uint level_and_flags, mz_uint64 uncomp_size,
1463 mz_uint32 uncomp_crc32);
1464
1465 #ifndef MINIZ_NO_STDIO
1466 // Adds the contents of a disk file to an archive. This function also records
1467 // the disk file's modified time into the archive.
1468 // level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1469 // MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1470 // just set to MZ_DEFAULT_COMPRESSION.
1471 mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
1472 const char *pSrc_filename, const void *pComment,
1473 mz_uint16 comment_size, mz_uint level_and_flags);
1474 #endif
1475
1476 // Adds a file to an archive by fully cloning the data from another archive.
1477 // This function fully clones the source file's compressed data (no
1478 // recompression), along with its full filename, extra data, and comment fields.
1479 mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
1480 mz_zip_archive *pSource_zip,
1481 mz_uint file_index);
1482
1483 // Finalizes the archive by writing the central directory records followed by
1484 // the end of central directory record.
1485 // After an archive is finalized, the only valid call on the mz_zip_archive
1486 // struct is mz_zip_writer_end().
1487 // An archive must be manually finalized by calling this function for it to be
1488 // valid.
1489 mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
1490 mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
1491 size_t *pSize);
1492
1493 // Ends archive writing, freeing all allocations, and closing the output file if
1494 // mz_zip_writer_init_file() was used.
1495 // Note for the archive to be valid, it must have been finalized before ending.
1496 mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
1497
1498 // Misc. high-level helper functions:
1499
1500 // mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically)
1501 // appends a memory blob to a ZIP archive.
1502 // level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1503 // MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1504 // just set to MZ_DEFAULT_COMPRESSION.
1505 mz_bool mz_zip_add_mem_to_archive_file_in_place(
1506 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
1507 size_t buf_size, const void *pComment, mz_uint16 comment_size,
1508 mz_uint level_and_flags);
1509
1510 // Reads a single file from an archive into a heap block.
1511 // Returns NULL on failure.
1512 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
1513 const char *pArchive_name,
1514 size_t *pSize, mz_uint zip_flags);
1515
1516 #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
1517
1518 #endif // #ifndef MINIZ_NO_ARCHIVE_APIS
1519
1520 // ------------------- Low-level Decompression API Definitions
1521
1522 // Decompression flags used by tinfl_decompress().
1523 // TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and
1524 // ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the
1525 // input is a raw deflate stream.
1526 // TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available
1527 // beyond the end of the supplied input buffer. If clear, the input buffer
1528 // contains all remaining input.
1529 // TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large
1530 // enough to hold the entire decompressed stream. If clear, the output buffer is
1531 // at least the size of the dictionary (typically 32KB).
1532 // TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the
1533 // decompressed bytes.
1534 enum {
1535 TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
1536 TINFL_FLAG_HAS_MORE_INPUT = 2,
1537 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
1538 TINFL_FLAG_COMPUTE_ADLER32 = 8
1539 };
1540
1541 // High level decompression functions:
1542 // tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block
1543 // allocated via malloc().
1544 // On entry:
1545 // pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data
1546 // to decompress.
1547 // On return:
1548 // Function returns a pointer to the decompressed data, or NULL on failure.
1549 // *pOut_len will be set to the decompressed data's size, which could be larger
1550 // than src_buf_len on uncompressible data.
1551 // The caller must call mz_free() on the returned block when it's no longer
1552 // needed.
1553 void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
1554 size_t *pOut_len, int flags);
1555
1556 // tinfl_decompress_mem_to_mem() decompresses a block in memory to another block
1557 // in memory.
1558 // Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes
1559 // written on success.
1560 #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
1561 size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
1562 const void *pSrc_buf, size_t src_buf_len,
1563 int flags);
1564
1565 // tinfl_decompress_mem_to_callback() decompresses a block in memory to an
1566 // internal 32KB buffer, and a user provided callback function will be called to
1567 // flush the buffer.
1568 // Returns 1 on success or 0 on failure.
1569 typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);
1570 int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
1571 tinfl_put_buf_func_ptr pPut_buf_func,
1572 void *pPut_buf_user, int flags);
1573
1574 struct tinfl_decompressor_tag;
1575 typedef struct tinfl_decompressor_tag tinfl_decompressor;
1576
1577 // Max size of LZ dictionary.
1578 #define TINFL_LZ_DICT_SIZE 32768
1579
1580 // Return status.
1581 typedef enum {
1582 TINFL_STATUS_BAD_PARAM = -3,
1583 TINFL_STATUS_ADLER32_MISMATCH = -2,
1584 TINFL_STATUS_FAILED = -1,
1585 TINFL_STATUS_DONE = 0,
1586 TINFL_STATUS_NEEDS_MORE_INPUT = 1,
1587 TINFL_STATUS_HAS_MORE_OUTPUT = 2
1588 } tinfl_status;
1589
1590 // Initializes the decompressor to its initial state.
1591 #define tinfl_init(r) \
1592 do { \
1593 (r)->m_state = 0; \
1594 } \
1595 MZ_MACRO_END
1596 #define tinfl_get_adler32(r) (r)->m_check_adler32
1597
1598 // Main low-level decompressor coroutine function. This is the only function
1599 // actually needed for decompression. All the other functions are just
1600 // high-level helpers for improved usability.
1601 // This is a universal API, i.e. it can be used as a building block to build any
1602 // desired higher level decompression API. In the limit case, it can be called
1603 // once per every byte input or output.
1604 tinfl_status tinfl_decompress(tinfl_decompressor *r,
1605 const mz_uint8 *pIn_buf_next,
1606 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
1607 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
1608 const mz_uint32 decomp_flags);
1609
1610 // Internal/private bits follow.
1611 enum {
1612 TINFL_MAX_HUFF_TABLES = 3,
1613 TINFL_MAX_HUFF_SYMBOLS_0 = 288,
1614 TINFL_MAX_HUFF_SYMBOLS_1 = 32,
1615 TINFL_MAX_HUFF_SYMBOLS_2 = 19,
1616 TINFL_FAST_LOOKUP_BITS = 10,
1617 TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
1618 };
1619
1620 typedef struct {
1621 mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
1622 mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE],
1623 m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
1624 } tinfl_huff_table;
1625
1626 #if MINIZ_HAS_64BIT_REGISTERS
1627 #define TINFL_USE_64BIT_BITBUF 1
1628 #endif
1629
1630 #if TINFL_USE_64BIT_BITBUF
1631 typedef mz_uint64 tinfl_bit_buf_t;
1632 #define TINFL_BITBUF_SIZE (64)
1633 #else
1634 typedef mz_uint32 tinfl_bit_buf_t;
1635 #define TINFL_BITBUF_SIZE (32)
1636 #endif
1637
1638 struct tinfl_decompressor_tag {
1639 mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type,
1640 m_check_adler32, m_dist, m_counter, m_num_extra,
1641 m_table_sizes[TINFL_MAX_HUFF_TABLES];
1642 tinfl_bit_buf_t m_bit_buf;
1643 size_t m_dist_from_out_buf_start;
1644 tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
1645 mz_uint8 m_raw_header[4],
1646 m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
1647 };
1648
1649 // ------------------- Low-level Compression API Definitions
1650
1651 // Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly
1652 // slower, and raw/dynamic blocks will be output more frequently).
1653 #define TDEFL_LESS_MEMORY 0
1654
1655 // tdefl_init() compression flags logically OR'd together (low 12 bits contain
1656 // the max. number of probes per dictionary search):
1657 // TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes
1658 // per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap
1659 // compression), 4095=Huffman+LZ (slowest/best compression).
1660 enum {
1661 TDEFL_HUFFMAN_ONLY = 0,
1662 TDEFL_DEFAULT_MAX_PROBES = 128,
1663 TDEFL_MAX_PROBES_MASK = 0xFFF
1664 };
1665
1666 // TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before
1667 // the deflate data, and the Adler-32 of the source data at the end. Otherwise,
1668 // you'll get raw deflate data.
1669 // TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even
1670 // when not writing zlib headers).
1671 // TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more
1672 // efficient lazy parsing.
1673 // TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's
1674 // initialization time to the minimum, but the output may vary from run to run
1675 // given the same input (depending on the contents of memory).
1676 // TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
1677 // TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
1678 // TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
1679 // TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
1680 // The low 12 bits are reserved to control the max # of hash probes per
1681 // dictionary lookup (see TDEFL_MAX_PROBES_MASK).
1682 enum {
1683 TDEFL_WRITE_ZLIB_HEADER = 0x01000,
1684 TDEFL_COMPUTE_ADLER32 = 0x02000,
1685 TDEFL_GREEDY_PARSING_FLAG = 0x04000,
1686 TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
1687 TDEFL_RLE_MATCHES = 0x10000,
1688 TDEFL_FILTER_MATCHES = 0x20000,
1689 TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
1690 TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
1691 };
1692
1693 // High level compression functions:
1694 // tdefl_compress_mem_to_heap() compresses a block in memory to a heap block
1695 // allocated via malloc().
1696 // On entry:
1697 // pSrc_buf, src_buf_len: Pointer and size of source block to compress.
1698 // flags: The max match finder probes (default is 128) logically OR'd against
1699 // the above flags. Higher probes are slower but improve compression.
1700 // On return:
1701 // Function returns a pointer to the compressed data, or NULL on failure.
1702 // *pOut_len will be set to the compressed data's size, which could be larger
1703 // than src_buf_len on uncompressible data.
1704 // The caller must free() the returned block when it's no longer needed.
1705 void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
1706 size_t *pOut_len, int flags);
1707
1708 // tdefl_compress_mem_to_mem() compresses a block in memory to another block in
1709 // memory.
1710 // Returns 0 on failure.
1711 size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
1712 const void *pSrc_buf, size_t src_buf_len,
1713 int flags);
1714
1715 // Compresses an image to a compressed PNG file in memory.
1716 // On entry:
1717 // pImage, w, h, and num_chans describe the image to compress. num_chans may be
1718 // 1, 2, 3, or 4.
1719 // The image pitch in bytes per scanline will be w*num_chans. The leftmost
1720 // pixel on the top scanline is stored first in memory.
1721 // level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED,
1722 // MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL
1723 // If flip is true, the image will be flipped on the Y axis (useful for OpenGL
1724 // apps).
1725 // On return:
1726 // Function returns a pointer to the compressed data, or NULL on failure.
1727 // *pLen_out will be set to the size of the PNG image file.
1728 // The caller must mz_free() the returned heap block (which will typically be
1729 // larger than *pLen_out) when it's no longer needed.
1730 void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
1731 int h, int num_chans,
1732 size_t *pLen_out,
1733 mz_uint level, mz_bool flip);
1734 void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
1735 int num_chans, size_t *pLen_out);
1736
1737 // Output stream interface. The compressor uses this interface to write
1738 // compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
1739 typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len,
1740 void *pUser);
1741
1742 // tdefl_compress_mem_to_output() compresses a block to an output stream. The
1743 // above helpers use this function internally.
1744 mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
1745 tdefl_put_buf_func_ptr pPut_buf_func,
1746 void *pPut_buf_user, int flags);
1747
1748 enum {
1749 TDEFL_MAX_HUFF_TABLES = 3,
1750 TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
1751 TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
1752 TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
1753 TDEFL_LZ_DICT_SIZE = 32768,
1754 TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
1755 TDEFL_MIN_MATCH_LEN = 3,
1756 TDEFL_MAX_MATCH_LEN = 258
1757 };
1758
1759 // TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed
1760 // output block (using static/fixed Huffman codes).
1761 #if TDEFL_LESS_MEMORY
1762 enum {
1763 TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,
1764 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
1765 TDEFL_MAX_HUFF_SYMBOLS = 288,
1766 TDEFL_LZ_HASH_BITS = 12,
1767 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
1768 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
1769 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
1770 };
1771 #else
1772 enum {
1773 TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
1774 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
1775 TDEFL_MAX_HUFF_SYMBOLS = 288,
1776 TDEFL_LZ_HASH_BITS = 15,
1777 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
1778 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
1779 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
1780 };
1781 #endif
1782
1783 // The low-level tdefl functions below may be used directly if the above helper
1784 // functions aren't flexible enough. The low-level functions don't make any heap
1785 // allocations, unlike the above helper functions.
1786 typedef enum {
1787 TDEFL_STATUS_BAD_PARAM = -2,
1788 TDEFL_STATUS_PUT_BUF_FAILED = -1,
1789 TDEFL_STATUS_OKAY = 0,
1790 TDEFL_STATUS_DONE = 1
1791 } tdefl_status;
1792
1793 // Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
1794 typedef enum {
1795 TDEFL_NO_FLUSH = 0,
1796 TDEFL_SYNC_FLUSH = 2,
1797 TDEFL_FULL_FLUSH = 3,
1798 TDEFL_FINISH = 4
1799 } tdefl_flush;
1800
1801 // tdefl's compression state structure.
1802 typedef struct {
1803 tdefl_put_buf_func_ptr m_pPut_buf_func;
1804 void *m_pPut_buf_user;
1805 mz_uint m_flags, m_max_probes[2];
1806 int m_greedy_parsing;
1807 mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
1808 mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
1809 mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in,
1810 m_bit_buffer;
1811 mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit,
1812 m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index,
1813 m_wants_to_finish;
1814 tdefl_status m_prev_return_status;
1815 const void *m_pIn_buf;
1816 void *m_pOut_buf;
1817 size_t *m_pIn_buf_size, *m_pOut_buf_size;
1818 tdefl_flush m_flush;
1819 const mz_uint8 *m_pSrc;
1820 size_t m_src_buf_left, m_out_buf_ofs;
1821 mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
1822 mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1823 mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1824 mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1825 mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
1826 mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
1827 mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
1828 mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
1829 } tdefl_compressor;
1830
1831 // Initializes the compressor.
1832 // There is no corresponding deinit() function because the tdefl API's do not
1833 // dynamically allocate memory.
1834 // pBut_buf_func: If NULL, output data will be supplied to the specified
1835 // callback. In this case, the user should call the tdefl_compress_buffer() API
1836 // for compression.
1837 // If pBut_buf_func is NULL the user should always call the tdefl_compress()
1838 // API.
1839 // flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER,
1840 // etc.)
1841 tdefl_status tdefl_init(tdefl_compressor *d,
1842 tdefl_put_buf_func_ptr pPut_buf_func,
1843 void *pPut_buf_user, int flags);
1844
1845 // Compresses a block of data, consuming as much of the specified input buffer
1846 // as possible, and writing as much compressed data to the specified output
1847 // buffer as possible.
1848 tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
1849 size_t *pIn_buf_size, void *pOut_buf,
1850 size_t *pOut_buf_size, tdefl_flush flush);
1851
1852 // tdefl_compress_buffer() is only usable when the tdefl_init() is called with a
1853 // non-NULL tdefl_put_buf_func_ptr.
1854 // tdefl_compress_buffer() always consumes the entire input buffer.
1855 tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
1856 size_t in_buf_size, tdefl_flush flush);
1857
1858 tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
1859 mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
1860
1861 // Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't
1862 // defined, because it uses some of its macros.
1863 #ifndef MINIZ_NO_ZLIB_APIS
1864 // Create tdefl_compress() flags given zlib-style compression parameters.
1865 // level may range from [0,10] (where 10 is absolute max compression, but may be
1866 // much slower on some files)
1867 // window_bits may be -15 (raw deflate) or 15 (zlib)
1868 // strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY,
1869 // MZ_RLE, or MZ_FIXED
1870 mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
1871 int strategy);
1872 #endif // #ifndef MINIZ_NO_ZLIB_APIS
1873
1874 #ifdef __cplusplus
1875 }
1876 #endif
1877
1878 #endif // MINIZ_HEADER_INCLUDED
1879
1880 // ------------------- End of Header: Implementation follows. (If you only want
1881 // the header, define MINIZ_HEADER_FILE_ONLY.)
1882
1883 #ifndef MINIZ_HEADER_FILE_ONLY
1884
1885 typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
1886 typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
1887 typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
1888
1889 //#include <assert.h>
1890 //#include <string.h>
1891
1892 #define MZ_ASSERT(x) assert(x)
1893
1894 #ifdef MINIZ_NO_MALLOC
1895 #define MZ_MALLOC(x) NULL
1896 #define MZ_FREE(x) (void)x, ((void)0)
1897 #define MZ_REALLOC(p, x) NULL
1898 #else
1899 #define MZ_MALLOC(x) malloc(x)
1900 #define MZ_FREE(x) free(x)
1901 #define MZ_REALLOC(p, x) realloc(p, x)
1902 #endif
1903
1904 #define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b))
1905 #define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b))
1906 #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
1907
1908 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1909 #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
1910 #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
1911 #else
1912 #define MZ_READ_LE16(p) \
1913 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
1914 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
1915 #define MZ_READ_LE32(p) \
1916 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
1917 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \
1918 ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \
1919 ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
1920 #endif
1921
1922 #ifdef _MSC_VER
1923 #define MZ_FORCEINLINE __forceinline
1924 #elif defined(__GNUC__)
1925 #define MZ_FORCEINLINE inline __attribute__((__always_inline__))
1926 #else
1927 #define MZ_FORCEINLINE inline
1928 #endif
1929
1930 #ifdef __cplusplus
1931 extern "C" {
1932 #endif
1933
1934 // ------------------- zlib-style API's
1935
mz_adler32(mz_ulong adler,const unsigned char * ptr,size_t buf_len)1936 mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) {
1937 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);
1938 size_t block_len = buf_len % 5552;
1939 if (!ptr) return MZ_ADLER32_INIT;
1940 while (buf_len) {
1941 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
1942 s1 += ptr[0], s2 += s1;
1943 s1 += ptr[1], s2 += s1;
1944 s1 += ptr[2], s2 += s1;
1945 s1 += ptr[3], s2 += s1;
1946 s1 += ptr[4], s2 += s1;
1947 s1 += ptr[5], s2 += s1;
1948 s1 += ptr[6], s2 += s1;
1949 s1 += ptr[7], s2 += s1;
1950 }
1951 for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
1952 s1 %= 65521U, s2 %= 65521U;
1953 buf_len -= block_len;
1954 block_len = 5552;
1955 }
1956 return (s2 << 16) + s1;
1957 }
1958
1959 // Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C
1960 // implementation that balances processor cache usage against speed":
1961 // http://www.geocities.com/malbrain/
mz_crc32(mz_ulong crc,const mz_uint8 * ptr,size_t buf_len)1962 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) {
1963 static const mz_uint32 s_crc32[16] = {
1964 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4,
1965 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
1966 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c};
1967 mz_uint32 crcu32 = (mz_uint32)crc;
1968 if (!ptr) return MZ_CRC32_INIT;
1969 crcu32 = ~crcu32;
1970 while (buf_len--) {
1971 mz_uint8 b = *ptr++;
1972 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
1973 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
1974 }
1975 return ~crcu32;
1976 }
1977
mz_free(void * p)1978 void mz_free(void *p) { MZ_FREE(p); }
1979
1980 #ifndef MINIZ_NO_ZLIB_APIS
1981
def_alloc_func(void * opaque,size_t items,size_t size)1982 static void *def_alloc_func(void *opaque, size_t items, size_t size) {
1983 (void)opaque, (void)items, (void)size;
1984 return MZ_MALLOC(items * size);
1985 }
def_free_func(void * opaque,void * address)1986 static void def_free_func(void *opaque, void *address) {
1987 (void)opaque, (void)address;
1988 MZ_FREE(address);
1989 }
1990 // static void *def_realloc_func(void *opaque, void *address, size_t items,
1991 // size_t size) {
1992 // (void)opaque, (void)address, (void)items, (void)size;
1993 // return MZ_REALLOC(address, items * size);
1994 //}
1995
mz_version(void)1996 const char *mz_version(void) { return MZ_VERSION; }
1997
mz_deflateInit(mz_streamp pStream,int level)1998 int mz_deflateInit(mz_streamp pStream, int level) {
1999 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9,
2000 MZ_DEFAULT_STRATEGY);
2001 }
2002
mz_deflateInit2(mz_streamp pStream,int level,int method,int window_bits,int mem_level,int strategy)2003 int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
2004 int mem_level, int strategy) {
2005 tdefl_compressor *pComp;
2006 mz_uint comp_flags =
2007 TDEFL_COMPUTE_ADLER32 |
2008 tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
2009
2010 if (!pStream) return MZ_STREAM_ERROR;
2011 if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) ||
2012 ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
2013 (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
2014 return MZ_PARAM_ERROR;
2015
2016 pStream->data_type = 0;
2017 pStream->adler = MZ_ADLER32_INIT;
2018 pStream->msg = NULL;
2019 pStream->reserved = 0;
2020 pStream->total_in = 0;
2021 pStream->total_out = 0;
2022 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
2023 if (!pStream->zfree) pStream->zfree = def_free_func;
2024
2025 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1,
2026 sizeof(tdefl_compressor));
2027 if (!pComp) return MZ_MEM_ERROR;
2028
2029 pStream->state = (struct mz_internal_state *)pComp;
2030
2031 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) {
2032 mz_deflateEnd(pStream);
2033 return MZ_PARAM_ERROR;
2034 }
2035
2036 return MZ_OK;
2037 }
2038
mz_deflateReset(mz_streamp pStream)2039 int mz_deflateReset(mz_streamp pStream) {
2040 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) ||
2041 (!pStream->zfree))
2042 return MZ_STREAM_ERROR;
2043 pStream->total_in = pStream->total_out = 0;
2044 tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL,
2045 ((tdefl_compressor *)pStream->state)->m_flags);
2046 return MZ_OK;
2047 }
2048
mz_deflate(mz_streamp pStream,int flush)2049 int mz_deflate(mz_streamp pStream, int flush) {
2050 size_t in_bytes, out_bytes;
2051 mz_ulong orig_total_in, orig_total_out;
2052 int mz_status = MZ_OK;
2053
2054 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) ||
2055 (!pStream->next_out))
2056 return MZ_STREAM_ERROR;
2057 if (!pStream->avail_out) return MZ_BUF_ERROR;
2058
2059 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
2060
2061 if (((tdefl_compressor *)pStream->state)->m_prev_return_status ==
2062 TDEFL_STATUS_DONE)
2063 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
2064
2065 orig_total_in = pStream->total_in;
2066 orig_total_out = pStream->total_out;
2067 for (;;) {
2068 tdefl_status defl_status;
2069 in_bytes = pStream->avail_in;
2070 out_bytes = pStream->avail_out;
2071
2072 defl_status = tdefl_compress((tdefl_compressor *)pStream->state,
2073 pStream->next_in, &in_bytes, pStream->next_out,
2074 &out_bytes, (tdefl_flush)flush);
2075 pStream->next_in += (mz_uint)in_bytes;
2076 pStream->avail_in -= (mz_uint)in_bytes;
2077 pStream->total_in += (mz_uint)in_bytes;
2078 pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);
2079
2080 pStream->next_out += (mz_uint)out_bytes;
2081 pStream->avail_out -= (mz_uint)out_bytes;
2082 pStream->total_out += (mz_uint)out_bytes;
2083
2084 if (defl_status < 0) {
2085 mz_status = MZ_STREAM_ERROR;
2086 break;
2087 } else if (defl_status == TDEFL_STATUS_DONE) {
2088 mz_status = MZ_STREAM_END;
2089 break;
2090 } else if (!pStream->avail_out)
2091 break;
2092 else if ((!pStream->avail_in) && (flush != MZ_FINISH)) {
2093 if ((flush) || (pStream->total_in != orig_total_in) ||
2094 (pStream->total_out != orig_total_out))
2095 break;
2096 return MZ_BUF_ERROR; // Can't make forward progress without some input.
2097 }
2098 }
2099 return mz_status;
2100 }
2101
mz_deflateEnd(mz_streamp pStream)2102 int mz_deflateEnd(mz_streamp pStream) {
2103 if (!pStream) return MZ_STREAM_ERROR;
2104 if (pStream->state) {
2105 pStream->zfree(pStream->opaque, pStream->state);
2106 pStream->state = NULL;
2107 }
2108 return MZ_OK;
2109 }
2110
mz_deflateBound(mz_streamp pStream,mz_ulong source_len)2111 mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) {
2112 (void)pStream;
2113 // This is really over conservative. (And lame, but it's actually pretty
2114 // tricky to compute a true upper bound given the way tdefl's blocking works.)
2115 return MZ_MAX(128 + (source_len * 110) / 100,
2116 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
2117 }
2118
mz_compress2(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len,int level)2119 int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
2120 const unsigned char *pSource, mz_ulong source_len, int level) {
2121 int status;
2122 mz_stream stream;
2123 memset(&stream, 0, sizeof(stream));
2124
2125 // In case mz_ulong is 64-bits (argh I hate longs).
2126 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
2127
2128 stream.next_in = pSource;
2129 stream.avail_in = (mz_uint32)source_len;
2130 stream.next_out = pDest;
2131 stream.avail_out = (mz_uint32)*pDest_len;
2132
2133 status = mz_deflateInit(&stream, level);
2134 if (status != MZ_OK) return status;
2135
2136 status = mz_deflate(&stream, MZ_FINISH);
2137 if (status != MZ_STREAM_END) {
2138 mz_deflateEnd(&stream);
2139 return (status == MZ_OK) ? MZ_BUF_ERROR : status;
2140 }
2141
2142 *pDest_len = stream.total_out;
2143 return mz_deflateEnd(&stream);
2144 }
2145
mz_compress(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len)2146 int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
2147 const unsigned char *pSource, mz_ulong source_len) {
2148 return mz_compress2(pDest, pDest_len, pSource, source_len,
2149 MZ_DEFAULT_COMPRESSION);
2150 }
2151
mz_compressBound(mz_ulong source_len)2152 mz_ulong mz_compressBound(mz_ulong source_len) {
2153 return mz_deflateBound(NULL, source_len);
2154 }
2155
2156 typedef struct {
2157 tinfl_decompressor m_decomp;
2158 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;
2159 int m_window_bits;
2160 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
2161 tinfl_status m_last_status;
2162 } inflate_state;
2163
mz_inflateInit2(mz_streamp pStream,int window_bits)2164 int mz_inflateInit2(mz_streamp pStream, int window_bits) {
2165 inflate_state *pDecomp;
2166 if (!pStream) return MZ_STREAM_ERROR;
2167 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
2168 (-window_bits != MZ_DEFAULT_WINDOW_BITS))
2169 return MZ_PARAM_ERROR;
2170
2171 pStream->data_type = 0;
2172 pStream->adler = 0;
2173 pStream->msg = NULL;
2174 pStream->total_in = 0;
2175 pStream->total_out = 0;
2176 pStream->reserved = 0;
2177 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
2178 if (!pStream->zfree) pStream->zfree = def_free_func;
2179
2180 pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1,
2181 sizeof(inflate_state));
2182 if (!pDecomp) return MZ_MEM_ERROR;
2183
2184 pStream->state = (struct mz_internal_state *)pDecomp;
2185
2186 tinfl_init(&pDecomp->m_decomp);
2187 pDecomp->m_dict_ofs = 0;
2188 pDecomp->m_dict_avail = 0;
2189 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
2190 pDecomp->m_first_call = 1;
2191 pDecomp->m_has_flushed = 0;
2192 pDecomp->m_window_bits = window_bits;
2193
2194 return MZ_OK;
2195 }
2196
mz_inflateInit(mz_streamp pStream)2197 int mz_inflateInit(mz_streamp pStream) {
2198 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
2199 }
2200
mz_inflate(mz_streamp pStream,int flush)2201 int mz_inflate(mz_streamp pStream, int flush) {
2202 inflate_state *pState;
2203 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
2204 size_t in_bytes, out_bytes, orig_avail_in;
2205 tinfl_status status;
2206
2207 if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
2208 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
2209 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))
2210 return MZ_STREAM_ERROR;
2211
2212 pState = (inflate_state *)pStream->state;
2213 if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
2214 orig_avail_in = pStream->avail_in;
2215
2216 first_call = pState->m_first_call;
2217 pState->m_first_call = 0;
2218 if (pState->m_last_status < 0) return MZ_DATA_ERROR;
2219
2220 if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
2221 pState->m_has_flushed |= (flush == MZ_FINISH);
2222
2223 if ((flush == MZ_FINISH) && (first_call)) {
2224 // MZ_FINISH on the first call implies that the input and output buffers are
2225 // large enough to hold the entire compressed/decompressed file.
2226 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
2227 in_bytes = pStream->avail_in;
2228 out_bytes = pStream->avail_out;
2229 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes,
2230 pStream->next_out, pStream->next_out, &out_bytes,
2231 decomp_flags);
2232 pState->m_last_status = status;
2233 pStream->next_in += (mz_uint)in_bytes;
2234 pStream->avail_in -= (mz_uint)in_bytes;
2235 pStream->total_in += (mz_uint)in_bytes;
2236 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
2237 pStream->next_out += (mz_uint)out_bytes;
2238 pStream->avail_out -= (mz_uint)out_bytes;
2239 pStream->total_out += (mz_uint)out_bytes;
2240
2241 if (status < 0)
2242 return MZ_DATA_ERROR;
2243 else if (status != TINFL_STATUS_DONE) {
2244 pState->m_last_status = TINFL_STATUS_FAILED;
2245 return MZ_BUF_ERROR;
2246 }
2247 return MZ_STREAM_END;
2248 }
2249 // flush != MZ_FINISH then we must assume there's more input.
2250 if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
2251
2252 if (pState->m_dict_avail) {
2253 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
2254 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
2255 pStream->next_out += n;
2256 pStream->avail_out -= n;
2257 pStream->total_out += n;
2258 pState->m_dict_avail -= n;
2259 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
2260 return ((pState->m_last_status == TINFL_STATUS_DONE) &&
2261 (!pState->m_dict_avail))
2262 ? MZ_STREAM_END
2263 : MZ_OK;
2264 }
2265
2266 for (;;) {
2267 in_bytes = pStream->avail_in;
2268 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
2269
2270 status = tinfl_decompress(
2271 &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict,
2272 pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
2273 pState->m_last_status = status;
2274
2275 pStream->next_in += (mz_uint)in_bytes;
2276 pStream->avail_in -= (mz_uint)in_bytes;
2277 pStream->total_in += (mz_uint)in_bytes;
2278 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
2279
2280 pState->m_dict_avail = (mz_uint)out_bytes;
2281
2282 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
2283 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
2284 pStream->next_out += n;
2285 pStream->avail_out -= n;
2286 pStream->total_out += n;
2287 pState->m_dict_avail -= n;
2288 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
2289
2290 if (status < 0)
2291 return MZ_DATA_ERROR; // Stream is corrupted (there could be some
2292 // uncompressed data left in the output dictionary -
2293 // oh well).
2294 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
2295 return MZ_BUF_ERROR; // Signal caller that we can't make forward progress
2296 // without supplying more input or by setting flush
2297 // to MZ_FINISH.
2298 else if (flush == MZ_FINISH) {
2299 // The output buffer MUST be large to hold the remaining uncompressed data
2300 // when flush==MZ_FINISH.
2301 if (status == TINFL_STATUS_DONE)
2302 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
2303 // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's
2304 // at least 1 more byte on the way. If there's no more room left in the
2305 // output buffer then something is wrong.
2306 else if (!pStream->avail_out)
2307 return MZ_BUF_ERROR;
2308 } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) ||
2309 (!pStream->avail_out) || (pState->m_dict_avail))
2310 break;
2311 }
2312
2313 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail))
2314 ? MZ_STREAM_END
2315 : MZ_OK;
2316 }
2317
mz_inflateEnd(mz_streamp pStream)2318 int mz_inflateEnd(mz_streamp pStream) {
2319 if (!pStream) return MZ_STREAM_ERROR;
2320 if (pStream->state) {
2321 pStream->zfree(pStream->opaque, pStream->state);
2322 pStream->state = NULL;
2323 }
2324 return MZ_OK;
2325 }
2326
mz_uncompress(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len)2327 int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
2328 const unsigned char *pSource, mz_ulong source_len) {
2329 mz_stream stream;
2330 int status;
2331 memset(&stream, 0, sizeof(stream));
2332
2333 // In case mz_ulong is 64-bits (argh I hate longs).
2334 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
2335
2336 stream.next_in = pSource;
2337 stream.avail_in = (mz_uint32)source_len;
2338 stream.next_out = pDest;
2339 stream.avail_out = (mz_uint32)*pDest_len;
2340
2341 status = mz_inflateInit(&stream);
2342 if (status != MZ_OK) return status;
2343
2344 status = mz_inflate(&stream, MZ_FINISH);
2345 if (status != MZ_STREAM_END) {
2346 mz_inflateEnd(&stream);
2347 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR
2348 : status;
2349 }
2350 *pDest_len = stream.total_out;
2351
2352 return mz_inflateEnd(&stream);
2353 }
2354
mz_error(int err)2355 const char *mz_error(int err) {
2356 static struct {
2357 int m_err;
2358 const char *m_pDesc;
2359 } s_error_descs[] = {{MZ_OK, ""},
2360 {MZ_STREAM_END, "stream end"},
2361 {MZ_NEED_DICT, "need dictionary"},
2362 {MZ_ERRNO, "file error"},
2363 {MZ_STREAM_ERROR, "stream error"},
2364 {MZ_DATA_ERROR, "data error"},
2365 {MZ_MEM_ERROR, "out of memory"},
2366 {MZ_BUF_ERROR, "buf error"},
2367 {MZ_VERSION_ERROR, "version error"},
2368 {MZ_PARAM_ERROR, "parameter error"}};
2369 mz_uint i;
2370 for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)
2371 if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc;
2372 return NULL;
2373 }
2374
2375 #endif // MINIZ_NO_ZLIB_APIS
2376
2377 // ------------------- Low-level Decompression (completely independent from all
2378 // compression API's)
2379
2380 #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
2381 #define TINFL_MEMSET(p, c, l) memset(p, c, l)
2382
2383 #define TINFL_CR_BEGIN \
2384 switch (r->m_state) { \
2385 case 0:
2386 #define TINFL_CR_RETURN(state_index, result) \
2387 do { \
2388 status = result; \
2389 r->m_state = state_index; \
2390 goto common_exit; \
2391 case state_index:; \
2392 } \
2393 MZ_MACRO_END
2394 #define TINFL_CR_RETURN_FOREVER(state_index, result) \
2395 do { \
2396 for (;;) { \
2397 TINFL_CR_RETURN(state_index, result); \
2398 } \
2399 } \
2400 MZ_MACRO_END
2401 #define TINFL_CR_FINISH }
2402
2403 // TODO: If the caller has indicated that there's no more input, and we attempt
2404 // to read beyond the input buf, then something is wrong with the input because
2405 // the inflator never
2406 // reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of
2407 // the stream with 0's in this scenario.
2408 #define TINFL_GET_BYTE(state_index, c) \
2409 do { \
2410 if (pIn_buf_cur >= pIn_buf_end) { \
2411 for (;;) { \
2412 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
2413 TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
2414 if (pIn_buf_cur < pIn_buf_end) { \
2415 c = *pIn_buf_cur++; \
2416 break; \
2417 } \
2418 } else { \
2419 c = 0; \
2420 break; \
2421 } \
2422 } \
2423 } else \
2424 c = *pIn_buf_cur++; \
2425 } \
2426 MZ_MACRO_END
2427
2428 #define TINFL_NEED_BITS(state_index, n) \
2429 do { \
2430 mz_uint c; \
2431 TINFL_GET_BYTE(state_index, c); \
2432 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
2433 num_bits += 8; \
2434 } while (num_bits < (mz_uint)(n))
2435 #define TINFL_SKIP_BITS(state_index, n) \
2436 do { \
2437 if (num_bits < (mz_uint)(n)) { \
2438 TINFL_NEED_BITS(state_index, n); \
2439 } \
2440 bit_buf >>= (n); \
2441 num_bits -= (n); \
2442 } \
2443 MZ_MACRO_END
2444 #define TINFL_GET_BITS(state_index, b, n) \
2445 do { \
2446 if (num_bits < (mz_uint)(n)) { \
2447 TINFL_NEED_BITS(state_index, n); \
2448 } \
2449 b = bit_buf & ((1 << (n)) - 1); \
2450 bit_buf >>= (n); \
2451 num_bits -= (n); \
2452 } \
2453 MZ_MACRO_END
2454
2455 // TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes
2456 // remaining in the input buffer falls below 2.
2457 // It reads just enough bytes from the input stream that are needed to decode
2458 // the next Huffman code (and absolutely no more). It works by trying to fully
2459 // decode a
2460 // Huffman code by using whatever bits are currently present in the bit buffer.
2461 // If this fails, it reads another byte, and tries again until it succeeds or
2462 // until the
2463 // bit buffer contains >=15 bits (deflate's max. Huffman code size).
2464 #define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
2465 do { \
2466 temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
2467 if (temp >= 0) { \
2468 code_len = temp >> 9; \
2469 if ((code_len) && (num_bits >= code_len)) break; \
2470 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
2471 code_len = TINFL_FAST_LOOKUP_BITS; \
2472 do { \
2473 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
2474 } while ((temp < 0) && (num_bits >= (code_len + 1))); \
2475 if (temp >= 0) break; \
2476 } \
2477 TINFL_GET_BYTE(state_index, c); \
2478 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
2479 num_bits += 8; \
2480 } while (num_bits < 15);
2481
2482 // TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex
2483 // than you would initially expect because the zlib API expects the decompressor
2484 // to never read
2485 // beyond the final byte of the deflate stream. (In other words, when this macro
2486 // wants to read another byte from the input, it REALLY needs another byte in
2487 // order to fully
2488 // decode the next Huffman code.) Handling this properly is particularly
2489 // important on raw deflate (non-zlib) streams, which aren't followed by a byte
2490 // aligned adler-32.
2491 // The slow path is only executed at the very end of the input buffer.
2492 #define TINFL_HUFF_DECODE(state_index, sym, pHuff) \
2493 do { \
2494 int temp; \
2495 mz_uint code_len, c; \
2496 if (num_bits < 15) { \
2497 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
2498 TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
2499 } else { \
2500 bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \
2501 (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \
2502 pIn_buf_cur += 2; \
2503 num_bits += 16; \
2504 } \
2505 } \
2506 if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \
2507 0) \
2508 code_len = temp >> 9, temp &= 511; \
2509 else { \
2510 code_len = TINFL_FAST_LOOKUP_BITS; \
2511 do { \
2512 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
2513 } while (temp < 0); \
2514 } \
2515 sym = temp; \
2516 bit_buf >>= code_len; \
2517 num_bits -= code_len; \
2518 } \
2519 MZ_MACRO_END
2520
tinfl_decompress(tinfl_decompressor * r,const mz_uint8 * pIn_buf_next,size_t * pIn_buf_size,mz_uint8 * pOut_buf_start,mz_uint8 * pOut_buf_next,size_t * pOut_buf_size,const mz_uint32 decomp_flags)2521 tinfl_status tinfl_decompress(tinfl_decompressor *r,
2522 const mz_uint8 *pIn_buf_next,
2523 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
2524 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
2525 const mz_uint32 decomp_flags) {
2526 static const int s_length_base[31] = {
2527 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
2528 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
2529 static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
2530 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
2531 4, 4, 5, 5, 5, 5, 0, 0, 0};
2532 static const int s_dist_base[32] = {
2533 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33,
2534 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
2535 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0};
2536 static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
2537 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
2538 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
2539 static const mz_uint8 s_length_dezigzag[19] = {
2540 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
2541 static const int s_min_table_sizes[3] = {257, 1, 4};
2542
2543 tinfl_status status = TINFL_STATUS_FAILED;
2544 mz_uint32 num_bits, dist, counter, num_extra;
2545 tinfl_bit_buf_t bit_buf;
2546 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
2547 pIn_buf_next + *pIn_buf_size;
2548 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
2549 pOut_buf_next + *pOut_buf_size;
2550 size_t out_buf_size_mask =
2551 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
2552 ? (size_t)-1
2553 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1,
2554 dist_from_out_buf_start;
2555
2556 // Ensure the output buffer's size is a power of 2, unless the output buffer
2557 // is large enough to hold the entire output file (in which case it doesn't
2558 // matter).
2559 if (((out_buf_size_mask + 1) & out_buf_size_mask) ||
2560 (pOut_buf_next < pOut_buf_start)) {
2561 *pIn_buf_size = *pOut_buf_size = 0;
2562 return TINFL_STATUS_BAD_PARAM;
2563 }
2564
2565 num_bits = r->m_num_bits;
2566 bit_buf = r->m_bit_buf;
2567 dist = r->m_dist;
2568 counter = r->m_counter;
2569 num_extra = r->m_num_extra;
2570 dist_from_out_buf_start = r->m_dist_from_out_buf_start;
2571 TINFL_CR_BEGIN
2572
2573 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;
2574 r->m_z_adler32 = r->m_check_adler32 = 1;
2575 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2576 TINFL_GET_BYTE(1, r->m_zhdr0);
2577 TINFL_GET_BYTE(2, r->m_zhdr1);
2578 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) ||
2579 (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
2580 if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
2581 counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) ||
2582 ((out_buf_size_mask + 1) <
2583 (size_t)(1ULL << (8U + (r->m_zhdr0 >> 4)))));
2584 if (counter) {
2585 TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);
2586 }
2587 }
2588
2589 do {
2590 TINFL_GET_BITS(3, r->m_final, 3);
2591 r->m_type = r->m_final >> 1;
2592 if (r->m_type == 0) {
2593 TINFL_SKIP_BITS(5, num_bits & 7);
2594 for (counter = 0; counter < 4; ++counter) {
2595 if (num_bits)
2596 TINFL_GET_BITS(6, r->m_raw_header[counter], 8);
2597 else
2598 TINFL_GET_BYTE(7, r->m_raw_header[counter]);
2599 }
2600 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) !=
2601 (mz_uint)(0xFFFF ^
2602 (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) {
2603 TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);
2604 }
2605 while ((counter) && (num_bits)) {
2606 TINFL_GET_BITS(51, dist, 8);
2607 while (pOut_buf_cur >= pOut_buf_end) {
2608 TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);
2609 }
2610 *pOut_buf_cur++ = (mz_uint8)dist;
2611 counter--;
2612 }
2613 while (counter) {
2614 size_t n;
2615 while (pOut_buf_cur >= pOut_buf_end) {
2616 TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);
2617 }
2618 while (pIn_buf_cur >= pIn_buf_end) {
2619 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) {
2620 TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
2621 } else {
2622 TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
2623 }
2624 }
2625 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur),
2626 (size_t)(pIn_buf_end - pIn_buf_cur)),
2627 counter);
2628 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);
2629 pIn_buf_cur += n;
2630 pOut_buf_cur += n;
2631 counter -= (mz_uint)n;
2632 }
2633 } else if (r->m_type == 3) {
2634 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
2635 } else {
2636 if (r->m_type == 1) {
2637 mz_uint8 *p = r->m_tables[0].m_code_size;
2638 mz_uint i;
2639 r->m_table_sizes[0] = 288;
2640 r->m_table_sizes[1] = 32;
2641 TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
2642 for (i = 0; i <= 143; ++i) *p++ = 8;
2643 for (; i <= 255; ++i) *p++ = 9;
2644 for (; i <= 279; ++i) *p++ = 7;
2645 for (; i <= 287; ++i) *p++ = 8;
2646 } else {
2647 for (counter = 0; counter < 3; counter++) {
2648 TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]);
2649 r->m_table_sizes[counter] += s_min_table_sizes[counter];
2650 }
2651 MZ_CLEAR_OBJ(r->m_tables[2].m_code_size);
2652 for (counter = 0; counter < r->m_table_sizes[2]; counter++) {
2653 mz_uint s;
2654 TINFL_GET_BITS(14, s, 3);
2655 r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s;
2656 }
2657 r->m_table_sizes[2] = 19;
2658 }
2659 for (; (int)r->m_type >= 0; r->m_type--) {
2660 int tree_next, tree_cur;
2661 tinfl_huff_table *pTable;
2662 mz_uint i, j, used_syms, total, sym_index, next_code[17],
2663 total_syms[16];
2664 pTable = &r->m_tables[r->m_type];
2665 MZ_CLEAR_OBJ(total_syms);
2666 MZ_CLEAR_OBJ(pTable->m_look_up);
2667 MZ_CLEAR_OBJ(pTable->m_tree);
2668 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)
2669 total_syms[pTable->m_code_size[i]]++;
2670 used_syms = 0, total = 0;
2671 next_code[0] = next_code[1] = 0;
2672 for (i = 1; i <= 15; ++i) {
2673 used_syms += total_syms[i];
2674 next_code[i + 1] = (total = ((total + total_syms[i]) << 1));
2675 }
2676 if ((65536 != total) && (used_syms > 1)) {
2677 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
2678 }
2679 for (tree_next = -1, sym_index = 0;
2680 sym_index < r->m_table_sizes[r->m_type]; ++sym_index) {
2681 mz_uint rev_code = 0, l, cur_code,
2682 code_size = pTable->m_code_size[sym_index];
2683 if (!code_size) continue;
2684 cur_code = next_code[code_size]++;
2685 for (l = code_size; l > 0; l--, cur_code >>= 1)
2686 rev_code = (rev_code << 1) | (cur_code & 1);
2687 if (code_size <= TINFL_FAST_LOOKUP_BITS) {
2688 mz_int16 k = (mz_int16)((code_size << 9) | sym_index);
2689 while (rev_code < TINFL_FAST_LOOKUP_SIZE) {
2690 pTable->m_look_up[rev_code] = k;
2691 rev_code += (1 << code_size);
2692 }
2693 continue;
2694 }
2695 if (0 ==
2696 (tree_cur = pTable->m_look_up[rev_code &
2697 (TINFL_FAST_LOOKUP_SIZE - 1)])) {
2698 pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] =
2699 (mz_int16)tree_next;
2700 tree_cur = tree_next;
2701 tree_next -= 2;
2702 }
2703 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
2704 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) {
2705 tree_cur -= ((rev_code >>= 1) & 1);
2706 if (!pTable->m_tree[-tree_cur - 1]) {
2707 pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next;
2708 tree_cur = tree_next;
2709 tree_next -= 2;
2710 } else
2711 tree_cur = pTable->m_tree[-tree_cur - 1];
2712 }
2713 tree_cur -= ((rev_code >>= 1) & 1);
2714 pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
2715 }
2716 if (r->m_type == 2) {
2717 for (counter = 0;
2718 counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) {
2719 mz_uint s;
2720 TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]);
2721 if (dist < 16) {
2722 r->m_len_codes[counter++] = (mz_uint8)dist;
2723 continue;
2724 }
2725 if ((dist == 16) && (!counter)) {
2726 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
2727 }
2728 num_extra = "\02\03\07"[dist - 16];
2729 TINFL_GET_BITS(18, s, num_extra);
2730 s += "\03\03\013"[dist - 16];
2731 TINFL_MEMSET(r->m_len_codes + counter,
2732 (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);
2733 counter += s;
2734 }
2735 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) {
2736 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
2737 }
2738 TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes,
2739 r->m_table_sizes[0]);
2740 TINFL_MEMCPY(r->m_tables[1].m_code_size,
2741 r->m_len_codes + r->m_table_sizes[0],
2742 r->m_table_sizes[1]);
2743 }
2744 }
2745 for (;;) {
2746 mz_uint8 *pSrc;
2747 for (;;) {
2748 if (((pIn_buf_end - pIn_buf_cur) < 4) ||
2749 ((pOut_buf_end - pOut_buf_cur) < 2)) {
2750 TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
2751 if (counter >= 256) break;
2752 while (pOut_buf_cur >= pOut_buf_end) {
2753 TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);
2754 }
2755 *pOut_buf_cur++ = (mz_uint8)counter;
2756 } else {
2757 int sym2;
2758 mz_uint code_len;
2759 #if TINFL_USE_64BIT_BITBUF
2760 if (num_bits < 30) {
2761 bit_buf |=
2762 (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);
2763 pIn_buf_cur += 4;
2764 num_bits += 32;
2765 }
2766 #else
2767 if (num_bits < 15) {
2768 bit_buf |=
2769 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2770 pIn_buf_cur += 2;
2771 num_bits += 16;
2772 }
2773 #endif
2774 if ((sym2 =
2775 r->m_tables[0]
2776 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2777 0)
2778 code_len = sym2 >> 9;
2779 else {
2780 code_len = TINFL_FAST_LOOKUP_BITS;
2781 do {
2782 sym2 = r->m_tables[0]
2783 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
2784 } while (sym2 < 0);
2785 }
2786 counter = sym2;
2787 bit_buf >>= code_len;
2788 num_bits -= code_len;
2789 if (counter & 256) break;
2790
2791 #if !TINFL_USE_64BIT_BITBUF
2792 if (num_bits < 15) {
2793 bit_buf |=
2794 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2795 pIn_buf_cur += 2;
2796 num_bits += 16;
2797 }
2798 #endif
2799 if ((sym2 =
2800 r->m_tables[0]
2801 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2802 0)
2803 code_len = sym2 >> 9;
2804 else {
2805 code_len = TINFL_FAST_LOOKUP_BITS;
2806 do {
2807 sym2 = r->m_tables[0]
2808 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
2809 } while (sym2 < 0);
2810 }
2811 bit_buf >>= code_len;
2812 num_bits -= code_len;
2813
2814 pOut_buf_cur[0] = (mz_uint8)counter;
2815 if (sym2 & 256) {
2816 pOut_buf_cur++;
2817 counter = sym2;
2818 break;
2819 }
2820 pOut_buf_cur[1] = (mz_uint8)sym2;
2821 pOut_buf_cur += 2;
2822 }
2823 }
2824 if ((counter &= 511) == 256) break;
2825
2826 num_extra = s_length_extra[counter - 257];
2827 counter = s_length_base[counter - 257];
2828 if (num_extra) {
2829 mz_uint extra_bits;
2830 TINFL_GET_BITS(25, extra_bits, num_extra);
2831 counter += extra_bits;
2832 }
2833
2834 TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
2835 num_extra = s_dist_extra[dist];
2836 dist = s_dist_base[dist];
2837 if (num_extra) {
2838 mz_uint extra_bits;
2839 TINFL_GET_BITS(27, extra_bits, num_extra);
2840 dist += extra_bits;
2841 }
2842
2843 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
2844 if ((dist > dist_from_out_buf_start) &&
2845 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) {
2846 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
2847 }
2848
2849 pSrc = pOut_buf_start +
2850 ((dist_from_out_buf_start - dist) & out_buf_size_mask);
2851
2852 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) {
2853 while (counter--) {
2854 while (pOut_buf_cur >= pOut_buf_end) {
2855 TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);
2856 }
2857 *pOut_buf_cur++ =
2858 pOut_buf_start[(dist_from_out_buf_start++ - dist) &
2859 out_buf_size_mask];
2860 }
2861 continue;
2862 }
2863 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
2864 else if ((counter >= 9) && (counter <= dist)) {
2865 const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
2866 do {
2867 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
2868 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
2869 pOut_buf_cur += 8;
2870 } while ((pSrc += 8) < pSrc_end);
2871 if ((counter &= 7) < 3) {
2872 if (counter) {
2873 pOut_buf_cur[0] = pSrc[0];
2874 if (counter > 1) pOut_buf_cur[1] = pSrc[1];
2875 pOut_buf_cur += counter;
2876 }
2877 continue;
2878 }
2879 }
2880 #endif
2881 do {
2882 pOut_buf_cur[0] = pSrc[0];
2883 pOut_buf_cur[1] = pSrc[1];
2884 pOut_buf_cur[2] = pSrc[2];
2885 pOut_buf_cur += 3;
2886 pSrc += 3;
2887 } while ((int)(counter -= 3) > 2);
2888 if ((int)counter > 0) {
2889 pOut_buf_cur[0] = pSrc[0];
2890 if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1];
2891 pOut_buf_cur += counter;
2892 }
2893 }
2894 }
2895 } while (!(r->m_final & 1));
2896 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2897 TINFL_SKIP_BITS(32, num_bits & 7);
2898 for (counter = 0; counter < 4; ++counter) {
2899 mz_uint s;
2900 if (num_bits)
2901 TINFL_GET_BITS(41, s, 8);
2902 else
2903 TINFL_GET_BYTE(42, s);
2904 r->m_z_adler32 = (r->m_z_adler32 << 8) | s;
2905 }
2906 }
2907 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
2908 TINFL_CR_FINISH
2909
2910 common_exit:
2911 r->m_num_bits = num_bits;
2912 r->m_bit_buf = bit_buf;
2913 r->m_dist = dist;
2914 r->m_counter = counter;
2915 r->m_num_extra = num_extra;
2916 r->m_dist_from_out_buf_start = dist_from_out_buf_start;
2917 *pIn_buf_size = pIn_buf_cur - pIn_buf_next;
2918 *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
2919 if ((decomp_flags &
2920 (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) &&
2921 (status >= 0)) {
2922 const mz_uint8 *ptr = pOut_buf_next;
2923 size_t buf_len = *pOut_buf_size;
2924 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff,
2925 s2 = r->m_check_adler32 >> 16;
2926 size_t block_len = buf_len % 5552;
2927 while (buf_len) {
2928 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
2929 s1 += ptr[0], s2 += s1;
2930 s1 += ptr[1], s2 += s1;
2931 s1 += ptr[2], s2 += s1;
2932 s1 += ptr[3], s2 += s1;
2933 s1 += ptr[4], s2 += s1;
2934 s1 += ptr[5], s2 += s1;
2935 s1 += ptr[6], s2 += s1;
2936 s1 += ptr[7], s2 += s1;
2937 }
2938 for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
2939 s1 %= 65521U, s2 %= 65521U;
2940 buf_len -= block_len;
2941 block_len = 5552;
2942 }
2943 r->m_check_adler32 = (s2 << 16) + s1;
2944 if ((status == TINFL_STATUS_DONE) &&
2945 (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) &&
2946 (r->m_check_adler32 != r->m_z_adler32))
2947 status = TINFL_STATUS_ADLER32_MISMATCH;
2948 }
2949 return status;
2950 }
2951
2952 // Higher level helper functions.
tinfl_decompress_mem_to_heap(const void * pSrc_buf,size_t src_buf_len,size_t * pOut_len,int flags)2953 void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
2954 size_t *pOut_len, int flags) {
2955 tinfl_decompressor decomp;
2956 void *pBuf = NULL, *pNew_buf;
2957 size_t src_buf_ofs = 0, out_buf_capacity = 0;
2958 *pOut_len = 0;
2959 tinfl_init(&decomp);
2960 for (;;) {
2961 size_t src_buf_size = src_buf_len - src_buf_ofs,
2962 dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
2963 tinfl_status status = tinfl_decompress(
2964 &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
2965 (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
2966 &dst_buf_size,
2967 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
2968 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
2969 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
2970 MZ_FREE(pBuf);
2971 *pOut_len = 0;
2972 return NULL;
2973 }
2974 src_buf_ofs += src_buf_size;
2975 *pOut_len += dst_buf_size;
2976 if (status == TINFL_STATUS_DONE) break;
2977 new_out_buf_capacity = out_buf_capacity * 2;
2978 if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
2979 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
2980 if (!pNew_buf) {
2981 MZ_FREE(pBuf);
2982 *pOut_len = 0;
2983 return NULL;
2984 }
2985 pBuf = pNew_buf;
2986 out_buf_capacity = new_out_buf_capacity;
2987 }
2988 return pBuf;
2989 }
2990
tinfl_decompress_mem_to_mem(void * pOut_buf,size_t out_buf_len,const void * pSrc_buf,size_t src_buf_len,int flags)2991 size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
2992 const void *pSrc_buf, size_t src_buf_len,
2993 int flags) {
2994 tinfl_decompressor decomp;
2995 tinfl_status status;
2996 tinfl_init(&decomp);
2997 status =
2998 tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len,
2999 (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len,
3000 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
3001 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
3002 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED
3003 : out_buf_len;
3004 }
3005
tinfl_decompress_mem_to_callback(const void * pIn_buf,size_t * pIn_buf_size,tinfl_put_buf_func_ptr pPut_buf_func,void * pPut_buf_user,int flags)3006 int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
3007 tinfl_put_buf_func_ptr pPut_buf_func,
3008 void *pPut_buf_user, int flags) {
3009 int result = 0;
3010 tinfl_decompressor decomp;
3011 mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);
3012 size_t in_buf_ofs = 0, dict_ofs = 0;
3013 if (!pDict) return TINFL_STATUS_FAILED;
3014 tinfl_init(&decomp);
3015 for (;;) {
3016 size_t in_buf_size = *pIn_buf_size - in_buf_ofs,
3017 dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
3018 tinfl_status status =
3019 tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
3020 &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
3021 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
3022 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
3023 in_buf_ofs += in_buf_size;
3024 if ((dst_buf_size) &&
3025 (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
3026 break;
3027 if (status != TINFL_STATUS_HAS_MORE_OUTPUT) {
3028 result = (status == TINFL_STATUS_DONE);
3029 break;
3030 }
3031 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
3032 }
3033 MZ_FREE(pDict);
3034 *pIn_buf_size = in_buf_ofs;
3035 return result;
3036 }
3037
3038 // ------------------- Low-level Compression (independent from all decompression
3039 // API's)
3040
3041 // Purposely making these tables static for faster init and thread safety.
3042 static const mz_uint16 s_tdefl_len_sym[256] = {
3043 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268,
3044 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272,
3045 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274,
3046 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276,
3047 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
3048 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
3049 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279,
3050 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280,
3051 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281,
3052 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
3053 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282,
3054 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
3055 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283,
3056 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
3057 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284,
3058 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
3059 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
3060 285};
3061
3062 static const mz_uint8 s_tdefl_len_extra[256] = {
3063 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
3064 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3065 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
3066 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3067 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3068 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3069 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3070 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3071 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3072 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3073 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0};
3074
3075 static const mz_uint8 s_tdefl_small_dist_sym[512] = {
3076 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
3077 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
3078 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
3079 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
3080 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
3081 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3082 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14,
3083 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
3084 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
3085 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
3086 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
3087 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
3088 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
3089 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3090 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3091 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3092 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3093 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3094 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3095 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3096 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3097 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3098 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3099 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3100 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3101 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3102 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17};
3103
3104 static const mz_uint8 s_tdefl_small_dist_extra[512] = {
3105 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3106 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3107 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3108 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3109 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3110 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3111 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3112 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3113 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3114 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3115 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3116 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3117 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3118 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3119 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3120 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3121 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3122 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3123 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3124 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3125 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
3126
3127 static const mz_uint8 s_tdefl_large_dist_sym[128] = {
3128 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24,
3129 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
3130 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27,
3131 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
3132 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
3133 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
3134 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29};
3135
3136 static const mz_uint8 s_tdefl_large_dist_extra[128] = {
3137 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
3138 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
3139 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
3140 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3141 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3142 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3143 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
3144
3145 // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
3146 // values.
3147 typedef struct {
3148 mz_uint16 m_key, m_sym_index;
3149 } tdefl_sym_freq;
tdefl_radix_sort_syms(mz_uint num_syms,tdefl_sym_freq * pSyms0,tdefl_sym_freq * pSyms1)3150 static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
3151 tdefl_sym_freq *pSyms0,
3152 tdefl_sym_freq *pSyms1) {
3153 mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];
3154 tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;
3155 MZ_CLEAR_OBJ(hist);
3156 for (i = 0; i < num_syms; i++) {
3157 mz_uint freq = pSyms0[i].m_key;
3158 hist[freq & 0xFF]++;
3159 hist[256 + ((freq >> 8) & 0xFF)]++;
3160 }
3161 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))
3162 total_passes--;
3163 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) {
3164 const mz_uint32 *pHist = &hist[pass << 8];
3165 mz_uint offsets[256], cur_ofs = 0;
3166 for (i = 0; i < 256; i++) {
3167 offsets[i] = cur_ofs;
3168 cur_ofs += pHist[i];
3169 }
3170 for (i = 0; i < num_syms; i++)
3171 pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] =
3172 pCur_syms[i];
3173 {
3174 tdefl_sym_freq *t = pCur_syms;
3175 pCur_syms = pNew_syms;
3176 pNew_syms = t;
3177 }
3178 }
3179 return pCur_syms;
3180 }
3181
3182 // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat,
3183 // alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
tdefl_calculate_minimum_redundancy(tdefl_sym_freq * A,int n)3184 static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) {
3185 int root, leaf, next, avbl, used, dpth;
3186 if (n == 0)
3187 return;
3188 else if (n == 1) {
3189 A[0].m_key = 1;
3190 return;
3191 }
3192 A[0].m_key += A[1].m_key;
3193 root = 0;
3194 leaf = 2;
3195 for (next = 1; next < n - 1; next++) {
3196 if (leaf >= n || A[root].m_key < A[leaf].m_key) {
3197 A[next].m_key = A[root].m_key;
3198 A[root++].m_key = (mz_uint16)next;
3199 } else
3200 A[next].m_key = A[leaf++].m_key;
3201 if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) {
3202 A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);
3203 A[root++].m_key = (mz_uint16)next;
3204 } else
3205 A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
3206 }
3207 A[n - 2].m_key = 0;
3208 for (next = n - 3; next >= 0; next--)
3209 A[next].m_key = A[A[next].m_key].m_key + 1;
3210 avbl = 1;
3211 used = dpth = 0;
3212 root = n - 2;
3213 next = n - 1;
3214 while (avbl > 0) {
3215 while (root >= 0 && (int)A[root].m_key == dpth) {
3216 used++;
3217 root--;
3218 }
3219 while (avbl > used) {
3220 A[next--].m_key = (mz_uint16)(dpth);
3221 avbl--;
3222 }
3223 avbl = 2 * used;
3224 dpth++;
3225 used = 0;
3226 }
3227 }
3228
3229 // Limits canonical Huffman code table's max code size.
3230 enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
tdefl_huffman_enforce_max_code_size(int * pNum_codes,int code_list_len,int max_code_size)3231 static void tdefl_huffman_enforce_max_code_size(int *pNum_codes,
3232 int code_list_len,
3233 int max_code_size) {
3234 int i;
3235 mz_uint32 total = 0;
3236 if (code_list_len <= 1) return;
3237 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)
3238 pNum_codes[max_code_size] += pNum_codes[i];
3239 for (i = max_code_size; i > 0; i--)
3240 total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
3241 while (total != (1UL << max_code_size)) {
3242 pNum_codes[max_code_size]--;
3243 for (i = max_code_size - 1; i > 0; i--)
3244 if (pNum_codes[i]) {
3245 pNum_codes[i]--;
3246 pNum_codes[i + 1] += 2;
3247 break;
3248 }
3249 total--;
3250 }
3251 }
3252
tdefl_optimize_huffman_table(tdefl_compressor * d,int table_num,int table_len,int code_size_limit,int static_table)3253 static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num,
3254 int table_len, int code_size_limit,
3255 int static_table) {
3256 int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];
3257 mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];
3258 MZ_CLEAR_OBJ(num_codes);
3259 if (static_table) {
3260 for (i = 0; i < table_len; i++)
3261 num_codes[d->m_huff_code_sizes[table_num][i]]++;
3262 } else {
3263 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS],
3264 *pSyms;
3265 int num_used_syms = 0;
3266 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
3267 for (i = 0; i < table_len; i++)
3268 if (pSym_count[i]) {
3269 syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];
3270 syms0[num_used_syms++].m_sym_index = (mz_uint16)i;
3271 }
3272
3273 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);
3274 tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
3275
3276 for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++;
3277
3278 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms,
3279 code_size_limit);
3280
3281 MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]);
3282 MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
3283 for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
3284 for (l = num_codes[i]; l > 0; l--)
3285 d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
3286 }
3287
3288 next_code[1] = 0;
3289 for (j = 0, i = 2; i <= code_size_limit; i++)
3290 next_code[i] = j = ((j + num_codes[i - 1]) << 1);
3291
3292 for (i = 0; i < table_len; i++) {
3293 mz_uint rev_code = 0, code, code_size;
3294 if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue;
3295 code = next_code[code_size]++;
3296 for (l = code_size; l > 0; l--, code >>= 1)
3297 rev_code = (rev_code << 1) | (code & 1);
3298 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
3299 }
3300 }
3301
3302 #define TDEFL_PUT_BITS(b, l) \
3303 do { \
3304 mz_uint bits = b; \
3305 mz_uint len = l; \
3306 MZ_ASSERT(bits <= ((1U << len) - 1U)); \
3307 d->m_bit_buffer |= (bits << d->m_bits_in); \
3308 d->m_bits_in += len; \
3309 while (d->m_bits_in >= 8) { \
3310 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
3311 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
3312 d->m_bit_buffer >>= 8; \
3313 d->m_bits_in -= 8; \
3314 } \
3315 } \
3316 MZ_MACRO_END
3317
3318 #define TDEFL_RLE_PREV_CODE_SIZE() \
3319 { \
3320 if (rle_repeat_count) { \
3321 if (rle_repeat_count < 3) { \
3322 d->m_huff_count[2][prev_code_size] = (mz_uint16)( \
3323 d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
3324 while (rle_repeat_count--) \
3325 packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
3326 } else { \
3327 d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \
3328 packed_code_sizes[num_packed_code_sizes++] = 16; \
3329 packed_code_sizes[num_packed_code_sizes++] = \
3330 (mz_uint8)(rle_repeat_count - 3); \
3331 } \
3332 rle_repeat_count = 0; \
3333 } \
3334 }
3335
3336 #define TDEFL_RLE_ZERO_CODE_SIZE() \
3337 { \
3338 if (rle_z_count) { \
3339 if (rle_z_count < 3) { \
3340 d->m_huff_count[2][0] = \
3341 (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \
3342 while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \
3343 } else if (rle_z_count <= 10) { \
3344 d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \
3345 packed_code_sizes[num_packed_code_sizes++] = 17; \
3346 packed_code_sizes[num_packed_code_sizes++] = \
3347 (mz_uint8)(rle_z_count - 3); \
3348 } else { \
3349 d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \
3350 packed_code_sizes[num_packed_code_sizes++] = 18; \
3351 packed_code_sizes[num_packed_code_sizes++] = \
3352 (mz_uint8)(rle_z_count - 11); \
3353 } \
3354 rle_z_count = 0; \
3355 } \
3356 }
3357
3358 static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {
3359 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
3360
tdefl_start_dynamic_block(tdefl_compressor * d)3361 static void tdefl_start_dynamic_block(tdefl_compressor *d) {
3362 int num_lit_codes, num_dist_codes, num_bit_lengths;
3363 mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count,
3364 rle_repeat_count, packed_code_sizes_index;
3365 mz_uint8
3366 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
3367 packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
3368 prev_code_size = 0xFF;
3369
3370 d->m_huff_count[0][256] = 1;
3371
3372 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
3373 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
3374
3375 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)
3376 if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break;
3377 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)
3378 if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break;
3379
3380 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
3381 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0],
3382 num_dist_codes);
3383 total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
3384 num_packed_code_sizes = 0;
3385 rle_z_count = 0;
3386 rle_repeat_count = 0;
3387
3388 memset(&d->m_huff_count[2][0], 0,
3389 sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
3390 for (i = 0; i < total_code_sizes_to_pack; i++) {
3391 mz_uint8 code_size = code_sizes_to_pack[i];
3392 if (!code_size) {
3393 TDEFL_RLE_PREV_CODE_SIZE();
3394 if (++rle_z_count == 138) {
3395 TDEFL_RLE_ZERO_CODE_SIZE();
3396 }
3397 } else {
3398 TDEFL_RLE_ZERO_CODE_SIZE();
3399 if (code_size != prev_code_size) {
3400 TDEFL_RLE_PREV_CODE_SIZE();
3401 d->m_huff_count[2][code_size] =
3402 (mz_uint16)(d->m_huff_count[2][code_size] + 1);
3403 packed_code_sizes[num_packed_code_sizes++] = code_size;
3404 } else if (++rle_repeat_count == 6) {
3405 TDEFL_RLE_PREV_CODE_SIZE();
3406 }
3407 }
3408 prev_code_size = code_size;
3409 }
3410 if (rle_repeat_count) {
3411 TDEFL_RLE_PREV_CODE_SIZE();
3412 } else {
3413 TDEFL_RLE_ZERO_CODE_SIZE();
3414 }
3415
3416 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
3417
3418 TDEFL_PUT_BITS(2, 2);
3419
3420 TDEFL_PUT_BITS(num_lit_codes - 257, 5);
3421 TDEFL_PUT_BITS(num_dist_codes - 1, 5);
3422
3423 for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)
3424 if (d->m_huff_code_sizes
3425 [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])
3426 break;
3427 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));
3428 TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
3429 for (i = 0; (int)i < num_bit_lengths; i++)
3430 TDEFL_PUT_BITS(
3431 d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
3432
3433 for (packed_code_sizes_index = 0;
3434 packed_code_sizes_index < num_packed_code_sizes;) {
3435 mz_uint code = packed_code_sizes[packed_code_sizes_index++];
3436 MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
3437 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
3438 if (code >= 16)
3439 TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++],
3440 "\02\03\07"[code - 16]);
3441 }
3442 }
3443
tdefl_start_static_block(tdefl_compressor * d)3444 static void tdefl_start_static_block(tdefl_compressor *d) {
3445 mz_uint i;
3446 mz_uint8 *p = &d->m_huff_code_sizes[0][0];
3447
3448 for (i = 0; i <= 143; ++i) *p++ = 8;
3449 for (; i <= 255; ++i) *p++ = 9;
3450 for (; i <= 279; ++i) *p++ = 7;
3451 for (; i <= 287; ++i) *p++ = 8;
3452
3453 memset(d->m_huff_code_sizes[1], 5, 32);
3454
3455 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
3456 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
3457
3458 TDEFL_PUT_BITS(1, 2);
3459 }
3460
3461 static const mz_uint mz_bitmasks[17] = {
3462 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
3463 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
3464
3465 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \
3466 MINIZ_HAS_64BIT_REGISTERS
tdefl_compress_lz_codes(tdefl_compressor * d)3467 static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
3468 mz_uint flags;
3469 mz_uint8 *pLZ_codes;
3470 mz_uint8 *pOutput_buf = d->m_pOutput_buf;
3471 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
3472 mz_uint64 bit_buffer = d->m_bit_buffer;
3473 mz_uint bits_in = d->m_bits_in;
3474
3475 #define TDEFL_PUT_BITS_FAST(b, l) \
3476 { \
3477 bit_buffer |= (((mz_uint64)(b)) << bits_in); \
3478 bits_in += (l); \
3479 }
3480
3481 flags = 1;
3482 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end;
3483 flags >>= 1) {
3484 if (flags == 1) flags = *pLZ_codes++ | 0x100;
3485
3486 if (flags & 1) {
3487 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
3488 mz_uint match_len = pLZ_codes[0],
3489 match_dist = *(const mz_uint16 *)(pLZ_codes + 1);
3490 pLZ_codes += 3;
3491
3492 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3493 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
3494 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3495 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
3496 s_tdefl_len_extra[match_len]);
3497
3498 // This sequence coaxes MSVC into using cmov's vs. jmp's.
3499 s0 = s_tdefl_small_dist_sym[match_dist & 511];
3500 n0 = s_tdefl_small_dist_extra[match_dist & 511];
3501 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
3502 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
3503 sym = (match_dist < 512) ? s0 : s1;
3504 num_extra_bits = (match_dist < 512) ? n0 : n1;
3505
3506 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
3507 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym],
3508 d->m_huff_code_sizes[1][sym]);
3509 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits],
3510 num_extra_bits);
3511 } else {
3512 mz_uint lit = *pLZ_codes++;
3513 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3514 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3515 d->m_huff_code_sizes[0][lit]);
3516
3517 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3518 flags >>= 1;
3519 lit = *pLZ_codes++;
3520 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3521 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3522 d->m_huff_code_sizes[0][lit]);
3523
3524 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3525 flags >>= 1;
3526 lit = *pLZ_codes++;
3527 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3528 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3529 d->m_huff_code_sizes[0][lit]);
3530 }
3531 }
3532 }
3533
3534 if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE;
3535
3536 *(mz_uint64 *)pOutput_buf = bit_buffer;
3537 pOutput_buf += (bits_in >> 3);
3538 bit_buffer >>= (bits_in & ~7);
3539 bits_in &= 7;
3540 }
3541
3542 #undef TDEFL_PUT_BITS_FAST
3543
3544 d->m_pOutput_buf = pOutput_buf;
3545 d->m_bits_in = 0;
3546 d->m_bit_buffer = 0;
3547
3548 while (bits_in) {
3549 mz_uint32 n = MZ_MIN(bits_in, 16);
3550 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
3551 bit_buffer >>= n;
3552 bits_in -= n;
3553 }
3554
3555 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3556
3557 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3558 }
3559 #else
tdefl_compress_lz_codes(tdefl_compressor * d)3560 static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
3561 mz_uint flags;
3562 mz_uint8 *pLZ_codes;
3563
3564 flags = 1;
3565 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf;
3566 flags >>= 1) {
3567 if (flags == 1) flags = *pLZ_codes++ | 0x100;
3568 if (flags & 1) {
3569 mz_uint sym, num_extra_bits;
3570 mz_uint match_len = pLZ_codes[0],
3571 match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
3572 pLZ_codes += 3;
3573
3574 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3575 TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
3576 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3577 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
3578 s_tdefl_len_extra[match_len]);
3579
3580 if (match_dist < 512) {
3581 sym = s_tdefl_small_dist_sym[match_dist];
3582 num_extra_bits = s_tdefl_small_dist_extra[match_dist];
3583 } else {
3584 sym = s_tdefl_large_dist_sym[match_dist >> 8];
3585 num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
3586 }
3587 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
3588 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
3589 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
3590 } else {
3591 mz_uint lit = *pLZ_codes++;
3592 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3593 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
3594 }
3595 }
3596
3597 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3598
3599 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3600 }
3601 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN &&
3602 // MINIZ_HAS_64BIT_REGISTERS
3603
tdefl_compress_block(tdefl_compressor * d,mz_bool static_block)3604 static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) {
3605 if (static_block)
3606 tdefl_start_static_block(d);
3607 else
3608 tdefl_start_dynamic_block(d);
3609 return tdefl_compress_lz_codes(d);
3610 }
3611
tdefl_flush_block(tdefl_compressor * d,int flush)3612 static int tdefl_flush_block(tdefl_compressor *d, int flush) {
3613 mz_uint saved_bit_buf, saved_bits_in;
3614 mz_uint8 *pSaved_output_buf;
3615 mz_bool comp_block_succeeded = MZ_FALSE;
3616 int n, use_raw_block =
3617 ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
3618 (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
3619 mz_uint8 *pOutput_buf_start =
3620 ((d->m_pPut_buf_func == NULL) &&
3621 ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE))
3622 ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs)
3623 : d->m_output_buf;
3624
3625 d->m_pOutput_buf = pOutput_buf_start;
3626 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
3627
3628 MZ_ASSERT(!d->m_output_flush_remaining);
3629 d->m_output_flush_ofs = 0;
3630 d->m_output_flush_remaining = 0;
3631
3632 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
3633 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
3634
3635 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) {
3636 TDEFL_PUT_BITS(0x78, 8);
3637 TDEFL_PUT_BITS(0x01, 8);
3638 }
3639
3640 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
3641
3642 pSaved_output_buf = d->m_pOutput_buf;
3643 saved_bit_buf = d->m_bit_buffer;
3644 saved_bits_in = d->m_bits_in;
3645
3646 if (!use_raw_block)
3647 comp_block_succeeded =
3648 tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
3649 (d->m_total_lz_bytes < 48));
3650
3651 // If the block gets expanded, forget the current contents of the output
3652 // buffer and send a raw block instead.
3653 if (((use_raw_block) ||
3654 ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >=
3655 d->m_total_lz_bytes))) &&
3656 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) {
3657 mz_uint i;
3658 d->m_pOutput_buf = pSaved_output_buf;
3659 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3660 TDEFL_PUT_BITS(0, 2);
3661 if (d->m_bits_in) {
3662 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3663 }
3664 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) {
3665 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
3666 }
3667 for (i = 0; i < d->m_total_lz_bytes; ++i) {
3668 TDEFL_PUT_BITS(
3669 d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK],
3670 8);
3671 }
3672 }
3673 // Check for the extremely unlikely (if not impossible) case of the compressed
3674 // block not fitting into the output buffer when using dynamic codes.
3675 else if (!comp_block_succeeded) {
3676 d->m_pOutput_buf = pSaved_output_buf;
3677 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3678 tdefl_compress_block(d, MZ_TRUE);
3679 }
3680
3681 if (flush) {
3682 if (flush == TDEFL_FINISH) {
3683 if (d->m_bits_in) {
3684 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3685 }
3686 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) {
3687 mz_uint i, a = d->m_adler32;
3688 for (i = 0; i < 4; i++) {
3689 TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);
3690 a <<= 8;
3691 }
3692 }
3693 } else {
3694 mz_uint i, z = 0;
3695 TDEFL_PUT_BITS(0, 3);
3696 if (d->m_bits_in) {
3697 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3698 }
3699 for (i = 2; i; --i, z ^= 0xFFFF) {
3700 TDEFL_PUT_BITS(z & 0xFFFF, 16);
3701 }
3702 }
3703 }
3704
3705 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
3706
3707 memset(&d->m_huff_count[0][0], 0,
3708 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
3709 memset(&d->m_huff_count[1][0], 0,
3710 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
3711
3712 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
3713 d->m_pLZ_flags = d->m_lz_code_buf;
3714 d->m_num_flags_left = 8;
3715 d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;
3716 d->m_total_lz_bytes = 0;
3717 d->m_block_index++;
3718
3719 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) {
3720 if (d->m_pPut_buf_func) {
3721 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
3722 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
3723 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
3724 } else if (pOutput_buf_start == d->m_output_buf) {
3725 int bytes_to_copy = (int)MZ_MIN(
3726 (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
3727 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf,
3728 bytes_to_copy);
3729 d->m_out_buf_ofs += bytes_to_copy;
3730 if ((n -= bytes_to_copy) != 0) {
3731 d->m_output_flush_ofs = bytes_to_copy;
3732 d->m_output_flush_remaining = n;
3733 }
3734 } else {
3735 d->m_out_buf_ofs += n;
3736 }
3737 }
3738
3739 return d->m_output_flush_remaining;
3740 }
3741
3742 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
3743 #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)
tdefl_find_match(tdefl_compressor * d,mz_uint lookahead_pos,mz_uint max_dist,mz_uint max_match_len,mz_uint * pMatch_dist,mz_uint * pMatch_len)3744 static MZ_FORCEINLINE void tdefl_find_match(
3745 tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3746 mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) {
3747 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3748 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3749 probe_len;
3750 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3751 const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;
3752 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]),
3753 s01 = TDEFL_READ_UNALIGNED_WORD(s);
3754 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3755 if (max_match_len <= match_len) return;
3756 for (;;) {
3757 for (;;) {
3758 if (--num_probes_left == 0) return;
3759 #define TDEFL_PROBE \
3760 next_probe_pos = d->m_next[probe_pos]; \
3761 if ((!next_probe_pos) || \
3762 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3763 return; \
3764 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3765 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \
3766 break;
3767 TDEFL_PROBE;
3768 TDEFL_PROBE;
3769 TDEFL_PROBE;
3770 }
3771 if (!dist) break;
3772 q = (const mz_uint16 *)(d->m_dict + probe_pos);
3773 if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue;
3774 p = s;
3775 probe_len = 32;
3776 do {
3777 } while (
3778 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3779 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3780 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3781 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3782 (--probe_len > 0));
3783 if (!probe_len) {
3784 *pMatch_dist = dist;
3785 *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN);
3786 break;
3787 } else if ((probe_len = ((mz_uint)(p - s) * 2) +
3788 (mz_uint)(*(const mz_uint8 *)p ==
3789 *(const mz_uint8 *)q)) > match_len) {
3790 *pMatch_dist = dist;
3791 if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) ==
3792 max_match_len)
3793 break;
3794 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
3795 }
3796 }
3797 }
3798 #else
tdefl_find_match(tdefl_compressor * d,mz_uint lookahead_pos,mz_uint max_dist,mz_uint max_match_len,mz_uint * pMatch_dist,mz_uint * pMatch_len)3799 static MZ_FORCEINLINE void tdefl_find_match(
3800 tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3801 mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) {
3802 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3803 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3804 probe_len;
3805 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3806 const mz_uint8 *s = d->m_dict + pos, *p, *q;
3807 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
3808 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3809 if (max_match_len <= match_len) return;
3810 for (;;) {
3811 for (;;) {
3812 if (--num_probes_left == 0) return;
3813 #define TDEFL_PROBE \
3814 next_probe_pos = d->m_next[probe_pos]; \
3815 if ((!next_probe_pos) || \
3816 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3817 return; \
3818 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3819 if ((d->m_dict[probe_pos + match_len] == c0) && \
3820 (d->m_dict[probe_pos + match_len - 1] == c1)) \
3821 break;
3822 TDEFL_PROBE;
3823 TDEFL_PROBE;
3824 TDEFL_PROBE;
3825 }
3826 if (!dist) break;
3827 p = s;
3828 q = d->m_dict + probe_pos;
3829 for (probe_len = 0; probe_len < max_match_len; probe_len++)
3830 if (*p++ != *q++) break;
3831 if (probe_len > match_len) {
3832 *pMatch_dist = dist;
3833 if ((*pMatch_len = match_len = probe_len) == max_match_len) return;
3834 c0 = d->m_dict[pos + match_len];
3835 c1 = d->m_dict[pos + match_len - 1];
3836 }
3837 }
3838 }
3839 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
3840
3841 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
tdefl_compress_fast(tdefl_compressor * d)3842 static mz_bool tdefl_compress_fast(tdefl_compressor *d) {
3843 // Faster, minimally featured LZRW1-style match+parse loop with better
3844 // register utilization. Intended for applications where raw throughput is
3845 // valued more highly than ratio.
3846 mz_uint lookahead_pos = d->m_lookahead_pos,
3847 lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size,
3848 total_lz_bytes = d->m_total_lz_bytes,
3849 num_flags_left = d->m_num_flags_left;
3850 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
3851 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
3852
3853 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) {
3854 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
3855 mz_uint dst_pos =
3856 (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
3857 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
3858 d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
3859 d->m_src_buf_left -= num_bytes_to_process;
3860 lookahead_size += num_bytes_to_process;
3861
3862 while (num_bytes_to_process) {
3863 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
3864 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
3865 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
3866 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc,
3867 MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
3868 d->m_pSrc += n;
3869 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
3870 num_bytes_to_process -= n;
3871 }
3872
3873 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
3874 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))
3875 break;
3876
3877 while (lookahead_size >= 4) {
3878 mz_uint cur_match_dist, cur_match_len = 1;
3879 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
3880 mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
3881 mz_uint hash =
3882 (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) &
3883 TDEFL_LEVEL1_HASH_SIZE_MASK;
3884 mz_uint probe_pos = d->m_hash[hash];
3885 d->m_hash[hash] = (mz_uint16)lookahead_pos;
3886
3887 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <=
3888 dict_size) &&
3889 ((*(const mz_uint32 *)(d->m_dict +
3890 (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) &
3891 0xFFFFFF) == first_trigram)) {
3892 const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
3893 const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
3894 mz_uint32 probe_len = 32;
3895 do {
3896 } while ((TDEFL_READ_UNALIGNED_WORD(++p) ==
3897 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3898 (TDEFL_READ_UNALIGNED_WORD(++p) ==
3899 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3900 (TDEFL_READ_UNALIGNED_WORD(++p) ==
3901 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3902 (TDEFL_READ_UNALIGNED_WORD(++p) ==
3903 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3904 (--probe_len > 0));
3905 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) +
3906 (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
3907 if (!probe_len)
3908 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
3909
3910 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) ||
3911 ((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
3912 (cur_match_dist >= 8U * 1024U))) {
3913 cur_match_len = 1;
3914 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3915 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3916 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3917 } else {
3918 mz_uint32 s0, s1;
3919 cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
3920
3921 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) &&
3922 (cur_match_dist >= 1) &&
3923 (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
3924
3925 cur_match_dist--;
3926
3927 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
3928 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
3929 pLZ_code_buf += 3;
3930 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
3931
3932 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
3933 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
3934 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
3935
3936 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len -
3937 TDEFL_MIN_MATCH_LEN]]++;
3938 }
3939 } else {
3940 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3941 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3942 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3943 }
3944
3945 if (--num_flags_left == 0) {
3946 num_flags_left = 8;
3947 pLZ_flags = pLZ_code_buf++;
3948 }
3949
3950 total_lz_bytes += cur_match_len;
3951 lookahead_pos += cur_match_len;
3952 dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
3953 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
3954 MZ_ASSERT(lookahead_size >= cur_match_len);
3955 lookahead_size -= cur_match_len;
3956
3957 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
3958 int n;
3959 d->m_lookahead_pos = lookahead_pos;
3960 d->m_lookahead_size = lookahead_size;
3961 d->m_dict_size = dict_size;
3962 d->m_total_lz_bytes = total_lz_bytes;
3963 d->m_pLZ_code_buf = pLZ_code_buf;
3964 d->m_pLZ_flags = pLZ_flags;
3965 d->m_num_flags_left = num_flags_left;
3966 if ((n = tdefl_flush_block(d, 0)) != 0)
3967 return (n < 0) ? MZ_FALSE : MZ_TRUE;
3968 total_lz_bytes = d->m_total_lz_bytes;
3969 pLZ_code_buf = d->m_pLZ_code_buf;
3970 pLZ_flags = d->m_pLZ_flags;
3971 num_flags_left = d->m_num_flags_left;
3972 }
3973 }
3974
3975 while (lookahead_size) {
3976 mz_uint8 lit = d->m_dict[cur_pos];
3977
3978 total_lz_bytes++;
3979 *pLZ_code_buf++ = lit;
3980 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3981 if (--num_flags_left == 0) {
3982 num_flags_left = 8;
3983 pLZ_flags = pLZ_code_buf++;
3984 }
3985
3986 d->m_huff_count[0][lit]++;
3987
3988 lookahead_pos++;
3989 dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
3990 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
3991 lookahead_size--;
3992
3993 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
3994 int n;
3995 d->m_lookahead_pos = lookahead_pos;
3996 d->m_lookahead_size = lookahead_size;
3997 d->m_dict_size = dict_size;
3998 d->m_total_lz_bytes = total_lz_bytes;
3999 d->m_pLZ_code_buf = pLZ_code_buf;
4000 d->m_pLZ_flags = pLZ_flags;
4001 d->m_num_flags_left = num_flags_left;
4002 if ((n = tdefl_flush_block(d, 0)) != 0)
4003 return (n < 0) ? MZ_FALSE : MZ_TRUE;
4004 total_lz_bytes = d->m_total_lz_bytes;
4005 pLZ_code_buf = d->m_pLZ_code_buf;
4006 pLZ_flags = d->m_pLZ_flags;
4007 num_flags_left = d->m_num_flags_left;
4008 }
4009 }
4010 }
4011
4012 d->m_lookahead_pos = lookahead_pos;
4013 d->m_lookahead_size = lookahead_size;
4014 d->m_dict_size = dict_size;
4015 d->m_total_lz_bytes = total_lz_bytes;
4016 d->m_pLZ_code_buf = pLZ_code_buf;
4017 d->m_pLZ_flags = pLZ_flags;
4018 d->m_num_flags_left = num_flags_left;
4019 return MZ_TRUE;
4020 }
4021 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
4022
tdefl_record_literal(tdefl_compressor * d,mz_uint8 lit)4023 static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d,
4024 mz_uint8 lit) {
4025 d->m_total_lz_bytes++;
4026 *d->m_pLZ_code_buf++ = lit;
4027 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);
4028 if (--d->m_num_flags_left == 0) {
4029 d->m_num_flags_left = 8;
4030 d->m_pLZ_flags = d->m_pLZ_code_buf++;
4031 }
4032 d->m_huff_count[0][lit]++;
4033 }
4034
tdefl_record_match(tdefl_compressor * d,mz_uint match_len,mz_uint match_dist)4035 static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d,
4036 mz_uint match_len,
4037 mz_uint match_dist) {
4038 mz_uint32 s0, s1;
4039
4040 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) &&
4041 (match_dist <= TDEFL_LZ_DICT_SIZE));
4042
4043 d->m_total_lz_bytes += match_len;
4044
4045 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
4046
4047 match_dist -= 1;
4048 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
4049 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);
4050 d->m_pLZ_code_buf += 3;
4051
4052 *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);
4053 if (--d->m_num_flags_left == 0) {
4054 d->m_num_flags_left = 8;
4055 d->m_pLZ_flags = d->m_pLZ_code_buf++;
4056 }
4057
4058 s0 = s_tdefl_small_dist_sym[match_dist & 511];
4059 s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
4060 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
4061
4062 if (match_len >= TDEFL_MIN_MATCH_LEN)
4063 d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
4064 }
4065
tdefl_compress_normal(tdefl_compressor * d)4066 static mz_bool tdefl_compress_normal(tdefl_compressor *d) {
4067 const mz_uint8 *pSrc = d->m_pSrc;
4068 size_t src_buf_left = d->m_src_buf_left;
4069 tdefl_flush flush = d->m_flush;
4070
4071 while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) {
4072 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
4073 // Update dictionary and hash chains. Keeps the lookahead size equal to
4074 // TDEFL_MAX_MATCH_LEN.
4075 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) {
4076 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
4077 TDEFL_LZ_DICT_SIZE_MASK,
4078 ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
4079 mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
4080 << TDEFL_LZ_HASH_SHIFT) ^
4081 d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
4082 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
4083 src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
4084 const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
4085 src_buf_left -= num_bytes_to_process;
4086 d->m_lookahead_size += num_bytes_to_process;
4087 while (pSrc != pSrc_end) {
4088 mz_uint8 c = *pSrc++;
4089 d->m_dict[dst_pos] = c;
4090 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
4091 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
4092 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
4093 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
4094 d->m_hash[hash] = (mz_uint16)(ins_pos);
4095 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
4096 ins_pos++;
4097 }
4098 } else {
4099 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) {
4100 mz_uint8 c = *pSrc++;
4101 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
4102 TDEFL_LZ_DICT_SIZE_MASK;
4103 src_buf_left--;
4104 d->m_dict[dst_pos] = c;
4105 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
4106 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
4107 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) {
4108 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
4109 mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
4110 << (TDEFL_LZ_HASH_SHIFT * 2)) ^
4111 (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]
4112 << TDEFL_LZ_HASH_SHIFT) ^
4113 c) &
4114 (TDEFL_LZ_HASH_SIZE - 1);
4115 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
4116 d->m_hash[hash] = (mz_uint16)(ins_pos);
4117 }
4118 }
4119 }
4120 d->m_dict_size =
4121 MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
4122 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break;
4123
4124 // Simple lazy/greedy parsing state machine.
4125 len_to_move = 1;
4126 cur_match_dist = 0;
4127 cur_match_len =
4128 d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);
4129 cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
4130 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) {
4131 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) {
4132 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
4133 cur_match_len = 0;
4134 while (cur_match_len < d->m_lookahead_size) {
4135 if (d->m_dict[cur_pos + cur_match_len] != c) break;
4136 cur_match_len++;
4137 }
4138 if (cur_match_len < TDEFL_MIN_MATCH_LEN)
4139 cur_match_len = 0;
4140 else
4141 cur_match_dist = 1;
4142 }
4143 } else {
4144 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size,
4145 d->m_lookahead_size, &cur_match_dist, &cur_match_len);
4146 }
4147 if (((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
4148 (cur_match_dist >= 8U * 1024U)) ||
4149 (cur_pos == cur_match_dist) ||
4150 ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) {
4151 cur_match_dist = cur_match_len = 0;
4152 }
4153 if (d->m_saved_match_len) {
4154 if (cur_match_len > d->m_saved_match_len) {
4155 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
4156 if (cur_match_len >= 128) {
4157 tdefl_record_match(d, cur_match_len, cur_match_dist);
4158 d->m_saved_match_len = 0;
4159 len_to_move = cur_match_len;
4160 } else {
4161 d->m_saved_lit = d->m_dict[cur_pos];
4162 d->m_saved_match_dist = cur_match_dist;
4163 d->m_saved_match_len = cur_match_len;
4164 }
4165 } else {
4166 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
4167 len_to_move = d->m_saved_match_len - 1;
4168 d->m_saved_match_len = 0;
4169 }
4170 } else if (!cur_match_dist)
4171 tdefl_record_literal(d,
4172 d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
4173 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) ||
4174 (cur_match_len >= 128)) {
4175 tdefl_record_match(d, cur_match_len, cur_match_dist);
4176 len_to_move = cur_match_len;
4177 } else {
4178 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];
4179 d->m_saved_match_dist = cur_match_dist;
4180 d->m_saved_match_len = cur_match_len;
4181 }
4182 // Move the lookahead forward by len_to_move bytes.
4183 d->m_lookahead_pos += len_to_move;
4184 MZ_ASSERT(d->m_lookahead_size >= len_to_move);
4185 d->m_lookahead_size -= len_to_move;
4186 d->m_dict_size =
4187 MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);
4188 // Check if it's time to flush the current LZ codes to the internal output
4189 // buffer.
4190 if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
4191 ((d->m_total_lz_bytes > 31 * 1024) &&
4192 (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >=
4193 d->m_total_lz_bytes) ||
4194 (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) {
4195 int n;
4196 d->m_pSrc = pSrc;
4197 d->m_src_buf_left = src_buf_left;
4198 if ((n = tdefl_flush_block(d, 0)) != 0)
4199 return (n < 0) ? MZ_FALSE : MZ_TRUE;
4200 }
4201 }
4202
4203 d->m_pSrc = pSrc;
4204 d->m_src_buf_left = src_buf_left;
4205 return MZ_TRUE;
4206 }
4207
tdefl_flush_output_buffer(tdefl_compressor * d)4208 static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) {
4209 if (d->m_pIn_buf_size) {
4210 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
4211 }
4212
4213 if (d->m_pOut_buf_size) {
4214 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs,
4215 d->m_output_flush_remaining);
4216 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs,
4217 d->m_output_buf + d->m_output_flush_ofs, n);
4218 d->m_output_flush_ofs += (mz_uint)n;
4219 d->m_output_flush_remaining -= (mz_uint)n;
4220 d->m_out_buf_ofs += n;
4221
4222 *d->m_pOut_buf_size = d->m_out_buf_ofs;
4223 }
4224
4225 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE
4226 : TDEFL_STATUS_OKAY;
4227 }
4228
tdefl_compress(tdefl_compressor * d,const void * pIn_buf,size_t * pIn_buf_size,void * pOut_buf,size_t * pOut_buf_size,tdefl_flush flush)4229 tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
4230 size_t *pIn_buf_size, void *pOut_buf,
4231 size_t *pOut_buf_size, tdefl_flush flush) {
4232 if (!d) {
4233 if (pIn_buf_size) *pIn_buf_size = 0;
4234 if (pOut_buf_size) *pOut_buf_size = 0;
4235 return TDEFL_STATUS_BAD_PARAM;
4236 }
4237
4238 d->m_pIn_buf = pIn_buf;
4239 d->m_pIn_buf_size = pIn_buf_size;
4240 d->m_pOut_buf = pOut_buf;
4241 d->m_pOut_buf_size = pOut_buf_size;
4242 d->m_pSrc = (const mz_uint8 *)(pIn_buf);
4243 d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
4244 d->m_out_buf_ofs = 0;
4245 d->m_flush = flush;
4246
4247 if (((d->m_pPut_buf_func != NULL) ==
4248 ((pOut_buf != NULL) || (pOut_buf_size != NULL))) ||
4249 (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
4250 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) ||
4251 (pIn_buf_size && *pIn_buf_size && !pIn_buf) ||
4252 (pOut_buf_size && *pOut_buf_size && !pOut_buf)) {
4253 if (pIn_buf_size) *pIn_buf_size = 0;
4254 if (pOut_buf_size) *pOut_buf_size = 0;
4255 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
4256 }
4257 d->m_wants_to_finish |= (flush == TDEFL_FINISH);
4258
4259 if ((d->m_output_flush_remaining) || (d->m_finished))
4260 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
4261
4262 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
4263 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
4264 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
4265 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS |
4266 TDEFL_RLE_MATCHES)) == 0)) {
4267 if (!tdefl_compress_fast(d)) return d->m_prev_return_status;
4268 } else
4269 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
4270 {
4271 if (!tdefl_compress_normal(d)) return d->m_prev_return_status;
4272 }
4273
4274 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) &&
4275 (pIn_buf))
4276 d->m_adler32 =
4277 (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf,
4278 d->m_pSrc - (const mz_uint8 *)pIn_buf);
4279
4280 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) &&
4281 (!d->m_output_flush_remaining)) {
4282 if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status;
4283 d->m_finished = (flush == TDEFL_FINISH);
4284 if (flush == TDEFL_FULL_FLUSH) {
4285 MZ_CLEAR_OBJ(d->m_hash);
4286 MZ_CLEAR_OBJ(d->m_next);
4287 d->m_dict_size = 0;
4288 }
4289 }
4290
4291 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
4292 }
4293
tdefl_compress_buffer(tdefl_compressor * d,const void * pIn_buf,size_t in_buf_size,tdefl_flush flush)4294 tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
4295 size_t in_buf_size, tdefl_flush flush) {
4296 MZ_ASSERT(d->m_pPut_buf_func);
4297 return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
4298 }
4299
tdefl_init(tdefl_compressor * d,tdefl_put_buf_func_ptr pPut_buf_func,void * pPut_buf_user,int flags)4300 tdefl_status tdefl_init(tdefl_compressor *d,
4301 tdefl_put_buf_func_ptr pPut_buf_func,
4302 void *pPut_buf_user, int flags) {
4303 d->m_pPut_buf_func = pPut_buf_func;
4304 d->m_pPut_buf_user = pPut_buf_user;
4305 d->m_flags = (mz_uint)(flags);
4306 d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;
4307 d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
4308 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
4309 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash);
4310 d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size =
4311 d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
4312 d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished =
4313 d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
4314 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
4315 d->m_pLZ_flags = d->m_lz_code_buf;
4316 d->m_num_flags_left = 8;
4317 d->m_pOutput_buf = d->m_output_buf;
4318 d->m_pOutput_buf_end = d->m_output_buf;
4319 d->m_prev_return_status = TDEFL_STATUS_OKAY;
4320 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;
4321 d->m_adler32 = 1;
4322 d->m_pIn_buf = NULL;
4323 d->m_pOut_buf = NULL;
4324 d->m_pIn_buf_size = NULL;
4325 d->m_pOut_buf_size = NULL;
4326 d->m_flush = TDEFL_NO_FLUSH;
4327 d->m_pSrc = NULL;
4328 d->m_src_buf_left = 0;
4329 d->m_out_buf_ofs = 0;
4330 memset(&d->m_huff_count[0][0], 0,
4331 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
4332 memset(&d->m_huff_count[1][0], 0,
4333 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
4334 return TDEFL_STATUS_OKAY;
4335 }
4336
tdefl_get_prev_return_status(tdefl_compressor * d)4337 tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) {
4338 return d->m_prev_return_status;
4339 }
4340
tdefl_get_adler32(tdefl_compressor * d)4341 mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; }
4342
tdefl_compress_mem_to_output(const void * pBuf,size_t buf_len,tdefl_put_buf_func_ptr pPut_buf_func,void * pPut_buf_user,int flags)4343 mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
4344 tdefl_put_buf_func_ptr pPut_buf_func,
4345 void *pPut_buf_user, int flags) {
4346 tdefl_compressor *pComp;
4347 mz_bool succeeded;
4348 if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE;
4349 pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
4350 if (!pComp) return MZ_FALSE;
4351 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) ==
4352 TDEFL_STATUS_OKAY);
4353 succeeded =
4354 succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) ==
4355 TDEFL_STATUS_DONE);
4356 MZ_FREE(pComp);
4357 return succeeded;
4358 }
4359
4360 typedef struct {
4361 size_t m_size, m_capacity;
4362 mz_uint8 *m_pBuf;
4363 mz_bool m_expandable;
4364 } tdefl_output_buffer;
4365
tdefl_output_buffer_putter(const void * pBuf,int len,void * pUser)4366 static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len,
4367 void *pUser) {
4368 tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
4369 size_t new_size = p->m_size + len;
4370 if (new_size > p->m_capacity) {
4371 size_t new_capacity = p->m_capacity;
4372 mz_uint8 *pNew_buf;
4373 if (!p->m_expandable) return MZ_FALSE;
4374 do {
4375 new_capacity = MZ_MAX(128U, new_capacity << 1U);
4376 } while (new_size > new_capacity);
4377 pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);
4378 if (!pNew_buf) return MZ_FALSE;
4379 p->m_pBuf = pNew_buf;
4380 p->m_capacity = new_capacity;
4381 }
4382 memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);
4383 p->m_size = new_size;
4384 return MZ_TRUE;
4385 }
4386
tdefl_compress_mem_to_heap(const void * pSrc_buf,size_t src_buf_len,size_t * pOut_len,int flags)4387 void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
4388 size_t *pOut_len, int flags) {
4389 tdefl_output_buffer out_buf;
4390 MZ_CLEAR_OBJ(out_buf);
4391 if (!pOut_len)
4392 return MZ_FALSE;
4393 else
4394 *pOut_len = 0;
4395 out_buf.m_expandable = MZ_TRUE;
4396 if (!tdefl_compress_mem_to_output(
4397 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
4398 return NULL;
4399 *pOut_len = out_buf.m_size;
4400 return out_buf.m_pBuf;
4401 }
4402
tdefl_compress_mem_to_mem(void * pOut_buf,size_t out_buf_len,const void * pSrc_buf,size_t src_buf_len,int flags)4403 size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
4404 const void *pSrc_buf, size_t src_buf_len,
4405 int flags) {
4406 tdefl_output_buffer out_buf;
4407 MZ_CLEAR_OBJ(out_buf);
4408 if (!pOut_buf) return 0;
4409 out_buf.m_pBuf = (mz_uint8 *)pOut_buf;
4410 out_buf.m_capacity = out_buf_len;
4411 if (!tdefl_compress_mem_to_output(
4412 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
4413 return 0;
4414 return out_buf.m_size;
4415 }
4416
4417 #ifndef MINIZ_NO_ZLIB_APIS
4418 static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32,
4419 128, 256, 512, 768, 1500};
4420
4421 // level may actually range from [0,10] (10 is a "hidden" max level, where we
4422 // want a bit more compression and it's fine if throughput to fall off a cliff
4423 // on some files).
tdefl_create_comp_flags_from_zip_params(int level,int window_bits,int strategy)4424 mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
4425 int strategy) {
4426 mz_uint comp_flags =
4427 s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] |
4428 ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
4429 if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
4430
4431 if (!level)
4432 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
4433 else if (strategy == MZ_FILTERED)
4434 comp_flags |= TDEFL_FILTER_MATCHES;
4435 else if (strategy == MZ_HUFFMAN_ONLY)
4436 comp_flags &= ~TDEFL_MAX_PROBES_MASK;
4437 else if (strategy == MZ_FIXED)
4438 comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
4439 else if (strategy == MZ_RLE)
4440 comp_flags |= TDEFL_RLE_MATCHES;
4441
4442 return comp_flags;
4443 }
4444 #endif // MINIZ_NO_ZLIB_APIS
4445
4446 #ifdef _MSC_VER
4447 #pragma warning(push)
4448 #pragma warning(disable : 4204) // nonstandard extension used : non-constant
4449 // aggregate initializer (also supported by GNU
4450 // C and C99, so no big deal)
4451 #pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
4452 // 'int', possible loss of data
4453 #pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
4454 // 'int', possible loss of data
4455 #pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
4456 // deprecated. Instead, use the ISO C and C++
4457 // conformant name: _strdup.
4458 #endif
4459
4460 // Simple PNG writer function by Alex Evans, 2011. Released into the public
4461 // domain: https://gist.github.com/908299, more context at
4462 // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
4463 // This is actually a modification of Alex's original code so PNG files
4464 // generated by this function pass pngcheck.
tdefl_write_image_to_png_file_in_memory_ex(const void * pImage,int w,int h,int num_chans,size_t * pLen_out,mz_uint level,mz_bool flip)4465 void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
4466 int h, int num_chans,
4467 size_t *pLen_out,
4468 mz_uint level, mz_bool flip) {
4469 // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was
4470 // defined.
4471 static const mz_uint s_tdefl_png_num_probes[11] = {
4472 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500};
4473 tdefl_compressor *pComp =
4474 (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
4475 tdefl_output_buffer out_buf;
4476 int i, bpl = w * num_chans, y, z;
4477 mz_uint32 c;
4478 *pLen_out = 0;
4479 if (!pComp) return NULL;
4480 MZ_CLEAR_OBJ(out_buf);
4481 out_buf.m_expandable = MZ_TRUE;
4482 out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);
4483 if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) {
4484 MZ_FREE(pComp);
4485 return NULL;
4486 }
4487 // write dummy header
4488 for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
4489 // compress image data
4490 tdefl_init(
4491 pComp, tdefl_output_buffer_putter, &out_buf,
4492 s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
4493 for (y = 0; y < h; ++y) {
4494 tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);
4495 tdefl_compress_buffer(pComp,
4496 (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl,
4497 bpl, TDEFL_NO_FLUSH);
4498 }
4499 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) !=
4500 TDEFL_STATUS_DONE) {
4501 MZ_FREE(pComp);
4502 MZ_FREE(out_buf.m_pBuf);
4503 return NULL;
4504 }
4505 // write real header
4506 *pLen_out = out_buf.m_size - 41;
4507 {
4508 static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
4509 mz_uint8 pnghdr[41] = {0x89,
4510 0x50,
4511 0x4e,
4512 0x47,
4513 0x0d,
4514 0x0a,
4515 0x1a,
4516 0x0a,
4517 0x00,
4518 0x00,
4519 0x00,
4520 0x0d,
4521 0x49,
4522 0x48,
4523 0x44,
4524 0x52,
4525 0,
4526 0,
4527 (mz_uint8)(w >> 8),
4528 (mz_uint8)w,
4529 0,
4530 0,
4531 (mz_uint8)(h >> 8),
4532 (mz_uint8)h,
4533 8,
4534 chans[num_chans],
4535 0,
4536 0,
4537 0,
4538 0,
4539 0,
4540 0,
4541 0,
4542 (mz_uint8)(*pLen_out >> 24),
4543 (mz_uint8)(*pLen_out >> 16),
4544 (mz_uint8)(*pLen_out >> 8),
4545 (mz_uint8)*pLen_out,
4546 0x49,
4547 0x44,
4548 0x41,
4549 0x54};
4550 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);
4551 for (i = 0; i < 4; ++i, c <<= 8)
4552 ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);
4553 memcpy(out_buf.m_pBuf, pnghdr, 41);
4554 }
4555 // write footer (IDAT CRC-32, followed by IEND chunk)
4556 if (!tdefl_output_buffer_putter(
4557 "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) {
4558 *pLen_out = 0;
4559 MZ_FREE(pComp);
4560 MZ_FREE(out_buf.m_pBuf);
4561 return NULL;
4562 }
4563 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4,
4564 *pLen_out + 4);
4565 for (i = 0; i < 4; ++i, c <<= 8)
4566 (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);
4567 // compute final size of file, grab compressed data buffer and return
4568 *pLen_out += 57;
4569 MZ_FREE(pComp);
4570 return out_buf.m_pBuf;
4571 }
tdefl_write_image_to_png_file_in_memory(const void * pImage,int w,int h,int num_chans,size_t * pLen_out)4572 void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
4573 int num_chans, size_t *pLen_out) {
4574 // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we
4575 // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's
4576 // where #defined out)
4577 return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans,
4578 pLen_out, 6, MZ_FALSE);
4579 }
4580
4581 // ------------------- .ZIP archive reading
4582
4583 #ifndef MINIZ_NO_ARCHIVE_APIS
4584 #error "No arvhive APIs"
4585
4586 #ifdef MINIZ_NO_STDIO
4587 #define MZ_FILE void *
4588 #else
4589 #include <stdio.h>
4590 #include <sys/stat.h>
4591
4592 #if defined(_MSC_VER) || defined(__MINGW64__)
mz_fopen(const char * pFilename,const char * pMode)4593 static FILE *mz_fopen(const char *pFilename, const char *pMode) {
4594 FILE *pFile = NULL;
4595 fopen_s(&pFile, pFilename, pMode);
4596 return pFile;
4597 }
mz_freopen(const char * pPath,const char * pMode,FILE * pStream)4598 static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) {
4599 FILE *pFile = NULL;
4600 if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL;
4601 return pFile;
4602 }
4603 #ifndef MINIZ_NO_TIME
4604 #include <sys/utime.h>
4605 #endif
4606 #define MZ_FILE FILE
4607 #define MZ_FOPEN mz_fopen
4608 #define MZ_FCLOSE fclose
4609 #define MZ_FREAD fread
4610 #define MZ_FWRITE fwrite
4611 #define MZ_FTELL64 _ftelli64
4612 #define MZ_FSEEK64 _fseeki64
4613 #define MZ_FILE_STAT_STRUCT _stat
4614 #define MZ_FILE_STAT _stat
4615 #define MZ_FFLUSH fflush
4616 #define MZ_FREOPEN mz_freopen
4617 #define MZ_DELETE_FILE remove
4618 #elif defined(__MINGW32__)
4619 #ifndef MINIZ_NO_TIME
4620 #include <sys/utime.h>
4621 #endif
4622 #define MZ_FILE FILE
4623 #define MZ_FOPEN(f, m) fopen(f, m)
4624 #define MZ_FCLOSE fclose
4625 #define MZ_FREAD fread
4626 #define MZ_FWRITE fwrite
4627 #define MZ_FTELL64 ftello64
4628 #define MZ_FSEEK64 fseeko64
4629 #define MZ_FILE_STAT_STRUCT _stat
4630 #define MZ_FILE_STAT _stat
4631 #define MZ_FFLUSH fflush
4632 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4633 #define MZ_DELETE_FILE remove
4634 #elif defined(__TINYC__)
4635 #ifndef MINIZ_NO_TIME
4636 #include <sys/utime.h>
4637 #endif
4638 #define MZ_FILE FILE
4639 #define MZ_FOPEN(f, m) fopen(f, m)
4640 #define MZ_FCLOSE fclose
4641 #define MZ_FREAD fread
4642 #define MZ_FWRITE fwrite
4643 #define MZ_FTELL64 ftell
4644 #define MZ_FSEEK64 fseek
4645 #define MZ_FILE_STAT_STRUCT stat
4646 #define MZ_FILE_STAT stat
4647 #define MZ_FFLUSH fflush
4648 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4649 #define MZ_DELETE_FILE remove
4650 #elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) && _LARGEFILE64_SOURCE
4651 #ifndef MINIZ_NO_TIME
4652 #include <utime.h>
4653 #endif
4654 #define MZ_FILE FILE
4655 #define MZ_FOPEN(f, m) fopen64(f, m)
4656 #define MZ_FCLOSE fclose
4657 #define MZ_FREAD fread
4658 #define MZ_FWRITE fwrite
4659 #define MZ_FTELL64 ftello64
4660 #define MZ_FSEEK64 fseeko64
4661 #define MZ_FILE_STAT_STRUCT stat64
4662 #define MZ_FILE_STAT stat64
4663 #define MZ_FFLUSH fflush
4664 #define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
4665 #define MZ_DELETE_FILE remove
4666 #else
4667 #ifndef MINIZ_NO_TIME
4668 #include <utime.h>
4669 #endif
4670 #define MZ_FILE FILE
4671 #define MZ_FOPEN(f, m) fopen(f, m)
4672 #define MZ_FCLOSE fclose
4673 #define MZ_FREAD fread
4674 #define MZ_FWRITE fwrite
4675 #define MZ_FTELL64 ftello
4676 #define MZ_FSEEK64 fseeko
4677 #define MZ_FILE_STAT_STRUCT stat
4678 #define MZ_FILE_STAT stat
4679 #define MZ_FFLUSH fflush
4680 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4681 #define MZ_DELETE_FILE remove
4682 #endif // #ifdef _MSC_VER
4683 #endif // #ifdef MINIZ_NO_STDIO
4684
4685 #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
4686
4687 // Various ZIP archive enums. To completely avoid cross platform compiler
4688 // alignment and platform endian issues, miniz.c doesn't use structs for any of
4689 // this stuff.
4690 enum {
4691 // ZIP archive identifiers and record sizes
4692 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,
4693 MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,
4694 MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
4695 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
4696 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
4697 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
4698 // Central directory header record offsets
4699 MZ_ZIP_CDH_SIG_OFS = 0,
4700 MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
4701 MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,
4702 MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
4703 MZ_ZIP_CDH_METHOD_OFS = 10,
4704 MZ_ZIP_CDH_FILE_TIME_OFS = 12,
4705 MZ_ZIP_CDH_FILE_DATE_OFS = 14,
4706 MZ_ZIP_CDH_CRC32_OFS = 16,
4707 MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,
4708 MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,
4709 MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,
4710 MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
4711 MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,
4712 MZ_ZIP_CDH_DISK_START_OFS = 34,
4713 MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,
4714 MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,
4715 MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
4716 // Local directory header offsets
4717 MZ_ZIP_LDH_SIG_OFS = 0,
4718 MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,
4719 MZ_ZIP_LDH_BIT_FLAG_OFS = 6,
4720 MZ_ZIP_LDH_METHOD_OFS = 8,
4721 MZ_ZIP_LDH_FILE_TIME_OFS = 10,
4722 MZ_ZIP_LDH_FILE_DATE_OFS = 12,
4723 MZ_ZIP_LDH_CRC32_OFS = 14,
4724 MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,
4725 MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
4726 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,
4727 MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
4728 // End of central directory offsets
4729 MZ_ZIP_ECDH_SIG_OFS = 0,
4730 MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,
4731 MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,
4732 MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
4733 MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,
4734 MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
4735 MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
4736 MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
4737 };
4738
4739 typedef struct {
4740 void *m_p;
4741 size_t m_size, m_capacity;
4742 mz_uint m_element_size;
4743 } mz_zip_array;
4744
4745 struct mz_zip_internal_state_tag {
4746 mz_zip_array m_central_dir;
4747 mz_zip_array m_central_dir_offsets;
4748 mz_zip_array m_sorted_central_dir_offsets;
4749 MZ_FILE *m_pFile;
4750 void *m_pMem;
4751 size_t m_mem_size;
4752 size_t m_mem_capacity;
4753 };
4754
4755 #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \
4756 (array_ptr)->m_element_size = element_size
4757 #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \
4758 ((element_type *)((array_ptr)->m_p))[index]
4759
mz_zip_array_clear(mz_zip_archive * pZip,mz_zip_array * pArray)4760 static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip,
4761 mz_zip_array *pArray) {
4762 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
4763 memset(pArray, 0, sizeof(mz_zip_array));
4764 }
4765
mz_zip_array_ensure_capacity(mz_zip_archive * pZip,mz_zip_array * pArray,size_t min_new_capacity,mz_uint growing)4766 static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip,
4767 mz_zip_array *pArray,
4768 size_t min_new_capacity,
4769 mz_uint growing) {
4770 void *pNew_p;
4771 size_t new_capacity = min_new_capacity;
4772 MZ_ASSERT(pArray->m_element_size);
4773 if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE;
4774 if (growing) {
4775 new_capacity = MZ_MAX(1, pArray->m_capacity);
4776 while (new_capacity < min_new_capacity) new_capacity *= 2;
4777 }
4778 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p,
4779 pArray->m_element_size, new_capacity)))
4780 return MZ_FALSE;
4781 pArray->m_p = pNew_p;
4782 pArray->m_capacity = new_capacity;
4783 return MZ_TRUE;
4784 }
4785
mz_zip_array_reserve(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_capacity,mz_uint growing)4786 static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip,
4787 mz_zip_array *pArray,
4788 size_t new_capacity,
4789 mz_uint growing) {
4790 if (new_capacity > pArray->m_capacity) {
4791 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
4792 return MZ_FALSE;
4793 }
4794 return MZ_TRUE;
4795 }
4796
mz_zip_array_resize(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_size,mz_uint growing)4797 static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip,
4798 mz_zip_array *pArray,
4799 size_t new_size,
4800 mz_uint growing) {
4801 if (new_size > pArray->m_capacity) {
4802 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
4803 return MZ_FALSE;
4804 }
4805 pArray->m_size = new_size;
4806 return MZ_TRUE;
4807 }
4808
mz_zip_array_ensure_room(mz_zip_archive * pZip,mz_zip_array * pArray,size_t n)4809 static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip,
4810 mz_zip_array *pArray,
4811 size_t n) {
4812 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
4813 }
4814
mz_zip_array_push_back(mz_zip_archive * pZip,mz_zip_array * pArray,const void * pElements,size_t n)4815 static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip,
4816 mz_zip_array *pArray,
4817 const void *pElements,
4818 size_t n) {
4819 size_t orig_size = pArray->m_size;
4820 if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))
4821 return MZ_FALSE;
4822 memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size,
4823 pElements, n * pArray->m_element_size);
4824 return MZ_TRUE;
4825 }
4826
4827 #ifndef MINIZ_NO_TIME
mz_zip_dos_to_time_t(int dos_time,int dos_date)4828 static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) {
4829 struct tm tm;
4830 memset(&tm, 0, sizeof(tm));
4831 tm.tm_isdst = -1;
4832 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;
4833 tm.tm_mon = ((dos_date >> 5) & 15) - 1;
4834 tm.tm_mday = dos_date & 31;
4835 tm.tm_hour = (dos_time >> 11) & 31;
4836 tm.tm_min = (dos_time >> 5) & 63;
4837 tm.tm_sec = (dos_time << 1) & 62;
4838 return mktime(&tm);
4839 }
4840
mz_zip_time_to_dos_time(time_t time,mz_uint16 * pDOS_time,mz_uint16 * pDOS_date)4841 static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time,
4842 mz_uint16 *pDOS_date) {
4843 #ifdef _MSC_VER
4844 struct tm tm_struct;
4845 struct tm *tm = &tm_struct;
4846 errno_t err = localtime_s(tm, &time);
4847 if (err) {
4848 *pDOS_date = 0;
4849 *pDOS_time = 0;
4850 return;
4851 }
4852 #else
4853 struct tm *tm = localtime(&time);
4854 #endif
4855 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) +
4856 ((tm->tm_sec) >> 1));
4857 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) +
4858 ((tm->tm_mon + 1) << 5) + tm->tm_mday);
4859 }
4860 #endif
4861
4862 #ifndef MINIZ_NO_STDIO
mz_zip_get_file_modified_time(const char * pFilename,mz_uint16 * pDOS_time,mz_uint16 * pDOS_date)4863 static mz_bool mz_zip_get_file_modified_time(const char *pFilename,
4864 mz_uint16 *pDOS_time,
4865 mz_uint16 *pDOS_date) {
4866 #ifdef MINIZ_NO_TIME
4867 (void)pFilename;
4868 *pDOS_date = *pDOS_time = 0;
4869 #else
4870 struct MZ_FILE_STAT_STRUCT file_stat;
4871 // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000
4872 // bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh.
4873 if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE;
4874 mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date);
4875 #endif // #ifdef MINIZ_NO_TIME
4876 return MZ_TRUE;
4877 }
4878
4879 #ifndef MINIZ_NO_TIME
mz_zip_set_file_times(const char * pFilename,time_t access_time,time_t modified_time)4880 static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
4881 time_t modified_time) {
4882 struct utimbuf t;
4883 t.actime = access_time;
4884 t.modtime = modified_time;
4885 return !utime(pFilename, &t);
4886 }
4887 #endif // #ifndef MINIZ_NO_TIME
4888 #endif // #ifndef MINIZ_NO_STDIO
4889
mz_zip_reader_init_internal(mz_zip_archive * pZip,mz_uint32 flags)4890 static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
4891 mz_uint32 flags) {
4892 (void)flags;
4893 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
4894 return MZ_FALSE;
4895
4896 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
4897 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
4898 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
4899
4900 pZip->m_zip_mode = MZ_ZIP_MODE_READING;
4901 pZip->m_archive_size = 0;
4902 pZip->m_central_directory_file_ofs = 0;
4903 pZip->m_total_files = 0;
4904
4905 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
4906 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
4907 return MZ_FALSE;
4908 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
4909 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
4910 sizeof(mz_uint8));
4911 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
4912 sizeof(mz_uint32));
4913 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
4914 sizeof(mz_uint32));
4915 return MZ_TRUE;
4916 }
4917
4918 static MZ_FORCEINLINE mz_bool
mz_zip_reader_filename_less(const mz_zip_array * pCentral_dir_array,const mz_zip_array * pCentral_dir_offsets,mz_uint l_index,mz_uint r_index)4919 mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array,
4920 const mz_zip_array *pCentral_dir_offsets,
4921 mz_uint l_index, mz_uint r_index) {
4922 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
4923 pCentral_dir_array, mz_uint8,
4924 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
4925 l_index)),
4926 *pE;
4927 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(
4928 pCentral_dir_array, mz_uint8,
4929 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
4930 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS),
4931 r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4932 mz_uint8 l = 0, r = 0;
4933 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4934 pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4935 pE = pL + MZ_MIN(l_len, r_len);
4936 while (pL < pE) {
4937 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break;
4938 pL++;
4939 pR++;
4940 }
4941 return (pL == pE) ? (l_len < r_len) : (l < r);
4942 }
4943
4944 #define MZ_SWAP_UINT32(a, b) \
4945 do { \
4946 mz_uint32 t = a; \
4947 a = b; \
4948 b = t; \
4949 } \
4950 MZ_MACRO_END
4951
4952 // Heap sort of lowercased filenames, used to help accelerate plain central
4953 // directory searches by mz_zip_reader_locate_file(). (Could also use qsort(),
4954 // but it could allocate memory.)
mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive * pZip)4955 static void mz_zip_reader_sort_central_dir_offsets_by_filename(
4956 mz_zip_archive *pZip) {
4957 mz_zip_internal_state *pState = pZip->m_pState;
4958 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
4959 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
4960 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
4961 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
4962 const int size = pZip->m_total_files;
4963 int start = (size - 2) >> 1, end;
4964 while (start >= 0) {
4965 int child, root = start;
4966 for (;;) {
4967 if ((child = (root << 1) + 1) >= size) break;
4968 child +=
4969 (((child + 1) < size) &&
4970 (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4971 pIndices[child], pIndices[child + 1])));
4972 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4973 pIndices[root], pIndices[child]))
4974 break;
4975 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
4976 root = child;
4977 }
4978 start--;
4979 }
4980
4981 end = size - 1;
4982 while (end > 0) {
4983 int child, root = 0;
4984 MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
4985 for (;;) {
4986 if ((child = (root << 1) + 1) >= end) break;
4987 child +=
4988 (((child + 1) < end) &&
4989 mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4990 pIndices[child], pIndices[child + 1]));
4991 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4992 pIndices[root], pIndices[child]))
4993 break;
4994 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
4995 root = child;
4996 }
4997 end--;
4998 }
4999 }
5000
mz_zip_reader_read_central_dir(mz_zip_archive * pZip,mz_uint32 flags)5001 static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
5002 mz_uint32 flags) {
5003 mz_uint cdir_size, num_this_disk, cdir_disk_index;
5004 mz_uint64 cdir_ofs;
5005 mz_int64 cur_file_ofs;
5006 const mz_uint8 *p;
5007 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
5008 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
5009 mz_bool sort_central_dir =
5010 ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
5011 // Basic sanity checks - reject files which are too small, and check the first
5012 // 4 bytes of the file to make sure a local header is there.
5013 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5014 return MZ_FALSE;
5015 // Find the end of central directory record by scanning the file from the end
5016 // towards the beginning.
5017 cur_file_ofs =
5018 MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
5019 for (;;) {
5020 int i,
5021 n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
5022 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
5023 return MZ_FALSE;
5024 for (i = n - 4; i >= 0; --i)
5025 if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break;
5026 if (i >= 0) {
5027 cur_file_ofs += i;
5028 break;
5029 }
5030 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
5031 (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
5032 return MZ_FALSE;
5033 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
5034 }
5035 // Read and verify the end of central directory record.
5036 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
5037 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
5038 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5039 return MZ_FALSE;
5040 if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
5041 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
5042 ((pZip->m_total_files =
5043 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
5044 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
5045 return MZ_FALSE;
5046
5047 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
5048 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
5049 if (((num_this_disk | cdir_disk_index) != 0) &&
5050 ((num_this_disk != 1) || (cdir_disk_index != 1)))
5051 return MZ_FALSE;
5052
5053 if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
5054 pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
5055 return MZ_FALSE;
5056
5057 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
5058 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE;
5059
5060 pZip->m_central_directory_file_ofs = cdir_ofs;
5061
5062 if (pZip->m_total_files) {
5063 mz_uint i, n;
5064
5065 // Read the entire central directory into a heap block, and allocate another
5066 // heap block to hold the unsorted central dir file record offsets, and
5067 // another to hold the sorted indices.
5068 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
5069 MZ_FALSE)) ||
5070 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
5071 pZip->m_total_files, MZ_FALSE)))
5072 return MZ_FALSE;
5073
5074 if (sort_central_dir) {
5075 if (!mz_zip_array_resize(pZip,
5076 &pZip->m_pState->m_sorted_central_dir_offsets,
5077 pZip->m_total_files, MZ_FALSE))
5078 return MZ_FALSE;
5079 }
5080
5081 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
5082 pZip->m_pState->m_central_dir.m_p,
5083 cdir_size) != cdir_size)
5084 return MZ_FALSE;
5085
5086 // Now create an index into the central directory file records, do some
5087 // basic sanity checking on each record, and check for zip64 entries (which
5088 // are not yet supported).
5089 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
5090 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
5091 mz_uint total_header_size, comp_size, decomp_size, disk_index;
5092 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
5093 (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
5094 return MZ_FALSE;
5095 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5096 i) =
5097 (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
5098 if (sort_central_dir)
5099 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
5100 mz_uint32, i) = i;
5101 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5102 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5103 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
5104 (decomp_size != comp_size)) ||
5105 (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
5106 (comp_size == 0xFFFFFFFF))
5107 return MZ_FALSE;
5108 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
5109 if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE;
5110 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
5111 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
5112 return MZ_FALSE;
5113 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5114 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
5115 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
5116 MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
5117 n)
5118 return MZ_FALSE;
5119 n -= total_header_size;
5120 p += total_header_size;
5121 }
5122 }
5123
5124 if (sort_central_dir)
5125 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
5126
5127 return MZ_TRUE;
5128 }
5129
mz_zip_reader_init(mz_zip_archive * pZip,mz_uint64 size,mz_uint32 flags)5130 mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
5131 mz_uint32 flags) {
5132 if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE;
5133 if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE;
5134 pZip->m_archive_size = size;
5135 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5136 mz_zip_reader_end(pZip);
5137 return MZ_FALSE;
5138 }
5139 return MZ_TRUE;
5140 }
5141
mz_zip_mem_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)5142 static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs,
5143 void *pBuf, size_t n) {
5144 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5145 size_t s = (file_ofs >= pZip->m_archive_size)
5146 ? 0
5147 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
5148 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
5149 return s;
5150 }
5151
mz_zip_reader_init_mem(mz_zip_archive * pZip,const void * pMem,size_t size,mz_uint32 flags)5152 mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
5153 size_t size, mz_uint32 flags) {
5154 if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE;
5155 pZip->m_archive_size = size;
5156 pZip->m_pRead = mz_zip_mem_read_func;
5157 pZip->m_pIO_opaque = pZip;
5158 #ifdef __cplusplus
5159 pZip->m_pState->m_pMem = const_cast<void *>(pMem);
5160 #else
5161 pZip->m_pState->m_pMem = (void *)pMem;
5162 #endif
5163 pZip->m_pState->m_mem_size = size;
5164 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5165 mz_zip_reader_end(pZip);
5166 return MZ_FALSE;
5167 }
5168 return MZ_TRUE;
5169 }
5170
5171 #ifndef MINIZ_NO_STDIO
mz_zip_file_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)5172 static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs,
5173 void *pBuf, size_t n) {
5174 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5175 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
5176 if (((mz_int64)file_ofs < 0) ||
5177 (((cur_ofs != (mz_int64)file_ofs)) &&
5178 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
5179 return 0;
5180 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
5181 }
5182
mz_zip_reader_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint32 flags)5183 mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
5184 mz_uint32 flags) {
5185 mz_uint64 file_size;
5186 MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb");
5187 if (!pFile) return MZ_FALSE;
5188 if (MZ_FSEEK64(pFile, 0, SEEK_END)) {
5189 MZ_FCLOSE(pFile);
5190 return MZ_FALSE;
5191 }
5192 file_size = MZ_FTELL64(pFile);
5193 if (!mz_zip_reader_init_internal(pZip, flags)) {
5194 MZ_FCLOSE(pFile);
5195 return MZ_FALSE;
5196 }
5197 pZip->m_pRead = mz_zip_file_read_func;
5198 pZip->m_pIO_opaque = pZip;
5199 pZip->m_pState->m_pFile = pFile;
5200 pZip->m_archive_size = file_size;
5201 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5202 mz_zip_reader_end(pZip);
5203 return MZ_FALSE;
5204 }
5205 return MZ_TRUE;
5206 }
5207 #endif // #ifndef MINIZ_NO_STDIO
5208
mz_zip_reader_get_num_files(mz_zip_archive * pZip)5209 mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) {
5210 return pZip ? pZip->m_total_files : 0;
5211 }
5212
mz_zip_reader_get_cdh(mz_zip_archive * pZip,mz_uint file_index)5213 static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(
5214 mz_zip_archive *pZip, mz_uint file_index) {
5215 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) ||
5216 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5217 return NULL;
5218 return &MZ_ZIP_ARRAY_ELEMENT(
5219 &pZip->m_pState->m_central_dir, mz_uint8,
5220 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5221 file_index));
5222 }
5223
mz_zip_reader_is_file_encrypted(mz_zip_archive * pZip,mz_uint file_index)5224 mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
5225 mz_uint file_index) {
5226 mz_uint m_bit_flag;
5227 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5228 if (!p) return MZ_FALSE;
5229 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
5230 return (m_bit_flag & 1);
5231 }
5232
mz_zip_reader_is_file_a_directory(mz_zip_archive * pZip,mz_uint file_index)5233 mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
5234 mz_uint file_index) {
5235 mz_uint filename_len, external_attr;
5236 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5237 if (!p) return MZ_FALSE;
5238
5239 // First see if the filename ends with a '/' character.
5240 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5241 if (filename_len) {
5242 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
5243 return MZ_TRUE;
5244 }
5245
5246 // Bugfix: This code was also checking if the internal attribute was non-zero,
5247 // which wasn't correct.
5248 // Most/all zip writers (hopefully) set DOS file/directory attributes in the
5249 // low 16-bits, so check for the DOS directory flag and ignore the source OS
5250 // ID in the created by field.
5251 // FIXME: Remove this check? Is it necessary - we already check the filename.
5252 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5253 if ((external_attr & 0x10) != 0) return MZ_TRUE;
5254
5255 return MZ_FALSE;
5256 }
5257
mz_zip_reader_file_stat(mz_zip_archive * pZip,mz_uint file_index,mz_zip_archive_file_stat * pStat)5258 mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
5259 mz_zip_archive_file_stat *pStat) {
5260 mz_uint n;
5261 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5262 if ((!p) || (!pStat)) return MZ_FALSE;
5263
5264 // Unpack the central directory record.
5265 pStat->m_file_index = file_index;
5266 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(
5267 &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
5268 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
5269 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
5270 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
5271 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
5272 #ifndef MINIZ_NO_TIME
5273 pStat->m_time =
5274 mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS),
5275 MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
5276 #endif
5277 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
5278 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5279 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5280 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
5281 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5282 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
5283
5284 // Copy as much of the filename and comment as possible.
5285 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5286 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
5287 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
5288 pStat->m_filename[n] = '\0';
5289
5290 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
5291 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
5292 pStat->m_comment_size = n;
5293 memcpy(pStat->m_comment,
5294 p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5295 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
5296 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
5297 n);
5298 pStat->m_comment[n] = '\0';
5299
5300 return MZ_TRUE;
5301 }
5302
mz_zip_reader_get_filename(mz_zip_archive * pZip,mz_uint file_index,char * pFilename,mz_uint filename_buf_size)5303 mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
5304 char *pFilename, mz_uint filename_buf_size) {
5305 mz_uint n;
5306 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5307 if (!p) {
5308 if (filename_buf_size) pFilename[0] = '\0';
5309 return 0;
5310 }
5311 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5312 if (filename_buf_size) {
5313 n = MZ_MIN(n, filename_buf_size - 1);
5314 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
5315 pFilename[n] = '\0';
5316 }
5317 return n + 1;
5318 }
5319
mz_zip_reader_string_equal(const char * pA,const char * pB,mz_uint len,mz_uint flags)5320 static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA,
5321 const char *pB,
5322 mz_uint len,
5323 mz_uint flags) {
5324 mz_uint i;
5325 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len);
5326 for (i = 0; i < len; ++i)
5327 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE;
5328 return MZ_TRUE;
5329 }
5330
mz_zip_reader_filename_compare(const mz_zip_array * pCentral_dir_array,const mz_zip_array * pCentral_dir_offsets,mz_uint l_index,const char * pR,mz_uint r_len)5331 static MZ_FORCEINLINE int mz_zip_reader_filename_compare(
5332 const mz_zip_array *pCentral_dir_array,
5333 const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR,
5334 mz_uint r_len) {
5335 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
5336 pCentral_dir_array, mz_uint8,
5337 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
5338 l_index)),
5339 *pE;
5340 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5341 mz_uint8 l = 0, r = 0;
5342 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5343 pE = pL + MZ_MIN(l_len, r_len);
5344 while (pL < pE) {
5345 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break;
5346 pL++;
5347 pR++;
5348 }
5349 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
5350 }
5351
mz_zip_reader_locate_file_binary_search(mz_zip_archive * pZip,const char * pFilename)5352 static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip,
5353 const char *pFilename) {
5354 mz_zip_internal_state *pState = pZip->m_pState;
5355 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
5356 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
5357 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
5358 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
5359 const int size = pZip->m_total_files;
5360 const mz_uint filename_len = (mz_uint)strlen(pFilename);
5361 int l = 0, h = size - 1;
5362 while (l <= h) {
5363 int m = (l + h) >> 1, file_index = pIndices[m],
5364 comp =
5365 mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets,
5366 file_index, pFilename, filename_len);
5367 if (!comp)
5368 return file_index;
5369 else if (comp < 0)
5370 l = m + 1;
5371 else
5372 h = m - 1;
5373 }
5374 return -1;
5375 }
5376
mz_zip_reader_locate_file(mz_zip_archive * pZip,const char * pName,const char * pComment,mz_uint flags)5377 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
5378 const char *pComment, mz_uint flags) {
5379 mz_uint file_index;
5380 size_t name_len, comment_len;
5381 if ((!pZip) || (!pZip->m_pState) || (!pName) ||
5382 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5383 return -1;
5384 if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) &&
5385 (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
5386 return mz_zip_reader_locate_file_binary_search(pZip, pName);
5387 name_len = strlen(pName);
5388 if (name_len > 0xFFFF) return -1;
5389 comment_len = pComment ? strlen(pComment) : 0;
5390 if (comment_len > 0xFFFF) return -1;
5391 for (file_index = 0; file_index < pZip->m_total_files; file_index++) {
5392 const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(
5393 &pZip->m_pState->m_central_dir, mz_uint8,
5394 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5395 file_index));
5396 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5397 const char *pFilename =
5398 (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5399 if (filename_len < name_len) continue;
5400 if (comment_len) {
5401 mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS),
5402 file_comment_len =
5403 MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
5404 const char *pFile_comment = pFilename + filename_len + file_extra_len;
5405 if ((file_comment_len != comment_len) ||
5406 (!mz_zip_reader_string_equal(pComment, pFile_comment,
5407 file_comment_len, flags)))
5408 continue;
5409 }
5410 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) {
5411 int ofs = filename_len - 1;
5412 do {
5413 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') ||
5414 (pFilename[ofs] == ':'))
5415 break;
5416 } while (--ofs >= 0);
5417 ofs++;
5418 pFilename += ofs;
5419 filename_len -= ofs;
5420 }
5421 if ((filename_len == name_len) &&
5422 (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
5423 return file_index;
5424 }
5425 return -1;
5426 }
5427
mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive * pZip,mz_uint file_index,void * pBuf,size_t buf_size,mz_uint flags,void * pUser_read_buf,size_t user_read_buf_size)5428 mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
5429 mz_uint file_index, void *pBuf,
5430 size_t buf_size, mz_uint flags,
5431 void *pUser_read_buf,
5432 size_t user_read_buf_size) {
5433 int status = TINFL_STATUS_DONE;
5434 mz_uint64 needed_size, cur_file_ofs, comp_remaining,
5435 out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
5436 mz_zip_archive_file_stat file_stat;
5437 void *pRead_buf;
5438 mz_uint32
5439 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5440 sizeof(mz_uint32)];
5441 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5442 tinfl_decompressor inflator;
5443
5444 if ((buf_size) && (!pBuf)) return MZ_FALSE;
5445
5446 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
5447
5448 // Empty file, or a directory (but not always a directory - I've seen odd zips
5449 // with directories that have compressed data which inflates to 0 bytes)
5450 if (!file_stat.m_comp_size) return MZ_TRUE;
5451
5452 // Entry is a subdirectory (I've seen old zips with dir entries which have
5453 // compressed deflate data which inflates to 0 bytes, but these entries claim
5454 // to uncompress to 512 bytes in the headers).
5455 // I'm torn how to handle this case - should it fail instead?
5456 if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE;
5457
5458 // Encryption and patch files are not supported.
5459 if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE;
5460
5461 // This function only supports stored and deflate.
5462 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
5463 (file_stat.m_method != MZ_DEFLATED))
5464 return MZ_FALSE;
5465
5466 // Ensure supplied output buffer is large enough.
5467 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size
5468 : file_stat.m_uncomp_size;
5469 if (buf_size < needed_size) return MZ_FALSE;
5470
5471 // Read and parse the local directory entry.
5472 cur_file_ofs = file_stat.m_local_header_ofs;
5473 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
5474 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5475 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5476 return MZ_FALSE;
5477 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5478 return MZ_FALSE;
5479
5480 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5481 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5482 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5483 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
5484 return MZ_FALSE;
5485
5486 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
5487 // The file is stored or the caller has requested the compressed data.
5488 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
5489 (size_t)needed_size) != needed_size)
5490 return MZ_FALSE;
5491 return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) ||
5492 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
5493 (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32);
5494 }
5495
5496 // Decompress the file either directly from memory or from a file input
5497 // buffer.
5498 tinfl_init(&inflator);
5499
5500 if (pZip->m_pState->m_pMem) {
5501 // Read directly from the archive in memory.
5502 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
5503 read_buf_size = read_buf_avail = file_stat.m_comp_size;
5504 comp_remaining = 0;
5505 } else if (pUser_read_buf) {
5506 // Use a user provided read buffer.
5507 if (!user_read_buf_size) return MZ_FALSE;
5508 pRead_buf = (mz_uint8 *)pUser_read_buf;
5509 read_buf_size = user_read_buf_size;
5510 read_buf_avail = 0;
5511 comp_remaining = file_stat.m_comp_size;
5512 } else {
5513 // Temporarily allocate a read buffer.
5514 read_buf_size =
5515 MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
5516 #ifdef _MSC_VER
5517 if (((0, sizeof(size_t) == sizeof(mz_uint32))) &&
5518 (read_buf_size > 0x7FFFFFFF))
5519 #else
5520 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
5521 #endif
5522 return MZ_FALSE;
5523 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5524 (size_t)read_buf_size)))
5525 return MZ_FALSE;
5526 read_buf_avail = 0;
5527 comp_remaining = file_stat.m_comp_size;
5528 }
5529
5530 do {
5531 size_t in_buf_size,
5532 out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
5533 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
5534 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5535 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5536 (size_t)read_buf_avail) != read_buf_avail) {
5537 status = TINFL_STATUS_FAILED;
5538 break;
5539 }
5540 cur_file_ofs += read_buf_avail;
5541 comp_remaining -= read_buf_avail;
5542 read_buf_ofs = 0;
5543 }
5544 in_buf_size = (size_t)read_buf_avail;
5545 status = tinfl_decompress(
5546 &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
5547 (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size,
5548 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF |
5549 (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
5550 read_buf_avail -= in_buf_size;
5551 read_buf_ofs += in_buf_size;
5552 out_buf_ofs += out_buf_size;
5553 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
5554
5555 if (status == TINFL_STATUS_DONE) {
5556 // Make sure the entire file was decompressed, and check its CRC.
5557 if ((out_buf_ofs != file_stat.m_uncomp_size) ||
5558 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
5559 (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32))
5560 status = TINFL_STATUS_FAILED;
5561 }
5562
5563 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
5564 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
5565
5566 return status == TINFL_STATUS_DONE;
5567 }
5568
mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive * pZip,const char * pFilename,void * pBuf,size_t buf_size,mz_uint flags,void * pUser_read_buf,size_t user_read_buf_size)5569 mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
5570 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
5571 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) {
5572 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5573 if (file_index < 0) return MZ_FALSE;
5574 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
5575 flags, pUser_read_buf,
5576 user_read_buf_size);
5577 }
5578
mz_zip_reader_extract_to_mem(mz_zip_archive * pZip,mz_uint file_index,void * pBuf,size_t buf_size,mz_uint flags)5579 mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
5580 void *pBuf, size_t buf_size,
5581 mz_uint flags) {
5582 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
5583 flags, NULL, 0);
5584 }
5585
mz_zip_reader_extract_file_to_mem(mz_zip_archive * pZip,const char * pFilename,void * pBuf,size_t buf_size,mz_uint flags)5586 mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
5587 const char *pFilename, void *pBuf,
5588 size_t buf_size, mz_uint flags) {
5589 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf,
5590 buf_size, flags, NULL, 0);
5591 }
5592
mz_zip_reader_extract_to_heap(mz_zip_archive * pZip,mz_uint file_index,size_t * pSize,mz_uint flags)5593 void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
5594 size_t *pSize, mz_uint flags) {
5595 mz_uint64 comp_size, uncomp_size, alloc_size;
5596 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5597 void *pBuf;
5598
5599 if (pSize) *pSize = 0;
5600 if (!p) return NULL;
5601
5602 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5603 uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5604
5605 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
5606 #ifdef _MSC_VER
5607 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
5608 #else
5609 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
5610 #endif
5611 return NULL;
5612 if (NULL ==
5613 (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
5614 return NULL;
5615
5616 if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size,
5617 flags)) {
5618 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
5619 return NULL;
5620 }
5621
5622 if (pSize) *pSize = (size_t)alloc_size;
5623 return pBuf;
5624 }
5625
mz_zip_reader_extract_file_to_heap(mz_zip_archive * pZip,const char * pFilename,size_t * pSize,mz_uint flags)5626 void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
5627 const char *pFilename, size_t *pSize,
5628 mz_uint flags) {
5629 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5630 if (file_index < 0) {
5631 if (pSize) *pSize = 0;
5632 return MZ_FALSE;
5633 }
5634 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
5635 }
5636
mz_zip_reader_extract_to_callback(mz_zip_archive * pZip,mz_uint file_index,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)5637 mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
5638 mz_uint file_index,
5639 mz_file_write_func pCallback,
5640 void *pOpaque, mz_uint flags) {
5641 int status = TINFL_STATUS_DONE;
5642 mz_uint file_crc32 = MZ_CRC32_INIT;
5643 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining,
5644 out_buf_ofs = 0, cur_file_ofs;
5645 mz_zip_archive_file_stat file_stat;
5646 void *pRead_buf = NULL;
5647 void *pWrite_buf = NULL;
5648 mz_uint32
5649 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5650 sizeof(mz_uint32)];
5651 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5652
5653 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
5654
5655 // Empty file, or a directory (but not always a directory - I've seen odd zips
5656 // with directories that have compressed data which inflates to 0 bytes)
5657 if (!file_stat.m_comp_size) return MZ_TRUE;
5658
5659 // Entry is a subdirectory (I've seen old zips with dir entries which have
5660 // compressed deflate data which inflates to 0 bytes, but these entries claim
5661 // to uncompress to 512 bytes in the headers).
5662 // I'm torn how to handle this case - should it fail instead?
5663 if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE;
5664
5665 // Encryption and patch files are not supported.
5666 if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE;
5667
5668 // This function only supports stored and deflate.
5669 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
5670 (file_stat.m_method != MZ_DEFLATED))
5671 return MZ_FALSE;
5672
5673 // Read and parse the local directory entry.
5674 cur_file_ofs = file_stat.m_local_header_ofs;
5675 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
5676 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5677 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5678 return MZ_FALSE;
5679 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5680 return MZ_FALSE;
5681
5682 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5683 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5684 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5685 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
5686 return MZ_FALSE;
5687
5688 // Decompress the file either directly from memory or from a file input
5689 // buffer.
5690 if (pZip->m_pState->m_pMem) {
5691 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
5692 read_buf_size = read_buf_avail = file_stat.m_comp_size;
5693 comp_remaining = 0;
5694 } else {
5695 read_buf_size =
5696 MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
5697 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5698 (size_t)read_buf_size)))
5699 return MZ_FALSE;
5700 read_buf_avail = 0;
5701 comp_remaining = file_stat.m_comp_size;
5702 }
5703
5704 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
5705 // The file is stored or the caller has requested the compressed data.
5706 if (pZip->m_pState->m_pMem) {
5707 #ifdef _MSC_VER
5708 if (((0, sizeof(size_t) == sizeof(mz_uint32))) &&
5709 (file_stat.m_comp_size > 0xFFFFFFFF))
5710 #else
5711 if (((sizeof(size_t) == sizeof(mz_uint32))) &&
5712 (file_stat.m_comp_size > 0xFFFFFFFF))
5713 #endif
5714 return MZ_FALSE;
5715 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5716 (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
5717 status = TINFL_STATUS_FAILED;
5718 else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
5719 file_crc32 =
5720 (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf,
5721 (size_t)file_stat.m_comp_size);
5722 cur_file_ofs += file_stat.m_comp_size;
5723 out_buf_ofs += file_stat.m_comp_size;
5724 comp_remaining = 0;
5725 } else {
5726 while (comp_remaining) {
5727 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5728 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5729 (size_t)read_buf_avail) != read_buf_avail) {
5730 status = TINFL_STATUS_FAILED;
5731 break;
5732 }
5733
5734 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
5735 file_crc32 = (mz_uint32)mz_crc32(
5736 file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
5737
5738 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5739 (size_t)read_buf_avail) != read_buf_avail) {
5740 status = TINFL_STATUS_FAILED;
5741 break;
5742 }
5743 cur_file_ofs += read_buf_avail;
5744 out_buf_ofs += read_buf_avail;
5745 comp_remaining -= read_buf_avail;
5746 }
5747 }
5748 } else {
5749 tinfl_decompressor inflator;
5750 tinfl_init(&inflator);
5751
5752 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5753 TINFL_LZ_DICT_SIZE)))
5754 status = TINFL_STATUS_FAILED;
5755 else {
5756 do {
5757 mz_uint8 *pWrite_buf_cur =
5758 (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5759 size_t in_buf_size,
5760 out_buf_size =
5761 TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5762 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
5763 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5764 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5765 (size_t)read_buf_avail) != read_buf_avail) {
5766 status = TINFL_STATUS_FAILED;
5767 break;
5768 }
5769 cur_file_ofs += read_buf_avail;
5770 comp_remaining -= read_buf_avail;
5771 read_buf_ofs = 0;
5772 }
5773
5774 in_buf_size = (size_t)read_buf_avail;
5775 status = tinfl_decompress(
5776 &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
5777 (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size,
5778 comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
5779 read_buf_avail -= in_buf_size;
5780 read_buf_ofs += in_buf_size;
5781
5782 if (out_buf_size) {
5783 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) !=
5784 out_buf_size) {
5785 status = TINFL_STATUS_FAILED;
5786 break;
5787 }
5788 file_crc32 =
5789 (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
5790 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) {
5791 status = TINFL_STATUS_FAILED;
5792 break;
5793 }
5794 }
5795 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) ||
5796 (status == TINFL_STATUS_HAS_MORE_OUTPUT));
5797 }
5798 }
5799
5800 if ((status == TINFL_STATUS_DONE) &&
5801 (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) {
5802 // Make sure the entire file was decompressed, and check its CRC.
5803 if ((out_buf_ofs != file_stat.m_uncomp_size) ||
5804 (file_crc32 != file_stat.m_crc32))
5805 status = TINFL_STATUS_FAILED;
5806 }
5807
5808 if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
5809 if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
5810
5811 return status == TINFL_STATUS_DONE;
5812 }
5813
mz_zip_reader_extract_file_to_callback(mz_zip_archive * pZip,const char * pFilename,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)5814 mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
5815 const char *pFilename,
5816 mz_file_write_func pCallback,
5817 void *pOpaque, mz_uint flags) {
5818 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5819 if (file_index < 0) return MZ_FALSE;
5820 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque,
5821 flags);
5822 }
5823
5824 #ifndef MINIZ_NO_STDIO
mz_zip_file_write_callback(void * pOpaque,mz_uint64 ofs,const void * pBuf,size_t n)5825 static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs,
5826 const void *pBuf, size_t n) {
5827 (void)ofs;
5828 return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);
5829 }
5830
mz_zip_reader_extract_to_file(mz_zip_archive * pZip,mz_uint file_index,const char * pDst_filename,mz_uint flags)5831 mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
5832 const char *pDst_filename,
5833 mz_uint flags) {
5834 mz_bool status;
5835 mz_zip_archive_file_stat file_stat;
5836 MZ_FILE *pFile;
5837 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
5838 pFile = MZ_FOPEN(pDst_filename, "wb");
5839 if (!pFile) return MZ_FALSE;
5840 status = mz_zip_reader_extract_to_callback(
5841 pZip, file_index, mz_zip_file_write_callback, pFile, flags);
5842 if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE;
5843 #ifndef MINIZ_NO_TIME
5844 if (status)
5845 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
5846 #endif
5847 return status;
5848 }
5849 #endif // #ifndef MINIZ_NO_STDIO
5850
mz_zip_reader_end(mz_zip_archive * pZip)5851 mz_bool mz_zip_reader_end(mz_zip_archive *pZip) {
5852 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
5853 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5854 return MZ_FALSE;
5855
5856 if (pZip->m_pState) {
5857 mz_zip_internal_state *pState = pZip->m_pState;
5858 pZip->m_pState = NULL;
5859 mz_zip_array_clear(pZip, &pState->m_central_dir);
5860 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
5861 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
5862
5863 #ifndef MINIZ_NO_STDIO
5864 if (pState->m_pFile) {
5865 MZ_FCLOSE(pState->m_pFile);
5866 pState->m_pFile = NULL;
5867 }
5868 #endif // #ifndef MINIZ_NO_STDIO
5869
5870 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5871 }
5872 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
5873
5874 return MZ_TRUE;
5875 }
5876
5877 #ifndef MINIZ_NO_STDIO
mz_zip_reader_extract_file_to_file(mz_zip_archive * pZip,const char * pArchive_filename,const char * pDst_filename,mz_uint flags)5878 mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
5879 const char *pArchive_filename,
5880 const char *pDst_filename,
5881 mz_uint flags) {
5882 int file_index =
5883 mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags);
5884 if (file_index < 0) return MZ_FALSE;
5885 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
5886 }
5887 #endif
5888
5889 // ------------------- .ZIP archive writing
5890
5891 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
5892
mz_write_le16(mz_uint8 * p,mz_uint16 v)5893 static void mz_write_le16(mz_uint8 *p, mz_uint16 v) {
5894 p[0] = (mz_uint8)v;
5895 p[1] = (mz_uint8)(v >> 8);
5896 }
mz_write_le32(mz_uint8 * p,mz_uint32 v)5897 static void mz_write_le32(mz_uint8 *p, mz_uint32 v) {
5898 p[0] = (mz_uint8)v;
5899 p[1] = (mz_uint8)(v >> 8);
5900 p[2] = (mz_uint8)(v >> 16);
5901 p[3] = (mz_uint8)(v >> 24);
5902 }
5903 #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
5904 #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
5905
mz_zip_writer_init(mz_zip_archive * pZip,mz_uint64 existing_size)5906 mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) {
5907 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) ||
5908 (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
5909 return MZ_FALSE;
5910
5911 if (pZip->m_file_offset_alignment) {
5912 // Ensure user specified file offset alignment is a power of 2.
5913 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
5914 return MZ_FALSE;
5915 }
5916
5917 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
5918 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
5919 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
5920
5921 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
5922 pZip->m_archive_size = existing_size;
5923 pZip->m_central_directory_file_ofs = 0;
5924 pZip->m_total_files = 0;
5925
5926 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
5927 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
5928 return MZ_FALSE;
5929 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
5930 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
5931 sizeof(mz_uint8));
5932 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
5933 sizeof(mz_uint32));
5934 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
5935 sizeof(mz_uint32));
5936 return MZ_TRUE;
5937 }
5938
mz_zip_heap_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)5939 static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs,
5940 const void *pBuf, size_t n) {
5941 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5942 mz_zip_internal_state *pState = pZip->m_pState;
5943 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
5944 #ifdef _MSC_VER
5945 if ((!n) ||
5946 ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
5947 #else
5948 if ((!n) ||
5949 ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
5950 #endif
5951 return 0;
5952 if (new_size > pState->m_mem_capacity) {
5953 void *pNew_block;
5954 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);
5955 while (new_capacity < new_size) new_capacity *= 2;
5956 if (NULL == (pNew_block = pZip->m_pRealloc(
5957 pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
5958 return 0;
5959 pState->m_pMem = pNew_block;
5960 pState->m_mem_capacity = new_capacity;
5961 }
5962 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
5963 pState->m_mem_size = (size_t)new_size;
5964 return n;
5965 }
5966
mz_zip_writer_init_heap(mz_zip_archive * pZip,size_t size_to_reserve_at_beginning,size_t initial_allocation_size)5967 mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
5968 size_t size_to_reserve_at_beginning,
5969 size_t initial_allocation_size) {
5970 pZip->m_pWrite = mz_zip_heap_write_func;
5971 pZip->m_pIO_opaque = pZip;
5972 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE;
5973 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size,
5974 size_to_reserve_at_beginning))) {
5975 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(
5976 pZip->m_pAlloc_opaque, 1, initial_allocation_size))) {
5977 mz_zip_writer_end(pZip);
5978 return MZ_FALSE;
5979 }
5980 pZip->m_pState->m_mem_capacity = initial_allocation_size;
5981 }
5982 return MZ_TRUE;
5983 }
5984
5985 #ifndef MINIZ_NO_STDIO
mz_zip_file_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)5986 static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs,
5987 const void *pBuf, size_t n) {
5988 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5989 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
5990 if (((mz_int64)file_ofs < 0) ||
5991 (((cur_ofs != (mz_int64)file_ofs)) &&
5992 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
5993 return 0;
5994 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
5995 }
5996
mz_zip_writer_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint64 size_to_reserve_at_beginning)5997 mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
5998 mz_uint64 size_to_reserve_at_beginning) {
5999 MZ_FILE *pFile;
6000 pZip->m_pWrite = mz_zip_file_write_func;
6001 pZip->m_pIO_opaque = pZip;
6002 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE;
6003 if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) {
6004 mz_zip_writer_end(pZip);
6005 return MZ_FALSE;
6006 }
6007 pZip->m_pState->m_pFile = pFile;
6008 if (size_to_reserve_at_beginning) {
6009 mz_uint64 cur_ofs = 0;
6010 char buf[4096];
6011 MZ_CLEAR_OBJ(buf);
6012 do {
6013 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
6014 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) {
6015 mz_zip_writer_end(pZip);
6016 return MZ_FALSE;
6017 }
6018 cur_ofs += n;
6019 size_to_reserve_at_beginning -= n;
6020 } while (size_to_reserve_at_beginning);
6021 }
6022 return MZ_TRUE;
6023 }
6024 #endif // #ifndef MINIZ_NO_STDIO
6025
mz_zip_writer_init_from_reader(mz_zip_archive * pZip,const char * pFilename)6026 mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
6027 const char *pFilename) {
6028 mz_zip_internal_state *pState;
6029 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
6030 return MZ_FALSE;
6031 // No sense in trying to write to an archive that's already at the support max
6032 // size
6033 if ((pZip->m_total_files == 0xFFFF) ||
6034 ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6035 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
6036 return MZ_FALSE;
6037
6038 pState = pZip->m_pState;
6039
6040 if (pState->m_pFile) {
6041 #ifdef MINIZ_NO_STDIO
6042 pFilename;
6043 return MZ_FALSE;
6044 #else
6045 // Archive is being read from stdio - try to reopen as writable.
6046 if (pZip->m_pIO_opaque != pZip) return MZ_FALSE;
6047 if (!pFilename) return MZ_FALSE;
6048 pZip->m_pWrite = mz_zip_file_write_func;
6049 if (NULL ==
6050 (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) {
6051 // The mz_zip_archive is now in a bogus state because pState->m_pFile is
6052 // NULL, so just close it.
6053 mz_zip_reader_end(pZip);
6054 return MZ_FALSE;
6055 }
6056 #endif // #ifdef MINIZ_NO_STDIO
6057 } else if (pState->m_pMem) {
6058 // Archive lives in a memory block. Assume it's from the heap that we can
6059 // resize using the realloc callback.
6060 if (pZip->m_pIO_opaque != pZip) return MZ_FALSE;
6061 pState->m_mem_capacity = pState->m_mem_size;
6062 pZip->m_pWrite = mz_zip_heap_write_func;
6063 }
6064 // Archive is being read via a user provided read function - make sure the
6065 // user has specified a write function too.
6066 else if (!pZip->m_pWrite)
6067 return MZ_FALSE;
6068
6069 // Start writing new files at the archive's current central directory
6070 // location.
6071 pZip->m_archive_size = pZip->m_central_directory_file_ofs;
6072 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
6073 pZip->m_central_directory_file_ofs = 0;
6074
6075 return MZ_TRUE;
6076 }
6077
mz_zip_writer_add_mem(mz_zip_archive * pZip,const char * pArchive_name,const void * pBuf,size_t buf_size,mz_uint level_and_flags)6078 mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
6079 const void *pBuf, size_t buf_size,
6080 mz_uint level_and_flags) {
6081 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0,
6082 level_and_flags, 0, 0);
6083 }
6084
6085 typedef struct {
6086 mz_zip_archive *m_pZip;
6087 mz_uint64 m_cur_archive_file_ofs;
6088 mz_uint64 m_comp_size;
6089 } mz_zip_writer_add_state;
6090
mz_zip_writer_add_put_buf_callback(const void * pBuf,int len,void * pUser)6091 static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len,
6092 void *pUser) {
6093 mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
6094 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque,
6095 pState->m_cur_archive_file_ofs, pBuf,
6096 len) != len)
6097 return MZ_FALSE;
6098 pState->m_cur_archive_file_ofs += len;
6099 pState->m_comp_size += len;
6100 return MZ_TRUE;
6101 }
6102
mz_zip_writer_create_local_dir_header(mz_zip_archive * pZip,mz_uint8 * pDst,mz_uint16 filename_size,mz_uint16 extra_size,mz_uint64 uncomp_size,mz_uint64 comp_size,mz_uint32 uncomp_crc32,mz_uint16 method,mz_uint16 bit_flags,mz_uint16 dos_time,mz_uint16 dos_date)6103 static mz_bool mz_zip_writer_create_local_dir_header(
6104 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
6105 mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
6106 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
6107 mz_uint16 dos_time, mz_uint16 dos_date) {
6108 (void)pZip;
6109 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
6110 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
6111 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
6112 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
6113 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
6114 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
6115 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
6116 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
6117 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size);
6118 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
6119 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
6120 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
6121 return MZ_TRUE;
6122 }
6123
mz_zip_writer_create_central_dir_header(mz_zip_archive * pZip,mz_uint8 * pDst,mz_uint16 filename_size,mz_uint16 extra_size,mz_uint16 comment_size,mz_uint64 uncomp_size,mz_uint64 comp_size,mz_uint32 uncomp_crc32,mz_uint16 method,mz_uint16 bit_flags,mz_uint16 dos_time,mz_uint16 dos_date,mz_uint64 local_header_ofs,mz_uint32 ext_attributes)6124 static mz_bool mz_zip_writer_create_central_dir_header(
6125 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
6126 mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size,
6127 mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method,
6128 mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
6129 mz_uint64 local_header_ofs, mz_uint32 ext_attributes) {
6130 (void)pZip;
6131 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
6132 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
6133 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
6134 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
6135 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
6136 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
6137 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
6138 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
6139 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size);
6140 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
6141 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
6142 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
6143 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
6144 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
6145 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs);
6146 return MZ_TRUE;
6147 }
6148
mz_zip_writer_add_to_central_dir(mz_zip_archive * pZip,const char * pFilename,mz_uint16 filename_size,const void * pExtra,mz_uint16 extra_size,const void * pComment,mz_uint16 comment_size,mz_uint64 uncomp_size,mz_uint64 comp_size,mz_uint32 uncomp_crc32,mz_uint16 method,mz_uint16 bit_flags,mz_uint16 dos_time,mz_uint16 dos_date,mz_uint64 local_header_ofs,mz_uint32 ext_attributes)6149 static mz_bool mz_zip_writer_add_to_central_dir(
6150 mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,
6151 const void *pExtra, mz_uint16 extra_size, const void *pComment,
6152 mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
6153 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
6154 mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs,
6155 mz_uint32 ext_attributes) {
6156 mz_zip_internal_state *pState = pZip->m_pState;
6157 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
6158 size_t orig_central_dir_size = pState->m_central_dir.m_size;
6159 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6160
6161 // No zip64 support yet
6162 if ((local_header_ofs > 0xFFFFFFFF) ||
6163 (((mz_uint64)pState->m_central_dir.m_size +
6164 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size +
6165 comment_size) > 0xFFFFFFFF))
6166 return MZ_FALSE;
6167
6168 if (!mz_zip_writer_create_central_dir_header(
6169 pZip, central_dir_header, filename_size, extra_size, comment_size,
6170 uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time,
6171 dos_date, local_header_ofs, ext_attributes))
6172 return MZ_FALSE;
6173
6174 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header,
6175 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
6176 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename,
6177 filename_size)) ||
6178 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra,
6179 extra_size)) ||
6180 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment,
6181 comment_size)) ||
6182 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets,
6183 ¢ral_dir_ofs, 1))) {
6184 // Try to push the central directory array back into its original state.
6185 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6186 MZ_FALSE);
6187 return MZ_FALSE;
6188 }
6189
6190 return MZ_TRUE;
6191 }
6192
mz_zip_writer_validate_archive_name(const char * pArchive_name)6193 static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) {
6194 // Basic ZIP archive filename validity checks: Valid filenames cannot start
6195 // with a forward slash, cannot contain a drive letter, and cannot use
6196 // DOS-style backward slashes.
6197 if (*pArchive_name == '/') return MZ_FALSE;
6198 while (*pArchive_name) {
6199 if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE;
6200 pArchive_name++;
6201 }
6202 return MZ_TRUE;
6203 }
6204
mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive * pZip)6205 static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(
6206 mz_zip_archive *pZip) {
6207 mz_uint32 n;
6208 if (!pZip->m_file_offset_alignment) return 0;
6209 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
6210 return (pZip->m_file_offset_alignment - n) &
6211 (pZip->m_file_offset_alignment - 1);
6212 }
6213
mz_zip_writer_write_zeros(mz_zip_archive * pZip,mz_uint64 cur_file_ofs,mz_uint32 n)6214 static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip,
6215 mz_uint64 cur_file_ofs, mz_uint32 n) {
6216 char buf[4096];
6217 memset(buf, 0, MZ_MIN(sizeof(buf), n));
6218 while (n) {
6219 mz_uint32 s = MZ_MIN(sizeof(buf), n);
6220 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
6221 return MZ_FALSE;
6222 cur_file_ofs += s;
6223 n -= s;
6224 }
6225 return MZ_TRUE;
6226 }
6227
mz_zip_writer_add_mem_ex(mz_zip_archive * pZip,const char * pArchive_name,const void * pBuf,size_t buf_size,const void * pComment,mz_uint16 comment_size,mz_uint level_and_flags,mz_uint64 uncomp_size,mz_uint32 uncomp_crc32)6228 mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
6229 const char *pArchive_name, const void *pBuf,
6230 size_t buf_size, const void *pComment,
6231 mz_uint16 comment_size,
6232 mz_uint level_and_flags, mz_uint64 uncomp_size,
6233 mz_uint32 uncomp_crc32) {
6234 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
6235 mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
6236 mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
6237 cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
6238 size_t archive_name_size;
6239 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6240 tdefl_compressor *pComp = NULL;
6241 mz_bool store_data_uncompressed;
6242 mz_zip_internal_state *pState;
6243
6244 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
6245 level = level_and_flags & 0xF;
6246 store_data_uncompressed =
6247 ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
6248
6249 if ((!pZip) || (!pZip->m_pState) ||
6250 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) ||
6251 (!pArchive_name) || ((comment_size) && (!pComment)) ||
6252 (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION))
6253 return MZ_FALSE;
6254
6255 pState = pZip->m_pState;
6256
6257 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
6258 return MZ_FALSE;
6259 // No zip64 support yet
6260 if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE;
6261 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
6262
6263 #ifndef MINIZ_NO_TIME
6264 {
6265 time_t cur_time;
6266 time(&cur_time);
6267 mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date);
6268 }
6269 #endif // #ifndef MINIZ_NO_TIME
6270
6271 archive_name_size = strlen(pArchive_name);
6272 if (archive_name_size > 0xFFFF) return MZ_FALSE;
6273
6274 num_alignment_padding_bytes =
6275 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6276
6277 // no zip64 support yet
6278 if ((pZip->m_total_files == 0xFFFF) ||
6279 ((pZip->m_archive_size + num_alignment_padding_bytes +
6280 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6281 comment_size + archive_name_size) > 0xFFFFFFFF))
6282 return MZ_FALSE;
6283
6284 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) {
6285 // Set DOS Subdirectory attribute bit.
6286 ext_attributes |= 0x10;
6287 // Subdirectories cannot contain data.
6288 if ((buf_size) || (uncomp_size)) return MZ_FALSE;
6289 }
6290
6291 // Try to do any allocations before writing to the archive, so if an
6292 // allocation fails the file remains unmodified. (A good idea if we're doing
6293 // an in-place modification.)
6294 if ((!mz_zip_array_ensure_room(
6295 pZip, &pState->m_central_dir,
6296 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) ||
6297 (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
6298 return MZ_FALSE;
6299
6300 if ((!store_data_uncompressed) && (buf_size)) {
6301 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(
6302 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
6303 return MZ_FALSE;
6304 }
6305
6306 if (!mz_zip_writer_write_zeros(
6307 pZip, cur_archive_file_ofs,
6308 num_alignment_padding_bytes + sizeof(local_dir_header))) {
6309 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6310 return MZ_FALSE;
6311 }
6312 local_dir_header_ofs += num_alignment_padding_bytes;
6313 if (pZip->m_file_offset_alignment) {
6314 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6315 0);
6316 }
6317 cur_archive_file_ofs +=
6318 num_alignment_padding_bytes + sizeof(local_dir_header);
6319
6320 MZ_CLEAR_OBJ(local_dir_header);
6321 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6322 archive_name_size) != archive_name_size) {
6323 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6324 return MZ_FALSE;
6325 }
6326 cur_archive_file_ofs += archive_name_size;
6327
6328 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
6329 uncomp_crc32 =
6330 (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
6331 uncomp_size = buf_size;
6332 if (uncomp_size <= 3) {
6333 level = 0;
6334 store_data_uncompressed = MZ_TRUE;
6335 }
6336 }
6337
6338 if (store_data_uncompressed) {
6339 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf,
6340 buf_size) != buf_size) {
6341 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6342 return MZ_FALSE;
6343 }
6344
6345 cur_archive_file_ofs += buf_size;
6346 comp_size = buf_size;
6347
6348 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED;
6349 } else if (buf_size) {
6350 mz_zip_writer_add_state state;
6351
6352 state.m_pZip = pZip;
6353 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6354 state.m_comp_size = 0;
6355
6356 if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
6357 tdefl_create_comp_flags_from_zip_params(
6358 level, -15, MZ_DEFAULT_STRATEGY)) !=
6359 TDEFL_STATUS_OKAY) ||
6360 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) !=
6361 TDEFL_STATUS_DONE)) {
6362 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6363 return MZ_FALSE;
6364 }
6365
6366 comp_size = state.m_comp_size;
6367 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6368
6369 method = MZ_DEFLATED;
6370 }
6371
6372 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6373 pComp = NULL;
6374
6375 // no zip64 support yet
6376 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
6377 return MZ_FALSE;
6378
6379 if (!mz_zip_writer_create_local_dir_header(
6380 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
6381 comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
6382 return MZ_FALSE;
6383
6384 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
6385 sizeof(local_dir_header)) != sizeof(local_dir_header))
6386 return MZ_FALSE;
6387
6388 if (!mz_zip_writer_add_to_central_dir(
6389 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
6390 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
6391 dos_time, dos_date, local_dir_header_ofs, ext_attributes))
6392 return MZ_FALSE;
6393
6394 pZip->m_total_files++;
6395 pZip->m_archive_size = cur_archive_file_ofs;
6396
6397 return MZ_TRUE;
6398 }
6399
6400 #ifndef MINIZ_NO_STDIO
mz_zip_writer_add_file(mz_zip_archive * pZip,const char * pArchive_name,const char * pSrc_filename,const void * pComment,mz_uint16 comment_size,mz_uint level_and_flags)6401 mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
6402 const char *pSrc_filename, const void *pComment,
6403 mz_uint16 comment_size,
6404 mz_uint level_and_flags) {
6405 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
6406 mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
6407 mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
6408 cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0,
6409 comp_size = 0;
6410 size_t archive_name_size;
6411 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6412 MZ_FILE *pSrc_file = NULL;
6413
6414 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
6415 level = level_and_flags & 0xF;
6416
6417 if ((!pZip) || (!pZip->m_pState) ||
6418 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) ||
6419 ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
6420 return MZ_FALSE;
6421 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE;
6422 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
6423
6424 archive_name_size = strlen(pArchive_name);
6425 if (archive_name_size > 0xFFFF) return MZ_FALSE;
6426
6427 num_alignment_padding_bytes =
6428 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6429
6430 // no zip64 support yet
6431 if ((pZip->m_total_files == 0xFFFF) ||
6432 ((pZip->m_archive_size + num_alignment_padding_bytes +
6433 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6434 comment_size + archive_name_size) > 0xFFFFFFFF))
6435 return MZ_FALSE;
6436
6437 if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date))
6438 return MZ_FALSE;
6439
6440 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
6441 if (!pSrc_file) return MZ_FALSE;
6442 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
6443 uncomp_size = MZ_FTELL64(pSrc_file);
6444 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
6445
6446 if (uncomp_size > 0xFFFFFFFF) {
6447 // No zip64 support yet
6448 MZ_FCLOSE(pSrc_file);
6449 return MZ_FALSE;
6450 }
6451 if (uncomp_size <= 3) level = 0;
6452
6453 if (!mz_zip_writer_write_zeros(
6454 pZip, cur_archive_file_ofs,
6455 num_alignment_padding_bytes + sizeof(local_dir_header))) {
6456 MZ_FCLOSE(pSrc_file);
6457 return MZ_FALSE;
6458 }
6459 local_dir_header_ofs += num_alignment_padding_bytes;
6460 if (pZip->m_file_offset_alignment) {
6461 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6462 0);
6463 }
6464 cur_archive_file_ofs +=
6465 num_alignment_padding_bytes + sizeof(local_dir_header);
6466
6467 MZ_CLEAR_OBJ(local_dir_header);
6468 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6469 archive_name_size) != archive_name_size) {
6470 MZ_FCLOSE(pSrc_file);
6471 return MZ_FALSE;
6472 }
6473 cur_archive_file_ofs += archive_name_size;
6474
6475 if (uncomp_size) {
6476 mz_uint64 uncomp_remaining = uncomp_size;
6477 void *pRead_buf =
6478 pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
6479 if (!pRead_buf) {
6480 MZ_FCLOSE(pSrc_file);
6481 return MZ_FALSE;
6482 }
6483
6484 if (!level) {
6485 while (uncomp_remaining) {
6486 mz_uint n =
6487 (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
6488 if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) ||
6489 (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf,
6490 n) != n)) {
6491 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6492 MZ_FCLOSE(pSrc_file);
6493 return MZ_FALSE;
6494 }
6495 uncomp_crc32 =
6496 (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
6497 uncomp_remaining -= n;
6498 cur_archive_file_ofs += n;
6499 }
6500 comp_size = uncomp_size;
6501 } else {
6502 mz_bool result = MZ_FALSE;
6503 mz_zip_writer_add_state state;
6504 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(
6505 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
6506 if (!pComp) {
6507 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6508 MZ_FCLOSE(pSrc_file);
6509 return MZ_FALSE;
6510 }
6511
6512 state.m_pZip = pZip;
6513 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6514 state.m_comp_size = 0;
6515
6516 if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
6517 tdefl_create_comp_flags_from_zip_params(
6518 level, -15, MZ_DEFAULT_STRATEGY)) !=
6519 TDEFL_STATUS_OKAY) {
6520 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6521 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6522 MZ_FCLOSE(pSrc_file);
6523 return MZ_FALSE;
6524 }
6525
6526 for (;;) {
6527 size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining,
6528 (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
6529 tdefl_status status;
6530
6531 if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
6532 break;
6533
6534 uncomp_crc32 = (mz_uint32)mz_crc32(
6535 uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
6536 uncomp_remaining -= in_buf_size;
6537
6538 status = tdefl_compress_buffer(
6539 pComp, pRead_buf, in_buf_size,
6540 uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH);
6541 if (status == TDEFL_STATUS_DONE) {
6542 result = MZ_TRUE;
6543 break;
6544 } else if (status != TDEFL_STATUS_OKAY)
6545 break;
6546 }
6547
6548 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6549
6550 if (!result) {
6551 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6552 MZ_FCLOSE(pSrc_file);
6553 return MZ_FALSE;
6554 }
6555
6556 comp_size = state.m_comp_size;
6557 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6558
6559 method = MZ_DEFLATED;
6560 }
6561
6562 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6563 }
6564
6565 MZ_FCLOSE(pSrc_file);
6566 pSrc_file = NULL;
6567
6568 // no zip64 support yet
6569 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
6570 return MZ_FALSE;
6571
6572 if (!mz_zip_writer_create_local_dir_header(
6573 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
6574 comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
6575 return MZ_FALSE;
6576
6577 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
6578 sizeof(local_dir_header)) != sizeof(local_dir_header))
6579 return MZ_FALSE;
6580
6581 if (!mz_zip_writer_add_to_central_dir(
6582 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
6583 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
6584 dos_time, dos_date, local_dir_header_ofs, ext_attributes))
6585 return MZ_FALSE;
6586
6587 pZip->m_total_files++;
6588 pZip->m_archive_size = cur_archive_file_ofs;
6589
6590 return MZ_TRUE;
6591 }
6592 #endif // #ifndef MINIZ_NO_STDIO
6593
mz_zip_writer_add_from_zip_reader(mz_zip_archive * pZip,mz_zip_archive * pSource_zip,mz_uint file_index)6594 mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
6595 mz_zip_archive *pSource_zip,
6596 mz_uint file_index) {
6597 mz_uint n, bit_flags, num_alignment_padding_bytes;
6598 mz_uint64 comp_bytes_remaining, local_dir_header_ofs;
6599 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
6600 mz_uint32
6601 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
6602 sizeof(mz_uint32)];
6603 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
6604 mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6605 size_t orig_central_dir_size;
6606 mz_zip_internal_state *pState;
6607 void *pBuf;
6608 const mz_uint8 *pSrc_central_header;
6609
6610 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
6611 return MZ_FALSE;
6612 if (NULL ==
6613 (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index)))
6614 return MZ_FALSE;
6615 pState = pZip->m_pState;
6616
6617 num_alignment_padding_bytes =
6618 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6619
6620 // no zip64 support yet
6621 if ((pZip->m_total_files == 0xFFFF) ||
6622 ((pZip->m_archive_size + num_alignment_padding_bytes +
6623 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) >
6624 0xFFFFFFFF))
6625 return MZ_FALSE;
6626
6627 cur_src_file_ofs =
6628 MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
6629 cur_dst_file_ofs = pZip->m_archive_size;
6630
6631 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
6632 pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6633 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6634 return MZ_FALSE;
6635 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
6636 return MZ_FALSE;
6637 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
6638
6639 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs,
6640 num_alignment_padding_bytes))
6641 return MZ_FALSE;
6642 cur_dst_file_ofs += num_alignment_padding_bytes;
6643 local_dir_header_ofs = cur_dst_file_ofs;
6644 if (pZip->m_file_offset_alignment) {
6645 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6646 0);
6647 }
6648
6649 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header,
6650 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6651 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6652 return MZ_FALSE;
6653 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
6654
6655 n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
6656 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
6657 comp_bytes_remaining =
6658 n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
6659
6660 if (NULL == (pBuf = pZip->m_pAlloc(
6661 pZip->m_pAlloc_opaque, 1,
6662 (size_t)MZ_MAX(sizeof(mz_uint32) * 4,
6663 MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE,
6664 comp_bytes_remaining)))))
6665 return MZ_FALSE;
6666
6667 while (comp_bytes_remaining) {
6668 n = (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining);
6669 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
6670 n) != n) {
6671 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6672 return MZ_FALSE;
6673 }
6674 cur_src_file_ofs += n;
6675
6676 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
6677 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6678 return MZ_FALSE;
6679 }
6680 cur_dst_file_ofs += n;
6681
6682 comp_bytes_remaining -= n;
6683 }
6684
6685 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
6686 if (bit_flags & 8) {
6687 // Copy data descriptor
6688 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
6689 sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) {
6690 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6691 return MZ_FALSE;
6692 }
6693
6694 n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3);
6695 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
6696 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6697 return MZ_FALSE;
6698 }
6699
6700 cur_src_file_ofs += n;
6701 cur_dst_file_ofs += n;
6702 }
6703 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6704
6705 // no zip64 support yet
6706 if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE;
6707
6708 orig_central_dir_size = pState->m_central_dir.m_size;
6709
6710 memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
6711 MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
6712 local_dir_header_ofs);
6713 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header,
6714 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
6715 return MZ_FALSE;
6716
6717 n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
6718 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
6719 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
6720 if (!mz_zip_array_push_back(
6721 pZip, &pState->m_central_dir,
6722 pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) {
6723 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6724 MZ_FALSE);
6725 return MZ_FALSE;
6726 }
6727
6728 if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE;
6729 n = (mz_uint32)orig_central_dir_size;
6730 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) {
6731 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6732 MZ_FALSE);
6733 return MZ_FALSE;
6734 }
6735
6736 pZip->m_total_files++;
6737 pZip->m_archive_size = cur_dst_file_ofs;
6738
6739 return MZ_TRUE;
6740 }
6741
mz_zip_writer_finalize_archive(mz_zip_archive * pZip)6742 mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) {
6743 mz_zip_internal_state *pState;
6744 mz_uint64 central_dir_ofs, central_dir_size;
6745 mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE];
6746
6747 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
6748 return MZ_FALSE;
6749
6750 pState = pZip->m_pState;
6751
6752 // no zip64 support yet
6753 if ((pZip->m_total_files > 0xFFFF) ||
6754 ((pZip->m_archive_size + pState->m_central_dir.m_size +
6755 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
6756 return MZ_FALSE;
6757
6758 central_dir_ofs = 0;
6759 central_dir_size = 0;
6760 if (pZip->m_total_files) {
6761 // Write central directory
6762 central_dir_ofs = pZip->m_archive_size;
6763 central_dir_size = pState->m_central_dir.m_size;
6764 pZip->m_central_directory_file_ofs = central_dir_ofs;
6765 if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs,
6766 pState->m_central_dir.m_p,
6767 (size_t)central_dir_size) != central_dir_size)
6768 return MZ_FALSE;
6769 pZip->m_archive_size += central_dir_size;
6770 }
6771
6772 // Write end of central directory record
6773 MZ_CLEAR_OBJ(hdr);
6774 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS,
6775 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
6776 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS,
6777 pZip->m_total_files);
6778 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
6779 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size);
6780 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs);
6781
6782 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
6783 sizeof(hdr)) != sizeof(hdr))
6784 return MZ_FALSE;
6785 #ifndef MINIZ_NO_STDIO
6786 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE;
6787 #endif // #ifndef MINIZ_NO_STDIO
6788
6789 pZip->m_archive_size += sizeof(hdr);
6790
6791 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
6792 return MZ_TRUE;
6793 }
6794
mz_zip_writer_finalize_heap_archive(mz_zip_archive * pZip,void ** pBuf,size_t * pSize)6795 mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
6796 size_t *pSize) {
6797 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE;
6798 if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE;
6799 if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE;
6800
6801 *pBuf = pZip->m_pState->m_pMem;
6802 *pSize = pZip->m_pState->m_mem_size;
6803 pZip->m_pState->m_pMem = NULL;
6804 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
6805 return MZ_TRUE;
6806 }
6807
mz_zip_writer_end(mz_zip_archive * pZip)6808 mz_bool mz_zip_writer_end(mz_zip_archive *pZip) {
6809 mz_zip_internal_state *pState;
6810 mz_bool status = MZ_TRUE;
6811 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
6812 ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) &&
6813 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))
6814 return MZ_FALSE;
6815
6816 pState = pZip->m_pState;
6817 pZip->m_pState = NULL;
6818 mz_zip_array_clear(pZip, &pState->m_central_dir);
6819 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
6820 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
6821
6822 #ifndef MINIZ_NO_STDIO
6823 if (pState->m_pFile) {
6824 MZ_FCLOSE(pState->m_pFile);
6825 pState->m_pFile = NULL;
6826 }
6827 #endif // #ifndef MINIZ_NO_STDIO
6828
6829 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
6830 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
6831 pState->m_pMem = NULL;
6832 }
6833
6834 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
6835 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
6836 return status;
6837 }
6838
6839 #ifndef MINIZ_NO_STDIO
mz_zip_add_mem_to_archive_file_in_place(const char * pZip_filename,const char * pArchive_name,const void * pBuf,size_t buf_size,const void * pComment,mz_uint16 comment_size,mz_uint level_and_flags)6840 mz_bool mz_zip_add_mem_to_archive_file_in_place(
6841 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
6842 size_t buf_size, const void *pComment, mz_uint16 comment_size,
6843 mz_uint level_and_flags) {
6844 mz_bool status, created_new_archive = MZ_FALSE;
6845 mz_zip_archive zip_archive;
6846 struct MZ_FILE_STAT_STRUCT file_stat;
6847 MZ_CLEAR_OBJ(zip_archive);
6848 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
6849 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) ||
6850 ((comment_size) && (!pComment)) ||
6851 ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
6852 return MZ_FALSE;
6853 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
6854 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) {
6855 // Create a new archive.
6856 if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0))
6857 return MZ_FALSE;
6858 created_new_archive = MZ_TRUE;
6859 } else {
6860 // Append to an existing archive.
6861 if (!mz_zip_reader_init_file(
6862 &zip_archive, pZip_filename,
6863 level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
6864 return MZ_FALSE;
6865 if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) {
6866 mz_zip_reader_end(&zip_archive);
6867 return MZ_FALSE;
6868 }
6869 }
6870 status =
6871 mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size,
6872 pComment, comment_size, level_and_flags, 0, 0);
6873 // Always finalize, even if adding failed for some reason, so we have a valid
6874 // central directory. (This may not always succeed, but we can try.)
6875 if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE;
6876 if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE;
6877 if ((!status) && (created_new_archive)) {
6878 // It's a new archive and something went wrong, so just delete it.
6879 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
6880 (void)ignoredStatus;
6881 }
6882 return status;
6883 }
6884
mz_zip_extract_archive_file_to_heap(const char * pZip_filename,const char * pArchive_name,size_t * pSize,mz_uint flags)6885 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
6886 const char *pArchive_name,
6887 size_t *pSize, mz_uint flags) {
6888 int file_index;
6889 mz_zip_archive zip_archive;
6890 void *p = NULL;
6891
6892 if (pSize) *pSize = 0;
6893
6894 if ((!pZip_filename) || (!pArchive_name)) return NULL;
6895
6896 MZ_CLEAR_OBJ(zip_archive);
6897 if (!mz_zip_reader_init_file(
6898 &zip_archive, pZip_filename,
6899 flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
6900 return NULL;
6901
6902 if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL,
6903 flags)) >= 0)
6904 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
6905
6906 mz_zip_reader_end(&zip_archive);
6907 return p;
6908 }
6909
6910 #endif // #ifndef MINIZ_NO_STDIO
6911
6912 #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
6913
6914 #endif // #ifndef MINIZ_NO_ARCHIVE_APIS
6915
6916 #ifdef __cplusplus
6917 }
6918 #endif
6919
6920 #endif // MINIZ_HEADER_FILE_ONLY
6921
6922 /*
6923 This is free and unencumbered software released into the public domain.
6924
6925 Anyone is free to copy, modify, publish, use, compile, sell, or
6926 distribute this software, either in source code form or as a compiled
6927 binary, for any purpose, commercial or non-commercial, and by any
6928 means.
6929
6930 In jurisdictions that recognize copyright laws, the author or authors
6931 of this software dedicate any and all copyright interest in the
6932 software to the public domain. We make this dedication for the benefit
6933 of the public at large and to the detriment of our heirs and
6934 successors. We intend this dedication to be an overt act of
6935 relinquishment in perpetuity of all present and future rights to this
6936 software under copyright law.
6937
6938 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
6939 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
6940 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
6941 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
6942 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
6943 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
6944 OTHER DEALINGS IN THE SOFTWARE.
6945
6946 For more information, please refer to <http://unlicense.org/>
6947 */
6948
6949 // ---------------------- end of miniz ----------------------------------------
6950
6951 #ifdef __clang__
6952 #pragma clang diagnostic pop
6953 #endif
6954
6955 #ifdef _MSC_VER
6956 #pragma warning(pop)
6957 #endif
6958 } // namespace miniz
6959 #else
6960
6961 // Reuse MINIZ_LITTE_ENDIAN macro
6962
6963 #if defined(__sparcv9)
6964 // Big endian
6965 #else
6966 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
6967 // Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
6968 #define MINIZ_LITTLE_ENDIAN 1
6969 #endif
6970 #endif
6971
6972 #endif // TINYEXR_USE_MINIZ
6973
6974 // static bool IsBigEndian(void) {
6975 // union {
6976 // unsigned int i;
6977 // char c[4];
6978 // } bint = {0x01020304};
6979 //
6980 // return bint.c[0] == 1;
6981 //}
6982
SetErrorMessage(const std::string & msg,const char ** err)6983 static void SetErrorMessage(const std::string &msg, const char **err) {
6984 if (err) {
6985 #ifdef _WIN32
6986 (*err) = _strdup(msg.c_str());
6987 #else
6988 (*err) = strdup(msg.c_str());
6989 #endif
6990 }
6991 }
6992
6993 static const int kEXRVersionSize = 8;
6994
cpy2(unsigned short * dst_val,const unsigned short * src_val)6995 static void cpy2(unsigned short *dst_val, const unsigned short *src_val) {
6996 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
6997 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
6998
6999 dst[0] = src[0];
7000 dst[1] = src[1];
7001 }
7002
swap2(unsigned short * val)7003 static void swap2(unsigned short *val) {
7004 #ifdef MINIZ_LITTLE_ENDIAN
7005 (void)val;
7006 #else
7007 unsigned short tmp = *val;
7008 unsigned char *dst = reinterpret_cast<unsigned char *>(val);
7009 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
7010
7011 dst[0] = src[1];
7012 dst[1] = src[0];
7013 #endif
7014 }
7015
7016 #ifdef __clang__
7017 #pragma clang diagnostic push
7018 #pragma clang diagnostic ignored "-Wunused-function"
7019 #endif
7020
7021 #ifdef __GNUC__
7022 #pragma GCC diagnostic push
7023 #pragma GCC diagnostic ignored "-Wunused-function"
7024 #endif
cpy4(int * dst_val,const int * src_val)7025 static void cpy4(int *dst_val, const int *src_val) {
7026 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7027 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7028
7029 dst[0] = src[0];
7030 dst[1] = src[1];
7031 dst[2] = src[2];
7032 dst[3] = src[3];
7033 }
7034
cpy4(unsigned int * dst_val,const unsigned int * src_val)7035 static void cpy4(unsigned int *dst_val, const unsigned int *src_val) {
7036 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7037 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7038
7039 dst[0] = src[0];
7040 dst[1] = src[1];
7041 dst[2] = src[2];
7042 dst[3] = src[3];
7043 }
7044
cpy4(float * dst_val,const float * src_val)7045 static void cpy4(float *dst_val, const float *src_val) {
7046 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7047 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7048
7049 dst[0] = src[0];
7050 dst[1] = src[1];
7051 dst[2] = src[2];
7052 dst[3] = src[3];
7053 }
7054 #ifdef __clang__
7055 #pragma clang diagnostic pop
7056 #endif
7057
7058 #ifdef __GNUC__
7059 #pragma GCC diagnostic pop
7060 #endif
7061
swap4(unsigned int * val)7062 static void swap4(unsigned int *val) {
7063 #ifdef MINIZ_LITTLE_ENDIAN
7064 (void)val;
7065 #else
7066 unsigned int tmp = *val;
7067 unsigned char *dst = reinterpret_cast<unsigned char *>(val);
7068 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
7069
7070 dst[0] = src[3];
7071 dst[1] = src[2];
7072 dst[2] = src[1];
7073 dst[3] = src[0];
7074 #endif
7075 }
7076
7077 #if 0
7078 static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) {
7079 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7080 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7081
7082 dst[0] = src[0];
7083 dst[1] = src[1];
7084 dst[2] = src[2];
7085 dst[3] = src[3];
7086 dst[4] = src[4];
7087 dst[5] = src[5];
7088 dst[6] = src[6];
7089 dst[7] = src[7];
7090 }
7091 #endif
7092
swap8(tinyexr::tinyexr_uint64 * val)7093 static void swap8(tinyexr::tinyexr_uint64 *val) {
7094 #ifdef MINIZ_LITTLE_ENDIAN
7095 (void)val;
7096 #else
7097 tinyexr::tinyexr_uint64 tmp = (*val);
7098 unsigned char *dst = reinterpret_cast<unsigned char *>(val);
7099 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
7100
7101 dst[0] = src[7];
7102 dst[1] = src[6];
7103 dst[2] = src[5];
7104 dst[3] = src[4];
7105 dst[4] = src[3];
7106 dst[5] = src[2];
7107 dst[6] = src[1];
7108 dst[7] = src[0];
7109 #endif
7110 }
7111
7112 // https://gist.github.com/rygorous/2156668
7113 // Reuse MINIZ_LITTLE_ENDIAN flag from miniz.
7114 union FP32 {
7115 unsigned int u;
7116 float f;
7117 struct {
7118 #if MINIZ_LITTLE_ENDIAN
7119 unsigned int Mantissa : 23;
7120 unsigned int Exponent : 8;
7121 unsigned int Sign : 1;
7122 #else
7123 unsigned int Sign : 1;
7124 unsigned int Exponent : 8;
7125 unsigned int Mantissa : 23;
7126 #endif
7127 } s;
7128 };
7129
7130 #ifdef __clang__
7131 #pragma clang diagnostic push
7132 #pragma clang diagnostic ignored "-Wpadded"
7133 #endif
7134
7135 union FP16 {
7136 unsigned short u;
7137 struct {
7138 #if MINIZ_LITTLE_ENDIAN
7139 unsigned int Mantissa : 10;
7140 unsigned int Exponent : 5;
7141 unsigned int Sign : 1;
7142 #else
7143 unsigned int Sign : 1;
7144 unsigned int Exponent : 5;
7145 unsigned int Mantissa : 10;
7146 #endif
7147 } s;
7148 };
7149
7150 #ifdef __clang__
7151 #pragma clang diagnostic pop
7152 #endif
7153
half_to_float(FP16 h)7154 static FP32 half_to_float(FP16 h) {
7155 static const FP32 magic = {113 << 23};
7156 static const unsigned int shifted_exp = 0x7c00
7157 << 13; // exponent mask after shift
7158 FP32 o;
7159
7160 o.u = (h.u & 0x7fffU) << 13U; // exponent/mantissa bits
7161 unsigned int exp_ = shifted_exp & o.u; // just the exponent
7162 o.u += (127 - 15) << 23; // exponent adjust
7163
7164 // handle exponent special cases
7165 if (exp_ == shifted_exp) // Inf/NaN?
7166 o.u += (128 - 16) << 23; // extra exp adjust
7167 else if (exp_ == 0) // Zero/Denormal?
7168 {
7169 o.u += 1 << 23; // extra exp adjust
7170 o.f -= magic.f; // renormalize
7171 }
7172
7173 o.u |= (h.u & 0x8000U) << 16U; // sign bit
7174 return o;
7175 }
7176
float_to_half_full(FP32 f)7177 static FP16 float_to_half_full(FP32 f) {
7178 FP16 o = {0};
7179
7180 // Based on ISPC reference code (with minor modifications)
7181 if (f.s.Exponent == 0) // Signed zero/denormal (which will underflow)
7182 o.s.Exponent = 0;
7183 else if (f.s.Exponent == 255) // Inf or NaN (all exponent bits set)
7184 {
7185 o.s.Exponent = 31;
7186 o.s.Mantissa = f.s.Mantissa ? 0x200 : 0; // NaN->qNaN and Inf->Inf
7187 } else // Normalized number
7188 {
7189 // Exponent unbias the single, then bias the halfp
7190 int newexp = f.s.Exponent - 127 + 15;
7191 if (newexp >= 31) // Overflow, return signed infinity
7192 o.s.Exponent = 31;
7193 else if (newexp <= 0) // Underflow
7194 {
7195 if ((14 - newexp) <= 24) // Mantissa might be non-zero
7196 {
7197 unsigned int mant = f.s.Mantissa | 0x800000; // Hidden 1 bit
7198 o.s.Mantissa = mant >> (14 - newexp);
7199 if ((mant >> (13 - newexp)) & 1) // Check for rounding
7200 o.u++; // Round, might overflow into exp bit, but this is OK
7201 }
7202 } else {
7203 o.s.Exponent = static_cast<unsigned int>(newexp);
7204 o.s.Mantissa = f.s.Mantissa >> 13;
7205 if (f.s.Mantissa & 0x1000) // Check for rounding
7206 o.u++; // Round, might overflow to inf, this is OK
7207 }
7208 }
7209
7210 o.s.Sign = f.s.Sign;
7211 return o;
7212 }
7213
7214 // NOTE: From OpenEXR code
7215 // #define IMF_INCREASING_Y 0
7216 // #define IMF_DECREASING_Y 1
7217 // #define IMF_RAMDOM_Y 2
7218 //
7219 // #define IMF_NO_COMPRESSION 0
7220 // #define IMF_RLE_COMPRESSION 1
7221 // #define IMF_ZIPS_COMPRESSION 2
7222 // #define IMF_ZIP_COMPRESSION 3
7223 // #define IMF_PIZ_COMPRESSION 4
7224 // #define IMF_PXR24_COMPRESSION 5
7225 // #define IMF_B44_COMPRESSION 6
7226 // #define IMF_B44A_COMPRESSION 7
7227
7228 #ifdef __clang__
7229 #pragma clang diagnostic push
7230
7231 #if __has_warning("-Wzero-as-null-pointer-constant")
7232 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
7233 #endif
7234
7235 #endif
7236
ReadString(std::string * s,const char * ptr,size_t len)7237 static const char *ReadString(std::string *s, const char *ptr, size_t len) {
7238 // Read untile NULL(\0).
7239 const char *p = ptr;
7240 const char *q = ptr;
7241 while ((size_t(q - ptr) < len) && (*q) != 0) {
7242 q++;
7243 }
7244
7245 if (size_t(q - ptr) >= len) {
7246 (*s) = std::string();
7247 return NULL;
7248 }
7249
7250 (*s) = std::string(p, q);
7251
7252 return q + 1; // skip '\0'
7253 }
7254
ReadAttribute(std::string * name,std::string * type,std::vector<unsigned char> * data,size_t * marker_size,const char * marker,size_t size)7255 static bool ReadAttribute(std::string *name, std::string *type,
7256 std::vector<unsigned char> *data, size_t *marker_size,
7257 const char *marker, size_t size) {
7258 size_t name_len = strnlen(marker, size);
7259 if (name_len == size) {
7260 // String does not have a terminating character.
7261 return false;
7262 }
7263 *name = std::string(marker, name_len);
7264
7265 marker += name_len + 1;
7266 size -= name_len + 1;
7267
7268 size_t type_len = strnlen(marker, size);
7269 if (type_len == size) {
7270 return false;
7271 }
7272 *type = std::string(marker, type_len);
7273
7274 marker += type_len + 1;
7275 size -= type_len + 1;
7276
7277 if (size < sizeof(uint32_t)) {
7278 return false;
7279 }
7280
7281 uint32_t data_len;
7282 memcpy(&data_len, marker, sizeof(uint32_t));
7283 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
7284
7285 if (data_len == 0) {
7286 if ((*type).compare("string") == 0) {
7287 // Accept empty string attribute.
7288
7289 marker += sizeof(uint32_t);
7290 size -= sizeof(uint32_t);
7291
7292 *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t);
7293
7294 data->resize(1);
7295 (*data)[0] = '\0';
7296
7297 return true;
7298 } else {
7299 return false;
7300 }
7301 }
7302
7303 marker += sizeof(uint32_t);
7304 size -= sizeof(uint32_t);
7305
7306 if (size < data_len) {
7307 return false;
7308 }
7309
7310 data->resize(static_cast<size_t>(data_len));
7311 memcpy(&data->at(0), marker, static_cast<size_t>(data_len));
7312
7313 *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t) + data_len;
7314 return true;
7315 }
7316
WriteAttributeToMemory(std::vector<unsigned char> * out,const char * name,const char * type,const unsigned char * data,int len)7317 static void WriteAttributeToMemory(std::vector<unsigned char> *out,
7318 const char *name, const char *type,
7319 const unsigned char *data, int len) {
7320 out->insert(out->end(), name, name + strlen(name) + 1);
7321 out->insert(out->end(), type, type + strlen(type) + 1);
7322
7323 int outLen = len;
7324 tinyexr::swap4(reinterpret_cast<unsigned int *>(&outLen));
7325 out->insert(out->end(), reinterpret_cast<unsigned char *>(&outLen),
7326 reinterpret_cast<unsigned char *>(&outLen) + sizeof(int));
7327 out->insert(out->end(), data, data + len);
7328 }
7329
7330 typedef struct {
7331 std::string name; // less than 255 bytes long
7332 int pixel_type;
7333 int x_sampling;
7334 int y_sampling;
7335 unsigned char p_linear;
7336 unsigned char pad[3];
7337 } ChannelInfo;
7338
7339 typedef struct {
7340 std::vector<tinyexr::ChannelInfo> channels;
7341 std::vector<EXRAttribute> attributes;
7342
7343 int data_window[4];
7344 int line_order;
7345 int display_window[4];
7346 float screen_window_center[2];
7347 float screen_window_width;
7348 float pixel_aspect_ratio;
7349
7350 int chunk_count;
7351
7352 // Tiled format
7353 int tile_size_x;
7354 int tile_size_y;
7355 int tile_level_mode;
7356 int tile_rounding_mode;
7357
7358 unsigned int header_len;
7359
7360 int compression_type;
7361
clear__anon3809bf2420087362 void clear() {
7363 channels.clear();
7364 attributes.clear();
7365
7366 data_window[0] = 0;
7367 data_window[1] = 0;
7368 data_window[2] = 0;
7369 data_window[3] = 0;
7370 line_order = 0;
7371 display_window[0] = 0;
7372 display_window[1] = 0;
7373 display_window[2] = 0;
7374 display_window[3] = 0;
7375 screen_window_center[0] = 0.0f;
7376 screen_window_center[1] = 0.0f;
7377 screen_window_width = 0.0f;
7378 pixel_aspect_ratio = 0.0f;
7379
7380 chunk_count = 0;
7381
7382 // Tiled format
7383 tile_size_x = 0;
7384 tile_size_y = 0;
7385 tile_level_mode = 0;
7386 tile_rounding_mode = 0;
7387
7388 header_len = 0;
7389 compression_type = 0;
7390 }
7391 } HeaderInfo;
7392
ReadChannelInfo(std::vector<ChannelInfo> & channels,const std::vector<unsigned char> & data)7393 static bool ReadChannelInfo(std::vector<ChannelInfo> &channels,
7394 const std::vector<unsigned char> &data) {
7395 const char *p = reinterpret_cast<const char *>(&data.at(0));
7396
7397 for (;;) {
7398 if ((*p) == 0) {
7399 break;
7400 }
7401 ChannelInfo info;
7402
7403 tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) -
7404 (p - reinterpret_cast<const char *>(data.data()));
7405 if (data_len < 0) {
7406 return false;
7407 }
7408
7409 p = ReadString(&info.name, p, size_t(data_len));
7410 if ((p == NULL) && (info.name.empty())) {
7411 // Buffer overrun. Issue #51.
7412 return false;
7413 }
7414
7415 const unsigned char *data_end =
7416 reinterpret_cast<const unsigned char *>(p) + 16;
7417 if (data_end >= (data.data() + data.size())) {
7418 return false;
7419 }
7420
7421 memcpy(&info.pixel_type, p, sizeof(int));
7422 p += 4;
7423 info.p_linear = static_cast<unsigned char>(p[0]); // uchar
7424 p += 1 + 3; // reserved: uchar[3]
7425 memcpy(&info.x_sampling, p, sizeof(int)); // int
7426 p += 4;
7427 memcpy(&info.y_sampling, p, sizeof(int)); // int
7428 p += 4;
7429
7430 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.pixel_type));
7431 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.x_sampling));
7432 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.y_sampling));
7433
7434 channels.push_back(info);
7435 }
7436
7437 return true;
7438 }
7439
WriteChannelInfo(std::vector<unsigned char> & data,const std::vector<ChannelInfo> & channels)7440 static void WriteChannelInfo(std::vector<unsigned char> &data,
7441 const std::vector<ChannelInfo> &channels) {
7442 size_t sz = 0;
7443
7444 // Calculate total size.
7445 for (size_t c = 0; c < channels.size(); c++) {
7446 sz += strlen(channels[c].name.c_str()) + 1; // +1 for \0
7447 sz += 16; // 4 * int
7448 }
7449 data.resize(sz + 1);
7450
7451 unsigned char *p = &data.at(0);
7452
7453 for (size_t c = 0; c < channels.size(); c++) {
7454 memcpy(p, channels[c].name.c_str(), strlen(channels[c].name.c_str()));
7455 p += strlen(channels[c].name.c_str());
7456 (*p) = '\0';
7457 p++;
7458
7459 int pixel_type = channels[c].pixel_type;
7460 int x_sampling = channels[c].x_sampling;
7461 int y_sampling = channels[c].y_sampling;
7462 tinyexr::swap4(reinterpret_cast<unsigned int *>(&pixel_type));
7463 tinyexr::swap4(reinterpret_cast<unsigned int *>(&x_sampling));
7464 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y_sampling));
7465
7466 memcpy(p, &pixel_type, sizeof(int));
7467 p += sizeof(int);
7468
7469 (*p) = channels[c].p_linear;
7470 p += 4;
7471
7472 memcpy(p, &x_sampling, sizeof(int));
7473 p += sizeof(int);
7474
7475 memcpy(p, &y_sampling, sizeof(int));
7476 p += sizeof(int);
7477 }
7478
7479 (*p) = '\0';
7480 }
7481
CompressZip(unsigned char * dst,tinyexr::tinyexr_uint64 & compressedSize,const unsigned char * src,unsigned long src_size)7482 static void CompressZip(unsigned char *dst,
7483 tinyexr::tinyexr_uint64 &compressedSize,
7484 const unsigned char *src, unsigned long src_size) {
7485 std::vector<unsigned char> tmpBuf(src_size);
7486
7487 //
7488 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7489 // ImfZipCompressor.cpp
7490 //
7491
7492 //
7493 // Reorder the pixel data.
7494 //
7495
7496 const char *srcPtr = reinterpret_cast<const char *>(src);
7497
7498 {
7499 char *t1 = reinterpret_cast<char *>(&tmpBuf.at(0));
7500 char *t2 = reinterpret_cast<char *>(&tmpBuf.at(0)) + (src_size + 1) / 2;
7501 const char *stop = srcPtr + src_size;
7502
7503 for (;;) {
7504 if (srcPtr < stop)
7505 *(t1++) = *(srcPtr++);
7506 else
7507 break;
7508
7509 if (srcPtr < stop)
7510 *(t2++) = *(srcPtr++);
7511 else
7512 break;
7513 }
7514 }
7515
7516 //
7517 // Predictor.
7518 //
7519
7520 {
7521 unsigned char *t = &tmpBuf.at(0) + 1;
7522 unsigned char *stop = &tmpBuf.at(0) + src_size;
7523 int p = t[-1];
7524
7525 while (t < stop) {
7526 int d = int(t[0]) - p + (128 + 256);
7527 p = t[0];
7528 t[0] = static_cast<unsigned char>(d);
7529 ++t;
7530 }
7531 }
7532
7533 #if TINYEXR_USE_MINIZ
7534 //
7535 // Compress the data using miniz
7536 //
7537
7538 miniz::mz_ulong outSize = miniz::mz_compressBound(src_size);
7539 int ret = miniz::mz_compress(
7540 dst, &outSize, static_cast<const unsigned char *>(&tmpBuf.at(0)),
7541 src_size);
7542 assert(ret == miniz::MZ_OK);
7543 (void)ret;
7544
7545 compressedSize = outSize;
7546 #else
7547 uLong outSize = compressBound(static_cast<uLong>(src_size));
7548 int ret = compress(dst, &outSize, static_cast<const Bytef *>(&tmpBuf.at(0)),
7549 src_size);
7550 assert(ret == Z_OK);
7551
7552 compressedSize = outSize;
7553 #endif
7554
7555 // Use uncompressed data when compressed data is larger than uncompressed.
7556 // (Issue 40)
7557 if (compressedSize >= src_size) {
7558 compressedSize = src_size;
7559 memcpy(dst, src, src_size);
7560 }
7561 }
7562
DecompressZip(unsigned char * dst,unsigned long * uncompressed_size,const unsigned char * src,unsigned long src_size)7563 static bool DecompressZip(unsigned char *dst,
7564 unsigned long *uncompressed_size /* inout */,
7565 const unsigned char *src, unsigned long src_size) {
7566 if ((*uncompressed_size) == src_size) {
7567 // Data is not compressed(Issue 40).
7568 memcpy(dst, src, src_size);
7569 return true;
7570 }
7571 std::vector<unsigned char> tmpBuf(*uncompressed_size);
7572
7573 #if TINYEXR_USE_MINIZ
7574 int ret =
7575 miniz::mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
7576 if (miniz::MZ_OK != ret) {
7577 return false;
7578 }
7579 #else
7580 int ret = uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
7581 if (Z_OK != ret) {
7582 return false;
7583 }
7584 #endif
7585
7586 //
7587 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7588 // ImfZipCompressor.cpp
7589 //
7590
7591 // Predictor.
7592 {
7593 unsigned char *t = &tmpBuf.at(0) + 1;
7594 unsigned char *stop = &tmpBuf.at(0) + (*uncompressed_size);
7595
7596 while (t < stop) {
7597 int d = int(t[-1]) + int(t[0]) - 128;
7598 t[0] = static_cast<unsigned char>(d);
7599 ++t;
7600 }
7601 }
7602
7603 // Reorder the pixel data.
7604 {
7605 const char *t1 = reinterpret_cast<const char *>(&tmpBuf.at(0));
7606 const char *t2 = reinterpret_cast<const char *>(&tmpBuf.at(0)) +
7607 (*uncompressed_size + 1) / 2;
7608 char *s = reinterpret_cast<char *>(dst);
7609 char *stop = s + (*uncompressed_size);
7610
7611 for (;;) {
7612 if (s < stop)
7613 *(s++) = *(t1++);
7614 else
7615 break;
7616
7617 if (s < stop)
7618 *(s++) = *(t2++);
7619 else
7620 break;
7621 }
7622 }
7623
7624 return true;
7625 }
7626
7627 // RLE code from OpenEXR --------------------------------------
7628
7629 #ifdef __clang__
7630 #pragma clang diagnostic push
7631 #pragma clang diagnostic ignored "-Wsign-conversion"
7632 #if __has_warning("-Wextra-semi-stmt")
7633 #pragma clang diagnostic ignored "-Wextra-semi-stmt"
7634 #endif
7635 #endif
7636
7637 #ifdef _MSC_VER
7638 #pragma warning(push)
7639 #pragma warning(disable : 4204) // nonstandard extension used : non-constant
7640 // aggregate initializer (also supported by GNU
7641 // C and C99, so no big deal)
7642 #pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
7643 // 'int', possible loss of data
7644 #pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
7645 // 'int', possible loss of data
7646 #pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
7647 // deprecated. Instead, use the ISO C and C++
7648 // conformant name: _strdup.
7649 #endif
7650
7651 const int MIN_RUN_LENGTH = 3;
7652 const int MAX_RUN_LENGTH = 127;
7653
7654 //
7655 // Compress an array of bytes, using run-length encoding,
7656 // and return the length of the compressed data.
7657 //
7658
rleCompress(int inLength,const char in[],signed char out[])7659 static int rleCompress(int inLength, const char in[], signed char out[]) {
7660 const char *inEnd = in + inLength;
7661 const char *runStart = in;
7662 const char *runEnd = in + 1;
7663 signed char *outWrite = out;
7664
7665 while (runStart < inEnd) {
7666 while (runEnd < inEnd && *runStart == *runEnd &&
7667 runEnd - runStart - 1 < MAX_RUN_LENGTH) {
7668 ++runEnd;
7669 }
7670
7671 if (runEnd - runStart >= MIN_RUN_LENGTH) {
7672 //
7673 // Compressable run
7674 //
7675
7676 *outWrite++ = static_cast<char>(runEnd - runStart) - 1;
7677 *outWrite++ = *(reinterpret_cast<const signed char *>(runStart));
7678 runStart = runEnd;
7679 } else {
7680 //
7681 // Uncompressable run
7682 //
7683
7684 while (runEnd < inEnd &&
7685 ((runEnd + 1 >= inEnd || *runEnd != *(runEnd + 1)) ||
7686 (runEnd + 2 >= inEnd || *(runEnd + 1) != *(runEnd + 2))) &&
7687 runEnd - runStart < MAX_RUN_LENGTH) {
7688 ++runEnd;
7689 }
7690
7691 *outWrite++ = static_cast<char>(runStart - runEnd);
7692
7693 while (runStart < runEnd) {
7694 *outWrite++ = *(reinterpret_cast<const signed char *>(runStart++));
7695 }
7696 }
7697
7698 ++runEnd;
7699 }
7700
7701 return static_cast<int>(outWrite - out);
7702 }
7703
7704 //
7705 // Uncompress an array of bytes compressed with rleCompress().
7706 // Returns the length of the oncompressed data, or 0 if the
7707 // length of the uncompressed data would be more than maxLength.
7708 //
7709
rleUncompress(int inLength,int maxLength,const signed char in[],char out[])7710 static int rleUncompress(int inLength, int maxLength, const signed char in[],
7711 char out[]) {
7712 char *outStart = out;
7713
7714 while (inLength > 0) {
7715 if (*in < 0) {
7716 int count = -(static_cast<int>(*in++));
7717 inLength -= count + 1;
7718
7719 // Fixes #116: Add bounds check to in buffer.
7720 if ((0 > (maxLength -= count)) || (inLength < 0)) return 0;
7721
7722 memcpy(out, in, count);
7723 out += count;
7724 in += count;
7725 } else {
7726 int count = *in++;
7727 inLength -= 2;
7728
7729 if (0 > (maxLength -= count + 1)) return 0;
7730
7731 memset(out, *reinterpret_cast<const char *>(in), count + 1);
7732 out += count + 1;
7733
7734 in++;
7735 }
7736 }
7737
7738 return static_cast<int>(out - outStart);
7739 }
7740
7741 #ifdef __clang__
7742 #pragma clang diagnostic pop
7743 #endif
7744
7745 // End of RLE code from OpenEXR -----------------------------------
7746
CompressRle(unsigned char * dst,tinyexr::tinyexr_uint64 & compressedSize,const unsigned char * src,unsigned long src_size)7747 static void CompressRle(unsigned char *dst,
7748 tinyexr::tinyexr_uint64 &compressedSize,
7749 const unsigned char *src, unsigned long src_size) {
7750 std::vector<unsigned char> tmpBuf(src_size);
7751
7752 //
7753 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7754 // ImfRleCompressor.cpp
7755 //
7756
7757 //
7758 // Reorder the pixel data.
7759 //
7760
7761 const char *srcPtr = reinterpret_cast<const char *>(src);
7762
7763 {
7764 char *t1 = reinterpret_cast<char *>(&tmpBuf.at(0));
7765 char *t2 = reinterpret_cast<char *>(&tmpBuf.at(0)) + (src_size + 1) / 2;
7766 const char *stop = srcPtr + src_size;
7767
7768 for (;;) {
7769 if (srcPtr < stop)
7770 *(t1++) = *(srcPtr++);
7771 else
7772 break;
7773
7774 if (srcPtr < stop)
7775 *(t2++) = *(srcPtr++);
7776 else
7777 break;
7778 }
7779 }
7780
7781 //
7782 // Predictor.
7783 //
7784
7785 {
7786 unsigned char *t = &tmpBuf.at(0) + 1;
7787 unsigned char *stop = &tmpBuf.at(0) + src_size;
7788 int p = t[-1];
7789
7790 while (t < stop) {
7791 int d = int(t[0]) - p + (128 + 256);
7792 p = t[0];
7793 t[0] = static_cast<unsigned char>(d);
7794 ++t;
7795 }
7796 }
7797
7798 // outSize will be (srcSiz * 3) / 2 at max.
7799 int outSize = rleCompress(static_cast<int>(src_size),
7800 reinterpret_cast<const char *>(&tmpBuf.at(0)),
7801 reinterpret_cast<signed char *>(dst));
7802 assert(outSize > 0);
7803
7804 compressedSize = static_cast<tinyexr::tinyexr_uint64>(outSize);
7805
7806 // Use uncompressed data when compressed data is larger than uncompressed.
7807 // (Issue 40)
7808 if (compressedSize >= src_size) {
7809 compressedSize = src_size;
7810 memcpy(dst, src, src_size);
7811 }
7812 }
7813
DecompressRle(unsigned char * dst,const unsigned long uncompressed_size,const unsigned char * src,unsigned long src_size)7814 static bool DecompressRle(unsigned char *dst,
7815 const unsigned long uncompressed_size,
7816 const unsigned char *src, unsigned long src_size) {
7817 if (uncompressed_size == src_size) {
7818 // Data is not compressed(Issue 40).
7819 memcpy(dst, src, src_size);
7820 return true;
7821 }
7822
7823 // Workaround for issue #112.
7824 // TODO(syoyo): Add more robust out-of-bounds check in `rleUncompress`.
7825 if (src_size <= 2) {
7826 return false;
7827 }
7828
7829 std::vector<unsigned char> tmpBuf(uncompressed_size);
7830
7831 int ret = rleUncompress(static_cast<int>(src_size),
7832 static_cast<int>(uncompressed_size),
7833 reinterpret_cast<const signed char *>(src),
7834 reinterpret_cast<char *>(&tmpBuf.at(0)));
7835 if (ret != static_cast<int>(uncompressed_size)) {
7836 return false;
7837 }
7838
7839 //
7840 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7841 // ImfRleCompressor.cpp
7842 //
7843
7844 // Predictor.
7845 {
7846 unsigned char *t = &tmpBuf.at(0) + 1;
7847 unsigned char *stop = &tmpBuf.at(0) + uncompressed_size;
7848
7849 while (t < stop) {
7850 int d = int(t[-1]) + int(t[0]) - 128;
7851 t[0] = static_cast<unsigned char>(d);
7852 ++t;
7853 }
7854 }
7855
7856 // Reorder the pixel data.
7857 {
7858 const char *t1 = reinterpret_cast<const char *>(&tmpBuf.at(0));
7859 const char *t2 = reinterpret_cast<const char *>(&tmpBuf.at(0)) +
7860 (uncompressed_size + 1) / 2;
7861 char *s = reinterpret_cast<char *>(dst);
7862 char *stop = s + uncompressed_size;
7863
7864 for (;;) {
7865 if (s < stop)
7866 *(s++) = *(t1++);
7867 else
7868 break;
7869
7870 if (s < stop)
7871 *(s++) = *(t2++);
7872 else
7873 break;
7874 }
7875 }
7876
7877 return true;
7878 }
7879
7880 #if TINYEXR_USE_PIZ
7881
7882 #ifdef __clang__
7883 #pragma clang diagnostic push
7884 #pragma clang diagnostic ignored "-Wc++11-long-long"
7885 #pragma clang diagnostic ignored "-Wold-style-cast"
7886 #pragma clang diagnostic ignored "-Wpadded"
7887 #pragma clang diagnostic ignored "-Wsign-conversion"
7888 #pragma clang diagnostic ignored "-Wc++11-extensions"
7889 #pragma clang diagnostic ignored "-Wconversion"
7890 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
7891
7892 #if __has_warning("-Wcast-qual")
7893 #pragma clang diagnostic ignored "-Wcast-qual"
7894 #endif
7895
7896 #if __has_warning("-Wextra-semi-stmt")
7897 #pragma clang diagnostic ignored "-Wextra-semi-stmt"
7898 #endif
7899
7900 #endif
7901
7902 //
7903 // PIZ compress/uncompress, based on OpenEXR's ImfPizCompressor.cpp
7904 //
7905 // -----------------------------------------------------------------
7906 // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
7907 // Digital Ltd. LLC)
7908 // (3 clause BSD license)
7909 //
7910
7911 struct PIZChannelData {
7912 unsigned short *start;
7913 unsigned short *end;
7914 int nx;
7915 int ny;
7916 int ys;
7917 int size;
7918 };
7919
7920 //-----------------------------------------------------------------------------
7921 //
7922 // 16-bit Haar Wavelet encoding and decoding
7923 //
7924 // The source code in this file is derived from the encoding
7925 // and decoding routines written by Christian Rouet for his
7926 // PIZ image file format.
7927 //
7928 //-----------------------------------------------------------------------------
7929
7930 //
7931 // Wavelet basis functions without modulo arithmetic; they produce
7932 // the best compression ratios when the wavelet-transformed data are
7933 // Huffman-encoded, but the wavelet transform works only for 14-bit
7934 // data (untransformed data values must be less than (1 << 14)).
7935 //
7936
wenc14(unsigned short a,unsigned short b,unsigned short & l,unsigned short & h)7937 inline void wenc14(unsigned short a, unsigned short b, unsigned short &l,
7938 unsigned short &h) {
7939 short as = static_cast<short>(a);
7940 short bs = static_cast<short>(b);
7941
7942 short ms = (as + bs) >> 1;
7943 short ds = as - bs;
7944
7945 l = static_cast<unsigned short>(ms);
7946 h = static_cast<unsigned short>(ds);
7947 }
7948
wdec14(unsigned short l,unsigned short h,unsigned short & a,unsigned short & b)7949 inline void wdec14(unsigned short l, unsigned short h, unsigned short &a,
7950 unsigned short &b) {
7951 short ls = static_cast<short>(l);
7952 short hs = static_cast<short>(h);
7953
7954 int hi = hs;
7955 int ai = ls + (hi & 1) + (hi >> 1);
7956
7957 short as = static_cast<short>(ai);
7958 short bs = static_cast<short>(ai - hi);
7959
7960 a = static_cast<unsigned short>(as);
7961 b = static_cast<unsigned short>(bs);
7962 }
7963
7964 //
7965 // Wavelet basis functions with modulo arithmetic; they work with full
7966 // 16-bit data, but Huffman-encoding the wavelet-transformed data doesn't
7967 // compress the data quite as well.
7968 //
7969
7970 const int NBITS = 16;
7971 const int A_OFFSET = 1 << (NBITS - 1);
7972 const int M_OFFSET = 1 << (NBITS - 1);
7973 const int MOD_MASK = (1 << NBITS) - 1;
7974
wenc16(unsigned short a,unsigned short b,unsigned short & l,unsigned short & h)7975 inline void wenc16(unsigned short a, unsigned short b, unsigned short &l,
7976 unsigned short &h) {
7977 int ao = (a + A_OFFSET) & MOD_MASK;
7978 int m = ((ao + b) >> 1);
7979 int d = ao - b;
7980
7981 if (d < 0) m = (m + M_OFFSET) & MOD_MASK;
7982
7983 d &= MOD_MASK;
7984
7985 l = static_cast<unsigned short>(m);
7986 h = static_cast<unsigned short>(d);
7987 }
7988
wdec16(unsigned short l,unsigned short h,unsigned short & a,unsigned short & b)7989 inline void wdec16(unsigned short l, unsigned short h, unsigned short &a,
7990 unsigned short &b) {
7991 int m = l;
7992 int d = h;
7993 int bb = (m - (d >> 1)) & MOD_MASK;
7994 int aa = (d + bb - A_OFFSET) & MOD_MASK;
7995 b = static_cast<unsigned short>(bb);
7996 a = static_cast<unsigned short>(aa);
7997 }
7998
7999 //
8000 // 2D Wavelet encoding:
8001 //
8002
wav2Encode(unsigned short * in,int nx,int ox,int ny,int oy,unsigned short mx)8003 static void wav2Encode(
8004 unsigned short *in, // io: values are transformed in place
8005 int nx, // i : x size
8006 int ox, // i : x offset
8007 int ny, // i : y size
8008 int oy, // i : y offset
8009 unsigned short mx) // i : maximum in[x][y] value
8010 {
8011 bool w14 = (mx < (1 << 14));
8012 int n = (nx > ny) ? ny : nx;
8013 int p = 1; // == 1 << level
8014 int p2 = 2; // == 1 << (level+1)
8015
8016 //
8017 // Hierachical loop on smaller dimension n
8018 //
8019
8020 while (p2 <= n) {
8021 unsigned short *py = in;
8022 unsigned short *ey = in + oy * (ny - p2);
8023 int oy1 = oy * p;
8024 int oy2 = oy * p2;
8025 int ox1 = ox * p;
8026 int ox2 = ox * p2;
8027 unsigned short i00, i01, i10, i11;
8028
8029 //
8030 // Y loop
8031 //
8032
8033 for (; py <= ey; py += oy2) {
8034 unsigned short *px = py;
8035 unsigned short *ex = py + ox * (nx - p2);
8036
8037 //
8038 // X loop
8039 //
8040
8041 for (; px <= ex; px += ox2) {
8042 unsigned short *p01 = px + ox1;
8043 unsigned short *p10 = px + oy1;
8044 unsigned short *p11 = p10 + ox1;
8045
8046 //
8047 // 2D wavelet encoding
8048 //
8049
8050 if (w14) {
8051 wenc14(*px, *p01, i00, i01);
8052 wenc14(*p10, *p11, i10, i11);
8053 wenc14(i00, i10, *px, *p10);
8054 wenc14(i01, i11, *p01, *p11);
8055 } else {
8056 wenc16(*px, *p01, i00, i01);
8057 wenc16(*p10, *p11, i10, i11);
8058 wenc16(i00, i10, *px, *p10);
8059 wenc16(i01, i11, *p01, *p11);
8060 }
8061 }
8062
8063 //
8064 // Encode (1D) odd column (still in Y loop)
8065 //
8066
8067 if (nx & p) {
8068 unsigned short *p10 = px + oy1;
8069
8070 if (w14)
8071 wenc14(*px, *p10, i00, *p10);
8072 else
8073 wenc16(*px, *p10, i00, *p10);
8074
8075 *px = i00;
8076 }
8077 }
8078
8079 //
8080 // Encode (1D) odd line (must loop in X)
8081 //
8082
8083 if (ny & p) {
8084 unsigned short *px = py;
8085 unsigned short *ex = py + ox * (nx - p2);
8086
8087 for (; px <= ex; px += ox2) {
8088 unsigned short *p01 = px + ox1;
8089
8090 if (w14)
8091 wenc14(*px, *p01, i00, *p01);
8092 else
8093 wenc16(*px, *p01, i00, *p01);
8094
8095 *px = i00;
8096 }
8097 }
8098
8099 //
8100 // Next level
8101 //
8102
8103 p = p2;
8104 p2 <<= 1;
8105 }
8106 }
8107
8108 //
8109 // 2D Wavelet decoding:
8110 //
8111
wav2Decode(unsigned short * in,int nx,int ox,int ny,int oy,unsigned short mx)8112 static void wav2Decode(
8113 unsigned short *in, // io: values are transformed in place
8114 int nx, // i : x size
8115 int ox, // i : x offset
8116 int ny, // i : y size
8117 int oy, // i : y offset
8118 unsigned short mx) // i : maximum in[x][y] value
8119 {
8120 bool w14 = (mx < (1 << 14));
8121 int n = (nx > ny) ? ny : nx;
8122 int p = 1;
8123 int p2;
8124
8125 //
8126 // Search max level
8127 //
8128
8129 while (p <= n) p <<= 1;
8130
8131 p >>= 1;
8132 p2 = p;
8133 p >>= 1;
8134
8135 //
8136 // Hierarchical loop on smaller dimension n
8137 //
8138
8139 while (p >= 1) {
8140 unsigned short *py = in;
8141 unsigned short *ey = in + oy * (ny - p2);
8142 int oy1 = oy * p;
8143 int oy2 = oy * p2;
8144 int ox1 = ox * p;
8145 int ox2 = ox * p2;
8146 unsigned short i00, i01, i10, i11;
8147
8148 //
8149 // Y loop
8150 //
8151
8152 for (; py <= ey; py += oy2) {
8153 unsigned short *px = py;
8154 unsigned short *ex = py + ox * (nx - p2);
8155
8156 //
8157 // X loop
8158 //
8159
8160 for (; px <= ex; px += ox2) {
8161 unsigned short *p01 = px + ox1;
8162 unsigned short *p10 = px + oy1;
8163 unsigned short *p11 = p10 + ox1;
8164
8165 //
8166 // 2D wavelet decoding
8167 //
8168
8169 if (w14) {
8170 wdec14(*px, *p10, i00, i10);
8171 wdec14(*p01, *p11, i01, i11);
8172 wdec14(i00, i01, *px, *p01);
8173 wdec14(i10, i11, *p10, *p11);
8174 } else {
8175 wdec16(*px, *p10, i00, i10);
8176 wdec16(*p01, *p11, i01, i11);
8177 wdec16(i00, i01, *px, *p01);
8178 wdec16(i10, i11, *p10, *p11);
8179 }
8180 }
8181
8182 //
8183 // Decode (1D) odd column (still in Y loop)
8184 //
8185
8186 if (nx & p) {
8187 unsigned short *p10 = px + oy1;
8188
8189 if (w14)
8190 wdec14(*px, *p10, i00, *p10);
8191 else
8192 wdec16(*px, *p10, i00, *p10);
8193
8194 *px = i00;
8195 }
8196 }
8197
8198 //
8199 // Decode (1D) odd line (must loop in X)
8200 //
8201
8202 if (ny & p) {
8203 unsigned short *px = py;
8204 unsigned short *ex = py + ox * (nx - p2);
8205
8206 for (; px <= ex; px += ox2) {
8207 unsigned short *p01 = px + ox1;
8208
8209 if (w14)
8210 wdec14(*px, *p01, i00, *p01);
8211 else
8212 wdec16(*px, *p01, i00, *p01);
8213
8214 *px = i00;
8215 }
8216 }
8217
8218 //
8219 // Next level
8220 //
8221
8222 p2 = p;
8223 p >>= 1;
8224 }
8225 }
8226
8227 //-----------------------------------------------------------------------------
8228 //
8229 // 16-bit Huffman compression and decompression.
8230 //
8231 // The source code in this file is derived from the 8-bit
8232 // Huffman compression and decompression routines written
8233 // by Christian Rouet for his PIZ image file format.
8234 //
8235 //-----------------------------------------------------------------------------
8236
8237 // Adds some modification for tinyexr.
8238
8239 const int HUF_ENCBITS = 16; // literal (value) bit length
8240 const int HUF_DECBITS = 14; // decoding bit size (>= 8)
8241
8242 const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1; // encoding table size
8243 const int HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size
8244 const int HUF_DECMASK = HUF_DECSIZE - 1;
8245
8246 struct HufDec { // short code long code
8247 //-------------------------------
8248 int len : 8; // code length 0
8249 int lit : 24; // lit p size
8250 int *p; // 0 lits
8251 };
8252
hufLength(long long code)8253 inline long long hufLength(long long code) { return code & 63; }
8254
hufCode(long long code)8255 inline long long hufCode(long long code) { return code >> 6; }
8256
outputBits(int nBits,long long bits,long long & c,int & lc,char * & out)8257 inline void outputBits(int nBits, long long bits, long long &c, int &lc,
8258 char *&out) {
8259 c <<= nBits;
8260 lc += nBits;
8261
8262 c |= bits;
8263
8264 while (lc >= 8) *out++ = static_cast<char>((c >> (lc -= 8)));
8265 }
8266
getBits(int nBits,long long & c,int & lc,const char * & in)8267 inline long long getBits(int nBits, long long &c, int &lc, const char *&in) {
8268 while (lc < nBits) {
8269 c = (c << 8) | *(reinterpret_cast<const unsigned char *>(in++));
8270 lc += 8;
8271 }
8272
8273 lc -= nBits;
8274 return (c >> lc) & ((1 << nBits) - 1);
8275 }
8276
8277 //
8278 // ENCODING TABLE BUILDING & (UN)PACKING
8279 //
8280
8281 //
8282 // Build a "canonical" Huffman code table:
8283 // - for each (uncompressed) symbol, hcode contains the length
8284 // of the corresponding code (in the compressed data)
8285 // - canonical codes are computed and stored in hcode
8286 // - the rules for constructing canonical codes are as follows:
8287 // * shorter codes (if filled with zeroes to the right)
8288 // have a numerically higher value than longer codes
8289 // * for codes with the same length, numerical values
8290 // increase with numerical symbol values
8291 // - because the canonical code table can be constructed from
8292 // symbol lengths alone, the code table can be transmitted
8293 // without sending the actual code values
8294 // - see http://www.compressconsult.com/huffman/
8295 //
8296
hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE])8297 static void hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE]) {
8298 long long n[59];
8299
8300 //
8301 // For each i from 0 through 58, count the
8302 // number of different codes of length i, and
8303 // store the count in n[i].
8304 //
8305
8306 for (int i = 0; i <= 58; ++i) n[i] = 0;
8307
8308 for (int i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1;
8309
8310 //
8311 // For each i from 58 through 1, compute the
8312 // numerically lowest code with length i, and
8313 // store that code in n[i].
8314 //
8315
8316 long long c = 0;
8317
8318 for (int i = 58; i > 0; --i) {
8319 long long nc = ((c + n[i]) >> 1);
8320 n[i] = c;
8321 c = nc;
8322 }
8323
8324 //
8325 // hcode[i] contains the length, l, of the
8326 // code for symbol i. Assign the next available
8327 // code of length l to the symbol and store both
8328 // l and the code in hcode[i].
8329 //
8330
8331 for (int i = 0; i < HUF_ENCSIZE; ++i) {
8332 int l = static_cast<int>(hcode[i]);
8333
8334 if (l > 0) hcode[i] = l | (n[l]++ << 6);
8335 }
8336 }
8337
8338 //
8339 // Compute Huffman codes (based on frq input) and store them in frq:
8340 // - code structure is : [63:lsb - 6:msb] | [5-0: bit length];
8341 // - max code length is 58 bits;
8342 // - codes outside the range [im-iM] have a null length (unused values);
8343 // - original frequencies are destroyed;
8344 // - encoding tables are used by hufEncode() and hufBuildDecTable();
8345 //
8346
8347 struct FHeapCompare {
operatorFHeapCompare8348 bool operator()(long long *a, long long *b) { return *a > *b; }
8349 };
8350
hufBuildEncTable(long long * frq,int * im,int * iM)8351 static void hufBuildEncTable(
8352 long long *frq, // io: input frequencies [HUF_ENCSIZE], output table
8353 int *im, // o: min frq index
8354 int *iM) // o: max frq index
8355 {
8356 //
8357 // This function assumes that when it is called, array frq
8358 // indicates the frequency of all possible symbols in the data
8359 // that are to be Huffman-encoded. (frq[i] contains the number
8360 // of occurrences of symbol i in the data.)
8361 //
8362 // The loop below does three things:
8363 //
8364 // 1) Finds the minimum and maximum indices that point
8365 // to non-zero entries in frq:
8366 //
8367 // frq[im] != 0, and frq[i] == 0 for all i < im
8368 // frq[iM] != 0, and frq[i] == 0 for all i > iM
8369 //
8370 // 2) Fills array fHeap with pointers to all non-zero
8371 // entries in frq.
8372 //
8373 // 3) Initializes array hlink such that hlink[i] == i
8374 // for all array entries.
8375 //
8376
8377 std::vector<int> hlink(HUF_ENCSIZE);
8378 std::vector<long long *> fHeap(HUF_ENCSIZE);
8379
8380 *im = 0;
8381
8382 while (!frq[*im]) (*im)++;
8383
8384 int nf = 0;
8385
8386 for (int i = *im; i < HUF_ENCSIZE; i++) {
8387 hlink[i] = i;
8388
8389 if (frq[i]) {
8390 fHeap[nf] = &frq[i];
8391 nf++;
8392 *iM = i;
8393 }
8394 }
8395
8396 //
8397 // Add a pseudo-symbol, with a frequency count of 1, to frq;
8398 // adjust the fHeap and hlink array accordingly. Function
8399 // hufEncode() uses the pseudo-symbol for run-length encoding.
8400 //
8401
8402 (*iM)++;
8403 frq[*iM] = 1;
8404 fHeap[nf] = &frq[*iM];
8405 nf++;
8406
8407 //
8408 // Build an array, scode, such that scode[i] contains the number
8409 // of bits assigned to symbol i. Conceptually this is done by
8410 // constructing a tree whose leaves are the symbols with non-zero
8411 // frequency:
8412 //
8413 // Make a heap that contains all symbols with a non-zero frequency,
8414 // with the least frequent symbol on top.
8415 //
8416 // Repeat until only one symbol is left on the heap:
8417 //
8418 // Take the two least frequent symbols off the top of the heap.
8419 // Create a new node that has first two nodes as children, and
8420 // whose frequency is the sum of the frequencies of the first
8421 // two nodes. Put the new node back into the heap.
8422 //
8423 // The last node left on the heap is the root of the tree. For each
8424 // leaf node, the distance between the root and the leaf is the length
8425 // of the code for the corresponding symbol.
8426 //
8427 // The loop below doesn't actually build the tree; instead we compute
8428 // the distances of the leaves from the root on the fly. When a new
8429 // node is added to the heap, then that node's descendants are linked
8430 // into a single linear list that starts at the new node, and the code
8431 // lengths of the descendants (that is, their distance from the root
8432 // of the tree) are incremented by one.
8433 //
8434
8435 std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8436
8437 std::vector<long long> scode(HUF_ENCSIZE);
8438 memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE);
8439
8440 while (nf > 1) {
8441 //
8442 // Find the indices, mm and m, of the two smallest non-zero frq
8443 // values in fHeap, add the smallest frq to the second-smallest
8444 // frq, and remove the smallest frq value from fHeap.
8445 //
8446
8447 int mm = fHeap[0] - frq;
8448 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8449 --nf;
8450
8451 int m = fHeap[0] - frq;
8452 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8453
8454 frq[m] += frq[mm];
8455 std::push_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8456
8457 //
8458 // The entries in scode are linked into lists with the
8459 // entries in hlink serving as "next" pointers and with
8460 // the end of a list marked by hlink[j] == j.
8461 //
8462 // Traverse the lists that start at scode[m] and scode[mm].
8463 // For each element visited, increment the length of the
8464 // corresponding code by one bit. (If we visit scode[j]
8465 // during the traversal, then the code for symbol j becomes
8466 // one bit longer.)
8467 //
8468 // Merge the lists that start at scode[m] and scode[mm]
8469 // into a single list that starts at scode[m].
8470 //
8471
8472 //
8473 // Add a bit to all codes in the first list.
8474 //
8475
8476 for (int j = m;; j = hlink[j]) {
8477 scode[j]++;
8478
8479 assert(scode[j] <= 58);
8480
8481 if (hlink[j] == j) {
8482 //
8483 // Merge the two lists.
8484 //
8485
8486 hlink[j] = mm;
8487 break;
8488 }
8489 }
8490
8491 //
8492 // Add a bit to all codes in the second list
8493 //
8494
8495 for (int j = mm;; j = hlink[j]) {
8496 scode[j]++;
8497
8498 assert(scode[j] <= 58);
8499
8500 if (hlink[j] == j) break;
8501 }
8502 }
8503
8504 //
8505 // Build a canonical Huffman code table, replacing the code
8506 // lengths in scode with (code, code length) pairs. Copy the
8507 // code table from scode into frq.
8508 //
8509
8510 hufCanonicalCodeTable(scode.data());
8511 memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE);
8512 }
8513
8514 //
8515 // Pack an encoding table:
8516 // - only code lengths, not actual codes, are stored
8517 // - runs of zeroes are compressed as follows:
8518 //
8519 // unpacked packed
8520 // --------------------------------
8521 // 1 zero 0 (6 bits)
8522 // 2 zeroes 59
8523 // 3 zeroes 60
8524 // 4 zeroes 61
8525 // 5 zeroes 62
8526 // n zeroes (6 or more) 63 n-6 (6 + 8 bits)
8527 //
8528
8529 const int SHORT_ZEROCODE_RUN = 59;
8530 const int LONG_ZEROCODE_RUN = 63;
8531 const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
8532 const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN;
8533
hufPackEncTable(const long long * hcode,int im,int iM,char ** pcode)8534 static void hufPackEncTable(
8535 const long long *hcode, // i : encoding table [HUF_ENCSIZE]
8536 int im, // i : min hcode index
8537 int iM, // i : max hcode index
8538 char **pcode) // o: ptr to packed table (updated)
8539 {
8540 char *p = *pcode;
8541 long long c = 0;
8542 int lc = 0;
8543
8544 for (; im <= iM; im++) {
8545 int l = hufLength(hcode[im]);
8546
8547 if (l == 0) {
8548 int zerun = 1;
8549
8550 while ((im < iM) && (zerun < LONGEST_LONG_RUN)) {
8551 if (hufLength(hcode[im + 1]) > 0) break;
8552 im++;
8553 zerun++;
8554 }
8555
8556 if (zerun >= 2) {
8557 if (zerun >= SHORTEST_LONG_RUN) {
8558 outputBits(6, LONG_ZEROCODE_RUN, c, lc, p);
8559 outputBits(8, zerun - SHORTEST_LONG_RUN, c, lc, p);
8560 } else {
8561 outputBits(6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p);
8562 }
8563 continue;
8564 }
8565 }
8566
8567 outputBits(6, l, c, lc, p);
8568 }
8569
8570 if (lc > 0) *p++ = (unsigned char)(c << (8 - lc));
8571
8572 *pcode = p;
8573 }
8574
8575 //
8576 // Unpack an encoding table packed by hufPackEncTable():
8577 //
8578
hufUnpackEncTable(const char ** pcode,int ni,int im,int iM,long long * hcode)8579 static bool hufUnpackEncTable(
8580 const char **pcode, // io: ptr to packed table (updated)
8581 int ni, // i : input size (in bytes)
8582 int im, // i : min hcode index
8583 int iM, // i : max hcode index
8584 long long *hcode) // o: encoding table [HUF_ENCSIZE]
8585 {
8586 memset(hcode, 0, sizeof(long long) * HUF_ENCSIZE);
8587
8588 const char *p = *pcode;
8589 long long c = 0;
8590 int lc = 0;
8591
8592 for (; im <= iM; im++) {
8593 if (p - *pcode >= ni) {
8594 return false;
8595 }
8596
8597 long long l = hcode[im] = getBits(6, c, lc, p); // code length
8598
8599 if (l == (long long)LONG_ZEROCODE_RUN) {
8600 if (p - *pcode > ni) {
8601 return false;
8602 }
8603
8604 int zerun = getBits(8, c, lc, p) + SHORTEST_LONG_RUN;
8605
8606 if (im + zerun > iM + 1) {
8607 return false;
8608 }
8609
8610 while (zerun--) hcode[im++] = 0;
8611
8612 im--;
8613 } else if (l >= (long long)SHORT_ZEROCODE_RUN) {
8614 int zerun = l - SHORT_ZEROCODE_RUN + 2;
8615
8616 if (im + zerun > iM + 1) {
8617 return false;
8618 }
8619
8620 while (zerun--) hcode[im++] = 0;
8621
8622 im--;
8623 }
8624 }
8625
8626 *pcode = const_cast<char *>(p);
8627
8628 hufCanonicalCodeTable(hcode);
8629
8630 return true;
8631 }
8632
8633 //
8634 // DECODING TABLE BUILDING
8635 //
8636
8637 //
8638 // Clear a newly allocated decoding table so that it contains only zeroes.
8639 //
8640
hufClearDecTable(HufDec * hdecod)8641 static void hufClearDecTable(HufDec *hdecod) // io: (allocated by caller)
8642 // decoding table [HUF_DECSIZE]
8643 {
8644 for (int i = 0; i < HUF_DECSIZE; i++) {
8645 hdecod[i].len = 0;
8646 hdecod[i].lit = 0;
8647 hdecod[i].p = NULL;
8648 }
8649 // memset(hdecod, 0, sizeof(HufDec) * HUF_DECSIZE);
8650 }
8651
8652 //
8653 // Build a decoding hash table based on the encoding table hcode:
8654 // - short codes (<= HUF_DECBITS) are resolved with a single table access;
8655 // - long code entry allocations are not optimized, because long codes are
8656 // unfrequent;
8657 // - decoding tables are used by hufDecode();
8658 //
8659
hufBuildDecTable(const long long * hcode,int im,int iM,HufDec * hdecod)8660 static bool hufBuildDecTable(const long long *hcode, // i : encoding table
8661 int im, // i : min index in hcode
8662 int iM, // i : max index in hcode
8663 HufDec *hdecod) // o: (allocated by caller)
8664 // decoding table [HUF_DECSIZE]
8665 {
8666 //
8667 // Init hashtable & loop on all codes.
8668 // Assumes that hufClearDecTable(hdecod) has already been called.
8669 //
8670
8671 for (; im <= iM; im++) {
8672 long long c = hufCode(hcode[im]);
8673 int l = hufLength(hcode[im]);
8674
8675 if (c >> l) {
8676 //
8677 // Error: c is supposed to be an l-bit code,
8678 // but c contains a value that is greater
8679 // than the largest l-bit number.
8680 //
8681
8682 // invalidTableEntry();
8683 return false;
8684 }
8685
8686 if (l > HUF_DECBITS) {
8687 //
8688 // Long code: add a secondary entry
8689 //
8690
8691 HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
8692
8693 if (pl->len) {
8694 //
8695 // Error: a short code has already
8696 // been stored in table entry *pl.
8697 //
8698
8699 // invalidTableEntry();
8700 return false;
8701 }
8702
8703 pl->lit++;
8704
8705 if (pl->p) {
8706 int *p = pl->p;
8707 pl->p = new int[pl->lit];
8708
8709 for (int i = 0; i < pl->lit - 1; ++i) pl->p[i] = p[i];
8710
8711 delete[] p;
8712 } else {
8713 pl->p = new int[1];
8714 }
8715
8716 pl->p[pl->lit - 1] = im;
8717 } else if (l) {
8718 //
8719 // Short code: init all primary entries
8720 //
8721
8722 HufDec *pl = hdecod + (c << (HUF_DECBITS - l));
8723
8724 for (long long i = 1ULL << (HUF_DECBITS - l); i > 0; i--, pl++) {
8725 if (pl->len || pl->p) {
8726 //
8727 // Error: a short code or a long code has
8728 // already been stored in table entry *pl.
8729 //
8730
8731 // invalidTableEntry();
8732 return false;
8733 }
8734
8735 pl->len = l;
8736 pl->lit = im;
8737 }
8738 }
8739 }
8740
8741 return true;
8742 }
8743
8744 //
8745 // Free the long code entries of a decoding table built by hufBuildDecTable()
8746 //
8747
hufFreeDecTable(HufDec * hdecod)8748 static void hufFreeDecTable(HufDec *hdecod) // io: Decoding table
8749 {
8750 for (int i = 0; i < HUF_DECSIZE; i++) {
8751 if (hdecod[i].p) {
8752 delete[] hdecod[i].p;
8753 hdecod[i].p = 0;
8754 }
8755 }
8756 }
8757
8758 //
8759 // ENCODING
8760 //
8761
outputCode(long long code,long long & c,int & lc,char * & out)8762 inline void outputCode(long long code, long long &c, int &lc, char *&out) {
8763 outputBits(hufLength(code), hufCode(code), c, lc, out);
8764 }
8765
sendCode(long long sCode,int runCount,long long runCode,long long & c,int & lc,char * & out)8766 inline void sendCode(long long sCode, int runCount, long long runCode,
8767 long long &c, int &lc, char *&out) {
8768 //
8769 // Output a run of runCount instances of the symbol sCount.
8770 // Output the symbols explicitly, or if that is shorter, output
8771 // the sCode symbol once followed by a runCode symbol and runCount
8772 // expressed as an 8-bit number.
8773 //
8774
8775 if (hufLength(sCode) + hufLength(runCode) + 8 < hufLength(sCode) * runCount) {
8776 outputCode(sCode, c, lc, out);
8777 outputCode(runCode, c, lc, out);
8778 outputBits(8, runCount, c, lc, out);
8779 } else {
8780 while (runCount-- >= 0) outputCode(sCode, c, lc, out);
8781 }
8782 }
8783
8784 //
8785 // Encode (compress) ni values based on the Huffman encoding table hcode:
8786 //
8787
hufEncode(const long long * hcode,const unsigned short * in,const int ni,int rlc,char * out)8788 static int hufEncode // return: output size (in bits)
8789 (const long long *hcode, // i : encoding table
8790 const unsigned short *in, // i : uncompressed input buffer
8791 const int ni, // i : input buffer size (in bytes)
8792 int rlc, // i : rl code
8793 char *out) // o: compressed output buffer
8794 {
8795 char *outStart = out;
8796 long long c = 0; // bits not yet written to out
8797 int lc = 0; // number of valid bits in c (LSB)
8798 int s = in[0];
8799 int cs = 0;
8800
8801 //
8802 // Loop on input values
8803 //
8804
8805 for (int i = 1; i < ni; i++) {
8806 //
8807 // Count same values or send code
8808 //
8809
8810 if (s == in[i] && cs < 255) {
8811 cs++;
8812 } else {
8813 sendCode(hcode[s], cs, hcode[rlc], c, lc, out);
8814 cs = 0;
8815 }
8816
8817 s = in[i];
8818 }
8819
8820 //
8821 // Send remaining code
8822 //
8823
8824 sendCode(hcode[s], cs, hcode[rlc], c, lc, out);
8825
8826 if (lc) *out = (c << (8 - lc)) & 0xff;
8827
8828 return (out - outStart) * 8 + lc;
8829 }
8830
8831 //
8832 // DECODING
8833 //
8834
8835 //
8836 // In order to force the compiler to inline them,
8837 // getChar() and getCode() are implemented as macros
8838 // instead of "inline" functions.
8839 //
8840
8841 #define getChar(c, lc, in) \
8842 { \
8843 c = (c << 8) | *(unsigned char *)(in++); \
8844 lc += 8; \
8845 }
8846
8847 #if 0
8848 #define getCode(po, rlc, c, lc, in, out, ob, oe) \
8849 { \
8850 if (po == rlc) { \
8851 if (lc < 8) getChar(c, lc, in); \
8852 \
8853 lc -= 8; \
8854 \
8855 unsigned char cs = (c >> lc); \
8856 \
8857 if (out + cs > oe) return false; \
8858 \
8859 /* TinyEXR issue 78 */ \
8860 unsigned short s = out[-1]; \
8861 \
8862 while (cs-- > 0) *out++ = s; \
8863 } else if (out < oe) { \
8864 *out++ = po; \
8865 } else { \
8866 return false; \
8867 } \
8868 }
8869 #else
getCode(int po,int rlc,long long & c,int & lc,const char * & in,const char * in_end,unsigned short * & out,const unsigned short * ob,const unsigned short * oe)8870 static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in,
8871 const char *in_end, unsigned short *&out,
8872 const unsigned short *ob, const unsigned short *oe) {
8873 (void)ob;
8874 if (po == rlc) {
8875 if (lc < 8) {
8876 /* TinyEXR issue 78 */
8877 if ((in + 1) >= in_end) {
8878 return false;
8879 }
8880
8881 getChar(c, lc, in);
8882 }
8883
8884 lc -= 8;
8885
8886 unsigned char cs = (c >> lc);
8887
8888 if (out + cs > oe) return false;
8889
8890 // Bounds check for safety
8891 // Issue 100.
8892 if ((out - 1) < ob) return false;
8893 unsigned short s = out[-1];
8894
8895 while (cs-- > 0) *out++ = s;
8896 } else if (out < oe) {
8897 *out++ = po;
8898 } else {
8899 return false;
8900 }
8901 return true;
8902 }
8903 #endif
8904
8905 //
8906 // Decode (uncompress) ni bits based on encoding & decoding tables:
8907 //
8908
hufDecode(const long long * hcode,const HufDec * hdecod,const char * in,int ni,int rlc,int no,unsigned short * out)8909 static bool hufDecode(const long long *hcode, // i : encoding table
8910 const HufDec *hdecod, // i : decoding table
8911 const char *in, // i : compressed input buffer
8912 int ni, // i : input size (in bits)
8913 int rlc, // i : run-length code
8914 int no, // i : expected output size (in bytes)
8915 unsigned short *out) // o: uncompressed output buffer
8916 {
8917 long long c = 0;
8918 int lc = 0;
8919 unsigned short *outb = out; // begin
8920 unsigned short *oe = out + no; // end
8921 const char *ie = in + (ni + 7) / 8; // input byte size
8922
8923 //
8924 // Loop on input bytes
8925 //
8926
8927 while (in < ie) {
8928 getChar(c, lc, in);
8929
8930 //
8931 // Access decoding table
8932 //
8933
8934 while (lc >= HUF_DECBITS) {
8935 const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK];
8936
8937 if (pl.len) {
8938 //
8939 // Get short code
8940 //
8941
8942 lc -= pl.len;
8943 // std::cout << "lit = " << pl.lit << std::endl;
8944 // std::cout << "rlc = " << rlc << std::endl;
8945 // std::cout << "c = " << c << std::endl;
8946 // std::cout << "lc = " << lc << std::endl;
8947 // std::cout << "in = " << in << std::endl;
8948 // std::cout << "out = " << out << std::endl;
8949 // std::cout << "oe = " << oe << std::endl;
8950 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
8951 return false;
8952 }
8953 } else {
8954 if (!pl.p) {
8955 return false;
8956 }
8957 // invalidCode(); // wrong code
8958
8959 //
8960 // Search long code
8961 //
8962
8963 int j;
8964
8965 for (j = 0; j < pl.lit; j++) {
8966 int l = hufLength(hcode[pl.p[j]]);
8967
8968 while (lc < l && in < ie) // get more bits
8969 getChar(c, lc, in);
8970
8971 if (lc >= l) {
8972 if (hufCode(hcode[pl.p[j]]) ==
8973 ((c >> (lc - l)) & (((long long)(1) << l) - 1))) {
8974 //
8975 // Found : get long code
8976 //
8977
8978 lc -= l;
8979 if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) {
8980 return false;
8981 }
8982 break;
8983 }
8984 }
8985 }
8986
8987 if (j == pl.lit) {
8988 return false;
8989 // invalidCode(); // Not found
8990 }
8991 }
8992 }
8993 }
8994
8995 //
8996 // Get remaining (short) codes
8997 //
8998
8999 int i = (8 - ni) & 7;
9000 c >>= i;
9001 lc -= i;
9002
9003 while (lc > 0) {
9004 const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
9005
9006 if (pl.len) {
9007 lc -= pl.len;
9008 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
9009 return false;
9010 }
9011 } else {
9012 return false;
9013 // invalidCode(); // wrong (long) code
9014 }
9015 }
9016
9017 if (out - outb != no) {
9018 return false;
9019 }
9020 // notEnoughData ();
9021
9022 return true;
9023 }
9024
countFrequencies(std::vector<long long> & freq,const unsigned short data[],int n)9025 static void countFrequencies(std::vector<long long> &freq,
9026 const unsigned short data[/*n*/], int n) {
9027 for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0;
9028
9029 for (int i = 0; i < n; ++i) ++freq[data[i]];
9030 }
9031
writeUInt(char buf[4],unsigned int i)9032 static void writeUInt(char buf[4], unsigned int i) {
9033 unsigned char *b = (unsigned char *)buf;
9034
9035 b[0] = i;
9036 b[1] = i >> 8;
9037 b[2] = i >> 16;
9038 b[3] = i >> 24;
9039 }
9040
readUInt(const char buf[4])9041 static unsigned int readUInt(const char buf[4]) {
9042 const unsigned char *b = (const unsigned char *)buf;
9043
9044 return (b[0] & 0x000000ff) | ((b[1] << 8) & 0x0000ff00) |
9045 ((b[2] << 16) & 0x00ff0000) | ((b[3] << 24) & 0xff000000);
9046 }
9047
9048 //
9049 // EXTERNAL INTERFACE
9050 //
9051
hufCompress(const unsigned short raw[],int nRaw,char compressed[])9052 static int hufCompress(const unsigned short raw[], int nRaw,
9053 char compressed[]) {
9054 if (nRaw == 0) return 0;
9055
9056 std::vector<long long> freq(HUF_ENCSIZE);
9057
9058 countFrequencies(freq, raw, nRaw);
9059
9060 int im = 0;
9061 int iM = 0;
9062 hufBuildEncTable(freq.data(), &im, &iM);
9063
9064 char *tableStart = compressed + 20;
9065 char *tableEnd = tableStart;
9066 hufPackEncTable(freq.data(), im, iM, &tableEnd);
9067 int tableLength = tableEnd - tableStart;
9068
9069 char *dataStart = tableEnd;
9070 int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart);
9071 int data_length = (nBits + 7) / 8;
9072
9073 writeUInt(compressed, im);
9074 writeUInt(compressed + 4, iM);
9075 writeUInt(compressed + 8, tableLength);
9076 writeUInt(compressed + 12, nBits);
9077 writeUInt(compressed + 16, 0); // room for future extensions
9078
9079 return dataStart + data_length - compressed;
9080 }
9081
hufUncompress(const char compressed[],int nCompressed,std::vector<unsigned short> * raw)9082 static bool hufUncompress(const char compressed[], int nCompressed,
9083 std::vector<unsigned short> *raw) {
9084 if (nCompressed == 0) {
9085 if (raw->size() != 0) return false;
9086
9087 return false;
9088 }
9089
9090 int im = readUInt(compressed);
9091 int iM = readUInt(compressed + 4);
9092 // int tableLength = readUInt (compressed + 8);
9093 int nBits = readUInt(compressed + 12);
9094
9095 if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) return false;
9096
9097 const char *ptr = compressed + 20;
9098
9099 //
9100 // Fast decoder needs at least 2x64-bits of compressed data, and
9101 // needs to be run-able on this platform. Otherwise, fall back
9102 // to the original decoder
9103 //
9104
9105 // if (FastHufDecoder::enabled() && nBits > 128)
9106 //{
9107 // FastHufDecoder fhd (ptr, nCompressed - (ptr - compressed), im, iM, iM);
9108 // fhd.decode ((unsigned char*)ptr, nBits, raw, nRaw);
9109 //}
9110 // else
9111 {
9112 std::vector<long long> freq(HUF_ENCSIZE);
9113 std::vector<HufDec> hdec(HUF_DECSIZE);
9114
9115 hufClearDecTable(&hdec.at(0));
9116
9117 hufUnpackEncTable(&ptr, nCompressed - (ptr - compressed), im, iM,
9118 &freq.at(0));
9119
9120 {
9121 if (nBits > 8 * (nCompressed - (ptr - compressed))) {
9122 return false;
9123 }
9124
9125 hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0));
9126 hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(),
9127 raw->data());
9128 }
9129 // catch (...)
9130 //{
9131 // hufFreeDecTable (hdec);
9132 // throw;
9133 //}
9134
9135 hufFreeDecTable(&hdec.at(0));
9136 }
9137
9138 return true;
9139 }
9140
9141 //
9142 // Functions to compress the range of values in the pixel data
9143 //
9144
9145 const int USHORT_RANGE = (1 << 16);
9146 const int BITMAP_SIZE = (USHORT_RANGE >> 3);
9147
bitmapFromData(const unsigned short data[],int nData,unsigned char bitmap[BITMAP_SIZE],unsigned short & minNonZero,unsigned short & maxNonZero)9148 static void bitmapFromData(const unsigned short data[/*nData*/], int nData,
9149 unsigned char bitmap[BITMAP_SIZE],
9150 unsigned short &minNonZero,
9151 unsigned short &maxNonZero) {
9152 for (int i = 0; i < BITMAP_SIZE; ++i) bitmap[i] = 0;
9153
9154 for (int i = 0; i < nData; ++i) bitmap[data[i] >> 3] |= (1 << (data[i] & 7));
9155
9156 bitmap[0] &= ~1; // zero is not explicitly stored in
9157 // the bitmap; we assume that the
9158 // data always contain zeroes
9159 minNonZero = BITMAP_SIZE - 1;
9160 maxNonZero = 0;
9161
9162 for (int i = 0; i < BITMAP_SIZE; ++i) {
9163 if (bitmap[i]) {
9164 if (minNonZero > i) minNonZero = i;
9165 if (maxNonZero < i) maxNonZero = i;
9166 }
9167 }
9168 }
9169
forwardLutFromBitmap(const unsigned char bitmap[BITMAP_SIZE],unsigned short lut[USHORT_RANGE])9170 static unsigned short forwardLutFromBitmap(
9171 const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) {
9172 int k = 0;
9173
9174 for (int i = 0; i < USHORT_RANGE; ++i) {
9175 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
9176 lut[i] = k++;
9177 else
9178 lut[i] = 0;
9179 }
9180
9181 return k - 1; // maximum value stored in lut[],
9182 } // i.e. number of ones in bitmap minus 1
9183
reverseLutFromBitmap(const unsigned char bitmap[BITMAP_SIZE],unsigned short lut[USHORT_RANGE])9184 static unsigned short reverseLutFromBitmap(
9185 const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) {
9186 int k = 0;
9187
9188 for (int i = 0; i < USHORT_RANGE; ++i) {
9189 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) lut[k++] = i;
9190 }
9191
9192 int n = k - 1;
9193
9194 while (k < USHORT_RANGE) lut[k++] = 0;
9195
9196 return n; // maximum k where lut[k] is non-zero,
9197 } // i.e. number of ones in bitmap minus 1
9198
applyLut(const unsigned short lut[USHORT_RANGE],unsigned short data[],int nData)9199 static void applyLut(const unsigned short lut[USHORT_RANGE],
9200 unsigned short data[/*nData*/], int nData) {
9201 for (int i = 0; i < nData; ++i) data[i] = lut[data[i]];
9202 }
9203
9204 #ifdef __clang__
9205 #pragma clang diagnostic pop
9206 #endif // __clang__
9207
9208 #ifdef _MSC_VER
9209 #pragma warning(pop)
9210 #endif
9211
CompressPiz(unsigned char * outPtr,unsigned int * outSize,const unsigned char * inPtr,size_t inSize,const std::vector<ChannelInfo> & channelInfo,int data_width,int num_lines)9212 static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
9213 const unsigned char *inPtr, size_t inSize,
9214 const std::vector<ChannelInfo> &channelInfo,
9215 int data_width, int num_lines) {
9216 std::vector<unsigned char> bitmap(BITMAP_SIZE);
9217 unsigned short minNonZero;
9218 unsigned short maxNonZero;
9219
9220 #if !MINIZ_LITTLE_ENDIAN
9221 // @todo { PIZ compression on BigEndian architecture. }
9222 assert(0);
9223 return false;
9224 #endif
9225
9226 // Assume `inSize` is multiple of 2 or 4.
9227 std::vector<unsigned short> tmpBuffer(inSize / sizeof(unsigned short));
9228
9229 std::vector<PIZChannelData> channelData(channelInfo.size());
9230 unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
9231
9232 for (size_t c = 0; c < channelData.size(); c++) {
9233 PIZChannelData &cd = channelData[c];
9234
9235 cd.start = tmpBufferEnd;
9236 cd.end = cd.start;
9237
9238 cd.nx = data_width;
9239 cd.ny = num_lines;
9240 // cd.ys = c.channel().ySampling;
9241
9242 size_t pixelSize = sizeof(int); // UINT and FLOAT
9243 if (channelInfo[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9244 pixelSize = sizeof(short);
9245 }
9246
9247 cd.size = static_cast<int>(pixelSize / sizeof(short));
9248
9249 tmpBufferEnd += cd.nx * cd.ny * cd.size;
9250 }
9251
9252 const unsigned char *ptr = inPtr;
9253 for (int y = 0; y < num_lines; ++y) {
9254 for (size_t i = 0; i < channelData.size(); ++i) {
9255 PIZChannelData &cd = channelData[i];
9256
9257 // if (modp (y, cd.ys) != 0)
9258 // continue;
9259
9260 size_t n = static_cast<size_t>(cd.nx * cd.size);
9261 memcpy(cd.end, ptr, n * sizeof(unsigned short));
9262 ptr += n * sizeof(unsigned short);
9263 cd.end += n;
9264 }
9265 }
9266
9267 bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()),
9268 bitmap.data(), minNonZero, maxNonZero);
9269
9270 std::vector<unsigned short> lut(USHORT_RANGE);
9271 unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data());
9272 applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()));
9273
9274 //
9275 // Store range compression info in _outBuffer
9276 //
9277
9278 char *buf = reinterpret_cast<char *>(outPtr);
9279
9280 memcpy(buf, &minNonZero, sizeof(unsigned short));
9281 buf += sizeof(unsigned short);
9282 memcpy(buf, &maxNonZero, sizeof(unsigned short));
9283 buf += sizeof(unsigned short);
9284
9285 if (minNonZero <= maxNonZero) {
9286 memcpy(buf, reinterpret_cast<char *>(&bitmap[0] + minNonZero),
9287 maxNonZero - minNonZero + 1);
9288 buf += maxNonZero - minNonZero + 1;
9289 }
9290
9291 //
9292 // Apply wavelet encoding
9293 //
9294
9295 for (size_t i = 0; i < channelData.size(); ++i) {
9296 PIZChannelData &cd = channelData[i];
9297
9298 for (int j = 0; j < cd.size; ++j) {
9299 wav2Encode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size,
9300 maxValue);
9301 }
9302 }
9303
9304 //
9305 // Apply Huffman encoding; append the result to _outBuffer
9306 //
9307
9308 // length header(4byte), then huff data. Initialize length header with zero,
9309 // then later fill it by `length`.
9310 char *lengthPtr = buf;
9311 int zero = 0;
9312 memcpy(buf, &zero, sizeof(int));
9313 buf += sizeof(int);
9314
9315 int length =
9316 hufCompress(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), buf);
9317 memcpy(lengthPtr, &length, sizeof(int));
9318
9319 (*outSize) = static_cast<unsigned int>(
9320 (reinterpret_cast<unsigned char *>(buf) - outPtr) +
9321 static_cast<unsigned int>(length));
9322
9323 // Use uncompressed data when compressed data is larger than uncompressed.
9324 // (Issue 40)
9325 if ((*outSize) >= inSize) {
9326 (*outSize) = static_cast<unsigned int>(inSize);
9327 memcpy(outPtr, inPtr, inSize);
9328 }
9329 return true;
9330 }
9331
DecompressPiz(unsigned char * outPtr,const unsigned char * inPtr,size_t tmpBufSize,size_t inLen,int num_channels,const EXRChannelInfo * channels,int data_width,int num_lines)9332 static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
9333 size_t tmpBufSize, size_t inLen, int num_channels,
9334 const EXRChannelInfo *channels, int data_width,
9335 int num_lines) {
9336 if (inLen == tmpBufSize) {
9337 // Data is not compressed(Issue 40).
9338 memcpy(outPtr, inPtr, inLen);
9339 return true;
9340 }
9341
9342 std::vector<unsigned char> bitmap(BITMAP_SIZE);
9343 unsigned short minNonZero;
9344 unsigned short maxNonZero;
9345
9346 #if !MINIZ_LITTLE_ENDIAN
9347 // @todo { PIZ compression on BigEndian architecture. }
9348 assert(0);
9349 return false;
9350 #endif
9351
9352 memset(bitmap.data(), 0, BITMAP_SIZE);
9353
9354 const unsigned char *ptr = inPtr;
9355 // minNonZero = *(reinterpret_cast<const unsigned short *>(ptr));
9356 tinyexr::cpy2(&minNonZero, reinterpret_cast<const unsigned short *>(ptr));
9357 // maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2));
9358 tinyexr::cpy2(&maxNonZero, reinterpret_cast<const unsigned short *>(ptr + 2));
9359 ptr += 4;
9360
9361 if (maxNonZero >= BITMAP_SIZE) {
9362 return false;
9363 }
9364
9365 if (minNonZero <= maxNonZero) {
9366 memcpy(reinterpret_cast<char *>(&bitmap[0] + minNonZero), ptr,
9367 maxNonZero - minNonZero + 1);
9368 ptr += maxNonZero - minNonZero + 1;
9369 }
9370
9371 std::vector<unsigned short> lut(USHORT_RANGE);
9372 memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE);
9373 unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data());
9374
9375 //
9376 // Huffman decoding
9377 //
9378
9379 int length;
9380
9381 // length = *(reinterpret_cast<const int *>(ptr));
9382 tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr));
9383 ptr += sizeof(int);
9384
9385 if (size_t((ptr - inPtr) + length) > inLen) {
9386 return false;
9387 }
9388
9389 std::vector<unsigned short> tmpBuffer(tmpBufSize);
9390 hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer);
9391
9392 //
9393 // Wavelet decoding
9394 //
9395
9396 std::vector<PIZChannelData> channelData(static_cast<size_t>(num_channels));
9397
9398 unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
9399
9400 for (size_t i = 0; i < static_cast<size_t>(num_channels); ++i) {
9401 const EXRChannelInfo &chan = channels[i];
9402
9403 size_t pixelSize = sizeof(int); // UINT and FLOAT
9404 if (chan.pixel_type == TINYEXR_PIXELTYPE_HALF) {
9405 pixelSize = sizeof(short);
9406 }
9407
9408 channelData[i].start = tmpBufferEnd;
9409 channelData[i].end = channelData[i].start;
9410 channelData[i].nx = data_width;
9411 channelData[i].ny = num_lines;
9412 // channelData[i].ys = 1;
9413 channelData[i].size = static_cast<int>(pixelSize / sizeof(short));
9414
9415 tmpBufferEnd += channelData[i].nx * channelData[i].ny * channelData[i].size;
9416 }
9417
9418 for (size_t i = 0; i < channelData.size(); ++i) {
9419 PIZChannelData &cd = channelData[i];
9420
9421 for (int j = 0; j < cd.size; ++j) {
9422 wav2Decode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size,
9423 maxValue);
9424 }
9425 }
9426
9427 //
9428 // Expand the pixel data to their original range
9429 //
9430
9431 applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBufSize));
9432
9433 for (int y = 0; y < num_lines; y++) {
9434 for (size_t i = 0; i < channelData.size(); ++i) {
9435 PIZChannelData &cd = channelData[i];
9436
9437 // if (modp (y, cd.ys) != 0)
9438 // continue;
9439
9440 size_t n = static_cast<size_t>(cd.nx * cd.size);
9441 memcpy(outPtr, cd.end, static_cast<size_t>(n * sizeof(unsigned short)));
9442 outPtr += n * sizeof(unsigned short);
9443 cd.end += n;
9444 }
9445 }
9446
9447 return true;
9448 }
9449 #endif // TINYEXR_USE_PIZ
9450
9451 #if TINYEXR_USE_ZFP
9452 struct ZFPCompressionParam {
9453 double rate;
9454 int precision;
9455 double tolerance;
9456 int type; // TINYEXR_ZFP_COMPRESSIONTYPE_*
9457
ZFPCompressionParamZFPCompressionParam9458 ZFPCompressionParam() {
9459 type = TINYEXR_ZFP_COMPRESSIONTYPE_RATE;
9460 rate = 2.0;
9461 precision = 0;
9462 tolerance = 0.0f;
9463 }
9464 };
9465
FindZFPCompressionParam(ZFPCompressionParam * param,const EXRAttribute * attributes,int num_attributes)9466 bool FindZFPCompressionParam(ZFPCompressionParam *param,
9467 const EXRAttribute *attributes,
9468 int num_attributes) {
9469 bool foundType = false;
9470
9471 for (int i = 0; i < num_attributes; i++) {
9472 if ((strcmp(attributes[i].name, "zfpCompressionType") == 0) &&
9473 (attributes[i].size == 1)) {
9474 param->type = static_cast<int>(attributes[i].value[0]);
9475
9476 foundType = true;
9477 }
9478 }
9479
9480 if (!foundType) {
9481 return false;
9482 }
9483
9484 if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
9485 for (int i = 0; i < num_attributes; i++) {
9486 if ((strcmp(attributes[i].name, "zfpCompressionRate") == 0) &&
9487 (attributes[i].size == 8)) {
9488 param->rate = *(reinterpret_cast<double *>(attributes[i].value));
9489 return true;
9490 }
9491 }
9492 } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
9493 for (int i = 0; i < num_attributes; i++) {
9494 if ((strcmp(attributes[i].name, "zfpCompressionPrecision") == 0) &&
9495 (attributes[i].size == 4)) {
9496 param->rate = *(reinterpret_cast<int *>(attributes[i].value));
9497 return true;
9498 }
9499 }
9500 } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
9501 for (int i = 0; i < num_attributes; i++) {
9502 if ((strcmp(attributes[i].name, "zfpCompressionTolerance") == 0) &&
9503 (attributes[i].size == 8)) {
9504 param->tolerance = *(reinterpret_cast<double *>(attributes[i].value));
9505 return true;
9506 }
9507 }
9508 } else {
9509 assert(0);
9510 }
9511
9512 return false;
9513 }
9514
9515 // Assume pixel format is FLOAT for all channels.
DecompressZfp(float * dst,int dst_width,int dst_num_lines,int num_channels,const unsigned char * src,unsigned long src_size,const ZFPCompressionParam & param)9516 static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
9517 int num_channels, const unsigned char *src,
9518 unsigned long src_size,
9519 const ZFPCompressionParam ¶m) {
9520 size_t uncompressed_size = dst_width * dst_num_lines * num_channels;
9521
9522 if (uncompressed_size == src_size) {
9523 // Data is not compressed(Issue 40).
9524 memcpy(dst, src, src_size);
9525 }
9526
9527 zfp_stream *zfp = NULL;
9528 zfp_field *field = NULL;
9529
9530 assert((dst_width % 4) == 0);
9531 assert((dst_num_lines % 4) == 0);
9532
9533 if ((dst_width & 3U) || (dst_num_lines & 3U)) {
9534 return false;
9535 }
9536
9537 field =
9538 zfp_field_2d(reinterpret_cast<void *>(const_cast<unsigned char *>(src)),
9539 zfp_type_float, dst_width, dst_num_lines * num_channels);
9540 zfp = zfp_stream_open(NULL);
9541
9542 if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
9543 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimention */ 2,
9544 /* write random access */ 0);
9545 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
9546 zfp_stream_set_precision(zfp, param.precision, zfp_type_float);
9547 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
9548 zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float);
9549 } else {
9550 assert(0);
9551 }
9552
9553 size_t buf_size = zfp_stream_maximum_size(zfp, field);
9554 std::vector<unsigned char> buf(buf_size);
9555 memcpy(&buf.at(0), src, src_size);
9556
9557 bitstream *stream = stream_open(&buf.at(0), buf_size);
9558 zfp_stream_set_bit_stream(zfp, stream);
9559 zfp_stream_rewind(zfp);
9560
9561 size_t image_size = dst_width * dst_num_lines;
9562
9563 for (int c = 0; c < num_channels; c++) {
9564 // decompress 4x4 pixel block.
9565 for (int y = 0; y < dst_num_lines; y += 4) {
9566 for (int x = 0; x < dst_width; x += 4) {
9567 float fblock[16];
9568 zfp_decode_block_float_2(zfp, fblock);
9569 for (int j = 0; j < 4; j++) {
9570 for (int i = 0; i < 4; i++) {
9571 dst[c * image_size + ((y + j) * dst_width + (x + i))] =
9572 fblock[j * 4 + i];
9573 }
9574 }
9575 }
9576 }
9577 }
9578
9579 zfp_field_free(field);
9580 zfp_stream_close(zfp);
9581 stream_close(stream);
9582
9583 return true;
9584 }
9585
9586 // Assume pixel format is FLOAT for all channels.
CompressZfp(std::vector<unsigned char> * outBuf,unsigned int * outSize,const float * inPtr,int width,int num_lines,int num_channels,const ZFPCompressionParam & param)9587 bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
9588 const float *inPtr, int width, int num_lines, int num_channels,
9589 const ZFPCompressionParam ¶m) {
9590 zfp_stream *zfp = NULL;
9591 zfp_field *field = NULL;
9592
9593 assert((width % 4) == 0);
9594 assert((num_lines % 4) == 0);
9595
9596 if ((width & 3U) || (num_lines & 3U)) {
9597 return false;
9598 }
9599
9600 // create input array.
9601 field = zfp_field_2d(reinterpret_cast<void *>(const_cast<float *>(inPtr)),
9602 zfp_type_float, width, num_lines * num_channels);
9603
9604 zfp = zfp_stream_open(NULL);
9605
9606 if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
9607 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0);
9608 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
9609 zfp_stream_set_precision(zfp, param.precision, zfp_type_float);
9610 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
9611 zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float);
9612 } else {
9613 assert(0);
9614 }
9615
9616 size_t buf_size = zfp_stream_maximum_size(zfp, field);
9617
9618 outBuf->resize(buf_size);
9619
9620 bitstream *stream = stream_open(&outBuf->at(0), buf_size);
9621 zfp_stream_set_bit_stream(zfp, stream);
9622 zfp_field_free(field);
9623
9624 size_t image_size = width * num_lines;
9625
9626 for (int c = 0; c < num_channels; c++) {
9627 // compress 4x4 pixel block.
9628 for (int y = 0; y < num_lines; y += 4) {
9629 for (int x = 0; x < width; x += 4) {
9630 float fblock[16];
9631 for (int j = 0; j < 4; j++) {
9632 for (int i = 0; i < 4; i++) {
9633 fblock[j * 4 + i] =
9634 inPtr[c * image_size + ((y + j) * width + (x + i))];
9635 }
9636 }
9637 zfp_encode_block_float_2(zfp, fblock);
9638 }
9639 }
9640 }
9641
9642 zfp_stream_flush(zfp);
9643 (*outSize) = zfp_stream_compressed_size(zfp);
9644
9645 zfp_stream_close(zfp);
9646
9647 return true;
9648 }
9649
9650 #endif
9651
9652 //
9653 // -----------------------------------------------------------------
9654 //
9655
9656 // TODO(syoyo): Refactor function arguments.
DecodePixelData(unsigned char ** out_images,const int * requested_pixel_types,const unsigned char * data_ptr,size_t data_len,int compression_type,int line_order,int width,int height,int x_stride,int y,int line_no,int num_lines,size_t pixel_data_size,size_t num_attributes,const EXRAttribute * attributes,size_t num_channels,const EXRChannelInfo * channels,const std::vector<size_t> & channel_offset_list)9657 static bool DecodePixelData(/* out */ unsigned char **out_images,
9658 const int *requested_pixel_types,
9659 const unsigned char *data_ptr, size_t data_len,
9660 int compression_type, int line_order, int width,
9661 int height, int x_stride, int y, int line_no,
9662 int num_lines, size_t pixel_data_size,
9663 size_t num_attributes,
9664 const EXRAttribute *attributes, size_t num_channels,
9665 const EXRChannelInfo *channels,
9666 const std::vector<size_t> &channel_offset_list) {
9667 if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ
9668 #if TINYEXR_USE_PIZ
9669 if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) {
9670 // Invalid input #90
9671 return false;
9672 }
9673
9674 // Allocate original data size.
9675 std::vector<unsigned char> outBuf(static_cast<size_t>(
9676 static_cast<size_t>(width * num_lines) * pixel_data_size));
9677 size_t tmpBufLen = outBuf.size();
9678
9679 bool ret = tinyexr::DecompressPiz(
9680 reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen,
9681 data_len, static_cast<int>(num_channels), channels, width, num_lines);
9682
9683 if (!ret) {
9684 return false;
9685 }
9686
9687 // For PIZ_COMPRESSION:
9688 // pixel sample data for channel 0 for scanline 0
9689 // pixel sample data for channel 1 for scanline 0
9690 // pixel sample data for channel ... for scanline 0
9691 // pixel sample data for channel n for scanline 0
9692 // pixel sample data for channel 0 for scanline 1
9693 // pixel sample data for channel 1 for scanline 1
9694 // pixel sample data for channel ... for scanline 1
9695 // pixel sample data for channel n for scanline 1
9696 // ...
9697 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
9698 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9699 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9700 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
9701 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9702 channel_offset_list[c] * static_cast<size_t>(width)));
9703 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9704 FP16 hf;
9705
9706 // hf.u = line_ptr[u];
9707 // use `cpy` to avoid unaligned memory access when compiler's
9708 // optimization is on.
9709 tinyexr::cpy2(&(hf.u), line_ptr + u);
9710
9711 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
9712
9713 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
9714 unsigned short *image =
9715 reinterpret_cast<unsigned short **>(out_images)[c];
9716 if (line_order == 0) {
9717 image += (static_cast<size_t>(line_no) + v) *
9718 static_cast<size_t>(x_stride) +
9719 u;
9720 } else {
9721 image += static_cast<size_t>(
9722 (height - 1 - (line_no + static_cast<int>(v)))) *
9723 static_cast<size_t>(x_stride) +
9724 u;
9725 }
9726 *image = hf.u;
9727 } else { // HALF -> FLOAT
9728 FP32 f32 = half_to_float(hf);
9729 float *image = reinterpret_cast<float **>(out_images)[c];
9730 size_t offset = 0;
9731 if (line_order == 0) {
9732 offset = (static_cast<size_t>(line_no) + v) *
9733 static_cast<size_t>(x_stride) +
9734 u;
9735 } else {
9736 offset = static_cast<size_t>(
9737 (height - 1 - (line_no + static_cast<int>(v)))) *
9738 static_cast<size_t>(x_stride) +
9739 u;
9740 }
9741 image += offset;
9742 *image = f32.f;
9743 }
9744 }
9745 }
9746 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
9747 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
9748
9749 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9750 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
9751 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9752 channel_offset_list[c] * static_cast<size_t>(width)));
9753 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9754 unsigned int val;
9755 // val = line_ptr[u];
9756 tinyexr::cpy4(&val, line_ptr + u);
9757
9758 tinyexr::swap4(&val);
9759
9760 unsigned int *image =
9761 reinterpret_cast<unsigned int **>(out_images)[c];
9762 if (line_order == 0) {
9763 image += (static_cast<size_t>(line_no) + v) *
9764 static_cast<size_t>(x_stride) +
9765 u;
9766 } else {
9767 image += static_cast<size_t>(
9768 (height - 1 - (line_no + static_cast<int>(v)))) *
9769 static_cast<size_t>(x_stride) +
9770 u;
9771 }
9772 *image = val;
9773 }
9774 }
9775 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
9776 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
9777 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9778 const float *line_ptr = reinterpret_cast<float *>(&outBuf.at(
9779 v * pixel_data_size * static_cast<size_t>(x_stride) +
9780 channel_offset_list[c] * static_cast<size_t>(x_stride)));
9781 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9782 float val;
9783 // val = line_ptr[u];
9784 tinyexr::cpy4(&val, line_ptr + u);
9785
9786 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
9787
9788 float *image = reinterpret_cast<float **>(out_images)[c];
9789 if (line_order == 0) {
9790 image += (static_cast<size_t>(line_no) + v) *
9791 static_cast<size_t>(x_stride) +
9792 u;
9793 } else {
9794 image += static_cast<size_t>(
9795 (height - 1 - (line_no + static_cast<int>(v)))) *
9796 static_cast<size_t>(x_stride) +
9797 u;
9798 }
9799 *image = val;
9800 }
9801 }
9802 } else {
9803 assert(0);
9804 }
9805 }
9806 #else
9807 assert(0 && "PIZ is enabled in this build");
9808 return false;
9809 #endif
9810
9811 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS ||
9812 compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
9813 // Allocate original data size.
9814 std::vector<unsigned char> outBuf(static_cast<size_t>(width) *
9815 static_cast<size_t>(num_lines) *
9816 pixel_data_size);
9817
9818 unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
9819 assert(dstLen > 0);
9820 if (!tinyexr::DecompressZip(
9821 reinterpret_cast<unsigned char *>(&outBuf.at(0)), &dstLen, data_ptr,
9822 static_cast<unsigned long>(data_len))) {
9823 return false;
9824 }
9825
9826 // For ZIP_COMPRESSION:
9827 // pixel sample data for channel 0 for scanline 0
9828 // pixel sample data for channel 1 for scanline 0
9829 // pixel sample data for channel ... for scanline 0
9830 // pixel sample data for channel n for scanline 0
9831 // pixel sample data for channel 0 for scanline 1
9832 // pixel sample data for channel 1 for scanline 1
9833 // pixel sample data for channel ... for scanline 1
9834 // pixel sample data for channel n for scanline 1
9835 // ...
9836 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
9837 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9838 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9839 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
9840 &outBuf.at(v * static_cast<size_t>(pixel_data_size) *
9841 static_cast<size_t>(width) +
9842 channel_offset_list[c] * static_cast<size_t>(width)));
9843 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9844 tinyexr::FP16 hf;
9845
9846 // hf.u = line_ptr[u];
9847 tinyexr::cpy2(&(hf.u), line_ptr + u);
9848
9849 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
9850
9851 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
9852 unsigned short *image =
9853 reinterpret_cast<unsigned short **>(out_images)[c];
9854 if (line_order == 0) {
9855 image += (static_cast<size_t>(line_no) + v) *
9856 static_cast<size_t>(x_stride) +
9857 u;
9858 } else {
9859 image += (static_cast<size_t>(height) - 1U -
9860 (static_cast<size_t>(line_no) + v)) *
9861 static_cast<size_t>(x_stride) +
9862 u;
9863 }
9864 *image = hf.u;
9865 } else { // HALF -> FLOAT
9866 tinyexr::FP32 f32 = half_to_float(hf);
9867 float *image = reinterpret_cast<float **>(out_images)[c];
9868 size_t offset = 0;
9869 if (line_order == 0) {
9870 offset = (static_cast<size_t>(line_no) + v) *
9871 static_cast<size_t>(x_stride) +
9872 u;
9873 } else {
9874 offset = (static_cast<size_t>(height) - 1U -
9875 (static_cast<size_t>(line_no) + v)) *
9876 static_cast<size_t>(x_stride) +
9877 u;
9878 }
9879 image += offset;
9880
9881 *image = f32.f;
9882 }
9883 }
9884 }
9885 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
9886 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
9887
9888 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9889 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
9890 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9891 channel_offset_list[c] * static_cast<size_t>(width)));
9892 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9893 unsigned int val;
9894 // val = line_ptr[u];
9895 tinyexr::cpy4(&val, line_ptr + u);
9896
9897 tinyexr::swap4(&val);
9898
9899 unsigned int *image =
9900 reinterpret_cast<unsigned int **>(out_images)[c];
9901 if (line_order == 0) {
9902 image += (static_cast<size_t>(line_no) + v) *
9903 static_cast<size_t>(x_stride) +
9904 u;
9905 } else {
9906 image += (static_cast<size_t>(height) - 1U -
9907 (static_cast<size_t>(line_no) + v)) *
9908 static_cast<size_t>(x_stride) +
9909 u;
9910 }
9911 *image = val;
9912 }
9913 }
9914 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
9915 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
9916 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9917 const float *line_ptr = reinterpret_cast<float *>(
9918 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9919 channel_offset_list[c] * static_cast<size_t>(width)));
9920 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9921 float val;
9922 // val = line_ptr[u];
9923 tinyexr::cpy4(&val, line_ptr + u);
9924
9925 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
9926
9927 float *image = reinterpret_cast<float **>(out_images)[c];
9928 if (line_order == 0) {
9929 image += (static_cast<size_t>(line_no) + v) *
9930 static_cast<size_t>(x_stride) +
9931 u;
9932 } else {
9933 image += (static_cast<size_t>(height) - 1U -
9934 (static_cast<size_t>(line_no) + v)) *
9935 static_cast<size_t>(x_stride) +
9936 u;
9937 }
9938 *image = val;
9939 }
9940 }
9941 } else {
9942 assert(0);
9943 return false;
9944 }
9945 }
9946 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) {
9947 // Allocate original data size.
9948 std::vector<unsigned char> outBuf(static_cast<size_t>(width) *
9949 static_cast<size_t>(num_lines) *
9950 pixel_data_size);
9951
9952 unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
9953 if (dstLen == 0) {
9954 return false;
9955 }
9956
9957 if (!tinyexr::DecompressRle(reinterpret_cast<unsigned char *>(&outBuf.at(0)),
9958 dstLen, data_ptr,
9959 static_cast<unsigned long>(data_len))) {
9960 return false;
9961 }
9962
9963 // For RLE_COMPRESSION:
9964 // pixel sample data for channel 0 for scanline 0
9965 // pixel sample data for channel 1 for scanline 0
9966 // pixel sample data for channel ... for scanline 0
9967 // pixel sample data for channel n for scanline 0
9968 // pixel sample data for channel 0 for scanline 1
9969 // pixel sample data for channel 1 for scanline 1
9970 // pixel sample data for channel ... for scanline 1
9971 // pixel sample data for channel n for scanline 1
9972 // ...
9973 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
9974 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9975 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9976 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
9977 &outBuf.at(v * static_cast<size_t>(pixel_data_size) *
9978 static_cast<size_t>(width) +
9979 channel_offset_list[c] * static_cast<size_t>(width)));
9980 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9981 tinyexr::FP16 hf;
9982
9983 // hf.u = line_ptr[u];
9984 tinyexr::cpy2(&(hf.u), line_ptr + u);
9985
9986 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
9987
9988 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
9989 unsigned short *image =
9990 reinterpret_cast<unsigned short **>(out_images)[c];
9991 if (line_order == 0) {
9992 image += (static_cast<size_t>(line_no) + v) *
9993 static_cast<size_t>(x_stride) +
9994 u;
9995 } else {
9996 image += (static_cast<size_t>(height) - 1U -
9997 (static_cast<size_t>(line_no) + v)) *
9998 static_cast<size_t>(x_stride) +
9999 u;
10000 }
10001 *image = hf.u;
10002 } else { // HALF -> FLOAT
10003 tinyexr::FP32 f32 = half_to_float(hf);
10004 float *image = reinterpret_cast<float **>(out_images)[c];
10005 if (line_order == 0) {
10006 image += (static_cast<size_t>(line_no) + v) *
10007 static_cast<size_t>(x_stride) +
10008 u;
10009 } else {
10010 image += (static_cast<size_t>(height) - 1U -
10011 (static_cast<size_t>(line_no) + v)) *
10012 static_cast<size_t>(x_stride) +
10013 u;
10014 }
10015 *image = f32.f;
10016 }
10017 }
10018 }
10019 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10020 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
10021
10022 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10023 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
10024 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
10025 channel_offset_list[c] * static_cast<size_t>(width)));
10026 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10027 unsigned int val;
10028 // val = line_ptr[u];
10029 tinyexr::cpy4(&val, line_ptr + u);
10030
10031 tinyexr::swap4(&val);
10032
10033 unsigned int *image =
10034 reinterpret_cast<unsigned int **>(out_images)[c];
10035 if (line_order == 0) {
10036 image += (static_cast<size_t>(line_no) + v) *
10037 static_cast<size_t>(x_stride) +
10038 u;
10039 } else {
10040 image += (static_cast<size_t>(height) - 1U -
10041 (static_cast<size_t>(line_no) + v)) *
10042 static_cast<size_t>(x_stride) +
10043 u;
10044 }
10045 *image = val;
10046 }
10047 }
10048 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10049 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
10050 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10051 const float *line_ptr = reinterpret_cast<float *>(
10052 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
10053 channel_offset_list[c] * static_cast<size_t>(width)));
10054 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10055 float val;
10056 // val = line_ptr[u];
10057 tinyexr::cpy4(&val, line_ptr + u);
10058
10059 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10060
10061 float *image = reinterpret_cast<float **>(out_images)[c];
10062 if (line_order == 0) {
10063 image += (static_cast<size_t>(line_no) + v) *
10064 static_cast<size_t>(x_stride) +
10065 u;
10066 } else {
10067 image += (static_cast<size_t>(height) - 1U -
10068 (static_cast<size_t>(line_no) + v)) *
10069 static_cast<size_t>(x_stride) +
10070 u;
10071 }
10072 *image = val;
10073 }
10074 }
10075 } else {
10076 assert(0);
10077 return false;
10078 }
10079 }
10080 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
10081 #if TINYEXR_USE_ZFP
10082 tinyexr::ZFPCompressionParam zfp_compression_param;
10083 if (!FindZFPCompressionParam(&zfp_compression_param, attributes,
10084 num_attributes)) {
10085 assert(0);
10086 return false;
10087 }
10088
10089 // Allocate original data size.
10090 std::vector<unsigned char> outBuf(static_cast<size_t>(width) *
10091 static_cast<size_t>(num_lines) *
10092 pixel_data_size);
10093
10094 unsigned long dstLen = outBuf.size();
10095 assert(dstLen > 0);
10096 tinyexr::DecompressZfp(reinterpret_cast<float *>(&outBuf.at(0)), width,
10097 num_lines, num_channels, data_ptr,
10098 static_cast<unsigned long>(data_len),
10099 zfp_compression_param);
10100
10101 // For ZFP_COMPRESSION:
10102 // pixel sample data for channel 0 for scanline 0
10103 // pixel sample data for channel 1 for scanline 0
10104 // pixel sample data for channel ... for scanline 0
10105 // pixel sample data for channel n for scanline 0
10106 // pixel sample data for channel 0 for scanline 1
10107 // pixel sample data for channel 1 for scanline 1
10108 // pixel sample data for channel ... for scanline 1
10109 // pixel sample data for channel n for scanline 1
10110 // ...
10111 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10112 assert(channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT);
10113 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10114 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
10115 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10116 const float *line_ptr = reinterpret_cast<float *>(
10117 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
10118 channel_offset_list[c] * static_cast<size_t>(width)));
10119 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10120 float val;
10121 tinyexr::cpy4(&val, line_ptr + u);
10122
10123 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10124
10125 float *image = reinterpret_cast<float **>(out_images)[c];
10126 if (line_order == 0) {
10127 image += (static_cast<size_t>(line_no) + v) *
10128 static_cast<size_t>(x_stride) +
10129 u;
10130 } else {
10131 image += (static_cast<size_t>(height) - 1U -
10132 (static_cast<size_t>(line_no) + v)) *
10133 static_cast<size_t>(x_stride) +
10134 u;
10135 }
10136 *image = val;
10137 }
10138 }
10139 } else {
10140 assert(0);
10141 return false;
10142 }
10143 }
10144 #else
10145 (void)attributes;
10146 (void)num_attributes;
10147 (void)num_channels;
10148 assert(0);
10149 return false;
10150 #endif
10151 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
10152 for (size_t c = 0; c < num_channels; c++) {
10153 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10154 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10155 const unsigned short *line_ptr =
10156 reinterpret_cast<const unsigned short *>(
10157 data_ptr + v * pixel_data_size * size_t(width) +
10158 channel_offset_list[c] * static_cast<size_t>(width));
10159
10160 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
10161 unsigned short *outLine =
10162 reinterpret_cast<unsigned short *>(out_images[c]);
10163 if (line_order == 0) {
10164 outLine += (size_t(y) + v) * size_t(x_stride);
10165 } else {
10166 outLine +=
10167 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10168 }
10169
10170 for (int u = 0; u < width; u++) {
10171 tinyexr::FP16 hf;
10172
10173 // hf.u = line_ptr[u];
10174 tinyexr::cpy2(&(hf.u), line_ptr + u);
10175
10176 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
10177
10178 outLine[u] = hf.u;
10179 }
10180 } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
10181 float *outLine = reinterpret_cast<float *>(out_images[c]);
10182 if (line_order == 0) {
10183 outLine += (size_t(y) + v) * size_t(x_stride);
10184 } else {
10185 outLine +=
10186 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10187 }
10188
10189 if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
10190 (data_ptr + data_len)) {
10191 // Insufficient data size
10192 return false;
10193 }
10194
10195 for (int u = 0; u < width; u++) {
10196 tinyexr::FP16 hf;
10197
10198 // address may not be aliged. use byte-wise copy for safety.#76
10199 // hf.u = line_ptr[u];
10200 tinyexr::cpy2(&(hf.u), line_ptr + u);
10201
10202 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
10203
10204 tinyexr::FP32 f32 = half_to_float(hf);
10205
10206 outLine[u] = f32.f;
10207 }
10208 } else {
10209 assert(0);
10210 return false;
10211 }
10212 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10213 const float *line_ptr = reinterpret_cast<const float *>(
10214 data_ptr + v * pixel_data_size * size_t(width) +
10215 channel_offset_list[c] * static_cast<size_t>(width));
10216
10217 float *outLine = reinterpret_cast<float *>(out_images[c]);
10218 if (line_order == 0) {
10219 outLine += (size_t(y) + v) * size_t(x_stride);
10220 } else {
10221 outLine +=
10222 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10223 }
10224
10225 if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
10226 (data_ptr + data_len)) {
10227 // Insufficient data size
10228 return false;
10229 }
10230
10231 for (int u = 0; u < width; u++) {
10232 float val;
10233 tinyexr::cpy4(&val, line_ptr + u);
10234
10235 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10236
10237 outLine[u] = val;
10238 }
10239 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10240 const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>(
10241 data_ptr + v * pixel_data_size * size_t(width) +
10242 channel_offset_list[c] * static_cast<size_t>(width));
10243
10244 unsigned int *outLine =
10245 reinterpret_cast<unsigned int *>(out_images[c]);
10246 if (line_order == 0) {
10247 outLine += (size_t(y) + v) * size_t(x_stride);
10248 } else {
10249 outLine +=
10250 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10251 }
10252
10253 for (int u = 0; u < width; u++) {
10254 if (reinterpret_cast<const unsigned char *>(line_ptr + u) >=
10255 (data_ptr + data_len)) {
10256 // Corrupsed data?
10257 return false;
10258 }
10259
10260 unsigned int val;
10261 tinyexr::cpy4(&val, line_ptr + u);
10262
10263 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10264
10265 outLine[u] = val;
10266 }
10267 }
10268 }
10269 }
10270 }
10271
10272 return true;
10273 }
10274
DecodeTiledPixelData(unsigned char ** out_images,int * width,int * height,const int * requested_pixel_types,const unsigned char * data_ptr,size_t data_len,int compression_type,int line_order,int data_width,int data_height,int tile_offset_x,int tile_offset_y,int tile_size_x,int tile_size_y,size_t pixel_data_size,size_t num_attributes,const EXRAttribute * attributes,size_t num_channels,const EXRChannelInfo * channels,const std::vector<size_t> & channel_offset_list)10275 static void DecodeTiledPixelData(
10276 unsigned char **out_images, int *width, int *height,
10277 const int *requested_pixel_types, const unsigned char *data_ptr,
10278 size_t data_len, int compression_type, int line_order, int data_width,
10279 int data_height, int tile_offset_x, int tile_offset_y, int tile_size_x,
10280 int tile_size_y, size_t pixel_data_size, size_t num_attributes,
10281 const EXRAttribute *attributes, size_t num_channels,
10282 const EXRChannelInfo *channels,
10283 const std::vector<size_t> &channel_offset_list) {
10284 assert(tile_offset_x * tile_size_x < data_width);
10285 assert(tile_offset_y * tile_size_y < data_height);
10286
10287 // Compute actual image size in a tile.
10288 if ((tile_offset_x + 1) * tile_size_x >= data_width) {
10289 (*width) = data_width - (tile_offset_x * tile_size_x);
10290 } else {
10291 (*width) = tile_size_x;
10292 }
10293
10294 if ((tile_offset_y + 1) * tile_size_y >= data_height) {
10295 (*height) = data_height - (tile_offset_y * tile_size_y);
10296 } else {
10297 (*height) = tile_size_y;
10298 }
10299
10300 // Image size = tile size.
10301 DecodePixelData(out_images, requested_pixel_types, data_ptr, data_len,
10302 compression_type, line_order, (*width), tile_size_y,
10303 /* stride */ tile_size_x, /* y */ 0, /* line_no */ 0,
10304 (*height), pixel_data_size, num_attributes, attributes,
10305 num_channels, channels, channel_offset_list);
10306 }
10307
ComputeChannelLayout(std::vector<size_t> * channel_offset_list,int * pixel_data_size,size_t * channel_offset,int num_channels,const EXRChannelInfo * channels)10308 static bool ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
10309 int *pixel_data_size, size_t *channel_offset,
10310 int num_channels,
10311 const EXRChannelInfo *channels) {
10312 channel_offset_list->resize(static_cast<size_t>(num_channels));
10313
10314 (*pixel_data_size) = 0;
10315 (*channel_offset) = 0;
10316
10317 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10318 (*channel_offset_list)[c] = (*channel_offset);
10319 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10320 (*pixel_data_size) += sizeof(unsigned short);
10321 (*channel_offset) += sizeof(unsigned short);
10322 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10323 (*pixel_data_size) += sizeof(float);
10324 (*channel_offset) += sizeof(float);
10325 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10326 (*pixel_data_size) += sizeof(unsigned int);
10327 (*channel_offset) += sizeof(unsigned int);
10328 } else {
10329 // ???
10330 return false;
10331 }
10332 }
10333 return true;
10334 }
10335
AllocateImage(int num_channels,const EXRChannelInfo * channels,const int * requested_pixel_types,int data_width,int data_height)10336 static unsigned char **AllocateImage(int num_channels,
10337 const EXRChannelInfo *channels,
10338 const int *requested_pixel_types,
10339 int data_width, int data_height) {
10340 unsigned char **images =
10341 reinterpret_cast<unsigned char **>(static_cast<float **>(
10342 malloc(sizeof(float *) * static_cast<size_t>(num_channels))));
10343
10344 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10345 size_t data_len =
10346 static_cast<size_t>(data_width) * static_cast<size_t>(data_height);
10347 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10348 // pixel_data_size += sizeof(unsigned short);
10349 // channel_offset += sizeof(unsigned short);
10350 // Alloc internal image for half type.
10351 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
10352 images[c] =
10353 reinterpret_cast<unsigned char *>(static_cast<unsigned short *>(
10354 malloc(sizeof(unsigned short) * data_len)));
10355 } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
10356 images[c] = reinterpret_cast<unsigned char *>(
10357 static_cast<float *>(malloc(sizeof(float) * data_len)));
10358 } else {
10359 assert(0);
10360 }
10361 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10362 // pixel_data_size += sizeof(float);
10363 // channel_offset += sizeof(float);
10364 images[c] = reinterpret_cast<unsigned char *>(
10365 static_cast<float *>(malloc(sizeof(float) * data_len)));
10366 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10367 // pixel_data_size += sizeof(unsigned int);
10368 // channel_offset += sizeof(unsigned int);
10369 images[c] = reinterpret_cast<unsigned char *>(
10370 static_cast<unsigned int *>(malloc(sizeof(unsigned int) * data_len)));
10371 } else {
10372 assert(0);
10373 }
10374 }
10375
10376 return images;
10377 }
10378
ParseEXRHeader(HeaderInfo * info,bool * empty_header,const EXRVersion * version,std::string * err,const unsigned char * buf,size_t size)10379 static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
10380 const EXRVersion *version, std::string *err,
10381 const unsigned char *buf, size_t size) {
10382 const char *marker = reinterpret_cast<const char *>(&buf[0]);
10383
10384 if (empty_header) {
10385 (*empty_header) = false;
10386 }
10387
10388 if (version->multipart) {
10389 if (size > 0 && marker[0] == '\0') {
10390 // End of header list.
10391 if (empty_header) {
10392 (*empty_header) = true;
10393 }
10394 return TINYEXR_SUCCESS;
10395 }
10396 }
10397
10398 // According to the spec, the header of every OpenEXR file must contain at
10399 // least the following attributes:
10400 //
10401 // channels chlist
10402 // compression compression
10403 // dataWindow box2i
10404 // displayWindow box2i
10405 // lineOrder lineOrder
10406 // pixelAspectRatio float
10407 // screenWindowCenter v2f
10408 // screenWindowWidth float
10409 bool has_channels = false;
10410 bool has_compression = false;
10411 bool has_data_window = false;
10412 bool has_display_window = false;
10413 bool has_line_order = false;
10414 bool has_pixel_aspect_ratio = false;
10415 bool has_screen_window_center = false;
10416 bool has_screen_window_width = false;
10417
10418 info->data_window[0] = 0;
10419 info->data_window[1] = 0;
10420 info->data_window[2] = 0;
10421 info->data_window[3] = 0;
10422 info->line_order = 0; // @fixme
10423 info->display_window[0] = 0;
10424 info->display_window[1] = 0;
10425 info->display_window[2] = 0;
10426 info->display_window[3] = 0;
10427 info->screen_window_center[0] = 0.0f;
10428 info->screen_window_center[1] = 0.0f;
10429 info->screen_window_width = -1.0f;
10430 info->pixel_aspect_ratio = -1.0f;
10431
10432 info->tile_size_x = -1;
10433 info->tile_size_y = -1;
10434 info->tile_level_mode = -1;
10435 info->tile_rounding_mode = -1;
10436
10437 info->attributes.clear();
10438
10439 // Read attributes
10440 size_t orig_size = size;
10441 for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) {
10442 if (0 == size) {
10443 if (err) {
10444 (*err) += "Insufficient data size for attributes.\n";
10445 }
10446 return TINYEXR_ERROR_INVALID_DATA;
10447 } else if (marker[0] == '\0') {
10448 size--;
10449 break;
10450 }
10451
10452 std::string attr_name;
10453 std::string attr_type;
10454 std::vector<unsigned char> data;
10455 size_t marker_size;
10456 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
10457 marker, size)) {
10458 if (err) {
10459 (*err) += "Failed to read attribute.\n";
10460 }
10461 return TINYEXR_ERROR_INVALID_DATA;
10462 }
10463 marker += marker_size;
10464 size -= marker_size;
10465
10466 if (version->tiled && attr_name.compare("tiles") == 0) {
10467 unsigned int x_size, y_size;
10468 unsigned char tile_mode;
10469 assert(data.size() == 9);
10470 memcpy(&x_size, &data.at(0), sizeof(int));
10471 memcpy(&y_size, &data.at(4), sizeof(int));
10472 tile_mode = data[8];
10473 tinyexr::swap4(&x_size);
10474 tinyexr::swap4(&y_size);
10475
10476 info->tile_size_x = static_cast<int>(x_size);
10477 info->tile_size_y = static_cast<int>(y_size);
10478
10479 // mode = levelMode + roundingMode * 16
10480 info->tile_level_mode = tile_mode & 0x3;
10481 info->tile_rounding_mode = (tile_mode >> 4) & 0x1;
10482
10483 } else if (attr_name.compare("compression") == 0) {
10484 bool ok = false;
10485 if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) {
10486 ok = true;
10487 }
10488
10489 if (data[0] == TINYEXR_COMPRESSIONTYPE_PIZ) {
10490 #if TINYEXR_USE_PIZ
10491 ok = true;
10492 #else
10493 if (err) {
10494 (*err) = "PIZ compression is not supported.";
10495 }
10496 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
10497 #endif
10498 }
10499
10500 if (data[0] == TINYEXR_COMPRESSIONTYPE_ZFP) {
10501 #if TINYEXR_USE_ZFP
10502 ok = true;
10503 #else
10504 if (err) {
10505 (*err) = "ZFP compression is not supported.";
10506 }
10507 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
10508 #endif
10509 }
10510
10511 if (!ok) {
10512 if (err) {
10513 (*err) = "Unknown compression type.";
10514 }
10515 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
10516 }
10517
10518 info->compression_type = static_cast<int>(data[0]);
10519 has_compression = true;
10520
10521 } else if (attr_name.compare("channels") == 0) {
10522 // name: zero-terminated string, from 1 to 255 bytes long
10523 // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2
10524 // pLinear: unsigned char, possible values are 0 and 1
10525 // reserved: three chars, should be zero
10526 // xSampling: int
10527 // ySampling: int
10528
10529 if (!ReadChannelInfo(info->channels, data)) {
10530 if (err) {
10531 (*err) += "Failed to parse channel info.\n";
10532 }
10533 return TINYEXR_ERROR_INVALID_DATA;
10534 }
10535
10536 if (info->channels.size() < 1) {
10537 if (err) {
10538 (*err) += "# of channels is zero.\n";
10539 }
10540 return TINYEXR_ERROR_INVALID_DATA;
10541 }
10542
10543 has_channels = true;
10544
10545 } else if (attr_name.compare("dataWindow") == 0) {
10546 if (data.size() >= 16) {
10547 memcpy(&info->data_window[0], &data.at(0), sizeof(int));
10548 memcpy(&info->data_window[1], &data.at(4), sizeof(int));
10549 memcpy(&info->data_window[2], &data.at(8), sizeof(int));
10550 memcpy(&info->data_window[3], &data.at(12), sizeof(int));
10551 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[0]));
10552 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[1]));
10553 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[2]));
10554 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[3]));
10555 has_data_window = true;
10556 }
10557 } else if (attr_name.compare("displayWindow") == 0) {
10558 if (data.size() >= 16) {
10559 memcpy(&info->display_window[0], &data.at(0), sizeof(int));
10560 memcpy(&info->display_window[1], &data.at(4), sizeof(int));
10561 memcpy(&info->display_window[2], &data.at(8), sizeof(int));
10562 memcpy(&info->display_window[3], &data.at(12), sizeof(int));
10563 tinyexr::swap4(
10564 reinterpret_cast<unsigned int *>(&info->display_window[0]));
10565 tinyexr::swap4(
10566 reinterpret_cast<unsigned int *>(&info->display_window[1]));
10567 tinyexr::swap4(
10568 reinterpret_cast<unsigned int *>(&info->display_window[2]));
10569 tinyexr::swap4(
10570 reinterpret_cast<unsigned int *>(&info->display_window[3]));
10571
10572 has_display_window = true;
10573 }
10574 } else if (attr_name.compare("lineOrder") == 0) {
10575 if (data.size() >= 1) {
10576 info->line_order = static_cast<int>(data[0]);
10577 has_line_order = true;
10578 }
10579 } else if (attr_name.compare("pixelAspectRatio") == 0) {
10580 if (data.size() >= sizeof(float)) {
10581 memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float));
10582 tinyexr::swap4(
10583 reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio));
10584 has_pixel_aspect_ratio = true;
10585 }
10586 } else if (attr_name.compare("screenWindowCenter") == 0) {
10587 if (data.size() >= 8) {
10588 memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float));
10589 memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float));
10590 tinyexr::swap4(
10591 reinterpret_cast<unsigned int *>(&info->screen_window_center[0]));
10592 tinyexr::swap4(
10593 reinterpret_cast<unsigned int *>(&info->screen_window_center[1]));
10594 has_screen_window_center = true;
10595 }
10596 } else if (attr_name.compare("screenWindowWidth") == 0) {
10597 if (data.size() >= sizeof(float)) {
10598 memcpy(&info->screen_window_width, &data.at(0), sizeof(float));
10599 tinyexr::swap4(
10600 reinterpret_cast<unsigned int *>(&info->screen_window_width));
10601
10602 has_screen_window_width = true;
10603 }
10604 } else if (attr_name.compare("chunkCount") == 0) {
10605 if (data.size() >= sizeof(int)) {
10606 memcpy(&info->chunk_count, &data.at(0), sizeof(int));
10607 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count));
10608 }
10609 } else {
10610 // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES)
10611 if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
10612 EXRAttribute attrib;
10613 #ifdef _MSC_VER
10614 strncpy_s(attrib.name, attr_name.c_str(), 255);
10615 strncpy_s(attrib.type, attr_type.c_str(), 255);
10616 #else
10617 strncpy(attrib.name, attr_name.c_str(), 255);
10618 strncpy(attrib.type, attr_type.c_str(), 255);
10619 #endif
10620 attrib.name[255] = '\0';
10621 attrib.type[255] = '\0';
10622 attrib.size = static_cast<int>(data.size());
10623 attrib.value = static_cast<unsigned char *>(malloc(data.size()));
10624 memcpy(reinterpret_cast<char *>(attrib.value), &data.at(0),
10625 data.size());
10626 info->attributes.push_back(attrib);
10627 }
10628 }
10629 }
10630
10631 // Check if required attributes exist
10632 {
10633 std::stringstream ss_err;
10634
10635 if (!has_compression) {
10636 ss_err << "\"compression\" attribute not found in the header."
10637 << std::endl;
10638 }
10639
10640 if (!has_channels) {
10641 ss_err << "\"channels\" attribute not found in the header." << std::endl;
10642 }
10643
10644 if (!has_line_order) {
10645 ss_err << "\"lineOrder\" attribute not found in the header." << std::endl;
10646 }
10647
10648 if (!has_display_window) {
10649 ss_err << "\"displayWindow\" attribute not found in the header."
10650 << std::endl;
10651 }
10652
10653 if (!has_data_window) {
10654 ss_err << "\"dataWindow\" attribute not found in the header or invalid."
10655 << std::endl;
10656 }
10657
10658 if (!has_pixel_aspect_ratio) {
10659 ss_err << "\"pixelAspectRatio\" attribute not found in the header."
10660 << std::endl;
10661 }
10662
10663 if (!has_screen_window_width) {
10664 ss_err << "\"screenWindowWidth\" attribute not found in the header."
10665 << std::endl;
10666 }
10667
10668 if (!has_screen_window_center) {
10669 ss_err << "\"screenWindowCenter\" attribute not found in the header."
10670 << std::endl;
10671 }
10672
10673 if (!(ss_err.str().empty())) {
10674 if (err) {
10675 (*err) += ss_err.str();
10676 }
10677 return TINYEXR_ERROR_INVALID_HEADER;
10678 }
10679 }
10680
10681 info->header_len = static_cast<unsigned int>(orig_size - size);
10682
10683 return TINYEXR_SUCCESS;
10684 }
10685
10686 // C++ HeaderInfo to C EXRHeader conversion.
ConvertHeader(EXRHeader * exr_header,const HeaderInfo & info)10687 static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
10688 exr_header->pixel_aspect_ratio = info.pixel_aspect_ratio;
10689 exr_header->screen_window_center[0] = info.screen_window_center[0];
10690 exr_header->screen_window_center[1] = info.screen_window_center[1];
10691 exr_header->screen_window_width = info.screen_window_width;
10692 exr_header->chunk_count = info.chunk_count;
10693 exr_header->display_window[0] = info.display_window[0];
10694 exr_header->display_window[1] = info.display_window[1];
10695 exr_header->display_window[2] = info.display_window[2];
10696 exr_header->display_window[3] = info.display_window[3];
10697 exr_header->data_window[0] = info.data_window[0];
10698 exr_header->data_window[1] = info.data_window[1];
10699 exr_header->data_window[2] = info.data_window[2];
10700 exr_header->data_window[3] = info.data_window[3];
10701 exr_header->line_order = info.line_order;
10702 exr_header->compression_type = info.compression_type;
10703
10704 exr_header->tile_size_x = info.tile_size_x;
10705 exr_header->tile_size_y = info.tile_size_y;
10706 exr_header->tile_level_mode = info.tile_level_mode;
10707 exr_header->tile_rounding_mode = info.tile_rounding_mode;
10708
10709 exr_header->num_channels = static_cast<int>(info.channels.size());
10710
10711 exr_header->channels = static_cast<EXRChannelInfo *>(malloc(
10712 sizeof(EXRChannelInfo) * static_cast<size_t>(exr_header->num_channels)));
10713 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
10714 #ifdef _MSC_VER
10715 strncpy_s(exr_header->channels[c].name, info.channels[c].name.c_str(), 255);
10716 #else
10717 strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255);
10718 #endif
10719 // manually add '\0' for safety.
10720 exr_header->channels[c].name[255] = '\0';
10721
10722 exr_header->channels[c].pixel_type = info.channels[c].pixel_type;
10723 exr_header->channels[c].p_linear = info.channels[c].p_linear;
10724 exr_header->channels[c].x_sampling = info.channels[c].x_sampling;
10725 exr_header->channels[c].y_sampling = info.channels[c].y_sampling;
10726 }
10727
10728 exr_header->pixel_types = static_cast<int *>(
10729 malloc(sizeof(int) * static_cast<size_t>(exr_header->num_channels)));
10730 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
10731 exr_header->pixel_types[c] = info.channels[c].pixel_type;
10732 }
10733
10734 // Initially fill with values of `pixel_types`
10735 exr_header->requested_pixel_types = static_cast<int *>(
10736 malloc(sizeof(int) * static_cast<size_t>(exr_header->num_channels)));
10737 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
10738 exr_header->requested_pixel_types[c] = info.channels[c].pixel_type;
10739 }
10740
10741 exr_header->num_custom_attributes = static_cast<int>(info.attributes.size());
10742
10743 if (exr_header->num_custom_attributes > 0) {
10744 // TODO(syoyo): Report warning when # of attributes exceeds
10745 // `TINYEXR_MAX_CUSTOM_ATTRIBUTES`
10746 if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
10747 exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES;
10748 }
10749
10750 exr_header->custom_attributes = static_cast<EXRAttribute *>(malloc(
10751 sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes)));
10752
10753 for (size_t i = 0; i < info.attributes.size(); i++) {
10754 memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name,
10755 256);
10756 memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type,
10757 256);
10758 exr_header->custom_attributes[i].size = info.attributes[i].size;
10759 // Just copy poiner
10760 exr_header->custom_attributes[i].value = info.attributes[i].value;
10761 }
10762
10763 } else {
10764 exr_header->custom_attributes = NULL;
10765 }
10766
10767 exr_header->header_len = info.header_len;
10768 }
10769
DecodeChunk(EXRImage * exr_image,const EXRHeader * exr_header,const std::vector<tinyexr::tinyexr_uint64> & offsets,const unsigned char * head,const size_t size,std::string * err)10770 static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
10771 const std::vector<tinyexr::tinyexr_uint64> &offsets,
10772 const unsigned char *head, const size_t size,
10773 std::string *err) {
10774 int num_channels = exr_header->num_channels;
10775
10776 int num_scanline_blocks = 1;
10777 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
10778 num_scanline_blocks = 16;
10779 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
10780 num_scanline_blocks = 32;
10781 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
10782 num_scanline_blocks = 16;
10783 }
10784
10785 int data_width = exr_header->data_window[2] - exr_header->data_window[0] + 1;
10786 int data_height = exr_header->data_window[3] - exr_header->data_window[1] + 1;
10787
10788 if ((data_width < 0) || (data_height < 0)) {
10789 if (err) {
10790 std::stringstream ss;
10791 ss << "Invalid data width or data height: " << data_width << ", "
10792 << data_height << std::endl;
10793 (*err) += ss.str();
10794 }
10795 return TINYEXR_ERROR_INVALID_DATA;
10796 }
10797
10798 // Do not allow too large data_width and data_height. header invalid?
10799 {
10800 const int threshold = 1024 * 8192; // heuristics
10801 if ((data_width > threshold) || (data_height > threshold)) {
10802 if (err) {
10803 std::stringstream ss;
10804 ss << "data_with or data_height too large. data_width: " << data_width
10805 << ", "
10806 << "data_height = " << data_height << std::endl;
10807 (*err) += ss.str();
10808 }
10809 return TINYEXR_ERROR_INVALID_DATA;
10810 }
10811 }
10812
10813 size_t num_blocks = offsets.size();
10814
10815 std::vector<size_t> channel_offset_list;
10816 int pixel_data_size = 0;
10817 size_t channel_offset = 0;
10818 if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size,
10819 &channel_offset, num_channels,
10820 exr_header->channels)) {
10821 if (err) {
10822 (*err) += "Failed to compute channel layout.\n";
10823 }
10824 return TINYEXR_ERROR_INVALID_DATA;
10825 }
10826
10827 bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety.
10828
10829 if (exr_header->tiled) {
10830 // value check
10831 if (exr_header->tile_size_x < 0) {
10832 if (err) {
10833 std::stringstream ss;
10834 ss << "Invalid tile size x : " << exr_header->tile_size_x << "\n";
10835 (*err) += ss.str();
10836 }
10837 return TINYEXR_ERROR_INVALID_HEADER;
10838 }
10839
10840 if (exr_header->tile_size_y < 0) {
10841 if (err) {
10842 std::stringstream ss;
10843 ss << "Invalid tile size y : " << exr_header->tile_size_y << "\n";
10844 (*err) += ss.str();
10845 }
10846 return TINYEXR_ERROR_INVALID_HEADER;
10847 }
10848
10849 size_t num_tiles = offsets.size(); // = # of blocks
10850
10851 exr_image->tiles = static_cast<EXRTile *>(
10852 calloc(sizeof(EXRTile), static_cast<size_t>(num_tiles)));
10853
10854 for (size_t tile_idx = 0; tile_idx < num_tiles; tile_idx++) {
10855 // Allocate memory for each tile.
10856 exr_image->tiles[tile_idx].images = tinyexr::AllocateImage(
10857 num_channels, exr_header->channels, exr_header->requested_pixel_types,
10858 exr_header->tile_size_x, exr_header->tile_size_y);
10859
10860 // 16 byte: tile coordinates
10861 // 4 byte : data size
10862 // ~ : data(uncompressed or compressed)
10863 if (offsets[tile_idx] + sizeof(int) * 5 > size) {
10864 if (err) {
10865 (*err) += "Insufficient data size.\n";
10866 }
10867 return TINYEXR_ERROR_INVALID_DATA;
10868 }
10869
10870 size_t data_size = size_t(size - (offsets[tile_idx] + sizeof(int) * 5));
10871 const unsigned char *data_ptr =
10872 reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]);
10873
10874 int tile_coordinates[4];
10875 memcpy(tile_coordinates, data_ptr, sizeof(int) * 4);
10876 tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[0]));
10877 tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[1]));
10878 tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[2]));
10879 tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[3]));
10880
10881 // @todo{ LoD }
10882 if (tile_coordinates[2] != 0) {
10883 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
10884 }
10885 if (tile_coordinates[3] != 0) {
10886 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
10887 }
10888
10889 int data_len;
10890 memcpy(&data_len, data_ptr + 16,
10891 sizeof(int)); // 16 = sizeof(tile_coordinates)
10892 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
10893
10894 if (data_len < 4 || size_t(data_len) > data_size) {
10895 if (err) {
10896 (*err) += "Insufficient data length.\n";
10897 }
10898 return TINYEXR_ERROR_INVALID_DATA;
10899 }
10900
10901 // Move to data addr: 20 = 16 + 4;
10902 data_ptr += 20;
10903
10904 tinyexr::DecodeTiledPixelData(
10905 exr_image->tiles[tile_idx].images,
10906 &(exr_image->tiles[tile_idx].width),
10907 &(exr_image->tiles[tile_idx].height),
10908 exr_header->requested_pixel_types, data_ptr,
10909 static_cast<size_t>(data_len), exr_header->compression_type,
10910 exr_header->line_order, data_width, data_height, tile_coordinates[0],
10911 tile_coordinates[1], exr_header->tile_size_x, exr_header->tile_size_y,
10912 static_cast<size_t>(pixel_data_size),
10913 static_cast<size_t>(exr_header->num_custom_attributes),
10914 exr_header->custom_attributes,
10915 static_cast<size_t>(exr_header->num_channels), exr_header->channels,
10916 channel_offset_list);
10917
10918 exr_image->tiles[tile_idx].offset_x = tile_coordinates[0];
10919 exr_image->tiles[tile_idx].offset_y = tile_coordinates[1];
10920 exr_image->tiles[tile_idx].level_x = tile_coordinates[2];
10921 exr_image->tiles[tile_idx].level_y = tile_coordinates[3];
10922
10923 exr_image->num_tiles = static_cast<int>(num_tiles);
10924 }
10925 } else { // scanline format
10926
10927 // Don't allow too large image(256GB * pixel_data_size or more). Workaround
10928 // for #104.
10929 size_t total_data_len =
10930 size_t(data_width) * size_t(data_height) * size_t(num_channels);
10931 const bool total_data_len_overflown = sizeof(void*) == 8 ? (total_data_len >= 0x4000000000) : false;
10932 if ((total_data_len == 0) || total_data_len_overflown ) {
10933 if (err) {
10934 std::stringstream ss;
10935 ss << "Image data size is zero or too large: width = " << data_width
10936 << ", height = " << data_height << ", channels = " << num_channels
10937 << std::endl;
10938 (*err) += ss.str();
10939 }
10940 return TINYEXR_ERROR_INVALID_DATA;
10941 }
10942
10943 exr_image->images = tinyexr::AllocateImage(
10944 num_channels, exr_header->channels, exr_header->requested_pixel_types,
10945 data_width, data_height);
10946
10947 #ifdef _OPENMP
10948 #pragma omp parallel for
10949 #endif
10950 for (int y = 0; y < static_cast<int>(num_blocks); y++) {
10951 size_t y_idx = static_cast<size_t>(y);
10952
10953 if (offsets[y_idx] + sizeof(int) * 2 > size) {
10954 invalid_data = true;
10955 } else {
10956 // 4 byte: scan line
10957 // 4 byte: data size
10958 // ~ : pixel data(uncompressed or compressed)
10959 size_t data_size = size_t(size - (offsets[y_idx] + sizeof(int) * 2));
10960 const unsigned char *data_ptr =
10961 reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
10962
10963 int line_no;
10964 memcpy(&line_no, data_ptr, sizeof(int));
10965 int data_len;
10966 memcpy(&data_len, data_ptr + 4, sizeof(int));
10967 tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
10968 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
10969
10970 if (size_t(data_len) > data_size) {
10971 invalid_data = true;
10972
10973 } else if ((line_no > (2 << 20)) || (line_no < -(2 << 20))) {
10974 // Too large value. Assume this is invalid
10975 // 2**20 = 1048576 = heuristic value.
10976 invalid_data = true;
10977 } else if (data_len == 0) {
10978 // TODO(syoyo): May be ok to raise the threshold for example `data_len
10979 // < 4`
10980 invalid_data = true;
10981 } else {
10982 // line_no may be negative.
10983 int end_line_no = (std::min)(line_no + num_scanline_blocks,
10984 (exr_header->data_window[3] + 1));
10985
10986 int num_lines = end_line_no - line_no;
10987
10988 if (num_lines <= 0) {
10989 invalid_data = true;
10990 } else {
10991 // Move to data addr: 8 = 4 + 4;
10992 data_ptr += 8;
10993
10994 // Adjust line_no with data_window.bmin.y
10995
10996 // overflow check
10997 tinyexr_int64 lno = static_cast<tinyexr_int64>(line_no) - static_cast<tinyexr_int64>(exr_header->data_window[1]);
10998 if (lno > std::numeric_limits<int>::max()) {
10999 line_no = -1; // invalid
11000 } else if (lno < -std::numeric_limits<int>::max()) {
11001 line_no = -1; // invalid
11002 } else {
11003 line_no -= exr_header->data_window[1];
11004 }
11005
11006 if (line_no < 0) {
11007 invalid_data = true;
11008 } else {
11009 if (!tinyexr::DecodePixelData(
11010 exr_image->images, exr_header->requested_pixel_types,
11011 data_ptr, static_cast<size_t>(data_len),
11012 exr_header->compression_type, exr_header->line_order,
11013 data_width, data_height, data_width, y, line_no,
11014 num_lines, static_cast<size_t>(pixel_data_size),
11015 static_cast<size_t>(exr_header->num_custom_attributes),
11016 exr_header->custom_attributes,
11017 static_cast<size_t>(exr_header->num_channels),
11018 exr_header->channels, channel_offset_list)) {
11019 invalid_data = true;
11020 }
11021 }
11022 }
11023 }
11024 }
11025 } // omp parallel
11026 }
11027
11028 if (invalid_data) {
11029 if (err) {
11030 std::stringstream ss;
11031 (*err) += "Invalid data found when decoding pixels.\n";
11032 }
11033 return TINYEXR_ERROR_INVALID_DATA;
11034 }
11035
11036 // Overwrite `pixel_type` with `requested_pixel_type`.
11037 {
11038 for (int c = 0; c < exr_header->num_channels; c++) {
11039 exr_header->pixel_types[c] = exr_header->requested_pixel_types[c];
11040 }
11041 }
11042
11043 {
11044 exr_image->num_channels = num_channels;
11045
11046 exr_image->width = data_width;
11047 exr_image->height = data_height;
11048 }
11049
11050 return TINYEXR_SUCCESS;
11051 }
11052
ReconstructLineOffsets(std::vector<tinyexr::tinyexr_uint64> * offsets,size_t n,const unsigned char * head,const unsigned char * marker,const size_t size)11053 static bool ReconstructLineOffsets(
11054 std::vector<tinyexr::tinyexr_uint64> *offsets, size_t n,
11055 const unsigned char *head, const unsigned char *marker, const size_t size) {
11056 assert(head < marker);
11057 assert(offsets->size() == n);
11058
11059 for (size_t i = 0; i < n; i++) {
11060 size_t offset = static_cast<size_t>(marker - head);
11061 // Offset should not exceed whole EXR file/data size.
11062 if ((offset + sizeof(tinyexr::tinyexr_uint64)) >= size) {
11063 return false;
11064 }
11065
11066 int y;
11067 unsigned int data_len;
11068
11069 memcpy(&y, marker, sizeof(int));
11070 memcpy(&data_len, marker + 4, sizeof(unsigned int));
11071
11072 if (data_len >= size) {
11073 return false;
11074 }
11075
11076 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y));
11077 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
11078
11079 (*offsets)[i] = offset;
11080
11081 marker += data_len + 8; // 8 = 4 bytes(y) + 4 bytes(data_len)
11082 }
11083
11084 return true;
11085 }
11086
DecodeEXRImage(EXRImage * exr_image,const EXRHeader * exr_header,const unsigned char * head,const unsigned char * marker,const size_t size,const char ** err)11087 static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
11088 const unsigned char *head,
11089 const unsigned char *marker, const size_t size,
11090 const char **err) {
11091 if (exr_image == NULL || exr_header == NULL || head == NULL ||
11092 marker == NULL || (size <= tinyexr::kEXRVersionSize)) {
11093 tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err);
11094 return TINYEXR_ERROR_INVALID_ARGUMENT;
11095 }
11096
11097 int num_scanline_blocks = 1;
11098 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
11099 num_scanline_blocks = 16;
11100 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
11101 num_scanline_blocks = 32;
11102 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
11103 num_scanline_blocks = 16;
11104 }
11105
11106 int data_width = exr_header->data_window[2] - exr_header->data_window[0];
11107 if (data_width >= std::numeric_limits<int>::max()) {
11108 // Issue 63
11109 tinyexr::SetErrorMessage("Invalid data width value", err);
11110 return TINYEXR_ERROR_INVALID_DATA;
11111 }
11112 data_width++;
11113
11114 int data_height = exr_header->data_window[3] - exr_header->data_window[1];
11115 if (data_height >= std::numeric_limits<int>::max()) {
11116 tinyexr::SetErrorMessage("Invalid data height value", err);
11117 return TINYEXR_ERROR_INVALID_DATA;
11118 }
11119 data_height++;
11120
11121 if ((data_width < 0) || (data_height < 0)) {
11122 tinyexr::SetErrorMessage("data width or data height is negative.", err);
11123 return TINYEXR_ERROR_INVALID_DATA;
11124 }
11125
11126 // Do not allow too large data_width and data_height. header invalid?
11127 {
11128 const int threshold = 1024 * 8192; // heuristics
11129 if (data_width > threshold) {
11130 tinyexr::SetErrorMessage("data width too large.", err);
11131 return TINYEXR_ERROR_INVALID_DATA;
11132 }
11133 if (data_height > threshold) {
11134 tinyexr::SetErrorMessage("data height too large.", err);
11135 return TINYEXR_ERROR_INVALID_DATA;
11136 }
11137 }
11138
11139 // Read offset tables.
11140 size_t num_blocks = 0;
11141
11142 if (exr_header->chunk_count > 0) {
11143 // Use `chunkCount` attribute.
11144 num_blocks = static_cast<size_t>(exr_header->chunk_count);
11145 } else if (exr_header->tiled) {
11146 // @todo { LoD }
11147 size_t num_x_tiles = static_cast<size_t>(data_width) /
11148 static_cast<size_t>(exr_header->tile_size_x);
11149 if (num_x_tiles * static_cast<size_t>(exr_header->tile_size_x) <
11150 static_cast<size_t>(data_width)) {
11151 num_x_tiles++;
11152 }
11153 size_t num_y_tiles = static_cast<size_t>(data_height) /
11154 static_cast<size_t>(exr_header->tile_size_y);
11155 if (num_y_tiles * static_cast<size_t>(exr_header->tile_size_y) <
11156 static_cast<size_t>(data_height)) {
11157 num_y_tiles++;
11158 }
11159
11160 num_blocks = num_x_tiles * num_y_tiles;
11161 } else {
11162 num_blocks = static_cast<size_t>(data_height) /
11163 static_cast<size_t>(num_scanline_blocks);
11164 if (num_blocks * static_cast<size_t>(num_scanline_blocks) <
11165 static_cast<size_t>(data_height)) {
11166 num_blocks++;
11167 }
11168 }
11169
11170 std::vector<tinyexr::tinyexr_uint64> offsets(num_blocks);
11171
11172 for (size_t y = 0; y < num_blocks; y++) {
11173 tinyexr::tinyexr_uint64 offset;
11174 // Issue #81
11175 if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) {
11176 tinyexr::SetErrorMessage("Insufficient data size in offset table.", err);
11177 return TINYEXR_ERROR_INVALID_DATA;
11178 }
11179
11180 memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64));
11181 tinyexr::swap8(&offset);
11182 if (offset >= size) {
11183 tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err);
11184 return TINYEXR_ERROR_INVALID_DATA;
11185 }
11186 marker += sizeof(tinyexr::tinyexr_uint64); // = 8
11187 offsets[y] = offset;
11188 }
11189
11190 // If line offsets are invalid, we try to reconstruct it.
11191 // See OpenEXR/IlmImf/ImfScanLineInputFile.cpp::readLineOffsets() for details.
11192 for (size_t y = 0; y < num_blocks; y++) {
11193 if (offsets[y] <= 0) {
11194 // TODO(syoyo) Report as warning?
11195 // if (err) {
11196 // stringstream ss;
11197 // ss << "Incomplete lineOffsets." << std::endl;
11198 // (*err) += ss.str();
11199 //}
11200 bool ret =
11201 ReconstructLineOffsets(&offsets, num_blocks, head, marker, size);
11202 if (ret) {
11203 // OK
11204 break;
11205 } else {
11206 tinyexr::SetErrorMessage(
11207 "Cannot reconstruct lineOffset table in DecodeEXRImage.", err);
11208 return TINYEXR_ERROR_INVALID_DATA;
11209 }
11210 }
11211 }
11212
11213 {
11214 std::string e;
11215 int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e);
11216
11217 if (ret != TINYEXR_SUCCESS) {
11218 if (!e.empty()) {
11219 tinyexr::SetErrorMessage(e, err);
11220 }
11221
11222 // release memory(if exists)
11223 if ((exr_header->num_channels > 0) && exr_image && exr_image->images) {
11224 for (size_t c = 0; c < size_t(exr_header->num_channels); c++) {
11225 if (exr_image->images[c]) {
11226 free(exr_image->images[c]);
11227 exr_image->images[c] = NULL;
11228 }
11229 }
11230 free(exr_image->images);
11231 exr_image->images = NULL;
11232 }
11233 }
11234
11235 return ret;
11236 }
11237 }
11238
11239 } // namespace tinyexr
11240
LoadEXR(float ** out_rgba,int * width,int * height,const char * filename,const char ** err)11241 int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
11242 const char **err) {
11243 if (out_rgba == NULL) {
11244 tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err);
11245 return TINYEXR_ERROR_INVALID_ARGUMENT;
11246 }
11247
11248 EXRVersion exr_version;
11249 EXRImage exr_image;
11250 EXRHeader exr_header;
11251 InitEXRHeader(&exr_header);
11252 InitEXRImage(&exr_image);
11253
11254 {
11255 int ret = ParseEXRVersionFromFile(&exr_version, filename);
11256 if (ret != TINYEXR_SUCCESS) {
11257 tinyexr::SetErrorMessage("Invalid EXR header.", err);
11258 return ret;
11259 }
11260
11261 if (exr_version.multipart || exr_version.non_image) {
11262 tinyexr::SetErrorMessage(
11263 "Loading multipart or DeepImage is not supported in LoadEXR() API",
11264 err);
11265 return TINYEXR_ERROR_INVALID_DATA; // @fixme.
11266 }
11267 }
11268
11269 {
11270 int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err);
11271 if (ret != TINYEXR_SUCCESS) {
11272 FreeEXRHeader(&exr_header);
11273 return ret;
11274 }
11275 }
11276
11277 // Read HALF channel as FLOAT.
11278 for (int i = 0; i < exr_header.num_channels; i++) {
11279 if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
11280 exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
11281 }
11282 }
11283
11284 {
11285 int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err);
11286 if (ret != TINYEXR_SUCCESS) {
11287 FreeEXRHeader(&exr_header);
11288 return ret;
11289 }
11290 }
11291
11292 // RGBA
11293 int idxR = -1;
11294 int idxG = -1;
11295 int idxB = -1;
11296 int idxA = -1;
11297 for (int c = 0; c < exr_header.num_channels; c++) {
11298 if (strcmp(exr_header.channels[c].name, "R") == 0) {
11299 idxR = c;
11300 } else if (strcmp(exr_header.channels[c].name, "G") == 0) {
11301 idxG = c;
11302 } else if (strcmp(exr_header.channels[c].name, "B") == 0) {
11303 idxB = c;
11304 } else if (strcmp(exr_header.channels[c].name, "A") == 0) {
11305 idxA = c;
11306 }
11307 }
11308
11309 if (exr_header.num_channels == 1) {
11310 // Grayscale channel only.
11311
11312 (*out_rgba) = reinterpret_cast<float *>(
11313 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11314 static_cast<size_t>(exr_image.height)));
11315
11316 if (exr_header.tiled) {
11317 for (int it = 0; it < exr_image.num_tiles; it++) {
11318 for (int j = 0; j < exr_header.tile_size_y; j++) {
11319 for (int i = 0; i < exr_header.tile_size_x; i++) {
11320 const int ii =
11321 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11322 const int jj =
11323 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11324 const int idx = ii + jj * exr_image.width;
11325
11326 // out of region check.
11327 if (ii >= exr_image.width) {
11328 continue;
11329 }
11330 if (jj >= exr_image.height) {
11331 continue;
11332 }
11333 const int srcIdx = i + j * exr_header.tile_size_x;
11334 unsigned char **src = exr_image.tiles[it].images;
11335 (*out_rgba)[4 * idx + 0] =
11336 reinterpret_cast<float **>(src)[0][srcIdx];
11337 (*out_rgba)[4 * idx + 1] =
11338 reinterpret_cast<float **>(src)[0][srcIdx];
11339 (*out_rgba)[4 * idx + 2] =
11340 reinterpret_cast<float **>(src)[0][srcIdx];
11341 (*out_rgba)[4 * idx + 3] =
11342 reinterpret_cast<float **>(src)[0][srcIdx];
11343 }
11344 }
11345 }
11346 } else {
11347 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11348 const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
11349 (*out_rgba)[4 * i + 0] = val;
11350 (*out_rgba)[4 * i + 1] = val;
11351 (*out_rgba)[4 * i + 2] = val;
11352 (*out_rgba)[4 * i + 3] = val;
11353 }
11354 }
11355 } else {
11356 // Assume RGB(A)
11357
11358 if (idxR == -1) {
11359 tinyexr::SetErrorMessage("R channel not found", err);
11360
11361 // @todo { free exr_image }
11362 FreeEXRHeader(&exr_header);
11363 return TINYEXR_ERROR_INVALID_DATA;
11364 }
11365
11366 if (idxG == -1) {
11367 tinyexr::SetErrorMessage("G channel not found", err);
11368 // @todo { free exr_image }
11369 FreeEXRHeader(&exr_header);
11370 return TINYEXR_ERROR_INVALID_DATA;
11371 }
11372
11373 if (idxB == -1) {
11374 tinyexr::SetErrorMessage("B channel not found", err);
11375 // @todo { free exr_image }
11376 FreeEXRHeader(&exr_header);
11377 return TINYEXR_ERROR_INVALID_DATA;
11378 }
11379
11380 (*out_rgba) = reinterpret_cast<float *>(
11381 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11382 static_cast<size_t>(exr_image.height)));
11383 if (exr_header.tiled) {
11384 for (int it = 0; it < exr_image.num_tiles; it++) {
11385 for (int j = 0; j < exr_header.tile_size_y; j++) {
11386 for (int i = 0; i < exr_header.tile_size_x; i++) {
11387 const int ii =
11388 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11389 const int jj =
11390 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11391 const int idx = ii + jj * exr_image.width;
11392
11393 // out of region check.
11394 if (ii >= exr_image.width) {
11395 continue;
11396 }
11397 if (jj >= exr_image.height) {
11398 continue;
11399 }
11400 const int srcIdx = i + j * exr_header.tile_size_x;
11401 unsigned char **src = exr_image.tiles[it].images;
11402 (*out_rgba)[4 * idx + 0] =
11403 reinterpret_cast<float **>(src)[idxR][srcIdx];
11404 (*out_rgba)[4 * idx + 1] =
11405 reinterpret_cast<float **>(src)[idxG][srcIdx];
11406 (*out_rgba)[4 * idx + 2] =
11407 reinterpret_cast<float **>(src)[idxB][srcIdx];
11408 if (idxA != -1) {
11409 (*out_rgba)[4 * idx + 3] =
11410 reinterpret_cast<float **>(src)[idxA][srcIdx];
11411 } else {
11412 (*out_rgba)[4 * idx + 3] = 1.0;
11413 }
11414 }
11415 }
11416 }
11417 } else {
11418 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11419 (*out_rgba)[4 * i + 0] =
11420 reinterpret_cast<float **>(exr_image.images)[idxR][i];
11421 (*out_rgba)[4 * i + 1] =
11422 reinterpret_cast<float **>(exr_image.images)[idxG][i];
11423 (*out_rgba)[4 * i + 2] =
11424 reinterpret_cast<float **>(exr_image.images)[idxB][i];
11425 if (idxA != -1) {
11426 (*out_rgba)[4 * i + 3] =
11427 reinterpret_cast<float **>(exr_image.images)[idxA][i];
11428 } else {
11429 (*out_rgba)[4 * i + 3] = 1.0;
11430 }
11431 }
11432 }
11433 }
11434
11435 (*width) = exr_image.width;
11436 (*height) = exr_image.height;
11437
11438 FreeEXRHeader(&exr_header);
11439 FreeEXRImage(&exr_image);
11440
11441 return TINYEXR_SUCCESS;
11442 }
11443
IsEXR(const char * filename)11444 int IsEXR(const char *filename) {
11445 EXRVersion exr_version;
11446
11447 int ret = ParseEXRVersionFromFile(&exr_version, filename);
11448 if (ret != TINYEXR_SUCCESS) {
11449 return TINYEXR_ERROR_INVALID_HEADER;
11450 }
11451
11452 return TINYEXR_SUCCESS;
11453 }
11454
ParseEXRHeaderFromMemory(EXRHeader * exr_header,const EXRVersion * version,const unsigned char * memory,size_t size,const char ** err)11455 int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
11456 const unsigned char *memory, size_t size,
11457 const char **err) {
11458 if (memory == NULL || exr_header == NULL) {
11459 tinyexr::SetErrorMessage(
11460 "Invalid argument. `memory` or `exr_header` argument is null in "
11461 "ParseEXRHeaderFromMemory()",
11462 err);
11463
11464 // Invalid argument
11465 return TINYEXR_ERROR_INVALID_ARGUMENT;
11466 }
11467
11468 if (size < tinyexr::kEXRVersionSize) {
11469 tinyexr::SetErrorMessage("Insufficient header/data size.\n", err);
11470 return TINYEXR_ERROR_INVALID_DATA;
11471 }
11472
11473 const unsigned char *marker = memory + tinyexr::kEXRVersionSize;
11474 size_t marker_size = size - tinyexr::kEXRVersionSize;
11475
11476 tinyexr::HeaderInfo info;
11477 info.clear();
11478
11479 std::string err_str;
11480 int ret = ParseEXRHeader(&info, NULL, version, &err_str, marker, marker_size);
11481
11482 if (ret != TINYEXR_SUCCESS) {
11483 if (err && !err_str.empty()) {
11484 tinyexr::SetErrorMessage(err_str, err);
11485 }
11486 }
11487
11488 ConvertHeader(exr_header, info);
11489
11490 // transfoer `tiled` from version.
11491 exr_header->tiled = version->tiled;
11492
11493 return ret;
11494 }
11495
LoadEXRFromMemory(float ** out_rgba,int * width,int * height,const unsigned char * memory,size_t size,const char ** err)11496 int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
11497 const unsigned char *memory, size_t size,
11498 const char **err) {
11499 if (out_rgba == NULL || memory == NULL) {
11500 tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err);
11501 return TINYEXR_ERROR_INVALID_ARGUMENT;
11502 }
11503
11504 EXRVersion exr_version;
11505 EXRImage exr_image;
11506 EXRHeader exr_header;
11507
11508 InitEXRHeader(&exr_header);
11509
11510 int ret = ParseEXRVersionFromMemory(&exr_version, memory, size);
11511 if (ret != TINYEXR_SUCCESS) {
11512 tinyexr::SetErrorMessage("Failed to parse EXR version", err);
11513 return ret;
11514 }
11515
11516 ret = ParseEXRHeaderFromMemory(&exr_header, &exr_version, memory, size, err);
11517 if (ret != TINYEXR_SUCCESS) {
11518 return ret;
11519 }
11520
11521 // Read HALF channel as FLOAT.
11522 for (int i = 0; i < exr_header.num_channels; i++) {
11523 if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
11524 exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
11525 }
11526 }
11527
11528 InitEXRImage(&exr_image);
11529 ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err);
11530 if (ret != TINYEXR_SUCCESS) {
11531 return ret;
11532 }
11533
11534 // RGBA
11535 int idxR = -1;
11536 int idxG = -1;
11537 int idxB = -1;
11538 int idxA = -1;
11539 for (int c = 0; c < exr_header.num_channels; c++) {
11540 if (strcmp(exr_header.channels[c].name, "R") == 0) {
11541 idxR = c;
11542 } else if (strcmp(exr_header.channels[c].name, "G") == 0) {
11543 idxG = c;
11544 } else if (strcmp(exr_header.channels[c].name, "B") == 0) {
11545 idxB = c;
11546 } else if (strcmp(exr_header.channels[c].name, "A") == 0) {
11547 idxA = c;
11548 }
11549 }
11550
11551 // TODO(syoyo): Refactor removing same code as used in LoadEXR().
11552 if (exr_header.num_channels == 1) {
11553 // Grayscale channel only.
11554
11555 (*out_rgba) = reinterpret_cast<float *>(
11556 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11557 static_cast<size_t>(exr_image.height)));
11558
11559 if (exr_header.tiled) {
11560 for (int it = 0; it < exr_image.num_tiles; it++) {
11561 for (int j = 0; j < exr_header.tile_size_y; j++) {
11562 for (int i = 0; i < exr_header.tile_size_x; i++) {
11563 const int ii =
11564 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11565 const int jj =
11566 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11567 const int idx = ii + jj * exr_image.width;
11568
11569 // out of region check.
11570 if (ii >= exr_image.width) {
11571 continue;
11572 }
11573 if (jj >= exr_image.height) {
11574 continue;
11575 }
11576 const int srcIdx = i + j * exr_header.tile_size_x;
11577 unsigned char **src = exr_image.tiles[it].images;
11578 (*out_rgba)[4 * idx + 0] =
11579 reinterpret_cast<float **>(src)[0][srcIdx];
11580 (*out_rgba)[4 * idx + 1] =
11581 reinterpret_cast<float **>(src)[0][srcIdx];
11582 (*out_rgba)[4 * idx + 2] =
11583 reinterpret_cast<float **>(src)[0][srcIdx];
11584 (*out_rgba)[4 * idx + 3] =
11585 reinterpret_cast<float **>(src)[0][srcIdx];
11586 }
11587 }
11588 }
11589 } else {
11590 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11591 const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
11592 (*out_rgba)[4 * i + 0] = val;
11593 (*out_rgba)[4 * i + 1] = val;
11594 (*out_rgba)[4 * i + 2] = val;
11595 (*out_rgba)[4 * i + 3] = val;
11596 }
11597 }
11598
11599 } else {
11600 // TODO(syoyo): Support non RGBA image.
11601
11602 if (idxR == -1) {
11603 tinyexr::SetErrorMessage("R channel not found", err);
11604
11605 // @todo { free exr_image }
11606 return TINYEXR_ERROR_INVALID_DATA;
11607 }
11608
11609 if (idxG == -1) {
11610 tinyexr::SetErrorMessage("G channel not found", err);
11611 // @todo { free exr_image }
11612 return TINYEXR_ERROR_INVALID_DATA;
11613 }
11614
11615 if (idxB == -1) {
11616 tinyexr::SetErrorMessage("B channel not found", err);
11617 // @todo { free exr_image }
11618 return TINYEXR_ERROR_INVALID_DATA;
11619 }
11620
11621 (*out_rgba) = reinterpret_cast<float *>(
11622 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11623 static_cast<size_t>(exr_image.height)));
11624
11625 if (exr_header.tiled) {
11626 for (int it = 0; it < exr_image.num_tiles; it++) {
11627 for (int j = 0; j < exr_header.tile_size_y; j++)
11628 for (int i = 0; i < exr_header.tile_size_x; i++) {
11629 const int ii =
11630 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11631 const int jj =
11632 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11633 const int idx = ii + jj * exr_image.width;
11634
11635 // out of region check.
11636 if (ii >= exr_image.width) {
11637 continue;
11638 }
11639 if (jj >= exr_image.height) {
11640 continue;
11641 }
11642 const int srcIdx = i + j * exr_header.tile_size_x;
11643 unsigned char **src = exr_image.tiles[it].images;
11644 (*out_rgba)[4 * idx + 0] =
11645 reinterpret_cast<float **>(src)[idxR][srcIdx];
11646 (*out_rgba)[4 * idx + 1] =
11647 reinterpret_cast<float **>(src)[idxG][srcIdx];
11648 (*out_rgba)[4 * idx + 2] =
11649 reinterpret_cast<float **>(src)[idxB][srcIdx];
11650 if (idxA != -1) {
11651 (*out_rgba)[4 * idx + 3] =
11652 reinterpret_cast<float **>(src)[idxA][srcIdx];
11653 } else {
11654 (*out_rgba)[4 * idx + 3] = 1.0;
11655 }
11656 }
11657 }
11658 } else {
11659 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11660 (*out_rgba)[4 * i + 0] =
11661 reinterpret_cast<float **>(exr_image.images)[idxR][i];
11662 (*out_rgba)[4 * i + 1] =
11663 reinterpret_cast<float **>(exr_image.images)[idxG][i];
11664 (*out_rgba)[4 * i + 2] =
11665 reinterpret_cast<float **>(exr_image.images)[idxB][i];
11666 if (idxA != -1) {
11667 (*out_rgba)[4 * i + 3] =
11668 reinterpret_cast<float **>(exr_image.images)[idxA][i];
11669 } else {
11670 (*out_rgba)[4 * i + 3] = 1.0;
11671 }
11672 }
11673 }
11674 }
11675
11676 (*width) = exr_image.width;
11677 (*height) = exr_image.height;
11678
11679 FreeEXRHeader(&exr_header);
11680 FreeEXRImage(&exr_image);
11681
11682 return TINYEXR_SUCCESS;
11683 }
11684
LoadEXRImageFromFile(EXRImage * exr_image,const EXRHeader * exr_header,const char * filename,const char ** err)11685 int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
11686 const char *filename, const char **err) {
11687 if (exr_image == NULL) {
11688 tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err);
11689 return TINYEXR_ERROR_INVALID_ARGUMENT;
11690 }
11691
11692 #ifdef _WIN32
11693 FILE *fp = NULL;
11694 fopen_s(&fp, filename, "rb");
11695 #else
11696 FILE *fp = fopen(filename, "rb");
11697 #endif
11698 if (!fp) {
11699 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
11700 return TINYEXR_ERROR_CANT_OPEN_FILE;
11701 }
11702
11703 size_t filesize;
11704 // Compute size
11705 fseek(fp, 0, SEEK_END);
11706 filesize = static_cast<size_t>(ftell(fp));
11707 fseek(fp, 0, SEEK_SET);
11708
11709 if (filesize < 16) {
11710 tinyexr::SetErrorMessage("File size too short " + std::string(filename),
11711 err);
11712 return TINYEXR_ERROR_INVALID_FILE;
11713 }
11714
11715 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
11716 {
11717 size_t ret;
11718 ret = fread(&buf[0], 1, filesize, fp);
11719 assert(ret == filesize);
11720 fclose(fp);
11721 (void)ret;
11722 }
11723
11724 return LoadEXRImageFromMemory(exr_image, exr_header, &buf.at(0), filesize,
11725 err);
11726 }
11727
LoadEXRImageFromMemory(EXRImage * exr_image,const EXRHeader * exr_header,const unsigned char * memory,const size_t size,const char ** err)11728 int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header,
11729 const unsigned char *memory, const size_t size,
11730 const char **err) {
11731 if (exr_image == NULL || memory == NULL ||
11732 (size < tinyexr::kEXRVersionSize)) {
11733 tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory",
11734 err);
11735 return TINYEXR_ERROR_INVALID_ARGUMENT;
11736 }
11737
11738 if (exr_header->header_len == 0) {
11739 tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
11740 return TINYEXR_ERROR_INVALID_ARGUMENT;
11741 }
11742
11743 const unsigned char *head = memory;
11744 const unsigned char *marker = reinterpret_cast<const unsigned char *>(
11745 memory + exr_header->header_len +
11746 8); // +8 for magic number + version header.
11747 return tinyexr::DecodeEXRImage(exr_image, exr_header, head, marker, size,
11748 err);
11749 }
11750
SaveEXRImageToMemory(const EXRImage * exr_image,const EXRHeader * exr_header,unsigned char ** memory_out,const char ** err)11751 size_t SaveEXRImageToMemory(const EXRImage *exr_image,
11752 const EXRHeader *exr_header,
11753 unsigned char **memory_out, const char **err) {
11754 if (exr_image == NULL || memory_out == NULL ||
11755 exr_header->compression_type < 0) {
11756 tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err);
11757 return 0;
11758 }
11759
11760 #if !TINYEXR_USE_PIZ
11761 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
11762 tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
11763 err);
11764 return 0;
11765 }
11766 #endif
11767
11768 #if !TINYEXR_USE_ZFP
11769 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
11770 tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
11771 err);
11772 return 0;
11773 }
11774 #endif
11775
11776 #if TINYEXR_USE_ZFP
11777 for (size_t i = 0; i < static_cast<size_t>(exr_header->num_channels); i++) {
11778 if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) {
11779 tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression",
11780 err);
11781 return 0;
11782 }
11783 }
11784 #endif
11785
11786 std::vector<unsigned char> memory;
11787
11788 // Header
11789 {
11790 const char header[] = {0x76, 0x2f, 0x31, 0x01};
11791 memory.insert(memory.end(), header, header + 4);
11792 }
11793
11794 // Version, scanline.
11795 {
11796 char marker[] = {2, 0, 0, 0};
11797 /* @todo
11798 if (exr_header->tiled) {
11799 marker[1] |= 0x2;
11800 }
11801 if (exr_header->long_name) {
11802 marker[1] |= 0x4;
11803 }
11804 if (exr_header->non_image) {
11805 marker[1] |= 0x8;
11806 }
11807 if (exr_header->multipart) {
11808 marker[1] |= 0x10;
11809 }
11810 */
11811 memory.insert(memory.end(), marker, marker + 4);
11812 }
11813
11814 int num_scanlines = 1;
11815 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
11816 num_scanlines = 16;
11817 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
11818 num_scanlines = 32;
11819 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
11820 num_scanlines = 16;
11821 }
11822
11823 // Write attributes.
11824 std::vector<tinyexr::ChannelInfo> channels;
11825 {
11826 std::vector<unsigned char> data;
11827
11828 for (int c = 0; c < exr_header->num_channels; c++) {
11829 tinyexr::ChannelInfo info;
11830 info.p_linear = 0;
11831 info.pixel_type = exr_header->requested_pixel_types[c];
11832 info.x_sampling = 1;
11833 info.y_sampling = 1;
11834 info.name = std::string(exr_header->channels[c].name);
11835 channels.push_back(info);
11836 }
11837
11838 tinyexr::WriteChannelInfo(data, channels);
11839
11840 tinyexr::WriteAttributeToMemory(&memory, "channels", "chlist", &data.at(0),
11841 static_cast<int>(data.size()));
11842 }
11843
11844 {
11845 int comp = exr_header->compression_type;
11846 tinyexr::swap4(reinterpret_cast<unsigned int *>(&comp));
11847 tinyexr::WriteAttributeToMemory(
11848 &memory, "compression", "compression",
11849 reinterpret_cast<const unsigned char *>(&comp), 1);
11850 }
11851
11852 {
11853 int data[4] = {0, 0, exr_image->width - 1, exr_image->height - 1};
11854 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[0]));
11855 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[1]));
11856 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[2]));
11857 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[3]));
11858 tinyexr::WriteAttributeToMemory(
11859 &memory, "dataWindow", "box2i",
11860 reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4);
11861 tinyexr::WriteAttributeToMemory(
11862 &memory, "displayWindow", "box2i",
11863 reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4);
11864 }
11865
11866 {
11867 unsigned char line_order = 0; // @fixme { read line_order from EXRHeader }
11868 tinyexr::WriteAttributeToMemory(&memory, "lineOrder", "lineOrder",
11869 &line_order, 1);
11870 }
11871
11872 {
11873 float aspectRatio = 1.0f;
11874 tinyexr::swap4(reinterpret_cast<unsigned int *>(&aspectRatio));
11875 tinyexr::WriteAttributeToMemory(
11876 &memory, "pixelAspectRatio", "float",
11877 reinterpret_cast<const unsigned char *>(&aspectRatio), sizeof(float));
11878 }
11879
11880 {
11881 float center[2] = {0.0f, 0.0f};
11882 tinyexr::swap4(reinterpret_cast<unsigned int *>(¢er[0]));
11883 tinyexr::swap4(reinterpret_cast<unsigned int *>(¢er[1]));
11884 tinyexr::WriteAttributeToMemory(
11885 &memory, "screenWindowCenter", "v2f",
11886 reinterpret_cast<const unsigned char *>(center), 2 * sizeof(float));
11887 }
11888
11889 {
11890 float w = static_cast<float>(exr_image->width);
11891 tinyexr::swap4(reinterpret_cast<unsigned int *>(&w));
11892 tinyexr::WriteAttributeToMemory(&memory, "screenWindowWidth", "float",
11893 reinterpret_cast<const unsigned char *>(&w),
11894 sizeof(float));
11895 }
11896
11897 // Custom attributes
11898 if (exr_header->num_custom_attributes > 0) {
11899 for (int i = 0; i < exr_header->num_custom_attributes; i++) {
11900 tinyexr::WriteAttributeToMemory(
11901 &memory, exr_header->custom_attributes[i].name,
11902 exr_header->custom_attributes[i].type,
11903 reinterpret_cast<const unsigned char *>(
11904 exr_header->custom_attributes[i].value),
11905 exr_header->custom_attributes[i].size);
11906 }
11907 }
11908
11909 { // end of header
11910 unsigned char e = 0;
11911 memory.push_back(e);
11912 }
11913
11914 int num_blocks = exr_image->height / num_scanlines;
11915 if (num_blocks * num_scanlines < exr_image->height) {
11916 num_blocks++;
11917 }
11918
11919 std::vector<tinyexr::tinyexr_uint64> offsets(static_cast<size_t>(num_blocks));
11920
11921 size_t headerSize = memory.size();
11922 tinyexr::tinyexr_uint64 offset =
11923 headerSize +
11924 static_cast<size_t>(num_blocks) *
11925 sizeof(
11926 tinyexr::tinyexr_int64); // sizeof(header) + sizeof(offsetTable)
11927
11928 std::vector<std::vector<unsigned char> > data_list(
11929 static_cast<size_t>(num_blocks));
11930 std::vector<size_t> channel_offset_list(
11931 static_cast<size_t>(exr_header->num_channels));
11932
11933 int pixel_data_size = 0;
11934 size_t channel_offset = 0;
11935 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
11936 channel_offset_list[c] = channel_offset;
11937 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
11938 pixel_data_size += sizeof(unsigned short);
11939 channel_offset += sizeof(unsigned short);
11940 } else if (exr_header->requested_pixel_types[c] ==
11941 TINYEXR_PIXELTYPE_FLOAT) {
11942 pixel_data_size += sizeof(float);
11943 channel_offset += sizeof(float);
11944 } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
11945 pixel_data_size += sizeof(unsigned int);
11946 channel_offset += sizeof(unsigned int);
11947 } else {
11948 assert(0);
11949 }
11950 }
11951
11952 #if TINYEXR_USE_ZFP
11953 tinyexr::ZFPCompressionParam zfp_compression_param;
11954
11955 // Use ZFP compression parameter from custom attributes(if such a parameter
11956 // exists)
11957 {
11958 bool ret = tinyexr::FindZFPCompressionParam(
11959 &zfp_compression_param, exr_header->custom_attributes,
11960 exr_header->num_custom_attributes);
11961
11962 if (!ret) {
11963 // Use predefined compression parameter.
11964 zfp_compression_param.type = 0;
11965 zfp_compression_param.rate = 2;
11966 }
11967 }
11968 #endif
11969
11970 // Use signed int since some OpenMP compiler doesn't allow unsigned type for
11971 // `parallel for`
11972 #ifdef _OPENMP
11973 #pragma omp parallel for
11974 #endif
11975 for (int i = 0; i < num_blocks; i++) {
11976 size_t ii = static_cast<size_t>(i);
11977 int start_y = num_scanlines * i;
11978 int endY = (std::min)(num_scanlines * (i + 1), exr_image->height);
11979 int h = endY - start_y;
11980
11981 std::vector<unsigned char> buf(
11982 static_cast<size_t>(exr_image->width * h * pixel_data_size));
11983
11984 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
11985 if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
11986 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
11987 for (int y = 0; y < h; y++) {
11988 // Assume increasing Y
11989 float *line_ptr = reinterpret_cast<float *>(&buf.at(
11990 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
11991 channel_offset_list[c] *
11992 static_cast<size_t>(exr_image->width)));
11993 for (int x = 0; x < exr_image->width; x++) {
11994 tinyexr::FP16 h16;
11995 h16.u = reinterpret_cast<unsigned short **>(
11996 exr_image->images)[c][(y + start_y) * exr_image->width + x];
11997
11998 tinyexr::FP32 f32 = half_to_float(h16);
11999
12000 tinyexr::swap4(reinterpret_cast<unsigned int *>(&f32.f));
12001
12002 // line_ptr[x] = f32.f;
12003 tinyexr::cpy4(line_ptr + x, &(f32.f));
12004 }
12005 }
12006 } else if (exr_header->requested_pixel_types[c] ==
12007 TINYEXR_PIXELTYPE_HALF) {
12008 for (int y = 0; y < h; y++) {
12009 // Assume increasing Y
12010 unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
12011 &buf.at(static_cast<size_t>(pixel_data_size * y *
12012 exr_image->width) +
12013 channel_offset_list[c] *
12014 static_cast<size_t>(exr_image->width)));
12015 for (int x = 0; x < exr_image->width; x++) {
12016 unsigned short val = reinterpret_cast<unsigned short **>(
12017 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12018
12019 tinyexr::swap2(&val);
12020
12021 // line_ptr[x] = val;
12022 tinyexr::cpy2(line_ptr + x, &val);
12023 }
12024 }
12025 } else {
12026 assert(0);
12027 }
12028
12029 } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
12030 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
12031 for (int y = 0; y < h; y++) {
12032 // Assume increasing Y
12033 unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
12034 &buf.at(static_cast<size_t>(pixel_data_size * y *
12035 exr_image->width) +
12036 channel_offset_list[c] *
12037 static_cast<size_t>(exr_image->width)));
12038 for (int x = 0; x < exr_image->width; x++) {
12039 tinyexr::FP32 f32;
12040 f32.f = reinterpret_cast<float **>(
12041 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12042
12043 tinyexr::FP16 h16;
12044 h16 = float_to_half_full(f32);
12045
12046 tinyexr::swap2(reinterpret_cast<unsigned short *>(&h16.u));
12047
12048 // line_ptr[x] = h16.u;
12049 tinyexr::cpy2(line_ptr + x, &(h16.u));
12050 }
12051 }
12052 } else if (exr_header->requested_pixel_types[c] ==
12053 TINYEXR_PIXELTYPE_FLOAT) {
12054 for (int y = 0; y < h; y++) {
12055 // Assume increasing Y
12056 float *line_ptr = reinterpret_cast<float *>(&buf.at(
12057 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
12058 channel_offset_list[c] *
12059 static_cast<size_t>(exr_image->width)));
12060 for (int x = 0; x < exr_image->width; x++) {
12061 float val = reinterpret_cast<float **>(
12062 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12063
12064 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
12065
12066 // line_ptr[x] = val;
12067 tinyexr::cpy4(line_ptr + x, &val);
12068 }
12069 }
12070 } else {
12071 assert(0);
12072 }
12073 } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
12074 for (int y = 0; y < h; y++) {
12075 // Assume increasing Y
12076 unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
12077 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
12078 channel_offset_list[c] * static_cast<size_t>(exr_image->width)));
12079 for (int x = 0; x < exr_image->width; x++) {
12080 unsigned int val = reinterpret_cast<unsigned int **>(
12081 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12082
12083 tinyexr::swap4(&val);
12084
12085 // line_ptr[x] = val;
12086 tinyexr::cpy4(line_ptr + x, &val);
12087 }
12088 }
12089 }
12090 }
12091
12092 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
12093 // 4 byte: scan line
12094 // 4 byte: data size
12095 // ~ : pixel data(uncompressed)
12096 std::vector<unsigned char> header(8);
12097 unsigned int data_len = static_cast<unsigned int>(buf.size());
12098 memcpy(&header.at(0), &start_y, sizeof(int));
12099 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12100
12101 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12102 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12103
12104 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12105 data_list[ii].insert(data_list[ii].end(), buf.begin(),
12106 buf.begin() + data_len);
12107
12108 } else if ((exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
12109 (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) {
12110 #if TINYEXR_USE_MINIZ
12111 std::vector<unsigned char> block(tinyexr::miniz::mz_compressBound(
12112 static_cast<unsigned long>(buf.size())));
12113 #else
12114 std::vector<unsigned char> block(
12115 compressBound(static_cast<uLong>(buf.size())));
12116 #endif
12117 tinyexr::tinyexr_uint64 outSize = block.size();
12118
12119 tinyexr::CompressZip(&block.at(0), outSize,
12120 reinterpret_cast<const unsigned char *>(&buf.at(0)),
12121 static_cast<unsigned long>(buf.size()));
12122
12123 // 4 byte: scan line
12124 // 4 byte: data size
12125 // ~ : pixel data(compressed)
12126 std::vector<unsigned char> header(8);
12127 unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
12128 memcpy(&header.at(0), &start_y, sizeof(int));
12129 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12130
12131 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12132 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12133
12134 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12135 data_list[ii].insert(data_list[ii].end(), block.begin(),
12136 block.begin() + data_len);
12137
12138 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_RLE) {
12139 // (buf.size() * 3) / 2 would be enough.
12140 std::vector<unsigned char> block((buf.size() * 3) / 2);
12141
12142 tinyexr::tinyexr_uint64 outSize = block.size();
12143
12144 tinyexr::CompressRle(&block.at(0), outSize,
12145 reinterpret_cast<const unsigned char *>(&buf.at(0)),
12146 static_cast<unsigned long>(buf.size()));
12147
12148 // 4 byte: scan line
12149 // 4 byte: data size
12150 // ~ : pixel data(compressed)
12151 std::vector<unsigned char> header(8);
12152 unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
12153 memcpy(&header.at(0), &start_y, sizeof(int));
12154 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12155
12156 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12157 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12158
12159 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12160 data_list[ii].insert(data_list[ii].end(), block.begin(),
12161 block.begin() + data_len);
12162
12163 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
12164 #if TINYEXR_USE_PIZ
12165 unsigned int bufLen =
12166 8192 + static_cast<unsigned int>(
12167 2 * static_cast<unsigned int>(
12168 buf.size())); // @fixme { compute good bound. }
12169 std::vector<unsigned char> block(bufLen);
12170 unsigned int outSize = static_cast<unsigned int>(block.size());
12171
12172 CompressPiz(&block.at(0), &outSize,
12173 reinterpret_cast<const unsigned char *>(&buf.at(0)),
12174 buf.size(), channels, exr_image->width, h);
12175
12176 // 4 byte: scan line
12177 // 4 byte: data size
12178 // ~ : pixel data(compressed)
12179 std::vector<unsigned char> header(8);
12180 unsigned int data_len = outSize;
12181 memcpy(&header.at(0), &start_y, sizeof(int));
12182 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12183
12184 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12185 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12186
12187 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12188 data_list[ii].insert(data_list[ii].end(), block.begin(),
12189 block.begin() + data_len);
12190
12191 #else
12192 assert(0);
12193 #endif
12194 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
12195 #if TINYEXR_USE_ZFP
12196 std::vector<unsigned char> block;
12197 unsigned int outSize;
12198
12199 tinyexr::CompressZfp(
12200 &block, &outSize, reinterpret_cast<const float *>(&buf.at(0)),
12201 exr_image->width, h, exr_header->num_channels, zfp_compression_param);
12202
12203 // 4 byte: scan line
12204 // 4 byte: data size
12205 // ~ : pixel data(compressed)
12206 std::vector<unsigned char> header(8);
12207 unsigned int data_len = outSize;
12208 memcpy(&header.at(0), &start_y, sizeof(int));
12209 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12210
12211 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12212 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12213
12214 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12215 data_list[ii].insert(data_list[ii].end(), block.begin(),
12216 block.begin() + data_len);
12217
12218 #else
12219 assert(0);
12220 #endif
12221 } else {
12222 assert(0);
12223 }
12224 } // omp parallel
12225
12226 for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
12227 offsets[i] = offset;
12228 tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offsets[i]));
12229 offset += data_list[i].size();
12230 }
12231
12232 size_t totalSize = static_cast<size_t>(offset);
12233 {
12234 memory.insert(
12235 memory.end(), reinterpret_cast<unsigned char *>(&offsets.at(0)),
12236 reinterpret_cast<unsigned char *>(&offsets.at(0)) +
12237 sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(num_blocks));
12238 }
12239
12240 if (memory.size() == 0) {
12241 tinyexr::SetErrorMessage("Output memory size is zero", err);
12242 return 0;
12243 }
12244
12245 (*memory_out) = static_cast<unsigned char *>(malloc(totalSize));
12246 memcpy((*memory_out), &memory.at(0), memory.size());
12247 unsigned char *memory_ptr = *memory_out + memory.size();
12248
12249 for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
12250 memcpy(memory_ptr, &data_list[i].at(0), data_list[i].size());
12251 memory_ptr += data_list[i].size();
12252 }
12253
12254 return totalSize; // OK
12255 }
12256
SaveEXRImageToFile(const EXRImage * exr_image,const EXRHeader * exr_header,const char * filename,const char ** err)12257 int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
12258 const char *filename, const char **err) {
12259 if (exr_image == NULL || filename == NULL ||
12260 exr_header->compression_type < 0) {
12261 tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err);
12262 return TINYEXR_ERROR_INVALID_ARGUMENT;
12263 }
12264
12265 #if !TINYEXR_USE_PIZ
12266 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
12267 tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
12268 err);
12269 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
12270 }
12271 #endif
12272
12273 #if !TINYEXR_USE_ZFP
12274 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
12275 tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
12276 err);
12277 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
12278 }
12279 #endif
12280
12281 #ifdef _WIN32
12282 FILE *fp = NULL;
12283 fopen_s(&fp, filename, "wb");
12284 #else
12285 FILE *fp = fopen(filename, "wb");
12286 #endif
12287 if (!fp) {
12288 tinyexr::SetErrorMessage("Cannot write a file", err);
12289 return TINYEXR_ERROR_CANT_WRITE_FILE;
12290 }
12291
12292 unsigned char *mem = NULL;
12293 size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err);
12294 if (mem_size == 0) {
12295 return TINYEXR_ERROR_SERIALZATION_FAILED;
12296 }
12297
12298 size_t written_size = 0;
12299 if ((mem_size > 0) && mem) {
12300 written_size = fwrite(mem, 1, mem_size, fp);
12301 }
12302 free(mem);
12303
12304 fclose(fp);
12305
12306 if (written_size != mem_size) {
12307 tinyexr::SetErrorMessage("Cannot write a file", err);
12308 return TINYEXR_ERROR_CANT_WRITE_FILE;
12309 }
12310
12311 return TINYEXR_SUCCESS;
12312 }
12313
LoadDeepEXR(DeepImage * deep_image,const char * filename,const char ** err)12314 int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
12315 if (deep_image == NULL) {
12316 tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err);
12317 return TINYEXR_ERROR_INVALID_ARGUMENT;
12318 }
12319
12320 #ifdef _MSC_VER
12321 FILE *fp = NULL;
12322 errno_t errcode = fopen_s(&fp, filename, "rb");
12323 if ((0 != errcode) || (!fp)) {
12324 tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
12325 err);
12326 return TINYEXR_ERROR_CANT_OPEN_FILE;
12327 }
12328 #else
12329 FILE *fp = fopen(filename, "rb");
12330 if (!fp) {
12331 tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
12332 err);
12333 return TINYEXR_ERROR_CANT_OPEN_FILE;
12334 }
12335 #endif
12336
12337 size_t filesize;
12338 // Compute size
12339 fseek(fp, 0, SEEK_END);
12340 filesize = static_cast<size_t>(ftell(fp));
12341 fseek(fp, 0, SEEK_SET);
12342
12343 if (filesize == 0) {
12344 fclose(fp);
12345 tinyexr::SetErrorMessage("File size is zero : " + std::string(filename),
12346 err);
12347 return TINYEXR_ERROR_INVALID_FILE;
12348 }
12349
12350 std::vector<char> buf(filesize); // @todo { use mmap }
12351 {
12352 size_t ret;
12353 ret = fread(&buf[0], 1, filesize, fp);
12354 assert(ret == filesize);
12355 (void)ret;
12356 }
12357 fclose(fp);
12358
12359 const char *head = &buf[0];
12360 const char *marker = &buf[0];
12361
12362 // Header check.
12363 {
12364 const char header[] = {0x76, 0x2f, 0x31, 0x01};
12365
12366 if (memcmp(marker, header, 4) != 0) {
12367 tinyexr::SetErrorMessage("Invalid magic number", err);
12368 return TINYEXR_ERROR_INVALID_MAGIC_NUMBER;
12369 }
12370 marker += 4;
12371 }
12372
12373 // Version, scanline.
12374 {
12375 // ver 2.0, scanline, deep bit on(0x800)
12376 // must be [2, 0, 0, 0]
12377 if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) {
12378 tinyexr::SetErrorMessage("Unsupported version or scanline", err);
12379 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
12380 }
12381
12382 marker += 4;
12383 }
12384
12385 int dx = -1;
12386 int dy = -1;
12387 int dw = -1;
12388 int dh = -1;
12389 int num_scanline_blocks = 1; // 16 for ZIP compression.
12390 int compression_type = -1;
12391 int num_channels = -1;
12392 std::vector<tinyexr::ChannelInfo> channels;
12393
12394 // Read attributes
12395 size_t size = filesize - tinyexr::kEXRVersionSize;
12396 for (;;) {
12397 if (0 == size) {
12398 return TINYEXR_ERROR_INVALID_DATA;
12399 } else if (marker[0] == '\0') {
12400 marker++;
12401 size--;
12402 break;
12403 }
12404
12405 std::string attr_name;
12406 std::string attr_type;
12407 std::vector<unsigned char> data;
12408 size_t marker_size;
12409 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
12410 marker, size)) {
12411 std::stringstream ss;
12412 ss << "Failed to parse attribute\n";
12413 tinyexr::SetErrorMessage(ss.str(), err);
12414 return TINYEXR_ERROR_INVALID_DATA;
12415 }
12416 marker += marker_size;
12417 size -= marker_size;
12418
12419 if (attr_name.compare("compression") == 0) {
12420 compression_type = data[0];
12421 if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) {
12422 std::stringstream ss;
12423 ss << "Unsupported compression type : " << compression_type;
12424 tinyexr::SetErrorMessage(ss.str(), err);
12425 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
12426 }
12427
12428 if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
12429 num_scanline_blocks = 16;
12430 }
12431
12432 } else if (attr_name.compare("channels") == 0) {
12433 // name: zero-terminated string, from 1 to 255 bytes long
12434 // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2
12435 // pLinear: unsigned char, possible values are 0 and 1
12436 // reserved: three chars, should be zero
12437 // xSampling: int
12438 // ySampling: int
12439
12440 if (!tinyexr::ReadChannelInfo(channels, data)) {
12441 tinyexr::SetErrorMessage("Failed to parse channel info", err);
12442 return TINYEXR_ERROR_INVALID_DATA;
12443 }
12444
12445 num_channels = static_cast<int>(channels.size());
12446
12447 if (num_channels < 1) {
12448 tinyexr::SetErrorMessage("Invalid channels format", err);
12449 return TINYEXR_ERROR_INVALID_DATA;
12450 }
12451
12452 } else if (attr_name.compare("dataWindow") == 0) {
12453 memcpy(&dx, &data.at(0), sizeof(int));
12454 memcpy(&dy, &data.at(4), sizeof(int));
12455 memcpy(&dw, &data.at(8), sizeof(int));
12456 memcpy(&dh, &data.at(12), sizeof(int));
12457 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dx));
12458 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dy));
12459 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dw));
12460 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dh));
12461
12462 } else if (attr_name.compare("displayWindow") == 0) {
12463 int x;
12464 int y;
12465 int w;
12466 int h;
12467 memcpy(&x, &data.at(0), sizeof(int));
12468 memcpy(&y, &data.at(4), sizeof(int));
12469 memcpy(&w, &data.at(8), sizeof(int));
12470 memcpy(&h, &data.at(12), sizeof(int));
12471 tinyexr::swap4(reinterpret_cast<unsigned int *>(&x));
12472 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y));
12473 tinyexr::swap4(reinterpret_cast<unsigned int *>(&w));
12474 tinyexr::swap4(reinterpret_cast<unsigned int *>(&h));
12475 }
12476 }
12477
12478 assert(dx >= 0);
12479 assert(dy >= 0);
12480 assert(dw >= 0);
12481 assert(dh >= 0);
12482 assert(num_channels >= 1);
12483
12484 int data_width = dw - dx + 1;
12485 int data_height = dh - dy + 1;
12486
12487 std::vector<float> image(
12488 static_cast<size_t>(data_width * data_height * 4)); // 4 = RGBA
12489
12490 // Read offset tables.
12491 int num_blocks = data_height / num_scanline_blocks;
12492 if (num_blocks * num_scanline_blocks < data_height) {
12493 num_blocks++;
12494 }
12495
12496 std::vector<tinyexr::tinyexr_int64> offsets(static_cast<size_t>(num_blocks));
12497
12498 for (size_t y = 0; y < static_cast<size_t>(num_blocks); y++) {
12499 tinyexr::tinyexr_int64 offset;
12500 memcpy(&offset, marker, sizeof(tinyexr::tinyexr_int64));
12501 tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offset));
12502 marker += sizeof(tinyexr::tinyexr_int64); // = 8
12503 offsets[y] = offset;
12504 }
12505
12506 #if TINYEXR_USE_PIZ
12507 if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) ||
12508 (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) ||
12509 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
12510 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) ||
12511 (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ)) {
12512 #else
12513 if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) ||
12514 (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) ||
12515 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
12516 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) {
12517 #endif
12518 // OK
12519 } else {
12520 tinyexr::SetErrorMessage("Unsupported compression format", err);
12521 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
12522 }
12523
12524 deep_image->image = static_cast<float ***>(
12525 malloc(sizeof(float **) * static_cast<size_t>(num_channels)));
12526 for (int c = 0; c < num_channels; c++) {
12527 deep_image->image[c] = static_cast<float **>(
12528 malloc(sizeof(float *) * static_cast<size_t>(data_height)));
12529 for (int y = 0; y < data_height; y++) {
12530 }
12531 }
12532
12533 deep_image->offset_table = static_cast<int **>(
12534 malloc(sizeof(int *) * static_cast<size_t>(data_height)));
12535 for (int y = 0; y < data_height; y++) {
12536 deep_image->offset_table[y] = static_cast<int *>(
12537 malloc(sizeof(int) * static_cast<size_t>(data_width)));
12538 }
12539
12540 for (size_t y = 0; y < static_cast<size_t>(num_blocks); y++) {
12541 const unsigned char *data_ptr =
12542 reinterpret_cast<const unsigned char *>(head + offsets[y]);
12543
12544 // int: y coordinate
12545 // int64: packed size of pixel offset table
12546 // int64: packed size of sample data
12547 // int64: unpacked size of sample data
12548 // compressed pixel offset table
12549 // compressed sample data
12550 int line_no;
12551 tinyexr::tinyexr_int64 packedOffsetTableSize;
12552 tinyexr::tinyexr_int64 packedSampleDataSize;
12553 tinyexr::tinyexr_int64 unpackedSampleDataSize;
12554 memcpy(&line_no, data_ptr, sizeof(int));
12555 memcpy(&packedOffsetTableSize, data_ptr + 4,
12556 sizeof(tinyexr::tinyexr_int64));
12557 memcpy(&packedSampleDataSize, data_ptr + 12,
12558 sizeof(tinyexr::tinyexr_int64));
12559 memcpy(&unpackedSampleDataSize, data_ptr + 20,
12560 sizeof(tinyexr::tinyexr_int64));
12561
12562 tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
12563 tinyexr::swap8(
12564 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&packedOffsetTableSize));
12565 tinyexr::swap8(
12566 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&packedSampleDataSize));
12567 tinyexr::swap8(
12568 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&unpackedSampleDataSize));
12569
12570 std::vector<int> pixelOffsetTable(static_cast<size_t>(data_width));
12571
12572 // decode pixel offset table.
12573 {
12574 unsigned long dstLen =
12575 static_cast<unsigned long>(pixelOffsetTable.size() * sizeof(int));
12576 if (!tinyexr::DecompressZip(
12577 reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)),
12578 &dstLen, data_ptr + 28,
12579 static_cast<unsigned long>(packedOffsetTableSize))) {
12580 return false;
12581 }
12582
12583 assert(dstLen == pixelOffsetTable.size() * sizeof(int));
12584 for (size_t i = 0; i < static_cast<size_t>(data_width); i++) {
12585 deep_image->offset_table[y][i] = pixelOffsetTable[i];
12586 }
12587 }
12588
12589 std::vector<unsigned char> sample_data(
12590 static_cast<size_t>(unpackedSampleDataSize));
12591
12592 // decode sample data.
12593 {
12594 unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize);
12595 if (dstLen) {
12596 if (!tinyexr::DecompressZip(
12597 reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen,
12598 data_ptr + 28 + packedOffsetTableSize,
12599 static_cast<unsigned long>(packedSampleDataSize))) {
12600 return false;
12601 }
12602 assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize));
12603 }
12604 }
12605
12606 // decode sample
12607 int sampleSize = -1;
12608 std::vector<int> channel_offset_list(static_cast<size_t>(num_channels));
12609 {
12610 int channel_offset = 0;
12611 for (size_t i = 0; i < static_cast<size_t>(num_channels); i++) {
12612 channel_offset_list[i] = channel_offset;
12613 if (channels[i].pixel_type == TINYEXR_PIXELTYPE_UINT) { // UINT
12614 channel_offset += 4;
12615 } else if (channels[i].pixel_type == TINYEXR_PIXELTYPE_HALF) { // half
12616 channel_offset += 2;
12617 } else if (channels[i].pixel_type ==
12618 TINYEXR_PIXELTYPE_FLOAT) { // float
12619 channel_offset += 4;
12620 } else {
12621 assert(0);
12622 }
12623 }
12624 sampleSize = channel_offset;
12625 }
12626 assert(sampleSize >= 2);
12627
12628 assert(static_cast<size_t>(
12629 pixelOffsetTable[static_cast<size_t>(data_width - 1)] *
12630 sampleSize) == sample_data.size());
12631 int samples_per_line = static_cast<int>(sample_data.size()) / sampleSize;
12632
12633 //
12634 // Alloc memory
12635 //
12636
12637 //
12638 // pixel data is stored as image[channels][pixel_samples]
12639 //
12640 {
12641 tinyexr::tinyexr_uint64 data_offset = 0;
12642 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
12643 deep_image->image[c][y] = static_cast<float *>(
12644 malloc(sizeof(float) * static_cast<size_t>(samples_per_line)));
12645
12646 if (channels[c].pixel_type == 0) { // UINT
12647 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
12648 unsigned int ui;
12649 unsigned int *src_ptr = reinterpret_cast<unsigned int *>(
12650 &sample_data.at(size_t(data_offset) + x * sizeof(int)));
12651 tinyexr::cpy4(&ui, src_ptr);
12652 deep_image->image[c][y][x] = static_cast<float>(ui); // @fixme
12653 }
12654 data_offset +=
12655 sizeof(unsigned int) * static_cast<size_t>(samples_per_line);
12656 } else if (channels[c].pixel_type == 1) { // half
12657 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
12658 tinyexr::FP16 f16;
12659 const unsigned short *src_ptr = reinterpret_cast<unsigned short *>(
12660 &sample_data.at(size_t(data_offset) + x * sizeof(short)));
12661 tinyexr::cpy2(&(f16.u), src_ptr);
12662 tinyexr::FP32 f32 = half_to_float(f16);
12663 deep_image->image[c][y][x] = f32.f;
12664 }
12665 data_offset += sizeof(short) * static_cast<size_t>(samples_per_line);
12666 } else { // float
12667 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
12668 float f;
12669 const float *src_ptr = reinterpret_cast<float *>(
12670 &sample_data.at(size_t(data_offset) + x * sizeof(float)));
12671 tinyexr::cpy4(&f, src_ptr);
12672 deep_image->image[c][y][x] = f;
12673 }
12674 data_offset += sizeof(float) * static_cast<size_t>(samples_per_line);
12675 }
12676 }
12677 }
12678 } // y
12679
12680 deep_image->width = data_width;
12681 deep_image->height = data_height;
12682
12683 deep_image->channel_names = static_cast<const char **>(
12684 malloc(sizeof(const char *) * static_cast<size_t>(num_channels)));
12685 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
12686 #ifdef _WIN32
12687 deep_image->channel_names[c] = _strdup(channels[c].name.c_str());
12688 #else
12689 deep_image->channel_names[c] = strdup(channels[c].name.c_str());
12690 #endif
12691 }
12692 deep_image->num_channels = num_channels;
12693
12694 return TINYEXR_SUCCESS;
12695 }
12696
12697 void InitEXRImage(EXRImage *exr_image) {
12698 if (exr_image == NULL) {
12699 return;
12700 }
12701
12702 exr_image->width = 0;
12703 exr_image->height = 0;
12704 exr_image->num_channels = 0;
12705
12706 exr_image->images = NULL;
12707 exr_image->tiles = NULL;
12708
12709 exr_image->num_tiles = 0;
12710 }
12711
12712 void FreeEXRErrorMessage(const char *msg) {
12713 if (msg) {
12714 free(reinterpret_cast<void *>(const_cast<char *>(msg)));
12715 }
12716 return;
12717 }
12718
12719 void InitEXRHeader(EXRHeader *exr_header) {
12720 if (exr_header == NULL) {
12721 return;
12722 }
12723
12724 memset(exr_header, 0, sizeof(EXRHeader));
12725 }
12726
12727 int FreeEXRHeader(EXRHeader *exr_header) {
12728 if (exr_header == NULL) {
12729 return TINYEXR_ERROR_INVALID_ARGUMENT;
12730 }
12731
12732 if (exr_header->channels) {
12733 free(exr_header->channels);
12734 }
12735
12736 if (exr_header->pixel_types) {
12737 free(exr_header->pixel_types);
12738 }
12739
12740 if (exr_header->requested_pixel_types) {
12741 free(exr_header->requested_pixel_types);
12742 }
12743
12744 for (int i = 0; i < exr_header->num_custom_attributes; i++) {
12745 if (exr_header->custom_attributes[i].value) {
12746 free(exr_header->custom_attributes[i].value);
12747 }
12748 }
12749
12750 if (exr_header->custom_attributes) {
12751 free(exr_header->custom_attributes);
12752 }
12753
12754 return TINYEXR_SUCCESS;
12755 }
12756
12757 int FreeEXRImage(EXRImage *exr_image) {
12758 if (exr_image == NULL) {
12759 return TINYEXR_ERROR_INVALID_ARGUMENT;
12760 }
12761
12762 for (int i = 0; i < exr_image->num_channels; i++) {
12763 if (exr_image->images && exr_image->images[i]) {
12764 free(exr_image->images[i]);
12765 }
12766 }
12767
12768 if (exr_image->images) {
12769 free(exr_image->images);
12770 }
12771
12772 if (exr_image->tiles) {
12773 for (int tid = 0; tid < exr_image->num_tiles; tid++) {
12774 for (int i = 0; i < exr_image->num_channels; i++) {
12775 if (exr_image->tiles[tid].images && exr_image->tiles[tid].images[i]) {
12776 free(exr_image->tiles[tid].images[i]);
12777 }
12778 }
12779 if (exr_image->tiles[tid].images) {
12780 free(exr_image->tiles[tid].images);
12781 }
12782 }
12783 free(exr_image->tiles);
12784 }
12785
12786 return TINYEXR_SUCCESS;
12787 }
12788
12789 int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
12790 const char *filename, const char **err) {
12791 if (exr_header == NULL || exr_version == NULL || filename == NULL) {
12792 tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile",
12793 err);
12794 return TINYEXR_ERROR_INVALID_ARGUMENT;
12795 }
12796
12797 #ifdef _WIN32
12798 FILE *fp = NULL;
12799 fopen_s(&fp, filename, "rb");
12800 #else
12801 FILE *fp = fopen(filename, "rb");
12802 #endif
12803 if (!fp) {
12804 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
12805 return TINYEXR_ERROR_CANT_OPEN_FILE;
12806 }
12807
12808 size_t filesize;
12809 // Compute size
12810 fseek(fp, 0, SEEK_END);
12811 filesize = static_cast<size_t>(ftell(fp));
12812 fseek(fp, 0, SEEK_SET);
12813
12814 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
12815 {
12816 size_t ret;
12817 ret = fread(&buf[0], 1, filesize, fp);
12818 assert(ret == filesize);
12819 fclose(fp);
12820
12821 if (ret != filesize) {
12822 tinyexr::SetErrorMessage("fread() error on " + std::string(filename),
12823 err);
12824 return TINYEXR_ERROR_INVALID_FILE;
12825 }
12826 }
12827
12828 return ParseEXRHeaderFromMemory(exr_header, exr_version, &buf.at(0), filesize,
12829 err);
12830 }
12831
12832 int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
12833 int *num_headers,
12834 const EXRVersion *exr_version,
12835 const unsigned char *memory, size_t size,
12836 const char **err) {
12837 if (memory == NULL || exr_headers == NULL || num_headers == NULL ||
12838 exr_version == NULL) {
12839 // Invalid argument
12840 tinyexr::SetErrorMessage(
12841 "Invalid argument for ParseEXRMultipartHeaderFromMemory", err);
12842 return TINYEXR_ERROR_INVALID_ARGUMENT;
12843 }
12844
12845 if (size < tinyexr::kEXRVersionSize) {
12846 tinyexr::SetErrorMessage("Data size too short", err);
12847 return TINYEXR_ERROR_INVALID_DATA;
12848 }
12849
12850 const unsigned char *marker = memory + tinyexr::kEXRVersionSize;
12851 size_t marker_size = size - tinyexr::kEXRVersionSize;
12852
12853 std::vector<tinyexr::HeaderInfo> infos;
12854
12855 for (;;) {
12856 tinyexr::HeaderInfo info;
12857 info.clear();
12858
12859 std::string err_str;
12860 bool empty_header = false;
12861 int ret = ParseEXRHeader(&info, &empty_header, exr_version, &err_str,
12862 marker, marker_size);
12863
12864 if (ret != TINYEXR_SUCCESS) {
12865 tinyexr::SetErrorMessage(err_str, err);
12866 return ret;
12867 }
12868
12869 if (empty_header) {
12870 marker += 1; // skip '\0'
12871 break;
12872 }
12873
12874 // `chunkCount` must exist in the header.
12875 if (info.chunk_count == 0) {
12876 tinyexr::SetErrorMessage(
12877 "`chunkCount' attribute is not found in the header.", err);
12878 return TINYEXR_ERROR_INVALID_DATA;
12879 }
12880
12881 infos.push_back(info);
12882
12883 // move to next header.
12884 marker += info.header_len;
12885 size -= info.header_len;
12886 }
12887
12888 // allocate memory for EXRHeader and create array of EXRHeader pointers.
12889 (*exr_headers) =
12890 static_cast<EXRHeader **>(malloc(sizeof(EXRHeader *) * infos.size()));
12891 for (size_t i = 0; i < infos.size(); i++) {
12892 EXRHeader *exr_header = static_cast<EXRHeader *>(malloc(sizeof(EXRHeader)));
12893
12894 ConvertHeader(exr_header, infos[i]);
12895
12896 // transfoer `tiled` from version.
12897 exr_header->tiled = exr_version->tiled;
12898
12899 (*exr_headers)[i] = exr_header;
12900 }
12901
12902 (*num_headers) = static_cast<int>(infos.size());
12903
12904 return TINYEXR_SUCCESS;
12905 }
12906
12907 int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
12908 const EXRVersion *exr_version,
12909 const char *filename, const char **err) {
12910 if (exr_headers == NULL || num_headers == NULL || exr_version == NULL ||
12911 filename == NULL) {
12912 tinyexr::SetErrorMessage(
12913 "Invalid argument for ParseEXRMultipartHeaderFromFile()", err);
12914 return TINYEXR_ERROR_INVALID_ARGUMENT;
12915 }
12916
12917 #ifdef _WIN32
12918 FILE *fp = NULL;
12919 fopen_s(&fp, filename, "rb");
12920 #else
12921 FILE *fp = fopen(filename, "rb");
12922 #endif
12923 if (!fp) {
12924 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
12925 return TINYEXR_ERROR_CANT_OPEN_FILE;
12926 }
12927
12928 size_t filesize;
12929 // Compute size
12930 fseek(fp, 0, SEEK_END);
12931 filesize = static_cast<size_t>(ftell(fp));
12932 fseek(fp, 0, SEEK_SET);
12933
12934 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
12935 {
12936 size_t ret;
12937 ret = fread(&buf[0], 1, filesize, fp);
12938 assert(ret == filesize);
12939 fclose(fp);
12940
12941 if (ret != filesize) {
12942 tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err);
12943 return TINYEXR_ERROR_INVALID_FILE;
12944 }
12945 }
12946
12947 return ParseEXRMultipartHeaderFromMemory(
12948 exr_headers, num_headers, exr_version, &buf.at(0), filesize, err);
12949 }
12950
12951 int ParseEXRVersionFromMemory(EXRVersion *version, const unsigned char *memory,
12952 size_t size) {
12953 if (version == NULL || memory == NULL) {
12954 return TINYEXR_ERROR_INVALID_ARGUMENT;
12955 }
12956
12957 if (size < tinyexr::kEXRVersionSize) {
12958 return TINYEXR_ERROR_INVALID_DATA;
12959 }
12960
12961 const unsigned char *marker = memory;
12962
12963 // Header check.
12964 {
12965 const char header[] = {0x76, 0x2f, 0x31, 0x01};
12966
12967 if (memcmp(marker, header, 4) != 0) {
12968 return TINYEXR_ERROR_INVALID_MAGIC_NUMBER;
12969 }
12970 marker += 4;
12971 }
12972
12973 version->tiled = false;
12974 version->long_name = false;
12975 version->non_image = false;
12976 version->multipart = false;
12977
12978 // Parse version header.
12979 {
12980 // must be 2
12981 if (marker[0] != 2) {
12982 return TINYEXR_ERROR_INVALID_EXR_VERSION;
12983 }
12984
12985 if (version == NULL) {
12986 return TINYEXR_SUCCESS; // May OK
12987 }
12988
12989 version->version = 2;
12990
12991 if (marker[1] & 0x2) { // 9th bit
12992 version->tiled = true;
12993 }
12994 if (marker[1] & 0x4) { // 10th bit
12995 version->long_name = true;
12996 }
12997 if (marker[1] & 0x8) { // 11th bit
12998 version->non_image = true; // (deep image)
12999 }
13000 if (marker[1] & 0x10) { // 12th bit
13001 version->multipart = true;
13002 }
13003 }
13004
13005 return TINYEXR_SUCCESS;
13006 }
13007
13008 int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) {
13009 if (filename == NULL) {
13010 return TINYEXR_ERROR_INVALID_ARGUMENT;
13011 }
13012
13013 #ifdef _WIN32
13014 FILE *fp = NULL;
13015 fopen_s(&fp, filename, "rb");
13016 #else
13017 FILE *fp = fopen(filename, "rb");
13018 #endif
13019 if (!fp) {
13020 return TINYEXR_ERROR_CANT_OPEN_FILE;
13021 }
13022
13023 size_t file_size;
13024 // Compute size
13025 fseek(fp, 0, SEEK_END);
13026 file_size = static_cast<size_t>(ftell(fp));
13027 fseek(fp, 0, SEEK_SET);
13028
13029 if (file_size < tinyexr::kEXRVersionSize) {
13030 return TINYEXR_ERROR_INVALID_FILE;
13031 }
13032
13033 unsigned char buf[tinyexr::kEXRVersionSize];
13034 size_t ret = fread(&buf[0], 1, tinyexr::kEXRVersionSize, fp);
13035 fclose(fp);
13036
13037 if (ret != tinyexr::kEXRVersionSize) {
13038 return TINYEXR_ERROR_INVALID_FILE;
13039 }
13040
13041 return ParseEXRVersionFromMemory(version, buf, tinyexr::kEXRVersionSize);
13042 }
13043
13044 int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
13045 const EXRHeader **exr_headers,
13046 unsigned int num_parts,
13047 const unsigned char *memory,
13048 const size_t size, const char **err) {
13049 if (exr_images == NULL || exr_headers == NULL || num_parts == 0 ||
13050 memory == NULL || (size <= tinyexr::kEXRVersionSize)) {
13051 tinyexr::SetErrorMessage(
13052 "Invalid argument for LoadEXRMultipartImageFromMemory()", err);
13053 return TINYEXR_ERROR_INVALID_ARGUMENT;
13054 }
13055
13056 // compute total header size.
13057 size_t total_header_size = 0;
13058 for (unsigned int i = 0; i < num_parts; i++) {
13059 if (exr_headers[i]->header_len == 0) {
13060 tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
13061 return TINYEXR_ERROR_INVALID_ARGUMENT;
13062 }
13063
13064 total_header_size += exr_headers[i]->header_len;
13065 }
13066
13067 const char *marker = reinterpret_cast<const char *>(
13068 memory + total_header_size + 4 +
13069 4); // +8 for magic number and version header.
13070
13071 marker += 1; // Skip empty header.
13072
13073 // NOTE 1:
13074 // In multipart image, There is 'part number' before chunk data.
13075 // 4 byte : part number
13076 // 4+ : chunk
13077 //
13078 // NOTE 2:
13079 // EXR spec says 'part number' is 'unsigned long' but actually this is
13080 // 'unsigned int(4 bytes)' in OpenEXR implementation...
13081 // http://www.openexr.com/openexrfilelayout.pdf
13082
13083 // Load chunk offset table.
13084 std::vector<std::vector<tinyexr::tinyexr_uint64> > chunk_offset_table_list;
13085 for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
13086 std::vector<tinyexr::tinyexr_uint64> offset_table(
13087 static_cast<size_t>(exr_headers[i]->chunk_count));
13088
13089 for (size_t c = 0; c < offset_table.size(); c++) {
13090 tinyexr::tinyexr_uint64 offset;
13091 memcpy(&offset, marker, 8);
13092 tinyexr::swap8(&offset);
13093
13094 if (offset >= size) {
13095 tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.",
13096 err);
13097 return TINYEXR_ERROR_INVALID_DATA;
13098 }
13099
13100 offset_table[c] = offset + 4; // +4 to skip 'part number'
13101 marker += 8;
13102 }
13103
13104 chunk_offset_table_list.push_back(offset_table);
13105 }
13106
13107 // Decode image.
13108 for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
13109 std::vector<tinyexr::tinyexr_uint64> &offset_table =
13110 chunk_offset_table_list[i];
13111
13112 // First check 'part number' is identitical to 'i'
13113 for (size_t c = 0; c < offset_table.size(); c++) {
13114 const unsigned char *part_number_addr =
13115 memory + offset_table[c] - 4; // -4 to move to 'part number' field.
13116 unsigned int part_no;
13117 memcpy(&part_no, part_number_addr, sizeof(unsigned int)); // 4
13118 tinyexr::swap4(&part_no);
13119
13120 if (part_no != i) {
13121 tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.",
13122 err);
13123 return TINYEXR_ERROR_INVALID_DATA;
13124 }
13125 }
13126
13127 std::string e;
13128 int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
13129 memory, size, &e);
13130 if (ret != TINYEXR_SUCCESS) {
13131 if (!e.empty()) {
13132 tinyexr::SetErrorMessage(e, err);
13133 }
13134 return ret;
13135 }
13136 }
13137
13138 return TINYEXR_SUCCESS;
13139 }
13140
13141 int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
13142 const EXRHeader **exr_headers,
13143 unsigned int num_parts, const char *filename,
13144 const char **err) {
13145 if (exr_images == NULL || exr_headers == NULL || num_parts == 0) {
13146 tinyexr::SetErrorMessage(
13147 "Invalid argument for LoadEXRMultipartImageFromFile", err);
13148 return TINYEXR_ERROR_INVALID_ARGUMENT;
13149 }
13150
13151 #ifdef _WIN32
13152 FILE *fp = NULL;
13153 fopen_s(&fp, filename, "rb");
13154 #else
13155 FILE *fp = fopen(filename, "rb");
13156 #endif
13157 if (!fp) {
13158 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
13159 return TINYEXR_ERROR_CANT_OPEN_FILE;
13160 }
13161
13162 size_t filesize;
13163 // Compute size
13164 fseek(fp, 0, SEEK_END);
13165 filesize = static_cast<size_t>(ftell(fp));
13166 fseek(fp, 0, SEEK_SET);
13167
13168 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
13169 {
13170 size_t ret;
13171 ret = fread(&buf[0], 1, filesize, fp);
13172 assert(ret == filesize);
13173 fclose(fp);
13174 (void)ret;
13175 }
13176
13177 return LoadEXRMultipartImageFromMemory(exr_images, exr_headers, num_parts,
13178 &buf.at(0), filesize, err);
13179 }
13180
13181 int SaveEXR(const float *data, int width, int height, int components,
13182 const int save_as_fp16, const char *outfilename, const char **err) {
13183 if ((components == 1) || components == 3 || components == 4) {
13184 // OK
13185 } else {
13186 std::stringstream ss;
13187 ss << "Unsupported component value : " << components << std::endl;
13188
13189 tinyexr::SetErrorMessage(ss.str(), err);
13190 return TINYEXR_ERROR_INVALID_ARGUMENT;
13191 }
13192
13193 EXRHeader header;
13194 InitEXRHeader(&header);
13195
13196 if ((width < 16) && (height < 16)) {
13197 // No compression for small image.
13198 header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE;
13199 } else {
13200 header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP;
13201 }
13202
13203 EXRImage image;
13204 InitEXRImage(&image);
13205
13206 image.num_channels = components;
13207
13208 std::vector<float> images[4];
13209
13210 if (components == 1) {
13211 images[0].resize(static_cast<size_t>(width * height));
13212 memcpy(images[0].data(), data, sizeof(float) * size_t(width * height));
13213 } else {
13214 images[0].resize(static_cast<size_t>(width * height));
13215 images[1].resize(static_cast<size_t>(width * height));
13216 images[2].resize(static_cast<size_t>(width * height));
13217 images[3].resize(static_cast<size_t>(width * height));
13218
13219 // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers
13220 for (size_t i = 0; i < static_cast<size_t>(width * height); i++) {
13221 images[0][i] = data[static_cast<size_t>(components) * i + 0];
13222 images[1][i] = data[static_cast<size_t>(components) * i + 1];
13223 images[2][i] = data[static_cast<size_t>(components) * i + 2];
13224 if (components == 4) {
13225 images[3][i] = data[static_cast<size_t>(components) * i + 3];
13226 }
13227 }
13228 }
13229
13230 float *image_ptr[4] = {0, 0, 0, 0};
13231 if (components == 4) {
13232 image_ptr[0] = &(images[3].at(0)); // A
13233 image_ptr[1] = &(images[2].at(0)); // B
13234 image_ptr[2] = &(images[1].at(0)); // G
13235 image_ptr[3] = &(images[0].at(0)); // R
13236 } else if (components == 3) {
13237 image_ptr[0] = &(images[2].at(0)); // B
13238 image_ptr[1] = &(images[1].at(0)); // G
13239 image_ptr[2] = &(images[0].at(0)); // R
13240 } else if (components == 1) {
13241 image_ptr[0] = &(images[0].at(0)); // A
13242 }
13243
13244 image.images = reinterpret_cast<unsigned char **>(image_ptr);
13245 image.width = width;
13246 image.height = height;
13247
13248 header.num_channels = components;
13249 header.channels = static_cast<EXRChannelInfo *>(malloc(
13250 sizeof(EXRChannelInfo) * static_cast<size_t>(header.num_channels)));
13251 // Must be (A)BGR order, since most of EXR viewers expect this channel order.
13252 if (components == 4) {
13253 #ifdef _MSC_VER
13254 strncpy_s(header.channels[0].name, "A", 255);
13255 strncpy_s(header.channels[1].name, "B", 255);
13256 strncpy_s(header.channels[2].name, "G", 255);
13257 strncpy_s(header.channels[3].name, "R", 255);
13258 #else
13259 strncpy(header.channels[0].name, "A", 255);
13260 strncpy(header.channels[1].name, "B", 255);
13261 strncpy(header.channels[2].name, "G", 255);
13262 strncpy(header.channels[3].name, "R", 255);
13263 #endif
13264 header.channels[0].name[strlen("A")] = '\0';
13265 header.channels[1].name[strlen("B")] = '\0';
13266 header.channels[2].name[strlen("G")] = '\0';
13267 header.channels[3].name[strlen("R")] = '\0';
13268 } else if (components == 3) {
13269 #ifdef _MSC_VER
13270 strncpy_s(header.channels[0].name, "B", 255);
13271 strncpy_s(header.channels[1].name, "G", 255);
13272 strncpy_s(header.channels[2].name, "R", 255);
13273 #else
13274 strncpy(header.channels[0].name, "B", 255);
13275 strncpy(header.channels[1].name, "G", 255);
13276 strncpy(header.channels[2].name, "R", 255);
13277 #endif
13278 header.channels[0].name[strlen("B")] = '\0';
13279 header.channels[1].name[strlen("G")] = '\0';
13280 header.channels[2].name[strlen("R")] = '\0';
13281 } else {
13282 #ifdef _MSC_VER
13283 strncpy_s(header.channels[0].name, "A", 255);
13284 #else
13285 strncpy(header.channels[0].name, "A", 255);
13286 #endif
13287 header.channels[0].name[strlen("A")] = '\0';
13288 }
13289
13290 header.pixel_types = static_cast<int *>(
13291 malloc(sizeof(int) * static_cast<size_t>(header.num_channels)));
13292 header.requested_pixel_types = static_cast<int *>(
13293 malloc(sizeof(int) * static_cast<size_t>(header.num_channels)));
13294 for (int i = 0; i < header.num_channels; i++) {
13295 header.pixel_types[i] =
13296 TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
13297
13298 if (save_as_fp16 > 0) {
13299 header.requested_pixel_types[i] =
13300 TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format
13301 } else {
13302 header.requested_pixel_types[i] =
13303 TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e.
13304 // no precision reduction)
13305 }
13306 }
13307
13308 int ret = SaveEXRImageToFile(&image, &header, outfilename, err);
13309 if (ret != TINYEXR_SUCCESS) {
13310 return ret;
13311 }
13312
13313 free(header.channels);
13314 free(header.pixel_types);
13315 free(header.requested_pixel_types);
13316
13317 return ret;
13318 }
13319
13320 #ifdef __clang__
13321 // zero-as-null-ppinter-constant
13322 #pragma clang diagnostic pop
13323 #endif
13324
13325 #endif // TINYEXR_IMPLEMENTATION_DEIFNED
13326 #endif // TINYEXR_IMPLEMENTATION
13327