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 #ifndef TINYEXR_USE_THREAD
109 #define TINYEXR_USE_THREAD (0) // No threaded loading.
110 // http://computation.llnl.gov/projects/floating-point-compression
111 #endif
112
113 #ifndef TINYEXR_USE_OPENMP
114 #ifdef _OPENMP
115 #define TINYEXR_USE_OPENMP (1)
116 #else
117 #define TINYEXR_USE_OPENMP (0)
118 #endif
119 #endif
120
121 #define TINYEXR_SUCCESS (0)
122 #define TINYEXR_ERROR_INVALID_MAGIC_NUMBER (-1)
123 #define TINYEXR_ERROR_INVALID_EXR_VERSION (-2)
124 #define TINYEXR_ERROR_INVALID_ARGUMENT (-3)
125 #define TINYEXR_ERROR_INVALID_DATA (-4)
126 #define TINYEXR_ERROR_INVALID_FILE (-5)
127 #define TINYEXR_ERROR_INVALID_PARAMETER (-6)
128 #define TINYEXR_ERROR_CANT_OPEN_FILE (-7)
129 #define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-8)
130 #define TINYEXR_ERROR_INVALID_HEADER (-9)
131 #define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-10)
132 #define TINYEXR_ERROR_CANT_WRITE_FILE (-11)
133 #define TINYEXR_ERROR_SERIALZATION_FAILED (-12)
134 #define TINYEXR_ERROR_LAYER_NOT_FOUND (-13)
135
136 // @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf }
137
138 // pixel type: possible values are: UINT = 0 HALF = 1 FLOAT = 2
139 #define TINYEXR_PIXELTYPE_UINT (0)
140 #define TINYEXR_PIXELTYPE_HALF (1)
141 #define TINYEXR_PIXELTYPE_FLOAT (2)
142
143 #define TINYEXR_MAX_HEADER_ATTRIBUTES (1024)
144 #define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128)
145
146 #define TINYEXR_COMPRESSIONTYPE_NONE (0)
147 #define TINYEXR_COMPRESSIONTYPE_RLE (1)
148 #define TINYEXR_COMPRESSIONTYPE_ZIPS (2)
149 #define TINYEXR_COMPRESSIONTYPE_ZIP (3)
150 #define TINYEXR_COMPRESSIONTYPE_PIZ (4)
151 #define TINYEXR_COMPRESSIONTYPE_ZFP (128) // TinyEXR extension
152
153 #define TINYEXR_ZFP_COMPRESSIONTYPE_RATE (0)
154 #define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION (1)
155 #define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY (2)
156
157 #define TINYEXR_TILE_ONE_LEVEL (0)
158 #define TINYEXR_TILE_MIPMAP_LEVELS (1)
159 #define TINYEXR_TILE_RIPMAP_LEVELS (2)
160
161 #define TINYEXR_TILE_ROUND_DOWN (0)
162 #define TINYEXR_TILE_ROUND_UP (1)
163
164 typedef struct _EXRVersion {
165 int version; // this must be 2
166 int tiled; // tile format image
167 int long_name; // long name attribute
168 int non_image; // deep image(EXR 2.0)
169 int multipart; // multi-part(EXR 2.0)
170 } EXRVersion;
171
172 typedef struct _EXRAttribute {
173 char name[256]; // name and type are up to 255 chars long.
174 char type[256];
175 unsigned char *value; // uint8_t*
176 int size;
177 int pad0;
178 } EXRAttribute;
179
180 typedef struct _EXRChannelInfo {
181 char name[256]; // less than 255 bytes long
182 int pixel_type;
183 int x_sampling;
184 int y_sampling;
185 unsigned char p_linear;
186 unsigned char pad[3];
187 } EXRChannelInfo;
188
189 typedef struct _EXRTile {
190 int offset_x;
191 int offset_y;
192 int level_x;
193 int level_y;
194
195 int width; // actual width in a tile.
196 int height; // actual height int a tile.
197
198 unsigned char **images; // image[channels][pixels]
199 } EXRTile;
200
201 typedef struct _EXRHeader {
202 float pixel_aspect_ratio;
203 int line_order;
204 int data_window[4];
205 int display_window[4];
206 float screen_window_center[2];
207 float screen_window_width;
208
209 int chunk_count;
210
211 // Properties for tiled format(`tiledesc`).
212 int tiled;
213 int tile_size_x;
214 int tile_size_y;
215 int tile_level_mode;
216 int tile_rounding_mode;
217
218 int long_name;
219 int non_image;
220 int multipart;
221 unsigned int header_len;
222
223 // Custom attributes(exludes required attributes(e.g. `channels`,
224 // `compression`, etc)
225 int num_custom_attributes;
226 EXRAttribute *custom_attributes; // array of EXRAttribute. size =
227 // `num_custom_attributes`.
228
229 EXRChannelInfo *channels; // [num_channels]
230
231 int *pixel_types; // Loaded pixel type(TINYEXR_PIXELTYPE_*) of `images` for
232 // each channel. This is overwritten with `requested_pixel_types` when
233 // loading.
234 int num_channels;
235
236 int compression_type; // compression type(TINYEXR_COMPRESSIONTYPE_*)
237 int *requested_pixel_types; // Filled initially by
238 // ParseEXRHeaderFrom(Meomory|File), then users
239 // can edit it(only valid for HALF pixel type
240 // channel)
241
242 } EXRHeader;
243
244 typedef struct _EXRMultiPartHeader {
245 int num_headers;
246 EXRHeader *headers;
247
248 } EXRMultiPartHeader;
249
250 typedef struct _EXRImage {
251 EXRTile *tiles; // Tiled pixel data. The application must reconstruct image
252 // from tiles manually. NULL if scanline format.
253 unsigned char **images; // image[channels][pixels]. NULL if tiled format.
254
255 int width;
256 int height;
257 int num_channels;
258
259 // Properties for tile format.
260 int num_tiles;
261
262 } EXRImage;
263
264 typedef struct _EXRMultiPartImage {
265 int num_images;
266 EXRImage *images;
267
268 } EXRMultiPartImage;
269
270 typedef struct _DeepImage {
271 const char **channel_names;
272 float ***image; // image[channels][scanlines][samples]
273 int **offset_table; // offset_table[scanline][offsets]
274 int num_channels;
275 int width;
276 int height;
277 int pad0;
278 } DeepImage;
279
280 // @deprecated { For backward compatibility. Not recommended to use. }
281 // Loads single-frame OpenEXR image. Assume EXR image contains A(single channel
282 // alpha) or RGB(A) channels.
283 // Application must free image data as returned by `out_rgba`
284 // Result image format is: float x RGBA x width x hight
285 // Returns negative value and may set error string in `err` when there's an
286 // error
287 extern int LoadEXR(float **out_rgba, int *width, int *height,
288 const char *filename, const char **err);
289
290 // Loads single-frame OpenEXR image by specifing layer name. Assume EXR image contains A(single channel
291 // alpha) or RGB(A) channels.
292 // Application must free image data as returned by `out_rgba`
293 // Result image format is: float x RGBA x width x hight
294 // Returns negative value and may set error string in `err` when there's an
295 // error
296 // When the specified layer name is not found in the EXR file, the function will return `TINYEXR_ERROR_LAYER_NOT_FOUND`.
297 extern int LoadEXRWithLayer(float **out_rgba, int *width, int *height,
298 const char *filename, const char *layer_name, const char **err);
299
300 //
301 // Get layer infos from EXR file.
302 //
303 // @param[out] layer_names List of layer names. Application must free memory after using this.
304 // @param[out] num_layers The number of layers
305 // @param[out] err Error string(wll be filled when the function returns error code). Free it using FreeEXRErrorMessage after using this value.
306 //
307 // @return TINYEXR_SUCCEES upon success.
308 //
309 extern int EXRLayers(const char *filename, const char **layer_names[], int *num_layers, const char **err);
310
311 // @deprecated { to be removed. }
312 // Simple wrapper API for ParseEXRHeaderFromFile.
313 // checking given file is a EXR file(by just look up header)
314 // @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for
315 // others
316 extern int IsEXR(const char *filename);
317
318 // @deprecated { to be removed. }
319 // Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels.
320 // components must be 1(Grayscale), 3(RGB) or 4(RGBA).
321 // Input image format is: `float x width x height`, or `float x RGB(A) x width x
322 // hight`
323 // Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero
324 // value.
325 // Save image as fp32(FLOAT) format when `save_as_fp16` is 0.
326 // Use ZIP compression by default.
327 // Returns negative value and may set error string in `err` when there's an
328 // error
329 extern int SaveEXR(const float *data, const int width, const int height,
330 const int components, const int save_as_fp16,
331 const char *filename, const char **err);
332
333 // Initialize EXRHeader struct
334 extern void InitEXRHeader(EXRHeader *exr_header);
335
336 // Initialize EXRImage struct
337 extern void InitEXRImage(EXRImage *exr_image);
338
339 // Free's internal data of EXRHeader struct
340 extern int FreeEXRHeader(EXRHeader *exr_header);
341
342 // Free's internal data of EXRImage struct
343 extern int FreeEXRImage(EXRImage *exr_image);
344
345 // Free's error message
346 extern void FreeEXRErrorMessage(const char *msg);
347
348 // Parse EXR version header of a file.
349 extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename);
350
351 // Parse EXR version header from memory-mapped EXR data.
352 extern int ParseEXRVersionFromMemory(EXRVersion *version,
353 const unsigned char *memory, size_t size);
354
355 // Parse single-part OpenEXR header from a file and initialize `EXRHeader`.
356 // When there was an error message, Application must free `err` with
357 // FreeEXRErrorMessage()
358 extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version,
359 const char *filename, const char **err);
360
361 // Parse single-part OpenEXR header from a memory and initialize `EXRHeader`.
362 // When there was an error message, Application must free `err` with
363 // FreeEXRErrorMessage()
364 extern int ParseEXRHeaderFromMemory(EXRHeader *header,
365 const EXRVersion *version,
366 const unsigned char *memory, size_t size,
367 const char **err);
368
369 // Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*`
370 // array.
371 // When there was an error message, Application must free `err` with
372 // FreeEXRErrorMessage()
373 extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
374 int *num_headers,
375 const EXRVersion *version,
376 const char *filename,
377 const char **err);
378
379 // Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*`
380 // array
381 // When there was an error message, Application must free `err` with
382 // FreeEXRErrorMessage()
383 extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
384 int *num_headers,
385 const EXRVersion *version,
386 const unsigned char *memory,
387 size_t size, const char **err);
388
389 // Loads single-part OpenEXR image from a file.
390 // Application must setup `ParseEXRHeaderFromFile` before calling this function.
391 // Application can free EXRImage using `FreeEXRImage`
392 // Returns negative value and may set error string in `err` when there's an
393 // error
394 // When there was an error message, Application must free `err` with
395 // FreeEXRErrorMessage()
396 extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
397 const char *filename, const char **err);
398
399 // Loads single-part OpenEXR image from a memory.
400 // Application must setup `EXRHeader` with
401 // `ParseEXRHeaderFromMemory` before calling this function.
402 // Application can free EXRImage using `FreeEXRImage`
403 // Returns negative value and may set error string in `err` when there's an
404 // error
405 // When there was an error message, Application must free `err` with
406 // FreeEXRErrorMessage()
407 extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
408 const unsigned char *memory,
409 const size_t size, const char **err);
410
411 // Loads multi-part OpenEXR image from a file.
412 // Application must setup `ParseEXRMultipartHeaderFromFile` before calling this
413 // function.
414 // Application can free EXRImage using `FreeEXRImage`
415 // Returns negative value and may set error string in `err` when there's an
416 // error
417 // When there was an error message, Application must free `err` with
418 // FreeEXRErrorMessage()
419 extern int LoadEXRMultipartImageFromFile(EXRImage *images,
420 const EXRHeader **headers,
421 unsigned int num_parts,
422 const char *filename,
423 const char **err);
424
425 // Loads multi-part OpenEXR image from a memory.
426 // Application must setup `EXRHeader*` array with
427 // `ParseEXRMultipartHeaderFromMemory` before calling this function.
428 // Application can free EXRImage using `FreeEXRImage`
429 // Returns negative value and may set error string in `err` when there's an
430 // error
431 // When there was an error message, Application must free `err` with
432 // FreeEXRErrorMessage()
433 extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
434 const EXRHeader **headers,
435 unsigned int num_parts,
436 const unsigned char *memory,
437 const size_t size, const char **err);
438
439 // Saves multi-channel, single-frame OpenEXR image to a file.
440 // Returns negative value and may set error string in `err` when there's an
441 // error
442 // When there was an error message, Application must free `err` with
443 // FreeEXRErrorMessage()
444 extern int SaveEXRImageToFile(const EXRImage *image,
445 const EXRHeader *exr_header, const char *filename,
446 const char **err);
447
448 // Saves multi-channel, single-frame OpenEXR image to a memory.
449 // Image is compressed using EXRImage.compression value.
450 // Return the number of bytes if success.
451 // Return zero and will set error string in `err` when there's an
452 // error.
453 // When there was an error message, Application must free `err` with
454 // FreeEXRErrorMessage()
455 extern size_t SaveEXRImageToMemory(const EXRImage *image,
456 const EXRHeader *exr_header,
457 unsigned char **memory, const char **err);
458
459 // Loads single-frame OpenEXR deep image.
460 // Application must free memory of variables in DeepImage(image, offset_table)
461 // Returns negative value and may set error string in `err` when there's an
462 // error
463 // When there was an error message, Application must free `err` with
464 // FreeEXRErrorMessage()
465 extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
466 const char **err);
467
468 // NOT YET IMPLEMENTED:
469 // Saves single-frame OpenEXR deep image.
470 // Returns negative value and may set error string in `err` when there's an
471 // error
472 // extern int SaveDeepEXR(const DeepImage *in_image, const char *filename,
473 // const char **err);
474
475 // NOT YET IMPLEMENTED:
476 // Loads multi-part OpenEXR deep image.
477 // Application must free memory of variables in DeepImage(image, offset_table)
478 // extern int LoadMultiPartDeepEXR(DeepImage **out_image, int num_parts, const
479 // char *filename,
480 // const char **err);
481
482 // For emscripten.
483 // Loads single-frame OpenEXR image from memory. Assume EXR image contains
484 // RGB(A) channels.
485 // Returns negative value and may set error string in `err` when there's an
486 // error
487 // When there was an error message, Application must free `err` with
488 // FreeEXRErrorMessage()
489 extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
490 const unsigned char *memory, size_t size,
491 const char **err);
492
493 #ifdef __cplusplus
494 }
495 #endif
496
497 #endif // TINYEXR_H_
498
499 #ifdef TINYEXR_IMPLEMENTATION
500 #ifndef TINYEXR_IMPLEMENTATION_DEIFNED
501 #define TINYEXR_IMPLEMENTATION_DEIFNED
502
503 #include <algorithm>
504 #include <cstdio>
505 #include <cstdlib>
506 #include <cstring>
507 #include <sstream>
508
509 // #include <iostream> // debug
510
511 #include <limits>
512 #include <string>
513 #include <vector>
514
515 #if __cplusplus > 199711L
516 // C++11
517 #include <cstdint>
518
519 #if TINYEXR_USE_THREAD
520 #include <atomic>
521 #include <thread>
522 #endif
523
524 #endif // __cplusplus > 199711L
525
526 #if TINYEXR_USE_OPENMP
527 #include <omp.h>
528 #endif
529
530 #if TINYEXR_USE_MINIZ
531 #else
532 // Issue #46. Please include your own zlib-compatible API header before
533 // including `tinyexr.h`
534 //#include "zlib.h"
535 #endif
536
537 #if TINYEXR_USE_ZFP
538 #include "zfp.h"
539 #endif
540
541 namespace tinyexr {
542
543 #if __cplusplus > 199711L
544 // C++11
545 typedef uint64_t tinyexr_uint64;
546 typedef int64_t tinyexr_int64;
547 #else
548 // Although `long long` is not a standard type pre C++11, assume it is defined
549 // as a compiler's extension.
550 #ifdef __clang__
551 #pragma clang diagnostic push
552 #pragma clang diagnostic ignored "-Wc++11-long-long"
553 #endif
554 typedef unsigned long long tinyexr_uint64;
555 typedef long long tinyexr_int64;
556 #ifdef __clang__
557 #pragma clang diagnostic pop
558 #endif
559 #endif
560
561 #if TINYEXR_USE_MINIZ
562
563 namespace miniz {
564
565 #ifdef __clang__
566 #pragma clang diagnostic push
567 #pragma clang diagnostic ignored "-Wc++11-long-long"
568 #pragma clang diagnostic ignored "-Wold-style-cast"
569 #pragma clang diagnostic ignored "-Wpadded"
570 #pragma clang diagnostic ignored "-Wsign-conversion"
571 #pragma clang diagnostic ignored "-Wc++11-extensions"
572 #pragma clang diagnostic ignored "-Wconversion"
573 #pragma clang diagnostic ignored "-Wunused-function"
574 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
575 #pragma clang diagnostic ignored "-Wundef"
576
577 #if __has_warning("-Wcomma")
578 #pragma clang diagnostic ignored "-Wcomma"
579 #endif
580
581 #if __has_warning("-Wmacro-redefined")
582 #pragma clang diagnostic ignored "-Wmacro-redefined"
583 #endif
584
585 #if __has_warning("-Wcast-qual")
586 #pragma clang diagnostic ignored "-Wcast-qual"
587 #endif
588
589 #if __has_warning("-Wzero-as-null-pointer-constant")
590 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
591 #endif
592
593 #if __has_warning("-Wtautological-constant-compare")
594 #pragma clang diagnostic ignored "-Wtautological-constant-compare"
595 #endif
596
597 #if __has_warning("-Wextra-semi-stmt")
598 #pragma clang diagnostic ignored "-Wextra-semi-stmt"
599 #endif
600
601 #endif
602
603 /* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
604 reading/writing/appending, PNG writing
605 See "unlicense" statement at the end of this file.
606 Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013
607 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951:
608 http://www.ietf.org/rfc/rfc1951.txt
609
610 Most API's defined in miniz.c are optional. For example, to disable the
611 archive related functions just define
612 MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO
613 (see the list below for more macros).
614
615 * Change History
616 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major
617 release with Zip64 support (almost there!):
618 - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug
619 (thanks kahmyong.moon@hp.com) which could cause locate files to not find
620 files. This bug
621 would only have occured in earlier versions if you explicitly used this
622 flag, OR if you used mz_zip_extract_archive_file_to_heap() or
623 mz_zip_add_mem_to_archive_file_in_place()
624 (which used this flag). If you can't switch to v1.15 but want to fix
625 this bug, just remove the uses of this flag from both helper funcs (and of
626 course don't use the flag).
627 - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when
628 pUser_read_buf is not NULL and compressed size is > uncompressed size
629 - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract
630 compressed data from directory entries, to account for weird zipfiles which
631 contain zero-size compressed data on dir entries.
632 Hopefully this fix won't cause any issues on weird zip archives,
633 because it assumes the low 16-bits of zip external attributes are DOS
634 attributes (which I believe they always are in practice).
635 - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the
636 internal attributes, just the filename and external attributes
637 - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed
638 - Added cmake support for Linux builds which builds all the examples,
639 tested with clang v3.3 and gcc v4.6.
640 - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti
641 - Merged MZ_FORCEINLINE fix from hdeanclark
642 - Fix <time.h> include before config #ifdef, thanks emil.brink
643 - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping
644 (super useful for OpenGL apps), and explicit control over the compression
645 level (so you can
646 set it to 1 for real-time compression).
647 - Merged in some compiler fixes from paulharris's github repro.
648 - Retested this build under Windows (VS 2010, including static analysis),
649 tcc 0.9.26, gcc v4.6 and clang v3.3.
650 - Added example6.c, which dumps an image of the mandelbrot set to a PNG
651 file.
652 - Modified example2 to help test the
653 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more.
654 - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix
655 possible src file fclose() leak if alignment bytes+local header file write
656 faiiled
657 - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader():
658 Was pushing the wrong central dir header offset, appears harmless in this
659 release, but it became a problem in the zip64 branch
660 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE,
661 #include <time.h> (thanks fermtect).
662 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix
663 mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit.
664 - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and
665 re-ran a randomized regression test on ~500k files.
666 - Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
667 - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze
668 (static analysis) option and fixed all warnings (except for the silly
669 "Use of the comma-operator in a tested expression.." analysis warning,
670 which I purposely use to work around a MSVC compiler warning).
671 - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and
672 tested Linux executables. The codeblocks workspace is compatible with
673 Linux+Win32/x64.
674 - Added miniz_tester solution/project, which is a useful little app
675 derived from LZHAM's tester app that I use as part of the regression test.
676 - Ran miniz.c and tinfl.c through another series of regression testing on
677 ~500,000 files and archives.
678 - Modified example5.c so it purposely disables a bunch of high-level
679 functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the
680 MINIZ_NO_STDIO bug report.)
681 - Fix ftell() usage in examples so they exit with an error on files which
682 are too large (a limitation of the examples, not miniz itself).
683 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple
684 minor level_and_flags issues in the archive API's.
685 level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce
686 Dawson <bruced@valvesoftware.com> for the feedback/bug report.
687 5/28/11 v1.11 - Added statement from unlicense.org
688 5/27/11 v1.10 - Substantial compressor optimizations:
689 - Level 1 is now ~4x faster than before. The L1 compressor's throughput
690 now varies between 70-110MB/sec. on a
691 - Core i7 (actual throughput varies depending on the type of data, and x64
692 vs. x86).
693 - Improved baseline L2-L9 compression perf. Also, greatly improved
694 compression perf. issues on some file types.
695 - Refactored the compression code for better readability and
696 maintainability.
697 - Added level 10 compression level (L10 has slightly better ratio than
698 level 9, but could have a potentially large
699 drop in throughput on some files).
700 5/15/11 v1.09 - Initial stable release.
701
702 * Low-level Deflate/Inflate implementation notes:
703
704 Compression: Use the "tdefl" API's. The compressor supports raw, static,
705 and dynamic blocks, lazy or
706 greedy parsing, match length filtering, RLE-only, and Huffman-only streams.
707 It performs and compresses
708 approximately as well as zlib.
709
710 Decompression: Use the "tinfl" API's. The entire decompressor is
711 implemented as a single function
712 coroutine: see tinfl_decompress(). It supports decompression into a 32KB
713 (or larger power of 2) wrapping buffer, or into a memory
714 block large enough to hold the entire file.
715
716 The low-level tdefl/tinfl API's do not make any use of dynamic memory
717 allocation.
718
719 * zlib-style API notes:
720
721 miniz.c implements a fairly large subset of zlib. There's enough
722 functionality present for it to be a drop-in
723 zlib replacement in many apps:
724 The z_stream struct, optional memory allocation callbacks
725 deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
726 inflateInit/inflateInit2/inflate/inflateEnd
727 compress, compress2, compressBound, uncompress
728 CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly
729 routines.
730 Supports raw deflate streams or standard zlib streams with adler-32
731 checking.
732
733 Limitations:
734 The callback API's are not implemented yet. No support for gzip headers or
735 zlib static dictionaries.
736 I've tried to closely emulate zlib's various flavors of stream flushing
737 and return status codes, but
738 there are no guarantees that miniz.c pulls this off perfectly.
739
740 * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function,
741 originally written by
742 Alex Evans. Supports 1-4 bytes/pixel images.
743
744 * ZIP archive API notes:
745
746 The ZIP archive API's where designed with simplicity and efficiency in
747 mind, with just enough abstraction to
748 get the job done with minimal fuss. There are simple API's to retrieve file
749 information, read files from
750 existing archives, create new archives, append new files to existing
751 archives, or clone archive data from
752 one archive to another. It supports archives located in memory or the heap,
753 on disk (using stdio.h),
754 or you can specify custom file read/write callbacks.
755
756 - Archive reading: Just call this function to read a single file from a
757 disk archive:
758
759 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const
760 char *pArchive_name,
761 size_t *pSize, mz_uint zip_flags);
762
763 For more complex cases, use the "mz_zip_reader" functions. Upon opening an
764 archive, the entire central
765 directory is located and read as-is into memory, and subsequent file access
766 only occurs when reading individual files.
767
768 - Archives file scanning: The simple way is to use this function to scan a
769 loaded archive for a specific file:
770
771 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
772 const char *pComment, mz_uint flags);
773
774 The locate operation can optionally check file comments too, which (as one
775 example) can be used to identify
776 multiple versions of the same file in an archive. This function uses a
777 simple linear search through the central
778 directory, so it's not very fast.
779
780 Alternately, you can iterate through all the files in an archive (using
781 mz_zip_reader_get_num_files()) and
782 retrieve detailed info on each file by calling mz_zip_reader_file_stat().
783
784 - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer
785 immediately writes compressed file data
786 to disk and builds an exact image of the central directory in memory. The
787 central directory image is written
788 all at once at the end of the archive file when the archive is finalized.
789
790 The archive writer can optionally align each file's local header and file
791 data to any power of 2 alignment,
792 which can be useful when the archive will be read from optical media. Also,
793 the writer supports placing
794 arbitrary data blobs at the very beginning of ZIP archives. Archives
795 written using either feature are still
796 readable by any ZIP tool.
797
798 - Archive appending: The simple way to add a single file to an archive is
799 to call this function:
800
801 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename,
802 const char *pArchive_name,
803 const void *pBuf, size_t buf_size, const void *pComment, mz_uint16
804 comment_size, mz_uint level_and_flags);
805
806 The archive will be created if it doesn't already exist, otherwise it'll be
807 appended to.
808 Note the appending is done in-place and is not an atomic operation, so if
809 something goes wrong
810 during the operation it's possible the archive could be left without a
811 central directory (although the local
812 file headers and file data will be fine, so the archive will be
813 recoverable).
814
815 For more complex archive modification scenarios:
816 1. The safest way is to use a mz_zip_reader to read the existing archive,
817 cloning only those bits you want to
818 preserve into a new archive using using the
819 mz_zip_writer_add_from_zip_reader() function (which compiles the
820 compressed file data as-is). When you're done, delete the old archive and
821 rename the newly written archive, and
822 you're done. This is safe but requires a bunch of temporary disk space or
823 heap memory.
824
825 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using
826 mz_zip_writer_init_from_reader(),
827 append new files as needed, then finalize the archive which will write an
828 updated central directory to the
829 original archive. (This is basically what
830 mz_zip_add_mem_to_archive_file_in_place() does.) There's a
831 possibility that the archive's central directory could be lost with this
832 method if anything goes wrong, though.
833
834 - ZIP archive support limitations:
835 No zip64 or spanning support. Extraction functions can only handle
836 unencrypted, stored or deflated files.
837 Requires streams capable of seeking.
838
839 * This is a header file library, like stb_image.c. To get only a header file,
840 either cut and paste the
841 below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then
842 include miniz.c from it.
843
844 * Important: For best perf. be sure to customize the below macros for your
845 target platform:
846 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
847 #define MINIZ_LITTLE_ENDIAN 1
848 #define MINIZ_HAS_64BIT_REGISTERS 1
849
850 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before
851 including miniz.c to ensure miniz
852 uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be
853 able to process large files
854 (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).
855 */
856
857 #ifndef MINIZ_HEADER_INCLUDED
858 #define MINIZ_HEADER_INCLUDED
859
860 //#include <stdlib.h>
861
862 // Defines to completely disable specific portions of miniz.c:
863 // If all macros here are defined the only functionality remaining will be
864 // CRC-32, adler-32, tinfl, and tdefl.
865
866 // Define MINIZ_NO_STDIO to disable all usage and any functions which rely on
867 // stdio for file I/O.
868 //#define MINIZ_NO_STDIO
869
870 // If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able
871 // to get the current time, or
872 // get/set file times, and the C run-time funcs that get/set times won't be
873 // called.
874 // The current downside is the times written to your archives will be from 1979.
875 #define MINIZ_NO_TIME
876
877 // Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
878 #define MINIZ_NO_ARCHIVE_APIS
879
880 // Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive
881 // API's.
882 //#define MINIZ_NO_ARCHIVE_WRITING_APIS
883
884 // Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression
885 // API's.
886 //#define MINIZ_NO_ZLIB_APIS
887
888 // Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent
889 // conflicts against stock zlib.
890 //#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
891
892 // Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
893 // Note if MINIZ_NO_MALLOC is defined then the user must always provide custom
894 // user alloc/free/realloc
895 // callbacks to the zlib and archive API's, and a few stand-alone helper API's
896 // which don't provide custom user
897 // functions (such as tdefl_compress_mem_to_heap() and
898 // tinfl_decompress_mem_to_heap()) won't work.
899 //#define MINIZ_NO_MALLOC
900
901 #if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
902 // TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc
903 // on Linux
904 #define MINIZ_NO_TIME
905 #endif
906
907 #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
908 //#include <time.h>
909 #endif
910
911 #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
912 defined(__i386) || defined(__i486__) || defined(__i486) || \
913 defined(i386) || defined(__ia64__) || defined(__x86_64__)
914 // MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
915 #define MINIZ_X86_OR_X64_CPU 1
916 #endif
917
918 #if defined(__sparcv9)
919 // Big endian
920 #else
921 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
922 // Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
923 #define MINIZ_LITTLE_ENDIAN 1
924 #endif
925 #endif
926
927 #if MINIZ_X86_OR_X64_CPU
928 // Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
929 // integer loads and stores from unaligned addresses.
930 //#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
931 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES \
932 0 // disable to suppress compiler warnings
933 #endif
934
935 #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \
936 defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \
937 defined(__x86_64__)
938 // Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are
939 // reasonably fast (and don't involve compiler generated calls to helper
940 // functions).
941 #define MINIZ_HAS_64BIT_REGISTERS 1
942 #endif
943
944 #ifdef __cplusplus
945 extern "C" {
946 #endif
947
948 // ------------------- zlib-style API Definitions.
949
950 // For more compatibility with zlib, miniz.c uses unsigned long for some
951 // parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits!
952 typedef unsigned long mz_ulong;
953
954 // mz_free() internally uses the MZ_FREE() macro (which by default calls free()
955 // unless you've modified the MZ_MALLOC macro) to release a block allocated from
956 // the heap.
957 void mz_free(void *p);
958
959 #define MZ_ADLER32_INIT (1)
960 // mz_adler32() returns the initial adler-32 value to use when called with
961 // ptr==NULL.
962 mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
963
964 #define MZ_CRC32_INIT (0)
965 // mz_crc32() returns the initial CRC-32 value to use when called with
966 // ptr==NULL.
967 mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
968
969 // Compression strategies.
970 enum {
971 MZ_DEFAULT_STRATEGY = 0,
972 MZ_FILTERED = 1,
973 MZ_HUFFMAN_ONLY = 2,
974 MZ_RLE = 3,
975 MZ_FIXED = 4
976 };
977
978 // Method
979 #define MZ_DEFLATED 8
980
981 #ifndef MINIZ_NO_ZLIB_APIS
982
983 // Heap allocation callbacks.
984 // Note that mz_alloc_func parameter types purpsosely differ from zlib's:
985 // items/size is size_t, not unsigned long.
986 typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
987 typedef void (*mz_free_func)(void *opaque, void *address);
988 typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items,
989 size_t size);
990
991 #define MZ_VERSION "9.1.15"
992 #define MZ_VERNUM 0x91F0
993 #define MZ_VER_MAJOR 9
994 #define MZ_VER_MINOR 1
995 #define MZ_VER_REVISION 15
996 #define MZ_VER_SUBREVISION 0
997
998 // Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The
999 // other values are for advanced use (refer to the zlib docs).
1000 enum {
1001 MZ_NO_FLUSH = 0,
1002 MZ_PARTIAL_FLUSH = 1,
1003 MZ_SYNC_FLUSH = 2,
1004 MZ_FULL_FLUSH = 3,
1005 MZ_FINISH = 4,
1006 MZ_BLOCK = 5
1007 };
1008
1009 // Return status codes. MZ_PARAM_ERROR is non-standard.
1010 enum {
1011 MZ_OK = 0,
1012 MZ_STREAM_END = 1,
1013 MZ_NEED_DICT = 2,
1014 MZ_ERRNO = -1,
1015 MZ_STREAM_ERROR = -2,
1016 MZ_DATA_ERROR = -3,
1017 MZ_MEM_ERROR = -4,
1018 MZ_BUF_ERROR = -5,
1019 MZ_VERSION_ERROR = -6,
1020 MZ_PARAM_ERROR = -10000
1021 };
1022
1023 // Compression levels: 0-9 are the standard zlib-style levels, 10 is best
1024 // possible compression (not zlib compatible, and may be very slow),
1025 // MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
1026 enum {
1027 MZ_NO_COMPRESSION = 0,
1028 MZ_BEST_SPEED = 1,
1029 MZ_BEST_COMPRESSION = 9,
1030 MZ_UBER_COMPRESSION = 10,
1031 MZ_DEFAULT_LEVEL = 6,
1032 MZ_DEFAULT_COMPRESSION = -1
1033 };
1034
1035 // Window bits
1036 #define MZ_DEFAULT_WINDOW_BITS 15
1037
1038 struct mz_internal_state;
1039
1040 // Compression/decompression stream struct.
1041 typedef struct mz_stream_s {
1042 const unsigned char *next_in; // pointer to next byte to read
1043 unsigned int avail_in; // number of bytes available at next_in
1044 mz_ulong total_in; // total number of bytes consumed so far
1045
1046 unsigned char *next_out; // pointer to next byte to write
1047 unsigned int avail_out; // number of bytes that can be written to next_out
1048 mz_ulong total_out; // total number of bytes produced so far
1049
1050 char *msg; // error msg (unused)
1051 struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
1052
1053 mz_alloc_func
1054 zalloc; // optional heap allocation function (defaults to malloc)
1055 mz_free_func zfree; // optional heap free function (defaults to free)
1056 void *opaque; // heap alloc function user pointer
1057
1058 int data_type; // data_type (unused)
1059 mz_ulong adler; // adler32 of the source or uncompressed data
1060 mz_ulong reserved; // not used
1061 } mz_stream;
1062
1063 typedef mz_stream *mz_streamp;
1064
1065 // Returns the version string of miniz.c.
1066 const char *mz_version(void);
1067
1068 // mz_deflateInit() initializes a compressor with default options:
1069 // Parameters:
1070 // pStream must point to an initialized mz_stream struct.
1071 // level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
1072 // level 1 enables a specially optimized compression function that's been
1073 // optimized purely for performance, not ratio.
1074 // (This special func. is currently only enabled when
1075 // MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.)
1076 // Return values:
1077 // MZ_OK on success.
1078 // MZ_STREAM_ERROR if the stream is bogus.
1079 // MZ_PARAM_ERROR if the input parameters are bogus.
1080 // MZ_MEM_ERROR on out of memory.
1081 int mz_deflateInit(mz_streamp pStream, int level);
1082
1083 // mz_deflateInit2() is like mz_deflate(), except with more control:
1084 // Additional parameters:
1085 // method must be MZ_DEFLATED
1086 // window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with
1087 // zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no
1088 // header or footer)
1089 // mem_level must be between [1, 9] (it's checked but ignored by miniz.c)
1090 int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
1091 int mem_level, int strategy);
1092
1093 // Quickly resets a compressor without having to reallocate anything. Same as
1094 // calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2().
1095 int mz_deflateReset(mz_streamp pStream);
1096
1097 // mz_deflate() compresses the input to output, consuming as much of the input
1098 // and producing as much output as possible.
1099 // Parameters:
1100 // pStream is the stream to read from and write to. You must initialize/update
1101 // the next_in, avail_in, next_out, and avail_out members.
1102 // flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or
1103 // MZ_FINISH.
1104 // Return values:
1105 // MZ_OK on success (when flushing, or if more input is needed but not
1106 // available, and/or there's more output to be written but the output buffer
1107 // is full).
1108 // MZ_STREAM_END if all input has been consumed and all output bytes have been
1109 // written. Don't call mz_deflate() on the stream anymore.
1110 // MZ_STREAM_ERROR if the stream is bogus.
1111 // MZ_PARAM_ERROR if one of the parameters is invalid.
1112 // MZ_BUF_ERROR if no forward progress is possible because the input and/or
1113 // output buffers are empty. (Fill up the input buffer or free up some output
1114 // space and try again.)
1115 int mz_deflate(mz_streamp pStream, int flush);
1116
1117 // mz_deflateEnd() deinitializes a compressor:
1118 // Return values:
1119 // MZ_OK on success.
1120 // MZ_STREAM_ERROR if the stream is bogus.
1121 int mz_deflateEnd(mz_streamp pStream);
1122
1123 // mz_deflateBound() returns a (very) conservative upper bound on the amount of
1124 // data that could be generated by deflate(), assuming flush is set to only
1125 // MZ_NO_FLUSH or MZ_FINISH.
1126 mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
1127
1128 // Single-call compression functions mz_compress() and mz_compress2():
1129 // Returns MZ_OK on success, or one of the error codes from mz_deflate() on
1130 // failure.
1131 int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
1132 const unsigned char *pSource, mz_ulong source_len);
1133 int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
1134 const unsigned char *pSource, mz_ulong source_len, int level);
1135
1136 // mz_compressBound() returns a (very) conservative upper bound on the amount of
1137 // data that could be generated by calling mz_compress().
1138 mz_ulong mz_compressBound(mz_ulong source_len);
1139
1140 // Initializes a decompressor.
1141 int mz_inflateInit(mz_streamp pStream);
1142
1143 // mz_inflateInit2() is like mz_inflateInit() with an additional option that
1144 // controls the window size and whether or not the stream has been wrapped with
1145 // a zlib header/footer:
1146 // window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or
1147 // -MZ_DEFAULT_WINDOW_BITS (raw deflate).
1148 int mz_inflateInit2(mz_streamp pStream, int window_bits);
1149
1150 // Decompresses the input stream to the output, consuming only as much of the
1151 // input as needed, and writing as much to the output as possible.
1152 // Parameters:
1153 // pStream is the stream to read from and write to. You must initialize/update
1154 // the next_in, avail_in, next_out, and avail_out members.
1155 // flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH.
1156 // On the first call, if flush is MZ_FINISH it's assumed the input and output
1157 // buffers are both sized large enough to decompress the entire stream in a
1158 // single call (this is slightly faster).
1159 // MZ_FINISH implies that there are no more source bytes available beside
1160 // what's already in the input buffer, and that the output buffer is large
1161 // enough to hold the rest of the decompressed data.
1162 // Return values:
1163 // MZ_OK on success. Either more input is needed but not available, and/or
1164 // there's more output to be written but the output buffer is full.
1165 // MZ_STREAM_END if all needed input has been consumed and all output bytes
1166 // have been written. For zlib streams, the adler-32 of the decompressed data
1167 // has also been verified.
1168 // MZ_STREAM_ERROR if the stream is bogus.
1169 // MZ_DATA_ERROR if the deflate stream is invalid.
1170 // MZ_PARAM_ERROR if one of the parameters is invalid.
1171 // MZ_BUF_ERROR if no forward progress is possible because the input buffer is
1172 // empty but the inflater needs more input to continue, or if the output
1173 // buffer is not large enough. Call mz_inflate() again
1174 // with more input data, or with more room in the output buffer (except when
1175 // using single call decompression, described above).
1176 int mz_inflate(mz_streamp pStream, int flush);
1177
1178 // Deinitializes a decompressor.
1179 int mz_inflateEnd(mz_streamp pStream);
1180
1181 // Single-call decompression.
1182 // Returns MZ_OK on success, or one of the error codes from mz_inflate() on
1183 // failure.
1184 int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
1185 const unsigned char *pSource, mz_ulong source_len);
1186
1187 // Returns a string description of the specified error code, or NULL if the
1188 // error code is invalid.
1189 const char *mz_error(int err);
1190
1191 // Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used
1192 // as a drop-in replacement for the subset of zlib that miniz.c supports.
1193 // Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you
1194 // use zlib in the same project.
1195 #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
1196 typedef unsigned char Byte;
1197 typedef unsigned int uInt;
1198 typedef mz_ulong uLong;
1199 typedef Byte Bytef;
1200 typedef uInt uIntf;
1201 typedef char charf;
1202 typedef int intf;
1203 typedef void *voidpf;
1204 typedef uLong uLongf;
1205 typedef void *voidp;
1206 typedef void *const voidpc;
1207 #define Z_NULL 0
1208 #define Z_NO_FLUSH MZ_NO_FLUSH
1209 #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
1210 #define Z_SYNC_FLUSH MZ_SYNC_FLUSH
1211 #define Z_FULL_FLUSH MZ_FULL_FLUSH
1212 #define Z_FINISH MZ_FINISH
1213 #define Z_BLOCK MZ_BLOCK
1214 #define Z_OK MZ_OK
1215 #define Z_STREAM_END MZ_STREAM_END
1216 #define Z_NEED_DICT MZ_NEED_DICT
1217 #define Z_ERRNO MZ_ERRNO
1218 #define Z_STREAM_ERROR MZ_STREAM_ERROR
1219 #define Z_DATA_ERROR MZ_DATA_ERROR
1220 #define Z_MEM_ERROR MZ_MEM_ERROR
1221 #define Z_BUF_ERROR MZ_BUF_ERROR
1222 #define Z_VERSION_ERROR MZ_VERSION_ERROR
1223 #define Z_PARAM_ERROR MZ_PARAM_ERROR
1224 #define Z_NO_COMPRESSION MZ_NO_COMPRESSION
1225 #define Z_BEST_SPEED MZ_BEST_SPEED
1226 #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
1227 #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
1228 #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
1229 #define Z_FILTERED MZ_FILTERED
1230 #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
1231 #define Z_RLE MZ_RLE
1232 #define Z_FIXED MZ_FIXED
1233 #define Z_DEFLATED MZ_DEFLATED
1234 #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
1235 #define alloc_func mz_alloc_func
1236 #define free_func mz_free_func
1237 #define internal_state mz_internal_state
1238 #define z_stream mz_stream
1239 #define deflateInit mz_deflateInit
1240 #define deflateInit2 mz_deflateInit2
1241 #define deflateReset mz_deflateReset
1242 #define deflate mz_deflate
1243 #define deflateEnd mz_deflateEnd
1244 #define deflateBound mz_deflateBound
1245 #define compress mz_compress
1246 #define compress2 mz_compress2
1247 #define compressBound mz_compressBound
1248 #define inflateInit mz_inflateInit
1249 #define inflateInit2 mz_inflateInit2
1250 #define inflate mz_inflate
1251 #define inflateEnd mz_inflateEnd
1252 #define uncompress mz_uncompress
1253 #define crc32 mz_crc32
1254 #define adler32 mz_adler32
1255 #define MAX_WBITS 15
1256 #define MAX_MEM_LEVEL 9
1257 #define zError mz_error
1258 #define ZLIB_VERSION MZ_VERSION
1259 #define ZLIB_VERNUM MZ_VERNUM
1260 #define ZLIB_VER_MAJOR MZ_VER_MAJOR
1261 #define ZLIB_VER_MINOR MZ_VER_MINOR
1262 #define ZLIB_VER_REVISION MZ_VER_REVISION
1263 #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
1264 #define zlibVersion mz_version
1265 #define zlib_version mz_version()
1266 #endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
1267
1268 #endif // MINIZ_NO_ZLIB_APIS
1269
1270 // ------------------- Types and macros
1271
1272 typedef unsigned char mz_uint8;
1273 typedef signed short mz_int16;
1274 typedef unsigned short mz_uint16;
1275 typedef unsigned int mz_uint32;
1276 typedef unsigned int mz_uint;
1277 typedef long long mz_int64;
1278 typedef unsigned long long mz_uint64;
1279 typedef int mz_bool;
1280
1281 #define MZ_FALSE (0)
1282 #define MZ_TRUE (1)
1283
1284 // An attempt to work around MSVC's spammy "warning C4127: conditional
1285 // expression is constant" message.
1286 #ifdef _MSC_VER
1287 #define MZ_MACRO_END while (0, 0)
1288 #else
1289 #define MZ_MACRO_END while (0)
1290 #endif
1291
1292 // ------------------- ZIP archive reading/writing
1293
1294 #ifndef MINIZ_NO_ARCHIVE_APIS
1295
1296 enum {
1297 MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
1298 MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
1299 MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
1300 };
1301
1302 typedef struct {
1303 mz_uint32 m_file_index;
1304 mz_uint32 m_central_dir_ofs;
1305 mz_uint16 m_version_made_by;
1306 mz_uint16 m_version_needed;
1307 mz_uint16 m_bit_flag;
1308 mz_uint16 m_method;
1309 #ifndef MINIZ_NO_TIME
1310 time_t m_time;
1311 #endif
1312 mz_uint32 m_crc32;
1313 mz_uint64 m_comp_size;
1314 mz_uint64 m_uncomp_size;
1315 mz_uint16 m_internal_attr;
1316 mz_uint32 m_external_attr;
1317 mz_uint64 m_local_header_ofs;
1318 mz_uint32 m_comment_size;
1319 char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
1320 char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
1321 } mz_zip_archive_file_stat;
1322
1323 typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
1324 void *pBuf, size_t n);
1325 typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
1326 const void *pBuf, size_t n);
1327
1328 struct mz_zip_internal_state_tag;
1329 typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
1330
1331 typedef enum {
1332 MZ_ZIP_MODE_INVALID = 0,
1333 MZ_ZIP_MODE_READING = 1,
1334 MZ_ZIP_MODE_WRITING = 2,
1335 MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
1336 } mz_zip_mode;
1337
1338 typedef struct mz_zip_archive_tag {
1339 mz_uint64 m_archive_size;
1340 mz_uint64 m_central_directory_file_ofs;
1341 mz_uint m_total_files;
1342 mz_zip_mode m_zip_mode;
1343
1344 mz_uint m_file_offset_alignment;
1345
1346 mz_alloc_func m_pAlloc;
1347 mz_free_func m_pFree;
1348 mz_realloc_func m_pRealloc;
1349 void *m_pAlloc_opaque;
1350
1351 mz_file_read_func m_pRead;
1352 mz_file_write_func m_pWrite;
1353 void *m_pIO_opaque;
1354
1355 mz_zip_internal_state *m_pState;
1356
1357 } mz_zip_archive;
1358
1359 typedef enum {
1360 MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
1361 MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
1362 MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
1363 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
1364 } mz_zip_flags;
1365
1366 // ZIP archive reading
1367
1368 // Inits a ZIP archive reader.
1369 // These functions read and validate the archive's central directory.
1370 mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
1371 mz_uint32 flags);
1372 mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
1373 size_t size, mz_uint32 flags);
1374
1375 #ifndef MINIZ_NO_STDIO
1376 mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
1377 mz_uint32 flags);
1378 #endif
1379
1380 // Returns the total number of files in the archive.
1381 mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
1382
1383 // Returns detailed information about an archive file entry.
1384 mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
1385 mz_zip_archive_file_stat *pStat);
1386
1387 // Determines if an archive file entry is a directory entry.
1388 mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
1389 mz_uint file_index);
1390 mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
1391 mz_uint file_index);
1392
1393 // Retrieves the filename of an archive file entry.
1394 // Returns the number of bytes written to pFilename, or if filename_buf_size is
1395 // 0 this function returns the number of bytes needed to fully store the
1396 // filename.
1397 mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
1398 char *pFilename, mz_uint filename_buf_size);
1399
1400 // Attempts to locates a file in the archive's central directory.
1401 // Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
1402 // Returns -1 if the file cannot be found.
1403 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
1404 const char *pComment, mz_uint flags);
1405
1406 // Extracts a archive file to a memory buffer using no memory allocation.
1407 mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
1408 mz_uint file_index, void *pBuf,
1409 size_t buf_size, mz_uint flags,
1410 void *pUser_read_buf,
1411 size_t user_read_buf_size);
1412 mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
1413 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
1414 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
1415
1416 // Extracts a archive file to a memory buffer.
1417 mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
1418 void *pBuf, size_t buf_size,
1419 mz_uint flags);
1420 mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
1421 const char *pFilename, void *pBuf,
1422 size_t buf_size, mz_uint flags);
1423
1424 // Extracts a archive file to a dynamically allocated heap buffer.
1425 void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
1426 size_t *pSize, mz_uint flags);
1427 void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
1428 const char *pFilename, size_t *pSize,
1429 mz_uint flags);
1430
1431 // Extracts a archive file using a callback function to output the file's data.
1432 mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
1433 mz_uint file_index,
1434 mz_file_write_func pCallback,
1435 void *pOpaque, mz_uint flags);
1436 mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
1437 const char *pFilename,
1438 mz_file_write_func pCallback,
1439 void *pOpaque, mz_uint flags);
1440
1441 #ifndef MINIZ_NO_STDIO
1442 // Extracts a archive file to a disk file and sets its last accessed and
1443 // modified times.
1444 // This function only extracts files, not archive directory records.
1445 mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
1446 const char *pDst_filename, mz_uint flags);
1447 mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
1448 const char *pArchive_filename,
1449 const char *pDst_filename,
1450 mz_uint flags);
1451 #endif
1452
1453 // Ends archive reading, freeing all allocations, and closing the input archive
1454 // file if mz_zip_reader_init_file() was used.
1455 mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
1456
1457 // ZIP archive writing
1458
1459 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
1460
1461 // Inits a ZIP archive writer.
1462 mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
1463 mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
1464 size_t size_to_reserve_at_beginning,
1465 size_t initial_allocation_size);
1466
1467 #ifndef MINIZ_NO_STDIO
1468 mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
1469 mz_uint64 size_to_reserve_at_beginning);
1470 #endif
1471
1472 // Converts a ZIP archive reader object into a writer object, to allow efficient
1473 // in-place file appends to occur on an existing archive.
1474 // For archives opened using mz_zip_reader_init_file, pFilename must be the
1475 // archive's filename so it can be reopened for writing. If the file can't be
1476 // reopened, mz_zip_reader_end() will be called.
1477 // For archives opened using mz_zip_reader_init_mem, the memory block must be
1478 // growable using the realloc callback (which defaults to realloc unless you've
1479 // overridden it).
1480 // Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's
1481 // user provided m_pWrite function cannot be NULL.
1482 // Note: In-place archive modification is not recommended unless you know what
1483 // you're doing, because if execution stops or something goes wrong before
1484 // the archive is finalized the file's central directory will be hosed.
1485 mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
1486 const char *pFilename);
1487
1488 // Adds the contents of a memory buffer to an archive. These functions record
1489 // the current local time into the archive.
1490 // To add a directory entry, call this method with an archive name ending in a
1491 // forwardslash with empty buffer.
1492 // level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1493 // MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1494 // just set to MZ_DEFAULT_COMPRESSION.
1495 mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
1496 const void *pBuf, size_t buf_size,
1497 mz_uint level_and_flags);
1498 mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
1499 const char *pArchive_name, const void *pBuf,
1500 size_t buf_size, const void *pComment,
1501 mz_uint16 comment_size,
1502 mz_uint level_and_flags, mz_uint64 uncomp_size,
1503 mz_uint32 uncomp_crc32);
1504
1505 #ifndef MINIZ_NO_STDIO
1506 // Adds the contents of a disk file to an archive. This function also records
1507 // the disk file's modified time into the archive.
1508 // level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1509 // MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1510 // just set to MZ_DEFAULT_COMPRESSION.
1511 mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
1512 const char *pSrc_filename, const void *pComment,
1513 mz_uint16 comment_size, mz_uint level_and_flags);
1514 #endif
1515
1516 // Adds a file to an archive by fully cloning the data from another archive.
1517 // This function fully clones the source file's compressed data (no
1518 // recompression), along with its full filename, extra data, and comment fields.
1519 mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
1520 mz_zip_archive *pSource_zip,
1521 mz_uint file_index);
1522
1523 // Finalizes the archive by writing the central directory records followed by
1524 // the end of central directory record.
1525 // After an archive is finalized, the only valid call on the mz_zip_archive
1526 // struct is mz_zip_writer_end().
1527 // An archive must be manually finalized by calling this function for it to be
1528 // valid.
1529 mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
1530 mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
1531 size_t *pSize);
1532
1533 // Ends archive writing, freeing all allocations, and closing the output file if
1534 // mz_zip_writer_init_file() was used.
1535 // Note for the archive to be valid, it must have been finalized before ending.
1536 mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
1537
1538 // Misc. high-level helper functions:
1539
1540 // mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically)
1541 // appends a memory blob to a ZIP archive.
1542 // level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1543 // MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1544 // just set to MZ_DEFAULT_COMPRESSION.
1545 mz_bool mz_zip_add_mem_to_archive_file_in_place(
1546 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
1547 size_t buf_size, const void *pComment, mz_uint16 comment_size,
1548 mz_uint level_and_flags);
1549
1550 // Reads a single file from an archive into a heap block.
1551 // Returns NULL on failure.
1552 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
1553 const char *pArchive_name,
1554 size_t *pSize, mz_uint zip_flags);
1555
1556 #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
1557
1558 #endif // #ifndef MINIZ_NO_ARCHIVE_APIS
1559
1560 // ------------------- Low-level Decompression API Definitions
1561
1562 // Decompression flags used by tinfl_decompress().
1563 // TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and
1564 // ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the
1565 // input is a raw deflate stream.
1566 // TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available
1567 // beyond the end of the supplied input buffer. If clear, the input buffer
1568 // contains all remaining input.
1569 // TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large
1570 // enough to hold the entire decompressed stream. If clear, the output buffer is
1571 // at least the size of the dictionary (typically 32KB).
1572 // TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the
1573 // decompressed bytes.
1574 enum {
1575 TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
1576 TINFL_FLAG_HAS_MORE_INPUT = 2,
1577 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
1578 TINFL_FLAG_COMPUTE_ADLER32 = 8
1579 };
1580
1581 // High level decompression functions:
1582 // tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block
1583 // allocated via malloc().
1584 // On entry:
1585 // pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data
1586 // to decompress.
1587 // On return:
1588 // Function returns a pointer to the decompressed data, or NULL on failure.
1589 // *pOut_len will be set to the decompressed data's size, which could be larger
1590 // than src_buf_len on uncompressible data.
1591 // The caller must call mz_free() on the returned block when it's no longer
1592 // needed.
1593 void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
1594 size_t *pOut_len, int flags);
1595
1596 // tinfl_decompress_mem_to_mem() decompresses a block in memory to another block
1597 // in memory.
1598 // Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes
1599 // written on success.
1600 #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
1601 size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
1602 const void *pSrc_buf, size_t src_buf_len,
1603 int flags);
1604
1605 // tinfl_decompress_mem_to_callback() decompresses a block in memory to an
1606 // internal 32KB buffer, and a user provided callback function will be called to
1607 // flush the buffer.
1608 // Returns 1 on success or 0 on failure.
1609 typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);
1610 int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
1611 tinfl_put_buf_func_ptr pPut_buf_func,
1612 void *pPut_buf_user, int flags);
1613
1614 struct tinfl_decompressor_tag;
1615 typedef struct tinfl_decompressor_tag tinfl_decompressor;
1616
1617 // Max size of LZ dictionary.
1618 #define TINFL_LZ_DICT_SIZE 32768
1619
1620 // Return status.
1621 typedef enum {
1622 TINFL_STATUS_BAD_PARAM = -3,
1623 TINFL_STATUS_ADLER32_MISMATCH = -2,
1624 TINFL_STATUS_FAILED = -1,
1625 TINFL_STATUS_DONE = 0,
1626 TINFL_STATUS_NEEDS_MORE_INPUT = 1,
1627 TINFL_STATUS_HAS_MORE_OUTPUT = 2
1628 } tinfl_status;
1629
1630 // Initializes the decompressor to its initial state.
1631 #define tinfl_init(r) \
1632 do { \
1633 (r)->m_state = 0; \
1634 } \
1635 MZ_MACRO_END
1636 #define tinfl_get_adler32(r) (r)->m_check_adler32
1637
1638 // Main low-level decompressor coroutine function. This is the only function
1639 // actually needed for decompression. All the other functions are just
1640 // high-level helpers for improved usability.
1641 // This is a universal API, i.e. it can be used as a building block to build any
1642 // desired higher level decompression API. In the limit case, it can be called
1643 // once per every byte input or output.
1644 tinfl_status tinfl_decompress(tinfl_decompressor *r,
1645 const mz_uint8 *pIn_buf_next,
1646 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
1647 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
1648 const mz_uint32 decomp_flags);
1649
1650 // Internal/private bits follow.
1651 enum {
1652 TINFL_MAX_HUFF_TABLES = 3,
1653 TINFL_MAX_HUFF_SYMBOLS_0 = 288,
1654 TINFL_MAX_HUFF_SYMBOLS_1 = 32,
1655 TINFL_MAX_HUFF_SYMBOLS_2 = 19,
1656 TINFL_FAST_LOOKUP_BITS = 10,
1657 TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
1658 };
1659
1660 typedef struct {
1661 mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
1662 mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE],
1663 m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
1664 } tinfl_huff_table;
1665
1666 #if MINIZ_HAS_64BIT_REGISTERS
1667 #define TINFL_USE_64BIT_BITBUF 1
1668 #endif
1669
1670 #if TINFL_USE_64BIT_BITBUF
1671 typedef mz_uint64 tinfl_bit_buf_t;
1672 #define TINFL_BITBUF_SIZE (64)
1673 #else
1674 typedef mz_uint32 tinfl_bit_buf_t;
1675 #define TINFL_BITBUF_SIZE (32)
1676 #endif
1677
1678 struct tinfl_decompressor_tag {
1679 mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type,
1680 m_check_adler32, m_dist, m_counter, m_num_extra,
1681 m_table_sizes[TINFL_MAX_HUFF_TABLES];
1682 tinfl_bit_buf_t m_bit_buf;
1683 size_t m_dist_from_out_buf_start;
1684 tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
1685 mz_uint8 m_raw_header[4],
1686 m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
1687 };
1688
1689 // ------------------- Low-level Compression API Definitions
1690
1691 // Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly
1692 // slower, and raw/dynamic blocks will be output more frequently).
1693 #define TDEFL_LESS_MEMORY 0
1694
1695 // tdefl_init() compression flags logically OR'd together (low 12 bits contain
1696 // the max. number of probes per dictionary search):
1697 // TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes
1698 // per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap
1699 // compression), 4095=Huffman+LZ (slowest/best compression).
1700 enum {
1701 TDEFL_HUFFMAN_ONLY = 0,
1702 TDEFL_DEFAULT_MAX_PROBES = 128,
1703 TDEFL_MAX_PROBES_MASK = 0xFFF
1704 };
1705
1706 // TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before
1707 // the deflate data, and the Adler-32 of the source data at the end. Otherwise,
1708 // you'll get raw deflate data.
1709 // TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even
1710 // when not writing zlib headers).
1711 // TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more
1712 // efficient lazy parsing.
1713 // TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's
1714 // initialization time to the minimum, but the output may vary from run to run
1715 // given the same input (depending on the contents of memory).
1716 // TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
1717 // TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
1718 // TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
1719 // TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
1720 // The low 12 bits are reserved to control the max # of hash probes per
1721 // dictionary lookup (see TDEFL_MAX_PROBES_MASK).
1722 enum {
1723 TDEFL_WRITE_ZLIB_HEADER = 0x01000,
1724 TDEFL_COMPUTE_ADLER32 = 0x02000,
1725 TDEFL_GREEDY_PARSING_FLAG = 0x04000,
1726 TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
1727 TDEFL_RLE_MATCHES = 0x10000,
1728 TDEFL_FILTER_MATCHES = 0x20000,
1729 TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
1730 TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
1731 };
1732
1733 // High level compression functions:
1734 // tdefl_compress_mem_to_heap() compresses a block in memory to a heap block
1735 // allocated via malloc().
1736 // On entry:
1737 // pSrc_buf, src_buf_len: Pointer and size of source block to compress.
1738 // flags: The max match finder probes (default is 128) logically OR'd against
1739 // the above flags. Higher probes are slower but improve compression.
1740 // On return:
1741 // Function returns a pointer to the compressed data, or NULL on failure.
1742 // *pOut_len will be set to the compressed data's size, which could be larger
1743 // than src_buf_len on uncompressible data.
1744 // The caller must free() the returned block when it's no longer needed.
1745 void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
1746 size_t *pOut_len, int flags);
1747
1748 // tdefl_compress_mem_to_mem() compresses a block in memory to another block in
1749 // memory.
1750 // Returns 0 on failure.
1751 size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
1752 const void *pSrc_buf, size_t src_buf_len,
1753 int flags);
1754
1755 // Compresses an image to a compressed PNG file in memory.
1756 // On entry:
1757 // pImage, w, h, and num_chans describe the image to compress. num_chans may be
1758 // 1, 2, 3, or 4.
1759 // The image pitch in bytes per scanline will be w*num_chans. The leftmost
1760 // pixel on the top scanline is stored first in memory.
1761 // level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED,
1762 // MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL
1763 // If flip is true, the image will be flipped on the Y axis (useful for OpenGL
1764 // apps).
1765 // On return:
1766 // Function returns a pointer to the compressed data, or NULL on failure.
1767 // *pLen_out will be set to the size of the PNG image file.
1768 // The caller must mz_free() the returned heap block (which will typically be
1769 // larger than *pLen_out) when it's no longer needed.
1770 void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
1771 int h, int num_chans,
1772 size_t *pLen_out,
1773 mz_uint level, mz_bool flip);
1774 void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
1775 int num_chans, size_t *pLen_out);
1776
1777 // Output stream interface. The compressor uses this interface to write
1778 // compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
1779 typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len,
1780 void *pUser);
1781
1782 // tdefl_compress_mem_to_output() compresses a block to an output stream. The
1783 // above helpers use this function internally.
1784 mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
1785 tdefl_put_buf_func_ptr pPut_buf_func,
1786 void *pPut_buf_user, int flags);
1787
1788 enum {
1789 TDEFL_MAX_HUFF_TABLES = 3,
1790 TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
1791 TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
1792 TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
1793 TDEFL_LZ_DICT_SIZE = 32768,
1794 TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
1795 TDEFL_MIN_MATCH_LEN = 3,
1796 TDEFL_MAX_MATCH_LEN = 258
1797 };
1798
1799 // TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed
1800 // output block (using static/fixed Huffman codes).
1801 #if TDEFL_LESS_MEMORY
1802 enum {
1803 TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,
1804 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
1805 TDEFL_MAX_HUFF_SYMBOLS = 288,
1806 TDEFL_LZ_HASH_BITS = 12,
1807 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
1808 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
1809 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
1810 };
1811 #else
1812 enum {
1813 TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
1814 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
1815 TDEFL_MAX_HUFF_SYMBOLS = 288,
1816 TDEFL_LZ_HASH_BITS = 15,
1817 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
1818 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
1819 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
1820 };
1821 #endif
1822
1823 // The low-level tdefl functions below may be used directly if the above helper
1824 // functions aren't flexible enough. The low-level functions don't make any heap
1825 // allocations, unlike the above helper functions.
1826 typedef enum {
1827 TDEFL_STATUS_BAD_PARAM = -2,
1828 TDEFL_STATUS_PUT_BUF_FAILED = -1,
1829 TDEFL_STATUS_OKAY = 0,
1830 TDEFL_STATUS_DONE = 1
1831 } tdefl_status;
1832
1833 // Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
1834 typedef enum {
1835 TDEFL_NO_FLUSH = 0,
1836 TDEFL_SYNC_FLUSH = 2,
1837 TDEFL_FULL_FLUSH = 3,
1838 TDEFL_FINISH = 4
1839 } tdefl_flush;
1840
1841 // tdefl's compression state structure.
1842 typedef struct {
1843 tdefl_put_buf_func_ptr m_pPut_buf_func;
1844 void *m_pPut_buf_user;
1845 mz_uint m_flags, m_max_probes[2];
1846 int m_greedy_parsing;
1847 mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
1848 mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
1849 mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in,
1850 m_bit_buffer;
1851 mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit,
1852 m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index,
1853 m_wants_to_finish;
1854 tdefl_status m_prev_return_status;
1855 const void *m_pIn_buf;
1856 void *m_pOut_buf;
1857 size_t *m_pIn_buf_size, *m_pOut_buf_size;
1858 tdefl_flush m_flush;
1859 const mz_uint8 *m_pSrc;
1860 size_t m_src_buf_left, m_out_buf_ofs;
1861 mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
1862 mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1863 mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1864 mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1865 mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
1866 mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
1867 mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
1868 mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
1869 } tdefl_compressor;
1870
1871 // Initializes the compressor.
1872 // There is no corresponding deinit() function because the tdefl API's do not
1873 // dynamically allocate memory.
1874 // pBut_buf_func: If NULL, output data will be supplied to the specified
1875 // callback. In this case, the user should call the tdefl_compress_buffer() API
1876 // for compression.
1877 // If pBut_buf_func is NULL the user should always call the tdefl_compress()
1878 // API.
1879 // flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER,
1880 // etc.)
1881 tdefl_status tdefl_init(tdefl_compressor *d,
1882 tdefl_put_buf_func_ptr pPut_buf_func,
1883 void *pPut_buf_user, int flags);
1884
1885 // Compresses a block of data, consuming as much of the specified input buffer
1886 // as possible, and writing as much compressed data to the specified output
1887 // buffer as possible.
1888 tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
1889 size_t *pIn_buf_size, void *pOut_buf,
1890 size_t *pOut_buf_size, tdefl_flush flush);
1891
1892 // tdefl_compress_buffer() is only usable when the tdefl_init() is called with a
1893 // non-NULL tdefl_put_buf_func_ptr.
1894 // tdefl_compress_buffer() always consumes the entire input buffer.
1895 tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
1896 size_t in_buf_size, tdefl_flush flush);
1897
1898 tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
1899 mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
1900
1901 // Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't
1902 // defined, because it uses some of its macros.
1903 #ifndef MINIZ_NO_ZLIB_APIS
1904 // Create tdefl_compress() flags given zlib-style compression parameters.
1905 // level may range from [0,10] (where 10 is absolute max compression, but may be
1906 // much slower on some files)
1907 // window_bits may be -15 (raw deflate) or 15 (zlib)
1908 // strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY,
1909 // MZ_RLE, or MZ_FIXED
1910 mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
1911 int strategy);
1912 #endif // #ifndef MINIZ_NO_ZLIB_APIS
1913
1914 #ifdef __cplusplus
1915 }
1916 #endif
1917
1918 #endif // MINIZ_HEADER_INCLUDED
1919
1920 // ------------------- End of Header: Implementation follows. (If you only want
1921 // the header, define MINIZ_HEADER_FILE_ONLY.)
1922
1923 #ifndef MINIZ_HEADER_FILE_ONLY
1924
1925 typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
1926 typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
1927 typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
1928
1929 #define MZ_ASSERT(x) TEXR_ASSERT(x)
1930
1931 #ifdef MINIZ_NO_MALLOC
1932 #define MZ_MALLOC(x) NULL
1933 #define MZ_FREE(x) (void)x, ((void)0)
1934 #define MZ_REALLOC(p, x) NULL
1935 #else
1936 #define MZ_MALLOC(x) malloc(x)
1937 #define MZ_FREE(x) free(x)
1938 #define MZ_REALLOC(p, x) realloc(p, x)
1939 #endif
1940
1941 #define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b))
1942 #define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b))
1943 #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
1944
1945 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1946 #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
1947 #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
1948 #else
1949 #define MZ_READ_LE16(p) \
1950 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
1951 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
1952 #define MZ_READ_LE32(p) \
1953 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
1954 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \
1955 ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \
1956 ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
1957 #endif
1958
1959 #ifdef _MSC_VER
1960 #define MZ_FORCEINLINE __forceinline
1961 #elif defined(__GNUC__)
1962 #define MZ_FORCEINLINE inline __attribute__((__always_inline__))
1963 #else
1964 #define MZ_FORCEINLINE inline
1965 #endif
1966
1967 #ifdef __cplusplus
1968 extern "C" {
1969 #endif
1970
1971 // ------------------- zlib-style API's
1972
mz_adler32(mz_ulong adler,const unsigned char * ptr,size_t buf_len)1973 mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) {
1974 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);
1975 size_t block_len = buf_len % 5552;
1976 if (!ptr) return MZ_ADLER32_INIT;
1977 while (buf_len) {
1978 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
1979 s1 += ptr[0], s2 += s1;
1980 s1 += ptr[1], s2 += s1;
1981 s1 += ptr[2], s2 += s1;
1982 s1 += ptr[3], s2 += s1;
1983 s1 += ptr[4], s2 += s1;
1984 s1 += ptr[5], s2 += s1;
1985 s1 += ptr[6], s2 += s1;
1986 s1 += ptr[7], s2 += s1;
1987 }
1988 for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
1989 s1 %= 65521U, s2 %= 65521U;
1990 buf_len -= block_len;
1991 block_len = 5552;
1992 }
1993 return (s2 << 16) + s1;
1994 }
1995
1996 // Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C
1997 // implementation that balances processor cache usage against speed":
1998 // http://www.geocities.com/malbrain/
mz_crc32(mz_ulong crc,const mz_uint8 * ptr,size_t buf_len)1999 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) {
2000 static const mz_uint32 s_crc32[16] = {
2001 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4,
2002 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
2003 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c};
2004 mz_uint32 crcu32 = (mz_uint32)crc;
2005 if (!ptr) return MZ_CRC32_INIT;
2006 crcu32 = ~crcu32;
2007 while (buf_len--) {
2008 mz_uint8 b = *ptr++;
2009 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
2010 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
2011 }
2012 return ~crcu32;
2013 }
2014
mz_free(void * p)2015 void mz_free(void *p) { MZ_FREE(p); }
2016
2017 #ifndef MINIZ_NO_ZLIB_APIS
2018
def_alloc_func(void * opaque,size_t items,size_t size)2019 static void *def_alloc_func(void *opaque, size_t items, size_t size) {
2020 (void)opaque, (void)items, (void)size;
2021 return MZ_MALLOC(items * size);
2022 }
def_free_func(void * opaque,void * address)2023 static void def_free_func(void *opaque, void *address) {
2024 (void)opaque, (void)address;
2025 MZ_FREE(address);
2026 }
2027 // static void *def_realloc_func(void *opaque, void *address, size_t items,
2028 // size_t size) {
2029 // (void)opaque, (void)address, (void)items, (void)size;
2030 // return MZ_REALLOC(address, items * size);
2031 //}
2032
mz_version(void)2033 const char *mz_version(void) { return MZ_VERSION; }
2034
mz_deflateInit(mz_streamp pStream,int level)2035 int mz_deflateInit(mz_streamp pStream, int level) {
2036 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9,
2037 MZ_DEFAULT_STRATEGY);
2038 }
2039
mz_deflateInit2(mz_streamp pStream,int level,int method,int window_bits,int mem_level,int strategy)2040 int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
2041 int mem_level, int strategy) {
2042 tdefl_compressor *pComp;
2043 mz_uint comp_flags =
2044 TDEFL_COMPUTE_ADLER32 |
2045 tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
2046
2047 if (!pStream) return MZ_STREAM_ERROR;
2048 if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) ||
2049 ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
2050 (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
2051 return MZ_PARAM_ERROR;
2052
2053 pStream->data_type = 0;
2054 pStream->adler = MZ_ADLER32_INIT;
2055 pStream->msg = NULL;
2056 pStream->reserved = 0;
2057 pStream->total_in = 0;
2058 pStream->total_out = 0;
2059 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
2060 if (!pStream->zfree) pStream->zfree = def_free_func;
2061
2062 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1,
2063 sizeof(tdefl_compressor));
2064 if (!pComp) return MZ_MEM_ERROR;
2065
2066 pStream->state = (struct mz_internal_state *)pComp;
2067
2068 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) {
2069 mz_deflateEnd(pStream);
2070 return MZ_PARAM_ERROR;
2071 }
2072
2073 return MZ_OK;
2074 }
2075
mz_deflateReset(mz_streamp pStream)2076 int mz_deflateReset(mz_streamp pStream) {
2077 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) ||
2078 (!pStream->zfree))
2079 return MZ_STREAM_ERROR;
2080 pStream->total_in = pStream->total_out = 0;
2081 tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL,
2082 ((tdefl_compressor *)pStream->state)->m_flags);
2083 return MZ_OK;
2084 }
2085
mz_deflate(mz_streamp pStream,int flush)2086 int mz_deflate(mz_streamp pStream, int flush) {
2087 size_t in_bytes, out_bytes;
2088 mz_ulong orig_total_in, orig_total_out;
2089 int mz_status = MZ_OK;
2090
2091 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) ||
2092 (!pStream->next_out))
2093 return MZ_STREAM_ERROR;
2094 if (!pStream->avail_out) return MZ_BUF_ERROR;
2095
2096 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
2097
2098 if (((tdefl_compressor *)pStream->state)->m_prev_return_status ==
2099 TDEFL_STATUS_DONE)
2100 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
2101
2102 orig_total_in = pStream->total_in;
2103 orig_total_out = pStream->total_out;
2104 for (;;) {
2105 tdefl_status defl_status;
2106 in_bytes = pStream->avail_in;
2107 out_bytes = pStream->avail_out;
2108
2109 defl_status = tdefl_compress((tdefl_compressor *)pStream->state,
2110 pStream->next_in, &in_bytes, pStream->next_out,
2111 &out_bytes, (tdefl_flush)flush);
2112 pStream->next_in += (mz_uint)in_bytes;
2113 pStream->avail_in -= (mz_uint)in_bytes;
2114 pStream->total_in += (mz_uint)in_bytes;
2115 pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);
2116
2117 pStream->next_out += (mz_uint)out_bytes;
2118 pStream->avail_out -= (mz_uint)out_bytes;
2119 pStream->total_out += (mz_uint)out_bytes;
2120
2121 if (defl_status < 0) {
2122 mz_status = MZ_STREAM_ERROR;
2123 break;
2124 } else if (defl_status == TDEFL_STATUS_DONE) {
2125 mz_status = MZ_STREAM_END;
2126 break;
2127 } else if (!pStream->avail_out)
2128 break;
2129 else if ((!pStream->avail_in) && (flush != MZ_FINISH)) {
2130 if ((flush) || (pStream->total_in != orig_total_in) ||
2131 (pStream->total_out != orig_total_out))
2132 break;
2133 return MZ_BUF_ERROR; // Can't make forward progress without some input.
2134 }
2135 }
2136 return mz_status;
2137 }
2138
mz_deflateEnd(mz_streamp pStream)2139 int mz_deflateEnd(mz_streamp pStream) {
2140 if (!pStream) return MZ_STREAM_ERROR;
2141 if (pStream->state) {
2142 pStream->zfree(pStream->opaque, pStream->state);
2143 pStream->state = NULL;
2144 }
2145 return MZ_OK;
2146 }
2147
mz_deflateBound(mz_streamp pStream,mz_ulong source_len)2148 mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) {
2149 (void)pStream;
2150 // This is really over conservative. (And lame, but it's actually pretty
2151 // tricky to compute a true upper bound given the way tdefl's blocking works.)
2152 return MZ_MAX(128 + (source_len * 110) / 100,
2153 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
2154 }
2155
mz_compress2(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len,int level)2156 int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
2157 const unsigned char *pSource, mz_ulong source_len, int level) {
2158 int status;
2159 mz_stream stream;
2160 memset(&stream, 0, sizeof(stream));
2161
2162 // In case mz_ulong is 64-bits (argh I hate longs).
2163 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
2164
2165 stream.next_in = pSource;
2166 stream.avail_in = (mz_uint32)source_len;
2167 stream.next_out = pDest;
2168 stream.avail_out = (mz_uint32)*pDest_len;
2169
2170 status = mz_deflateInit(&stream, level);
2171 if (status != MZ_OK) return status;
2172
2173 status = mz_deflate(&stream, MZ_FINISH);
2174 if (status != MZ_STREAM_END) {
2175 mz_deflateEnd(&stream);
2176 return (status == MZ_OK) ? MZ_BUF_ERROR : status;
2177 }
2178
2179 *pDest_len = stream.total_out;
2180 return mz_deflateEnd(&stream);
2181 }
2182
mz_compress(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len)2183 int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
2184 const unsigned char *pSource, mz_ulong source_len) {
2185 return mz_compress2(pDest, pDest_len, pSource, source_len,
2186 MZ_DEFAULT_COMPRESSION);
2187 }
2188
mz_compressBound(mz_ulong source_len)2189 mz_ulong mz_compressBound(mz_ulong source_len) {
2190 return mz_deflateBound(NULL, source_len);
2191 }
2192
2193 typedef struct {
2194 tinfl_decompressor m_decomp;
2195 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;
2196 int m_window_bits;
2197 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
2198 tinfl_status m_last_status;
2199 } inflate_state;
2200
mz_inflateInit2(mz_streamp pStream,int window_bits)2201 int mz_inflateInit2(mz_streamp pStream, int window_bits) {
2202 inflate_state *pDecomp;
2203 if (!pStream) return MZ_STREAM_ERROR;
2204 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
2205 (-window_bits != MZ_DEFAULT_WINDOW_BITS))
2206 return MZ_PARAM_ERROR;
2207
2208 pStream->data_type = 0;
2209 pStream->adler = 0;
2210 pStream->msg = NULL;
2211 pStream->total_in = 0;
2212 pStream->total_out = 0;
2213 pStream->reserved = 0;
2214 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
2215 if (!pStream->zfree) pStream->zfree = def_free_func;
2216
2217 pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1,
2218 sizeof(inflate_state));
2219 if (!pDecomp) return MZ_MEM_ERROR;
2220
2221 pStream->state = (struct mz_internal_state *)pDecomp;
2222
2223 tinfl_init(&pDecomp->m_decomp);
2224 pDecomp->m_dict_ofs = 0;
2225 pDecomp->m_dict_avail = 0;
2226 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
2227 pDecomp->m_first_call = 1;
2228 pDecomp->m_has_flushed = 0;
2229 pDecomp->m_window_bits = window_bits;
2230
2231 return MZ_OK;
2232 }
2233
mz_inflateInit(mz_streamp pStream)2234 int mz_inflateInit(mz_streamp pStream) {
2235 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
2236 }
2237
mz_inflate(mz_streamp pStream,int flush)2238 int mz_inflate(mz_streamp pStream, int flush) {
2239 inflate_state *pState;
2240 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
2241 size_t in_bytes, out_bytes, orig_avail_in;
2242 tinfl_status status;
2243
2244 if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
2245 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
2246 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))
2247 return MZ_STREAM_ERROR;
2248
2249 pState = (inflate_state *)pStream->state;
2250 if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
2251 orig_avail_in = pStream->avail_in;
2252
2253 first_call = pState->m_first_call;
2254 pState->m_first_call = 0;
2255 if (pState->m_last_status < 0) return MZ_DATA_ERROR;
2256
2257 if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
2258 pState->m_has_flushed |= (flush == MZ_FINISH);
2259
2260 if ((flush == MZ_FINISH) && (first_call)) {
2261 // MZ_FINISH on the first call implies that the input and output buffers are
2262 // large enough to hold the entire compressed/decompressed file.
2263 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
2264 in_bytes = pStream->avail_in;
2265 out_bytes = pStream->avail_out;
2266 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes,
2267 pStream->next_out, pStream->next_out, &out_bytes,
2268 decomp_flags);
2269 pState->m_last_status = status;
2270 pStream->next_in += (mz_uint)in_bytes;
2271 pStream->avail_in -= (mz_uint)in_bytes;
2272 pStream->total_in += (mz_uint)in_bytes;
2273 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
2274 pStream->next_out += (mz_uint)out_bytes;
2275 pStream->avail_out -= (mz_uint)out_bytes;
2276 pStream->total_out += (mz_uint)out_bytes;
2277
2278 if (status < 0)
2279 return MZ_DATA_ERROR;
2280 else if (status != TINFL_STATUS_DONE) {
2281 pState->m_last_status = TINFL_STATUS_FAILED;
2282 return MZ_BUF_ERROR;
2283 }
2284 return MZ_STREAM_END;
2285 }
2286 // flush != MZ_FINISH then we must assume there's more input.
2287 if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
2288
2289 if (pState->m_dict_avail) {
2290 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
2291 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
2292 pStream->next_out += n;
2293 pStream->avail_out -= n;
2294 pStream->total_out += n;
2295 pState->m_dict_avail -= n;
2296 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
2297 return ((pState->m_last_status == TINFL_STATUS_DONE) &&
2298 (!pState->m_dict_avail))
2299 ? MZ_STREAM_END
2300 : MZ_OK;
2301 }
2302
2303 for (;;) {
2304 in_bytes = pStream->avail_in;
2305 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
2306
2307 status = tinfl_decompress(
2308 &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict,
2309 pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
2310 pState->m_last_status = status;
2311
2312 pStream->next_in += (mz_uint)in_bytes;
2313 pStream->avail_in -= (mz_uint)in_bytes;
2314 pStream->total_in += (mz_uint)in_bytes;
2315 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
2316
2317 pState->m_dict_avail = (mz_uint)out_bytes;
2318
2319 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
2320 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
2321 pStream->next_out += n;
2322 pStream->avail_out -= n;
2323 pStream->total_out += n;
2324 pState->m_dict_avail -= n;
2325 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
2326
2327 if (status < 0)
2328 return MZ_DATA_ERROR; // Stream is corrupted (there could be some
2329 // uncompressed data left in the output dictionary -
2330 // oh well).
2331 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
2332 return MZ_BUF_ERROR; // Signal caller that we can't make forward progress
2333 // without supplying more input or by setting flush
2334 // to MZ_FINISH.
2335 else if (flush == MZ_FINISH) {
2336 // The output buffer MUST be large to hold the remaining uncompressed data
2337 // when flush==MZ_FINISH.
2338 if (status == TINFL_STATUS_DONE)
2339 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
2340 // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's
2341 // at least 1 more byte on the way. If there's no more room left in the
2342 // output buffer then something is wrong.
2343 else if (!pStream->avail_out)
2344 return MZ_BUF_ERROR;
2345 } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) ||
2346 (!pStream->avail_out) || (pState->m_dict_avail))
2347 break;
2348 }
2349
2350 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail))
2351 ? MZ_STREAM_END
2352 : MZ_OK;
2353 }
2354
mz_inflateEnd(mz_streamp pStream)2355 int mz_inflateEnd(mz_streamp pStream) {
2356 if (!pStream) return MZ_STREAM_ERROR;
2357 if (pStream->state) {
2358 pStream->zfree(pStream->opaque, pStream->state);
2359 pStream->state = NULL;
2360 }
2361 return MZ_OK;
2362 }
2363
mz_uncompress(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len)2364 int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
2365 const unsigned char *pSource, mz_ulong source_len) {
2366 mz_stream stream;
2367 int status;
2368 memset(&stream, 0, sizeof(stream));
2369
2370 // In case mz_ulong is 64-bits (argh I hate longs).
2371 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
2372
2373 stream.next_in = pSource;
2374 stream.avail_in = (mz_uint32)source_len;
2375 stream.next_out = pDest;
2376 stream.avail_out = (mz_uint32)*pDest_len;
2377
2378 status = mz_inflateInit(&stream);
2379 if (status != MZ_OK) return status;
2380
2381 status = mz_inflate(&stream, MZ_FINISH);
2382 if (status != MZ_STREAM_END) {
2383 mz_inflateEnd(&stream);
2384 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR
2385 : status;
2386 }
2387 *pDest_len = stream.total_out;
2388
2389 return mz_inflateEnd(&stream);
2390 }
2391
mz_error(int err)2392 const char *mz_error(int err) {
2393 static struct {
2394 int m_err;
2395 const char *m_pDesc;
2396 } s_error_descs[] = {{MZ_OK, ""},
2397 {MZ_STREAM_END, "stream end"},
2398 {MZ_NEED_DICT, "need dictionary"},
2399 {MZ_ERRNO, "file error"},
2400 {MZ_STREAM_ERROR, "stream error"},
2401 {MZ_DATA_ERROR, "data error"},
2402 {MZ_MEM_ERROR, "out of memory"},
2403 {MZ_BUF_ERROR, "buf error"},
2404 {MZ_VERSION_ERROR, "version error"},
2405 {MZ_PARAM_ERROR, "parameter error"}};
2406 mz_uint i;
2407 for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)
2408 if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc;
2409 return NULL;
2410 }
2411
2412 #endif // MINIZ_NO_ZLIB_APIS
2413
2414 // ------------------- Low-level Decompression (completely independent from all
2415 // compression API's)
2416
2417 #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
2418 #define TINFL_MEMSET(p, c, l) memset(p, c, l)
2419
2420 #define TINFL_CR_BEGIN \
2421 switch (r->m_state) { \
2422 case 0:
2423 #define TINFL_CR_RETURN(state_index, result) \
2424 do { \
2425 status = result; \
2426 r->m_state = state_index; \
2427 goto common_exit; \
2428 case state_index:; \
2429 } \
2430 MZ_MACRO_END
2431 #define TINFL_CR_RETURN_FOREVER(state_index, result) \
2432 do { \
2433 for (;;) { \
2434 TINFL_CR_RETURN(state_index, result); \
2435 } \
2436 } \
2437 MZ_MACRO_END
2438 #define TINFL_CR_FINISH }
2439
2440 // TODO: If the caller has indicated that there's no more input, and we attempt
2441 // to read beyond the input buf, then something is wrong with the input because
2442 // the inflator never
2443 // reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of
2444 // the stream with 0's in this scenario.
2445 #define TINFL_GET_BYTE(state_index, c) \
2446 do { \
2447 if (pIn_buf_cur >= pIn_buf_end) { \
2448 for (;;) { \
2449 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
2450 TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
2451 if (pIn_buf_cur < pIn_buf_end) { \
2452 c = *pIn_buf_cur++; \
2453 break; \
2454 } \
2455 } else { \
2456 c = 0; \
2457 break; \
2458 } \
2459 } \
2460 } else \
2461 c = *pIn_buf_cur++; \
2462 } \
2463 MZ_MACRO_END
2464
2465 #define TINFL_NEED_BITS(state_index, n) \
2466 do { \
2467 mz_uint c; \
2468 TINFL_GET_BYTE(state_index, c); \
2469 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
2470 num_bits += 8; \
2471 } while (num_bits < (mz_uint)(n))
2472 #define TINFL_SKIP_BITS(state_index, n) \
2473 do { \
2474 if (num_bits < (mz_uint)(n)) { \
2475 TINFL_NEED_BITS(state_index, n); \
2476 } \
2477 bit_buf >>= (n); \
2478 num_bits -= (n); \
2479 } \
2480 MZ_MACRO_END
2481 #define TINFL_GET_BITS(state_index, b, n) \
2482 do { \
2483 if (num_bits < (mz_uint)(n)) { \
2484 TINFL_NEED_BITS(state_index, n); \
2485 } \
2486 b = bit_buf & ((1 << (n)) - 1); \
2487 bit_buf >>= (n); \
2488 num_bits -= (n); \
2489 } \
2490 MZ_MACRO_END
2491
2492 // TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes
2493 // remaining in the input buffer falls below 2.
2494 // It reads just enough bytes from the input stream that are needed to decode
2495 // the next Huffman code (and absolutely no more). It works by trying to fully
2496 // decode a
2497 // Huffman code by using whatever bits are currently present in the bit buffer.
2498 // If this fails, it reads another byte, and tries again until it succeeds or
2499 // until the
2500 // bit buffer contains >=15 bits (deflate's max. Huffman code size).
2501 #define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
2502 do { \
2503 temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
2504 if (temp >= 0) { \
2505 code_len = temp >> 9; \
2506 if ((code_len) && (num_bits >= code_len)) break; \
2507 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
2508 code_len = TINFL_FAST_LOOKUP_BITS; \
2509 do { \
2510 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
2511 } while ((temp < 0) && (num_bits >= (code_len + 1))); \
2512 if (temp >= 0) break; \
2513 } \
2514 TINFL_GET_BYTE(state_index, c); \
2515 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
2516 num_bits += 8; \
2517 } while (num_bits < 15);
2518
2519 // TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex
2520 // than you would initially expect because the zlib API expects the decompressor
2521 // to never read
2522 // beyond the final byte of the deflate stream. (In other words, when this macro
2523 // wants to read another byte from the input, it REALLY needs another byte in
2524 // order to fully
2525 // decode the next Huffman code.) Handling this properly is particularly
2526 // important on raw deflate (non-zlib) streams, which aren't followed by a byte
2527 // aligned adler-32.
2528 // The slow path is only executed at the very end of the input buffer.
2529 #define TINFL_HUFF_DECODE(state_index, sym, pHuff) \
2530 do { \
2531 int temp; \
2532 mz_uint code_len, c; \
2533 if (num_bits < 15) { \
2534 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
2535 TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
2536 } else { \
2537 bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \
2538 (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \
2539 pIn_buf_cur += 2; \
2540 num_bits += 16; \
2541 } \
2542 } \
2543 if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \
2544 0) \
2545 code_len = temp >> 9, temp &= 511; \
2546 else { \
2547 code_len = TINFL_FAST_LOOKUP_BITS; \
2548 do { \
2549 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
2550 } while (temp < 0); \
2551 } \
2552 sym = temp; \
2553 bit_buf >>= code_len; \
2554 num_bits -= code_len; \
2555 } \
2556 MZ_MACRO_END
2557
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)2558 tinfl_status tinfl_decompress(tinfl_decompressor *r,
2559 const mz_uint8 *pIn_buf_next,
2560 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
2561 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
2562 const mz_uint32 decomp_flags) {
2563 static const int s_length_base[31] = {
2564 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
2565 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
2566 static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
2567 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
2568 4, 4, 5, 5, 5, 5, 0, 0, 0};
2569 static const int s_dist_base[32] = {
2570 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33,
2571 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
2572 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0};
2573 static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
2574 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
2575 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
2576 static const mz_uint8 s_length_dezigzag[19] = {
2577 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
2578 static const int s_min_table_sizes[3] = {257, 1, 4};
2579
2580 tinfl_status status = TINFL_STATUS_FAILED;
2581 mz_uint32 num_bits, dist, counter, num_extra;
2582 tinfl_bit_buf_t bit_buf;
2583 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
2584 pIn_buf_next + *pIn_buf_size;
2585 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
2586 pOut_buf_next + *pOut_buf_size;
2587 size_t out_buf_size_mask =
2588 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
2589 ? (size_t)-1
2590 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1,
2591 dist_from_out_buf_start;
2592
2593 // Ensure the output buffer's size is a power of 2, unless the output buffer
2594 // is large enough to hold the entire output file (in which case it doesn't
2595 // matter).
2596 if (((out_buf_size_mask + 1) & out_buf_size_mask) ||
2597 (pOut_buf_next < pOut_buf_start)) {
2598 *pIn_buf_size = *pOut_buf_size = 0;
2599 return TINFL_STATUS_BAD_PARAM;
2600 }
2601
2602 num_bits = r->m_num_bits;
2603 bit_buf = r->m_bit_buf;
2604 dist = r->m_dist;
2605 counter = r->m_counter;
2606 num_extra = r->m_num_extra;
2607 dist_from_out_buf_start = r->m_dist_from_out_buf_start;
2608 TINFL_CR_BEGIN
2609
2610 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;
2611 r->m_z_adler32 = r->m_check_adler32 = 1;
2612 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2613 TINFL_GET_BYTE(1, r->m_zhdr0);
2614 TINFL_GET_BYTE(2, r->m_zhdr1);
2615 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) ||
2616 (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
2617 if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
2618 counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) ||
2619 ((out_buf_size_mask + 1) <
2620 (size_t)(1ULL << (8U + (r->m_zhdr0 >> 4)))));
2621 if (counter) {
2622 TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);
2623 }
2624 }
2625
2626 do {
2627 TINFL_GET_BITS(3, r->m_final, 3);
2628 r->m_type = r->m_final >> 1;
2629 if (r->m_type == 0) {
2630 TINFL_SKIP_BITS(5, num_bits & 7);
2631 for (counter = 0; counter < 4; ++counter) {
2632 if (num_bits)
2633 TINFL_GET_BITS(6, r->m_raw_header[counter], 8);
2634 else
2635 TINFL_GET_BYTE(7, r->m_raw_header[counter]);
2636 }
2637 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) !=
2638 (mz_uint)(0xFFFF ^
2639 (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) {
2640 TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);
2641 }
2642 while ((counter) && (num_bits)) {
2643 TINFL_GET_BITS(51, dist, 8);
2644 while (pOut_buf_cur >= pOut_buf_end) {
2645 TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);
2646 }
2647 *pOut_buf_cur++ = (mz_uint8)dist;
2648 counter--;
2649 }
2650 while (counter) {
2651 size_t n;
2652 while (pOut_buf_cur >= pOut_buf_end) {
2653 TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);
2654 }
2655 while (pIn_buf_cur >= pIn_buf_end) {
2656 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) {
2657 TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
2658 } else {
2659 TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
2660 }
2661 }
2662 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur),
2663 (size_t)(pIn_buf_end - pIn_buf_cur)),
2664 counter);
2665 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);
2666 pIn_buf_cur += n;
2667 pOut_buf_cur += n;
2668 counter -= (mz_uint)n;
2669 }
2670 } else if (r->m_type == 3) {
2671 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
2672 } else {
2673 if (r->m_type == 1) {
2674 mz_uint8 *p = r->m_tables[0].m_code_size;
2675 mz_uint i;
2676 r->m_table_sizes[0] = 288;
2677 r->m_table_sizes[1] = 32;
2678 TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
2679 for (i = 0; i <= 143; ++i) *p++ = 8;
2680 for (; i <= 255; ++i) *p++ = 9;
2681 for (; i <= 279; ++i) *p++ = 7;
2682 for (; i <= 287; ++i) *p++ = 8;
2683 } else {
2684 for (counter = 0; counter < 3; counter++) {
2685 TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]);
2686 r->m_table_sizes[counter] += s_min_table_sizes[counter];
2687 }
2688 MZ_CLEAR_OBJ(r->m_tables[2].m_code_size);
2689 for (counter = 0; counter < r->m_table_sizes[2]; counter++) {
2690 mz_uint s;
2691 TINFL_GET_BITS(14, s, 3);
2692 r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s;
2693 }
2694 r->m_table_sizes[2] = 19;
2695 }
2696 for (; (int)r->m_type >= 0; r->m_type--) {
2697 int tree_next, tree_cur;
2698 tinfl_huff_table *pTable;
2699 mz_uint i, j, used_syms, total, sym_index, next_code[17],
2700 total_syms[16];
2701 pTable = &r->m_tables[r->m_type];
2702 MZ_CLEAR_OBJ(total_syms);
2703 MZ_CLEAR_OBJ(pTable->m_look_up);
2704 MZ_CLEAR_OBJ(pTable->m_tree);
2705 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)
2706 total_syms[pTable->m_code_size[i]]++;
2707 used_syms = 0, total = 0;
2708 next_code[0] = next_code[1] = 0;
2709 for (i = 1; i <= 15; ++i) {
2710 used_syms += total_syms[i];
2711 next_code[i + 1] = (total = ((total + total_syms[i]) << 1));
2712 }
2713 if ((65536 != total) && (used_syms > 1)) {
2714 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
2715 }
2716 for (tree_next = -1, sym_index = 0;
2717 sym_index < r->m_table_sizes[r->m_type]; ++sym_index) {
2718 mz_uint rev_code = 0, l, cur_code,
2719 code_size = pTable->m_code_size[sym_index];
2720 if (!code_size) continue;
2721 cur_code = next_code[code_size]++;
2722 for (l = code_size; l > 0; l--, cur_code >>= 1)
2723 rev_code = (rev_code << 1) | (cur_code & 1);
2724 if (code_size <= TINFL_FAST_LOOKUP_BITS) {
2725 mz_int16 k = (mz_int16)((code_size << 9) | sym_index);
2726 while (rev_code < TINFL_FAST_LOOKUP_SIZE) {
2727 pTable->m_look_up[rev_code] = k;
2728 rev_code += (1 << code_size);
2729 }
2730 continue;
2731 }
2732 if (0 ==
2733 (tree_cur = pTable->m_look_up[rev_code &
2734 (TINFL_FAST_LOOKUP_SIZE - 1)])) {
2735 pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] =
2736 (mz_int16)tree_next;
2737 tree_cur = tree_next;
2738 tree_next -= 2;
2739 }
2740 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
2741 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) {
2742 tree_cur -= ((rev_code >>= 1) & 1);
2743 if (!pTable->m_tree[-tree_cur - 1]) {
2744 pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next;
2745 tree_cur = tree_next;
2746 tree_next -= 2;
2747 } else
2748 tree_cur = pTable->m_tree[-tree_cur - 1];
2749 }
2750 tree_cur -= ((rev_code >>= 1) & 1);
2751 pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
2752 }
2753 if (r->m_type == 2) {
2754 for (counter = 0;
2755 counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) {
2756 mz_uint s;
2757 TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]);
2758 if (dist < 16) {
2759 r->m_len_codes[counter++] = (mz_uint8)dist;
2760 continue;
2761 }
2762 if ((dist == 16) && (!counter)) {
2763 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
2764 }
2765 num_extra = "\02\03\07"[dist - 16];
2766 TINFL_GET_BITS(18, s, num_extra);
2767 s += "\03\03\013"[dist - 16];
2768 TINFL_MEMSET(r->m_len_codes + counter,
2769 (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);
2770 counter += s;
2771 }
2772 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) {
2773 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
2774 }
2775 TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes,
2776 r->m_table_sizes[0]);
2777 TINFL_MEMCPY(r->m_tables[1].m_code_size,
2778 r->m_len_codes + r->m_table_sizes[0],
2779 r->m_table_sizes[1]);
2780 }
2781 }
2782 for (;;) {
2783 mz_uint8 *pSrc;
2784 for (;;) {
2785 if (((pIn_buf_end - pIn_buf_cur) < 4) ||
2786 ((pOut_buf_end - pOut_buf_cur) < 2)) {
2787 TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
2788 if (counter >= 256) break;
2789 while (pOut_buf_cur >= pOut_buf_end) {
2790 TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);
2791 }
2792 *pOut_buf_cur++ = (mz_uint8)counter;
2793 } else {
2794 int sym2;
2795 mz_uint code_len;
2796 #if TINFL_USE_64BIT_BITBUF
2797 if (num_bits < 30) {
2798 bit_buf |=
2799 (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);
2800 pIn_buf_cur += 4;
2801 num_bits += 32;
2802 }
2803 #else
2804 if (num_bits < 15) {
2805 bit_buf |=
2806 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2807 pIn_buf_cur += 2;
2808 num_bits += 16;
2809 }
2810 #endif
2811 if ((sym2 =
2812 r->m_tables[0]
2813 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2814 0)
2815 code_len = sym2 >> 9;
2816 else {
2817 code_len = TINFL_FAST_LOOKUP_BITS;
2818 do {
2819 sym2 = r->m_tables[0]
2820 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
2821 } while (sym2 < 0);
2822 }
2823 counter = sym2;
2824 bit_buf >>= code_len;
2825 num_bits -= code_len;
2826 if (counter & 256) break;
2827
2828 #if !TINFL_USE_64BIT_BITBUF
2829 if (num_bits < 15) {
2830 bit_buf |=
2831 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2832 pIn_buf_cur += 2;
2833 num_bits += 16;
2834 }
2835 #endif
2836 if ((sym2 =
2837 r->m_tables[0]
2838 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2839 0)
2840 code_len = sym2 >> 9;
2841 else {
2842 code_len = TINFL_FAST_LOOKUP_BITS;
2843 do {
2844 sym2 = r->m_tables[0]
2845 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
2846 } while (sym2 < 0);
2847 }
2848 bit_buf >>= code_len;
2849 num_bits -= code_len;
2850
2851 pOut_buf_cur[0] = (mz_uint8)counter;
2852 if (sym2 & 256) {
2853 pOut_buf_cur++;
2854 counter = sym2;
2855 break;
2856 }
2857 pOut_buf_cur[1] = (mz_uint8)sym2;
2858 pOut_buf_cur += 2;
2859 }
2860 }
2861 if ((counter &= 511) == 256) break;
2862
2863 num_extra = s_length_extra[counter - 257];
2864 counter = s_length_base[counter - 257];
2865 if (num_extra) {
2866 mz_uint extra_bits;
2867 TINFL_GET_BITS(25, extra_bits, num_extra);
2868 counter += extra_bits;
2869 }
2870
2871 TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
2872 num_extra = s_dist_extra[dist];
2873 dist = s_dist_base[dist];
2874 if (num_extra) {
2875 mz_uint extra_bits;
2876 TINFL_GET_BITS(27, extra_bits, num_extra);
2877 dist += extra_bits;
2878 }
2879
2880 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
2881 if ((dist > dist_from_out_buf_start) &&
2882 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) {
2883 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
2884 }
2885
2886 pSrc = pOut_buf_start +
2887 ((dist_from_out_buf_start - dist) & out_buf_size_mask);
2888
2889 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) {
2890 while (counter--) {
2891 while (pOut_buf_cur >= pOut_buf_end) {
2892 TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);
2893 }
2894 *pOut_buf_cur++ =
2895 pOut_buf_start[(dist_from_out_buf_start++ - dist) &
2896 out_buf_size_mask];
2897 }
2898 continue;
2899 }
2900 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
2901 else if ((counter >= 9) && (counter <= dist)) {
2902 const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
2903 do {
2904 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
2905 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
2906 pOut_buf_cur += 8;
2907 } while ((pSrc += 8) < pSrc_end);
2908 if ((counter &= 7) < 3) {
2909 if (counter) {
2910 pOut_buf_cur[0] = pSrc[0];
2911 if (counter > 1) pOut_buf_cur[1] = pSrc[1];
2912 pOut_buf_cur += counter;
2913 }
2914 continue;
2915 }
2916 }
2917 #endif
2918 do {
2919 pOut_buf_cur[0] = pSrc[0];
2920 pOut_buf_cur[1] = pSrc[1];
2921 pOut_buf_cur[2] = pSrc[2];
2922 pOut_buf_cur += 3;
2923 pSrc += 3;
2924 } while ((int)(counter -= 3) > 2);
2925 if ((int)counter > 0) {
2926 pOut_buf_cur[0] = pSrc[0];
2927 if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1];
2928 pOut_buf_cur += counter;
2929 }
2930 }
2931 }
2932 } while (!(r->m_final & 1));
2933 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2934 TINFL_SKIP_BITS(32, num_bits & 7);
2935 for (counter = 0; counter < 4; ++counter) {
2936 mz_uint s;
2937 if (num_bits)
2938 TINFL_GET_BITS(41, s, 8);
2939 else
2940 TINFL_GET_BYTE(42, s);
2941 r->m_z_adler32 = (r->m_z_adler32 << 8) | s;
2942 }
2943 }
2944 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
2945 TINFL_CR_FINISH
2946
2947 common_exit:
2948 r->m_num_bits = num_bits;
2949 r->m_bit_buf = bit_buf;
2950 r->m_dist = dist;
2951 r->m_counter = counter;
2952 r->m_num_extra = num_extra;
2953 r->m_dist_from_out_buf_start = dist_from_out_buf_start;
2954 *pIn_buf_size = pIn_buf_cur - pIn_buf_next;
2955 *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
2956 if ((decomp_flags &
2957 (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) &&
2958 (status >= 0)) {
2959 const mz_uint8 *ptr = pOut_buf_next;
2960 size_t buf_len = *pOut_buf_size;
2961 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff,
2962 s2 = r->m_check_adler32 >> 16;
2963 size_t block_len = buf_len % 5552;
2964 while (buf_len) {
2965 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
2966 s1 += ptr[0], s2 += s1;
2967 s1 += ptr[1], s2 += s1;
2968 s1 += ptr[2], s2 += s1;
2969 s1 += ptr[3], s2 += s1;
2970 s1 += ptr[4], s2 += s1;
2971 s1 += ptr[5], s2 += s1;
2972 s1 += ptr[6], s2 += s1;
2973 s1 += ptr[7], s2 += s1;
2974 }
2975 for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
2976 s1 %= 65521U, s2 %= 65521U;
2977 buf_len -= block_len;
2978 block_len = 5552;
2979 }
2980 r->m_check_adler32 = (s2 << 16) + s1;
2981 if ((status == TINFL_STATUS_DONE) &&
2982 (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) &&
2983 (r->m_check_adler32 != r->m_z_adler32))
2984 status = TINFL_STATUS_ADLER32_MISMATCH;
2985 }
2986 return status;
2987 }
2988
2989 // Higher level helper functions.
tinfl_decompress_mem_to_heap(const void * pSrc_buf,size_t src_buf_len,size_t * pOut_len,int flags)2990 void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
2991 size_t *pOut_len, int flags) {
2992 tinfl_decompressor decomp;
2993 void *pBuf = NULL, *pNew_buf;
2994 size_t src_buf_ofs = 0, out_buf_capacity = 0;
2995 *pOut_len = 0;
2996 tinfl_init(&decomp);
2997 for (;;) {
2998 size_t src_buf_size = src_buf_len - src_buf_ofs,
2999 dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
3000 tinfl_status status = tinfl_decompress(
3001 &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
3002 (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
3003 &dst_buf_size,
3004 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
3005 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
3006 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
3007 MZ_FREE(pBuf);
3008 *pOut_len = 0;
3009 return NULL;
3010 }
3011 src_buf_ofs += src_buf_size;
3012 *pOut_len += dst_buf_size;
3013 if (status == TINFL_STATUS_DONE) break;
3014 new_out_buf_capacity = out_buf_capacity * 2;
3015 if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
3016 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
3017 if (!pNew_buf) {
3018 MZ_FREE(pBuf);
3019 *pOut_len = 0;
3020 return NULL;
3021 }
3022 pBuf = pNew_buf;
3023 out_buf_capacity = new_out_buf_capacity;
3024 }
3025 return pBuf;
3026 }
3027
tinfl_decompress_mem_to_mem(void * pOut_buf,size_t out_buf_len,const void * pSrc_buf,size_t src_buf_len,int flags)3028 size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
3029 const void *pSrc_buf, size_t src_buf_len,
3030 int flags) {
3031 tinfl_decompressor decomp;
3032 tinfl_status status;
3033 tinfl_init(&decomp);
3034 status =
3035 tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len,
3036 (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len,
3037 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
3038 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
3039 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED
3040 : out_buf_len;
3041 }
3042
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)3043 int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
3044 tinfl_put_buf_func_ptr pPut_buf_func,
3045 void *pPut_buf_user, int flags) {
3046 int result = 0;
3047 tinfl_decompressor decomp;
3048 mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);
3049 size_t in_buf_ofs = 0, dict_ofs = 0;
3050 if (!pDict) return TINFL_STATUS_FAILED;
3051 tinfl_init(&decomp);
3052 for (;;) {
3053 size_t in_buf_size = *pIn_buf_size - in_buf_ofs,
3054 dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
3055 tinfl_status status =
3056 tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
3057 &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
3058 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
3059 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
3060 in_buf_ofs += in_buf_size;
3061 if ((dst_buf_size) &&
3062 (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
3063 break;
3064 if (status != TINFL_STATUS_HAS_MORE_OUTPUT) {
3065 result = (status == TINFL_STATUS_DONE);
3066 break;
3067 }
3068 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
3069 }
3070 MZ_FREE(pDict);
3071 *pIn_buf_size = in_buf_ofs;
3072 return result;
3073 }
3074
3075 // ------------------- Low-level Compression (independent from all decompression
3076 // API's)
3077
3078 // Purposely making these tables static for faster init and thread safety.
3079 static const mz_uint16 s_tdefl_len_sym[256] = {
3080 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268,
3081 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272,
3082 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274,
3083 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276,
3084 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
3085 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
3086 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279,
3087 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280,
3088 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281,
3089 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
3090 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282,
3091 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
3092 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283,
3093 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
3094 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284,
3095 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
3096 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
3097 285};
3098
3099 static const mz_uint8 s_tdefl_len_extra[256] = {
3100 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
3101 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3102 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
3103 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3104 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3105 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3106 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3107 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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,
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,
3110 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0};
3111
3112 static const mz_uint8 s_tdefl_small_dist_sym[512] = {
3113 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
3114 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
3115 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
3116 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
3117 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
3118 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3119 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14,
3120 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
3121 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
3122 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
3123 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
3124 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
3125 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
3126 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3127 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3128 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3129 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3130 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3131 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3132 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3133 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3134 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3135 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3136 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3137 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3138 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3139 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17};
3140
3141 static const mz_uint8 s_tdefl_small_dist_extra[512] = {
3142 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,
3143 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,
3144 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,
3145 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,
3146 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,
3147 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,
3148 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,
3149 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,
3150 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,
3151 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,
3152 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,
3153 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,
3154 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,
3155 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,
3156 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,
3157 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,
3158 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,
3159 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,
3160 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,
3161 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,
3162 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
3163
3164 static const mz_uint8 s_tdefl_large_dist_sym[128] = {
3165 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24,
3166 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
3167 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27,
3168 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
3169 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
3170 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
3171 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29};
3172
3173 static const mz_uint8 s_tdefl_large_dist_extra[128] = {
3174 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
3175 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
3176 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
3177 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3178 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3179 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3180 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
3181
3182 // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
3183 // values.
3184 typedef struct {
3185 mz_uint16 m_key, m_sym_index;
3186 } tdefl_sym_freq;
tdefl_radix_sort_syms(mz_uint num_syms,tdefl_sym_freq * pSyms0,tdefl_sym_freq * pSyms1)3187 static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
3188 tdefl_sym_freq *pSyms0,
3189 tdefl_sym_freq *pSyms1) {
3190 mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];
3191 tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;
3192 MZ_CLEAR_OBJ(hist);
3193 for (i = 0; i < num_syms; i++) {
3194 mz_uint freq = pSyms0[i].m_key;
3195 hist[freq & 0xFF]++;
3196 hist[256 + ((freq >> 8) & 0xFF)]++;
3197 }
3198 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))
3199 total_passes--;
3200 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) {
3201 const mz_uint32 *pHist = &hist[pass << 8];
3202 mz_uint offsets[256], cur_ofs = 0;
3203 for (i = 0; i < 256; i++) {
3204 offsets[i] = cur_ofs;
3205 cur_ofs += pHist[i];
3206 }
3207 for (i = 0; i < num_syms; i++)
3208 pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] =
3209 pCur_syms[i];
3210 {
3211 tdefl_sym_freq *t = pCur_syms;
3212 pCur_syms = pNew_syms;
3213 pNew_syms = t;
3214 }
3215 }
3216 return pCur_syms;
3217 }
3218
3219 // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat,
3220 // alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
tdefl_calculate_minimum_redundancy(tdefl_sym_freq * A,int n)3221 static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) {
3222 int root, leaf, next, avbl, used, dpth;
3223 if (n == 0)
3224 return;
3225 else if (n == 1) {
3226 A[0].m_key = 1;
3227 return;
3228 }
3229 A[0].m_key += A[1].m_key;
3230 root = 0;
3231 leaf = 2;
3232 for (next = 1; next < n - 1; next++) {
3233 if (leaf >= n || A[root].m_key < A[leaf].m_key) {
3234 A[next].m_key = A[root].m_key;
3235 A[root++].m_key = (mz_uint16)next;
3236 } else
3237 A[next].m_key = A[leaf++].m_key;
3238 if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) {
3239 A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);
3240 A[root++].m_key = (mz_uint16)next;
3241 } else
3242 A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
3243 }
3244 A[n - 2].m_key = 0;
3245 for (next = n - 3; next >= 0; next--)
3246 A[next].m_key = A[A[next].m_key].m_key + 1;
3247 avbl = 1;
3248 used = dpth = 0;
3249 root = n - 2;
3250 next = n - 1;
3251 while (avbl > 0) {
3252 while (root >= 0 && (int)A[root].m_key == dpth) {
3253 used++;
3254 root--;
3255 }
3256 while (avbl > used) {
3257 A[next--].m_key = (mz_uint16)(dpth);
3258 avbl--;
3259 }
3260 avbl = 2 * used;
3261 dpth++;
3262 used = 0;
3263 }
3264 }
3265
3266 // Limits canonical Huffman code table's max code size.
3267 enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
tdefl_huffman_enforce_max_code_size(int * pNum_codes,int code_list_len,int max_code_size)3268 static void tdefl_huffman_enforce_max_code_size(int *pNum_codes,
3269 int code_list_len,
3270 int max_code_size) {
3271 int i;
3272 mz_uint32 total = 0;
3273 if (code_list_len <= 1) return;
3274 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)
3275 pNum_codes[max_code_size] += pNum_codes[i];
3276 for (i = max_code_size; i > 0; i--)
3277 total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
3278 while (total != (1UL << max_code_size)) {
3279 pNum_codes[max_code_size]--;
3280 for (i = max_code_size - 1; i > 0; i--)
3281 if (pNum_codes[i]) {
3282 pNum_codes[i]--;
3283 pNum_codes[i + 1] += 2;
3284 break;
3285 }
3286 total--;
3287 }
3288 }
3289
tdefl_optimize_huffman_table(tdefl_compressor * d,int table_num,int table_len,int code_size_limit,int static_table)3290 static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num,
3291 int table_len, int code_size_limit,
3292 int static_table) {
3293 int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];
3294 mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];
3295 MZ_CLEAR_OBJ(num_codes);
3296 if (static_table) {
3297 for (i = 0; i < table_len; i++)
3298 num_codes[d->m_huff_code_sizes[table_num][i]]++;
3299 } else {
3300 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS],
3301 *pSyms;
3302 int num_used_syms = 0;
3303 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
3304 for (i = 0; i < table_len; i++)
3305 if (pSym_count[i]) {
3306 syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];
3307 syms0[num_used_syms++].m_sym_index = (mz_uint16)i;
3308 }
3309
3310 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);
3311 tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
3312
3313 for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++;
3314
3315 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms,
3316 code_size_limit);
3317
3318 MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]);
3319 MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
3320 for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
3321 for (l = num_codes[i]; l > 0; l--)
3322 d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
3323 }
3324
3325 next_code[1] = 0;
3326 for (j = 0, i = 2; i <= code_size_limit; i++)
3327 next_code[i] = j = ((j + num_codes[i - 1]) << 1);
3328
3329 for (i = 0; i < table_len; i++) {
3330 mz_uint rev_code = 0, code, code_size;
3331 if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue;
3332 code = next_code[code_size]++;
3333 for (l = code_size; l > 0; l--, code >>= 1)
3334 rev_code = (rev_code << 1) | (code & 1);
3335 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
3336 }
3337 }
3338
3339 #define TDEFL_PUT_BITS(b, l) \
3340 do { \
3341 mz_uint bits = b; \
3342 mz_uint len = l; \
3343 MZ_ASSERT(bits <= ((1U << len) - 1U)); \
3344 d->m_bit_buffer |= (bits << d->m_bits_in); \
3345 d->m_bits_in += len; \
3346 while (d->m_bits_in >= 8) { \
3347 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
3348 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
3349 d->m_bit_buffer >>= 8; \
3350 d->m_bits_in -= 8; \
3351 } \
3352 } \
3353 MZ_MACRO_END
3354
3355 #define TDEFL_RLE_PREV_CODE_SIZE() \
3356 { \
3357 if (rle_repeat_count) { \
3358 if (rle_repeat_count < 3) { \
3359 d->m_huff_count[2][prev_code_size] = (mz_uint16)( \
3360 d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
3361 while (rle_repeat_count--) \
3362 packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
3363 } else { \
3364 d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \
3365 packed_code_sizes[num_packed_code_sizes++] = 16; \
3366 packed_code_sizes[num_packed_code_sizes++] = \
3367 (mz_uint8)(rle_repeat_count - 3); \
3368 } \
3369 rle_repeat_count = 0; \
3370 } \
3371 }
3372
3373 #define TDEFL_RLE_ZERO_CODE_SIZE() \
3374 { \
3375 if (rle_z_count) { \
3376 if (rle_z_count < 3) { \
3377 d->m_huff_count[2][0] = \
3378 (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \
3379 while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \
3380 } else if (rle_z_count <= 10) { \
3381 d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \
3382 packed_code_sizes[num_packed_code_sizes++] = 17; \
3383 packed_code_sizes[num_packed_code_sizes++] = \
3384 (mz_uint8)(rle_z_count - 3); \
3385 } else { \
3386 d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \
3387 packed_code_sizes[num_packed_code_sizes++] = 18; \
3388 packed_code_sizes[num_packed_code_sizes++] = \
3389 (mz_uint8)(rle_z_count - 11); \
3390 } \
3391 rle_z_count = 0; \
3392 } \
3393 }
3394
3395 static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {
3396 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
3397
tdefl_start_dynamic_block(tdefl_compressor * d)3398 static void tdefl_start_dynamic_block(tdefl_compressor *d) {
3399 int num_lit_codes, num_dist_codes, num_bit_lengths;
3400 mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count,
3401 rle_repeat_count, packed_code_sizes_index;
3402 mz_uint8
3403 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
3404 packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
3405 prev_code_size = 0xFF;
3406
3407 d->m_huff_count[0][256] = 1;
3408
3409 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
3410 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
3411
3412 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)
3413 if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break;
3414 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)
3415 if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break;
3416
3417 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
3418 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0],
3419 num_dist_codes);
3420 total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
3421 num_packed_code_sizes = 0;
3422 rle_z_count = 0;
3423 rle_repeat_count = 0;
3424
3425 memset(&d->m_huff_count[2][0], 0,
3426 sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
3427 for (i = 0; i < total_code_sizes_to_pack; i++) {
3428 mz_uint8 code_size = code_sizes_to_pack[i];
3429 if (!code_size) {
3430 TDEFL_RLE_PREV_CODE_SIZE();
3431 if (++rle_z_count == 138) {
3432 TDEFL_RLE_ZERO_CODE_SIZE();
3433 }
3434 } else {
3435 TDEFL_RLE_ZERO_CODE_SIZE();
3436 if (code_size != prev_code_size) {
3437 TDEFL_RLE_PREV_CODE_SIZE();
3438 d->m_huff_count[2][code_size] =
3439 (mz_uint16)(d->m_huff_count[2][code_size] + 1);
3440 packed_code_sizes[num_packed_code_sizes++] = code_size;
3441 } else if (++rle_repeat_count == 6) {
3442 TDEFL_RLE_PREV_CODE_SIZE();
3443 }
3444 }
3445 prev_code_size = code_size;
3446 }
3447 if (rle_repeat_count) {
3448 TDEFL_RLE_PREV_CODE_SIZE();
3449 } else {
3450 TDEFL_RLE_ZERO_CODE_SIZE();
3451 }
3452
3453 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
3454
3455 TDEFL_PUT_BITS(2, 2);
3456
3457 TDEFL_PUT_BITS(num_lit_codes - 257, 5);
3458 TDEFL_PUT_BITS(num_dist_codes - 1, 5);
3459
3460 for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)
3461 if (d->m_huff_code_sizes
3462 [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])
3463 break;
3464 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));
3465 TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
3466 for (i = 0; (int)i < num_bit_lengths; i++)
3467 TDEFL_PUT_BITS(
3468 d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
3469
3470 for (packed_code_sizes_index = 0;
3471 packed_code_sizes_index < num_packed_code_sizes;) {
3472 mz_uint code = packed_code_sizes[packed_code_sizes_index++];
3473 MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
3474 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
3475 if (code >= 16)
3476 TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++],
3477 "\02\03\07"[code - 16]);
3478 }
3479 }
3480
tdefl_start_static_block(tdefl_compressor * d)3481 static void tdefl_start_static_block(tdefl_compressor *d) {
3482 mz_uint i;
3483 mz_uint8 *p = &d->m_huff_code_sizes[0][0];
3484
3485 for (i = 0; i <= 143; ++i) *p++ = 8;
3486 for (; i <= 255; ++i) *p++ = 9;
3487 for (; i <= 279; ++i) *p++ = 7;
3488 for (; i <= 287; ++i) *p++ = 8;
3489
3490 memset(d->m_huff_code_sizes[1], 5, 32);
3491
3492 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
3493 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
3494
3495 TDEFL_PUT_BITS(1, 2);
3496 }
3497
3498 static const mz_uint mz_bitmasks[17] = {
3499 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
3500 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
3501
3502 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \
3503 MINIZ_HAS_64BIT_REGISTERS
tdefl_compress_lz_codes(tdefl_compressor * d)3504 static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
3505 mz_uint flags;
3506 mz_uint8 *pLZ_codes;
3507 mz_uint8 *pOutput_buf = d->m_pOutput_buf;
3508 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
3509 mz_uint64 bit_buffer = d->m_bit_buffer;
3510 mz_uint bits_in = d->m_bits_in;
3511
3512 #define TDEFL_PUT_BITS_FAST(b, l) \
3513 { \
3514 bit_buffer |= (((mz_uint64)(b)) << bits_in); \
3515 bits_in += (l); \
3516 }
3517
3518 flags = 1;
3519 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end;
3520 flags >>= 1) {
3521 if (flags == 1) flags = *pLZ_codes++ | 0x100;
3522
3523 if (flags & 1) {
3524 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
3525 mz_uint match_len = pLZ_codes[0],
3526 match_dist = *(const mz_uint16 *)(pLZ_codes + 1);
3527 pLZ_codes += 3;
3528
3529 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3530 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
3531 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3532 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
3533 s_tdefl_len_extra[match_len]);
3534
3535 // This sequence coaxes MSVC into using cmov's vs. jmp's.
3536 s0 = s_tdefl_small_dist_sym[match_dist & 511];
3537 n0 = s_tdefl_small_dist_extra[match_dist & 511];
3538 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
3539 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
3540 sym = (match_dist < 512) ? s0 : s1;
3541 num_extra_bits = (match_dist < 512) ? n0 : n1;
3542
3543 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
3544 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym],
3545 d->m_huff_code_sizes[1][sym]);
3546 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits],
3547 num_extra_bits);
3548 } else {
3549 mz_uint lit = *pLZ_codes++;
3550 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3551 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3552 d->m_huff_code_sizes[0][lit]);
3553
3554 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3555 flags >>= 1;
3556 lit = *pLZ_codes++;
3557 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3558 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3559 d->m_huff_code_sizes[0][lit]);
3560
3561 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3562 flags >>= 1;
3563 lit = *pLZ_codes++;
3564 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3565 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3566 d->m_huff_code_sizes[0][lit]);
3567 }
3568 }
3569 }
3570
3571 if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE;
3572
3573 *(mz_uint64 *)pOutput_buf = bit_buffer;
3574 pOutput_buf += (bits_in >> 3);
3575 bit_buffer >>= (bits_in & ~7);
3576 bits_in &= 7;
3577 }
3578
3579 #undef TDEFL_PUT_BITS_FAST
3580
3581 d->m_pOutput_buf = pOutput_buf;
3582 d->m_bits_in = 0;
3583 d->m_bit_buffer = 0;
3584
3585 while (bits_in) {
3586 mz_uint32 n = MZ_MIN(bits_in, 16);
3587 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
3588 bit_buffer >>= n;
3589 bits_in -= n;
3590 }
3591
3592 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3593
3594 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3595 }
3596 #else
tdefl_compress_lz_codes(tdefl_compressor * d)3597 static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
3598 mz_uint flags;
3599 mz_uint8 *pLZ_codes;
3600
3601 flags = 1;
3602 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf;
3603 flags >>= 1) {
3604 if (flags == 1) flags = *pLZ_codes++ | 0x100;
3605 if (flags & 1) {
3606 mz_uint sym, num_extra_bits;
3607 mz_uint match_len = pLZ_codes[0],
3608 match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
3609 pLZ_codes += 3;
3610
3611 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3612 TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
3613 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3614 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
3615 s_tdefl_len_extra[match_len]);
3616
3617 if (match_dist < 512) {
3618 sym = s_tdefl_small_dist_sym[match_dist];
3619 num_extra_bits = s_tdefl_small_dist_extra[match_dist];
3620 } else {
3621 sym = s_tdefl_large_dist_sym[match_dist >> 8];
3622 num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
3623 }
3624 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
3625 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
3626 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
3627 } else {
3628 mz_uint lit = *pLZ_codes++;
3629 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3630 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
3631 }
3632 }
3633
3634 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3635
3636 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3637 }
3638 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN &&
3639 // MINIZ_HAS_64BIT_REGISTERS
3640
tdefl_compress_block(tdefl_compressor * d,mz_bool static_block)3641 static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) {
3642 if (static_block)
3643 tdefl_start_static_block(d);
3644 else
3645 tdefl_start_dynamic_block(d);
3646 return tdefl_compress_lz_codes(d);
3647 }
3648
tdefl_flush_block(tdefl_compressor * d,int flush)3649 static int tdefl_flush_block(tdefl_compressor *d, int flush) {
3650 mz_uint saved_bit_buf, saved_bits_in;
3651 mz_uint8 *pSaved_output_buf;
3652 mz_bool comp_block_succeeded = MZ_FALSE;
3653 int n, use_raw_block =
3654 ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
3655 (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
3656 mz_uint8 *pOutput_buf_start =
3657 ((d->m_pPut_buf_func == NULL) &&
3658 ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE))
3659 ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs)
3660 : d->m_output_buf;
3661
3662 d->m_pOutput_buf = pOutput_buf_start;
3663 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
3664
3665 MZ_ASSERT(!d->m_output_flush_remaining);
3666 d->m_output_flush_ofs = 0;
3667 d->m_output_flush_remaining = 0;
3668
3669 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
3670 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
3671
3672 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) {
3673 TDEFL_PUT_BITS(0x78, 8);
3674 TDEFL_PUT_BITS(0x01, 8);
3675 }
3676
3677 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
3678
3679 pSaved_output_buf = d->m_pOutput_buf;
3680 saved_bit_buf = d->m_bit_buffer;
3681 saved_bits_in = d->m_bits_in;
3682
3683 if (!use_raw_block)
3684 comp_block_succeeded =
3685 tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
3686 (d->m_total_lz_bytes < 48));
3687
3688 // If the block gets expanded, forget the current contents of the output
3689 // buffer and send a raw block instead.
3690 if (((use_raw_block) ||
3691 ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >=
3692 d->m_total_lz_bytes))) &&
3693 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) {
3694 mz_uint i;
3695 d->m_pOutput_buf = pSaved_output_buf;
3696 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3697 TDEFL_PUT_BITS(0, 2);
3698 if (d->m_bits_in) {
3699 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3700 }
3701 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) {
3702 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
3703 }
3704 for (i = 0; i < d->m_total_lz_bytes; ++i) {
3705 TDEFL_PUT_BITS(
3706 d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK],
3707 8);
3708 }
3709 }
3710 // Check for the extremely unlikely (if not impossible) case of the compressed
3711 // block not fitting into the output buffer when using dynamic codes.
3712 else if (!comp_block_succeeded) {
3713 d->m_pOutput_buf = pSaved_output_buf;
3714 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3715 tdefl_compress_block(d, MZ_TRUE);
3716 }
3717
3718 if (flush) {
3719 if (flush == TDEFL_FINISH) {
3720 if (d->m_bits_in) {
3721 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3722 }
3723 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) {
3724 mz_uint i, a = d->m_adler32;
3725 for (i = 0; i < 4; i++) {
3726 TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);
3727 a <<= 8;
3728 }
3729 }
3730 } else {
3731 mz_uint i, z = 0;
3732 TDEFL_PUT_BITS(0, 3);
3733 if (d->m_bits_in) {
3734 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3735 }
3736 for (i = 2; i; --i, z ^= 0xFFFF) {
3737 TDEFL_PUT_BITS(z & 0xFFFF, 16);
3738 }
3739 }
3740 }
3741
3742 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
3743
3744 memset(&d->m_huff_count[0][0], 0,
3745 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
3746 memset(&d->m_huff_count[1][0], 0,
3747 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
3748
3749 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
3750 d->m_pLZ_flags = d->m_lz_code_buf;
3751 d->m_num_flags_left = 8;
3752 d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;
3753 d->m_total_lz_bytes = 0;
3754 d->m_block_index++;
3755
3756 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) {
3757 if (d->m_pPut_buf_func) {
3758 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
3759 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
3760 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
3761 } else if (pOutput_buf_start == d->m_output_buf) {
3762 int bytes_to_copy = (int)MZ_MIN(
3763 (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
3764 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf,
3765 bytes_to_copy);
3766 d->m_out_buf_ofs += bytes_to_copy;
3767 if ((n -= bytes_to_copy) != 0) {
3768 d->m_output_flush_ofs = bytes_to_copy;
3769 d->m_output_flush_remaining = n;
3770 }
3771 } else {
3772 d->m_out_buf_ofs += n;
3773 }
3774 }
3775
3776 return d->m_output_flush_remaining;
3777 }
3778
3779 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
3780 #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)3781 static MZ_FORCEINLINE void tdefl_find_match(
3782 tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3783 mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) {
3784 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3785 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3786 probe_len;
3787 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3788 const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;
3789 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]),
3790 s01 = TDEFL_READ_UNALIGNED_WORD(s);
3791 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3792 if (max_match_len <= match_len) return;
3793 for (;;) {
3794 for (;;) {
3795 if (--num_probes_left == 0) return;
3796 #define TDEFL_PROBE \
3797 next_probe_pos = d->m_next[probe_pos]; \
3798 if ((!next_probe_pos) || \
3799 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3800 return; \
3801 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3802 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \
3803 break;
3804 TDEFL_PROBE;
3805 TDEFL_PROBE;
3806 TDEFL_PROBE;
3807 }
3808 if (!dist) break;
3809 q = (const mz_uint16 *)(d->m_dict + probe_pos);
3810 if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue;
3811 p = s;
3812 probe_len = 32;
3813 do {
3814 } while (
3815 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3816 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3817 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3818 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3819 (--probe_len > 0));
3820 if (!probe_len) {
3821 *pMatch_dist = dist;
3822 *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN);
3823 break;
3824 } else if ((probe_len = ((mz_uint)(p - s) * 2) +
3825 (mz_uint)(*(const mz_uint8 *)p ==
3826 *(const mz_uint8 *)q)) > match_len) {
3827 *pMatch_dist = dist;
3828 if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) ==
3829 max_match_len)
3830 break;
3831 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
3832 }
3833 }
3834 }
3835 #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)3836 static MZ_FORCEINLINE void tdefl_find_match(
3837 tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3838 mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) {
3839 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3840 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3841 probe_len;
3842 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3843 const mz_uint8 *s = d->m_dict + pos, *p, *q;
3844 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
3845 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3846 if (max_match_len <= match_len) return;
3847 for (;;) {
3848 for (;;) {
3849 if (--num_probes_left == 0) return;
3850 #define TDEFL_PROBE \
3851 next_probe_pos = d->m_next[probe_pos]; \
3852 if ((!next_probe_pos) || \
3853 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3854 return; \
3855 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3856 if ((d->m_dict[probe_pos + match_len] == c0) && \
3857 (d->m_dict[probe_pos + match_len - 1] == c1)) \
3858 break;
3859 TDEFL_PROBE;
3860 TDEFL_PROBE;
3861 TDEFL_PROBE;
3862 }
3863 if (!dist) break;
3864 p = s;
3865 q = d->m_dict + probe_pos;
3866 for (probe_len = 0; probe_len < max_match_len; probe_len++)
3867 if (*p++ != *q++) break;
3868 if (probe_len > match_len) {
3869 *pMatch_dist = dist;
3870 if ((*pMatch_len = match_len = probe_len) == max_match_len) return;
3871 c0 = d->m_dict[pos + match_len];
3872 c1 = d->m_dict[pos + match_len - 1];
3873 }
3874 }
3875 }
3876 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
3877
3878 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
tdefl_compress_fast(tdefl_compressor * d)3879 static mz_bool tdefl_compress_fast(tdefl_compressor *d) {
3880 // Faster, minimally featured LZRW1-style match+parse loop with better
3881 // register utilization. Intended for applications where raw throughput is
3882 // valued more highly than ratio.
3883 mz_uint lookahead_pos = d->m_lookahead_pos,
3884 lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size,
3885 total_lz_bytes = d->m_total_lz_bytes,
3886 num_flags_left = d->m_num_flags_left;
3887 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
3888 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
3889
3890 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) {
3891 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
3892 mz_uint dst_pos =
3893 (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
3894 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
3895 d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
3896 d->m_src_buf_left -= num_bytes_to_process;
3897 lookahead_size += num_bytes_to_process;
3898
3899 while (num_bytes_to_process) {
3900 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
3901 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
3902 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
3903 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc,
3904 MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
3905 d->m_pSrc += n;
3906 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
3907 num_bytes_to_process -= n;
3908 }
3909
3910 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
3911 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))
3912 break;
3913
3914 while (lookahead_size >= 4) {
3915 mz_uint cur_match_dist, cur_match_len = 1;
3916 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
3917 mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
3918 mz_uint hash =
3919 (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) &
3920 TDEFL_LEVEL1_HASH_SIZE_MASK;
3921 mz_uint probe_pos = d->m_hash[hash];
3922 d->m_hash[hash] = (mz_uint16)lookahead_pos;
3923
3924 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <=
3925 dict_size) &&
3926 ((*(const mz_uint32 *)(d->m_dict +
3927 (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) &
3928 0xFFFFFF) == first_trigram)) {
3929 const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
3930 const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
3931 mz_uint32 probe_len = 32;
3932 do {
3933 } while ((TDEFL_READ_UNALIGNED_WORD(++p) ==
3934 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3935 (TDEFL_READ_UNALIGNED_WORD(++p) ==
3936 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3937 (TDEFL_READ_UNALIGNED_WORD(++p) ==
3938 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3939 (TDEFL_READ_UNALIGNED_WORD(++p) ==
3940 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3941 (--probe_len > 0));
3942 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) +
3943 (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
3944 if (!probe_len)
3945 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
3946
3947 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) ||
3948 ((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
3949 (cur_match_dist >= 8U * 1024U))) {
3950 cur_match_len = 1;
3951 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3952 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3953 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3954 } else {
3955 mz_uint32 s0, s1;
3956 cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
3957
3958 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) &&
3959 (cur_match_dist >= 1) &&
3960 (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
3961
3962 cur_match_dist--;
3963
3964 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
3965 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
3966 pLZ_code_buf += 3;
3967 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
3968
3969 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
3970 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
3971 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
3972
3973 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len -
3974 TDEFL_MIN_MATCH_LEN]]++;
3975 }
3976 } else {
3977 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3978 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3979 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3980 }
3981
3982 if (--num_flags_left == 0) {
3983 num_flags_left = 8;
3984 pLZ_flags = pLZ_code_buf++;
3985 }
3986
3987 total_lz_bytes += cur_match_len;
3988 lookahead_pos += cur_match_len;
3989 dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
3990 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
3991 MZ_ASSERT(lookahead_size >= cur_match_len);
3992 lookahead_size -= cur_match_len;
3993
3994 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
3995 int n;
3996 d->m_lookahead_pos = lookahead_pos;
3997 d->m_lookahead_size = lookahead_size;
3998 d->m_dict_size = dict_size;
3999 d->m_total_lz_bytes = total_lz_bytes;
4000 d->m_pLZ_code_buf = pLZ_code_buf;
4001 d->m_pLZ_flags = pLZ_flags;
4002 d->m_num_flags_left = num_flags_left;
4003 if ((n = tdefl_flush_block(d, 0)) != 0)
4004 return (n < 0) ? MZ_FALSE : MZ_TRUE;
4005 total_lz_bytes = d->m_total_lz_bytes;
4006 pLZ_code_buf = d->m_pLZ_code_buf;
4007 pLZ_flags = d->m_pLZ_flags;
4008 num_flags_left = d->m_num_flags_left;
4009 }
4010 }
4011
4012 while (lookahead_size) {
4013 mz_uint8 lit = d->m_dict[cur_pos];
4014
4015 total_lz_bytes++;
4016 *pLZ_code_buf++ = lit;
4017 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
4018 if (--num_flags_left == 0) {
4019 num_flags_left = 8;
4020 pLZ_flags = pLZ_code_buf++;
4021 }
4022
4023 d->m_huff_count[0][lit]++;
4024
4025 lookahead_pos++;
4026 dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
4027 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
4028 lookahead_size--;
4029
4030 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
4031 int n;
4032 d->m_lookahead_pos = lookahead_pos;
4033 d->m_lookahead_size = lookahead_size;
4034 d->m_dict_size = dict_size;
4035 d->m_total_lz_bytes = total_lz_bytes;
4036 d->m_pLZ_code_buf = pLZ_code_buf;
4037 d->m_pLZ_flags = pLZ_flags;
4038 d->m_num_flags_left = num_flags_left;
4039 if ((n = tdefl_flush_block(d, 0)) != 0)
4040 return (n < 0) ? MZ_FALSE : MZ_TRUE;
4041 total_lz_bytes = d->m_total_lz_bytes;
4042 pLZ_code_buf = d->m_pLZ_code_buf;
4043 pLZ_flags = d->m_pLZ_flags;
4044 num_flags_left = d->m_num_flags_left;
4045 }
4046 }
4047 }
4048
4049 d->m_lookahead_pos = lookahead_pos;
4050 d->m_lookahead_size = lookahead_size;
4051 d->m_dict_size = dict_size;
4052 d->m_total_lz_bytes = total_lz_bytes;
4053 d->m_pLZ_code_buf = pLZ_code_buf;
4054 d->m_pLZ_flags = pLZ_flags;
4055 d->m_num_flags_left = num_flags_left;
4056 return MZ_TRUE;
4057 }
4058 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
4059
tdefl_record_literal(tdefl_compressor * d,mz_uint8 lit)4060 static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d,
4061 mz_uint8 lit) {
4062 d->m_total_lz_bytes++;
4063 *d->m_pLZ_code_buf++ = lit;
4064 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);
4065 if (--d->m_num_flags_left == 0) {
4066 d->m_num_flags_left = 8;
4067 d->m_pLZ_flags = d->m_pLZ_code_buf++;
4068 }
4069 d->m_huff_count[0][lit]++;
4070 }
4071
tdefl_record_match(tdefl_compressor * d,mz_uint match_len,mz_uint match_dist)4072 static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d,
4073 mz_uint match_len,
4074 mz_uint match_dist) {
4075 mz_uint32 s0, s1;
4076
4077 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) &&
4078 (match_dist <= TDEFL_LZ_DICT_SIZE));
4079
4080 d->m_total_lz_bytes += match_len;
4081
4082 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
4083
4084 match_dist -= 1;
4085 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
4086 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);
4087 d->m_pLZ_code_buf += 3;
4088
4089 *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);
4090 if (--d->m_num_flags_left == 0) {
4091 d->m_num_flags_left = 8;
4092 d->m_pLZ_flags = d->m_pLZ_code_buf++;
4093 }
4094
4095 s0 = s_tdefl_small_dist_sym[match_dist & 511];
4096 s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
4097 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
4098
4099 if (match_len >= TDEFL_MIN_MATCH_LEN)
4100 d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
4101 }
4102
tdefl_compress_normal(tdefl_compressor * d)4103 static mz_bool tdefl_compress_normal(tdefl_compressor *d) {
4104 const mz_uint8 *pSrc = d->m_pSrc;
4105 size_t src_buf_left = d->m_src_buf_left;
4106 tdefl_flush flush = d->m_flush;
4107
4108 while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) {
4109 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
4110 // Update dictionary and hash chains. Keeps the lookahead size equal to
4111 // TDEFL_MAX_MATCH_LEN.
4112 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) {
4113 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
4114 TDEFL_LZ_DICT_SIZE_MASK,
4115 ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
4116 mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
4117 << TDEFL_LZ_HASH_SHIFT) ^
4118 d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
4119 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
4120 src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
4121 const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
4122 src_buf_left -= num_bytes_to_process;
4123 d->m_lookahead_size += num_bytes_to_process;
4124 while (pSrc != pSrc_end) {
4125 mz_uint8 c = *pSrc++;
4126 d->m_dict[dst_pos] = c;
4127 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
4128 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
4129 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
4130 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
4131 d->m_hash[hash] = (mz_uint16)(ins_pos);
4132 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
4133 ins_pos++;
4134 }
4135 } else {
4136 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) {
4137 mz_uint8 c = *pSrc++;
4138 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
4139 TDEFL_LZ_DICT_SIZE_MASK;
4140 src_buf_left--;
4141 d->m_dict[dst_pos] = c;
4142 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
4143 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
4144 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) {
4145 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
4146 mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
4147 << (TDEFL_LZ_HASH_SHIFT * 2)) ^
4148 (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]
4149 << TDEFL_LZ_HASH_SHIFT) ^
4150 c) &
4151 (TDEFL_LZ_HASH_SIZE - 1);
4152 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
4153 d->m_hash[hash] = (mz_uint16)(ins_pos);
4154 }
4155 }
4156 }
4157 d->m_dict_size =
4158 MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
4159 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break;
4160
4161 // Simple lazy/greedy parsing state machine.
4162 len_to_move = 1;
4163 cur_match_dist = 0;
4164 cur_match_len =
4165 d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);
4166 cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
4167 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) {
4168 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) {
4169 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
4170 cur_match_len = 0;
4171 while (cur_match_len < d->m_lookahead_size) {
4172 if (d->m_dict[cur_pos + cur_match_len] != c) break;
4173 cur_match_len++;
4174 }
4175 if (cur_match_len < TDEFL_MIN_MATCH_LEN)
4176 cur_match_len = 0;
4177 else
4178 cur_match_dist = 1;
4179 }
4180 } else {
4181 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size,
4182 d->m_lookahead_size, &cur_match_dist, &cur_match_len);
4183 }
4184 if (((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
4185 (cur_match_dist >= 8U * 1024U)) ||
4186 (cur_pos == cur_match_dist) ||
4187 ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) {
4188 cur_match_dist = cur_match_len = 0;
4189 }
4190 if (d->m_saved_match_len) {
4191 if (cur_match_len > d->m_saved_match_len) {
4192 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
4193 if (cur_match_len >= 128) {
4194 tdefl_record_match(d, cur_match_len, cur_match_dist);
4195 d->m_saved_match_len = 0;
4196 len_to_move = cur_match_len;
4197 } else {
4198 d->m_saved_lit = d->m_dict[cur_pos];
4199 d->m_saved_match_dist = cur_match_dist;
4200 d->m_saved_match_len = cur_match_len;
4201 }
4202 } else {
4203 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
4204 len_to_move = d->m_saved_match_len - 1;
4205 d->m_saved_match_len = 0;
4206 }
4207 } else if (!cur_match_dist)
4208 tdefl_record_literal(d,
4209 d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
4210 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) ||
4211 (cur_match_len >= 128)) {
4212 tdefl_record_match(d, cur_match_len, cur_match_dist);
4213 len_to_move = cur_match_len;
4214 } else {
4215 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];
4216 d->m_saved_match_dist = cur_match_dist;
4217 d->m_saved_match_len = cur_match_len;
4218 }
4219 // Move the lookahead forward by len_to_move bytes.
4220 d->m_lookahead_pos += len_to_move;
4221 MZ_ASSERT(d->m_lookahead_size >= len_to_move);
4222 d->m_lookahead_size -= len_to_move;
4223 d->m_dict_size =
4224 MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);
4225 // Check if it's time to flush the current LZ codes to the internal output
4226 // buffer.
4227 if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
4228 ((d->m_total_lz_bytes > 31 * 1024) &&
4229 (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >=
4230 d->m_total_lz_bytes) ||
4231 (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) {
4232 int n;
4233 d->m_pSrc = pSrc;
4234 d->m_src_buf_left = src_buf_left;
4235 if ((n = tdefl_flush_block(d, 0)) != 0)
4236 return (n < 0) ? MZ_FALSE : MZ_TRUE;
4237 }
4238 }
4239
4240 d->m_pSrc = pSrc;
4241 d->m_src_buf_left = src_buf_left;
4242 return MZ_TRUE;
4243 }
4244
tdefl_flush_output_buffer(tdefl_compressor * d)4245 static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) {
4246 if (d->m_pIn_buf_size) {
4247 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
4248 }
4249
4250 if (d->m_pOut_buf_size) {
4251 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs,
4252 d->m_output_flush_remaining);
4253 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs,
4254 d->m_output_buf + d->m_output_flush_ofs, n);
4255 d->m_output_flush_ofs += (mz_uint)n;
4256 d->m_output_flush_remaining -= (mz_uint)n;
4257 d->m_out_buf_ofs += n;
4258
4259 *d->m_pOut_buf_size = d->m_out_buf_ofs;
4260 }
4261
4262 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE
4263 : TDEFL_STATUS_OKAY;
4264 }
4265
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)4266 tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
4267 size_t *pIn_buf_size, void *pOut_buf,
4268 size_t *pOut_buf_size, tdefl_flush flush) {
4269 if (!d) {
4270 if (pIn_buf_size) *pIn_buf_size = 0;
4271 if (pOut_buf_size) *pOut_buf_size = 0;
4272 return TDEFL_STATUS_BAD_PARAM;
4273 }
4274
4275 d->m_pIn_buf = pIn_buf;
4276 d->m_pIn_buf_size = pIn_buf_size;
4277 d->m_pOut_buf = pOut_buf;
4278 d->m_pOut_buf_size = pOut_buf_size;
4279 d->m_pSrc = (const mz_uint8 *)(pIn_buf);
4280 d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
4281 d->m_out_buf_ofs = 0;
4282 d->m_flush = flush;
4283
4284 if (((d->m_pPut_buf_func != NULL) ==
4285 ((pOut_buf != NULL) || (pOut_buf_size != NULL))) ||
4286 (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
4287 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) ||
4288 (pIn_buf_size && *pIn_buf_size && !pIn_buf) ||
4289 (pOut_buf_size && *pOut_buf_size && !pOut_buf)) {
4290 if (pIn_buf_size) *pIn_buf_size = 0;
4291 if (pOut_buf_size) *pOut_buf_size = 0;
4292 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
4293 }
4294 d->m_wants_to_finish |= (flush == TDEFL_FINISH);
4295
4296 if ((d->m_output_flush_remaining) || (d->m_finished))
4297 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
4298
4299 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
4300 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
4301 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
4302 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS |
4303 TDEFL_RLE_MATCHES)) == 0)) {
4304 if (!tdefl_compress_fast(d)) return d->m_prev_return_status;
4305 } else
4306 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
4307 {
4308 if (!tdefl_compress_normal(d)) return d->m_prev_return_status;
4309 }
4310
4311 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) &&
4312 (pIn_buf))
4313 d->m_adler32 =
4314 (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf,
4315 d->m_pSrc - (const mz_uint8 *)pIn_buf);
4316
4317 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) &&
4318 (!d->m_output_flush_remaining)) {
4319 if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status;
4320 d->m_finished = (flush == TDEFL_FINISH);
4321 if (flush == TDEFL_FULL_FLUSH) {
4322 MZ_CLEAR_OBJ(d->m_hash);
4323 MZ_CLEAR_OBJ(d->m_next);
4324 d->m_dict_size = 0;
4325 }
4326 }
4327
4328 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
4329 }
4330
tdefl_compress_buffer(tdefl_compressor * d,const void * pIn_buf,size_t in_buf_size,tdefl_flush flush)4331 tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
4332 size_t in_buf_size, tdefl_flush flush) {
4333 MZ_ASSERT(d->m_pPut_buf_func);
4334 return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
4335 }
4336
tdefl_init(tdefl_compressor * d,tdefl_put_buf_func_ptr pPut_buf_func,void * pPut_buf_user,int flags)4337 tdefl_status tdefl_init(tdefl_compressor *d,
4338 tdefl_put_buf_func_ptr pPut_buf_func,
4339 void *pPut_buf_user, int flags) {
4340 d->m_pPut_buf_func = pPut_buf_func;
4341 d->m_pPut_buf_user = pPut_buf_user;
4342 d->m_flags = (mz_uint)(flags);
4343 d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;
4344 d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
4345 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
4346 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash);
4347 d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size =
4348 d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
4349 d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished =
4350 d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
4351 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
4352 d->m_pLZ_flags = d->m_lz_code_buf;
4353 d->m_num_flags_left = 8;
4354 d->m_pOutput_buf = d->m_output_buf;
4355 d->m_pOutput_buf_end = d->m_output_buf;
4356 d->m_prev_return_status = TDEFL_STATUS_OKAY;
4357 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;
4358 d->m_adler32 = 1;
4359 d->m_pIn_buf = NULL;
4360 d->m_pOut_buf = NULL;
4361 d->m_pIn_buf_size = NULL;
4362 d->m_pOut_buf_size = NULL;
4363 d->m_flush = TDEFL_NO_FLUSH;
4364 d->m_pSrc = NULL;
4365 d->m_src_buf_left = 0;
4366 d->m_out_buf_ofs = 0;
4367 memset(&d->m_huff_count[0][0], 0,
4368 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
4369 memset(&d->m_huff_count[1][0], 0,
4370 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
4371 return TDEFL_STATUS_OKAY;
4372 }
4373
tdefl_get_prev_return_status(tdefl_compressor * d)4374 tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) {
4375 return d->m_prev_return_status;
4376 }
4377
tdefl_get_adler32(tdefl_compressor * d)4378 mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; }
4379
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)4380 mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
4381 tdefl_put_buf_func_ptr pPut_buf_func,
4382 void *pPut_buf_user, int flags) {
4383 tdefl_compressor *pComp;
4384 mz_bool succeeded;
4385 if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE;
4386 pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
4387 if (!pComp) return MZ_FALSE;
4388 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) ==
4389 TDEFL_STATUS_OKAY);
4390 succeeded =
4391 succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) ==
4392 TDEFL_STATUS_DONE);
4393 MZ_FREE(pComp);
4394 return succeeded;
4395 }
4396
4397 typedef struct {
4398 size_t m_size, m_capacity;
4399 mz_uint8 *m_pBuf;
4400 mz_bool m_expandable;
4401 } tdefl_output_buffer;
4402
tdefl_output_buffer_putter(const void * pBuf,int len,void * pUser)4403 static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len,
4404 void *pUser) {
4405 tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
4406 size_t new_size = p->m_size + len;
4407 if (new_size > p->m_capacity) {
4408 size_t new_capacity = p->m_capacity;
4409 mz_uint8 *pNew_buf;
4410 if (!p->m_expandable) return MZ_FALSE;
4411 do {
4412 new_capacity = MZ_MAX(128U, new_capacity << 1U);
4413 } while (new_size > new_capacity);
4414 pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);
4415 if (!pNew_buf) return MZ_FALSE;
4416 p->m_pBuf = pNew_buf;
4417 p->m_capacity = new_capacity;
4418 }
4419 memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);
4420 p->m_size = new_size;
4421 return MZ_TRUE;
4422 }
4423
tdefl_compress_mem_to_heap(const void * pSrc_buf,size_t src_buf_len,size_t * pOut_len,int flags)4424 void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
4425 size_t *pOut_len, int flags) {
4426 tdefl_output_buffer out_buf;
4427 MZ_CLEAR_OBJ(out_buf);
4428 if (!pOut_len)
4429 return MZ_FALSE;
4430 else
4431 *pOut_len = 0;
4432 out_buf.m_expandable = MZ_TRUE;
4433 if (!tdefl_compress_mem_to_output(
4434 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
4435 return NULL;
4436 *pOut_len = out_buf.m_size;
4437 return out_buf.m_pBuf;
4438 }
4439
tdefl_compress_mem_to_mem(void * pOut_buf,size_t out_buf_len,const void * pSrc_buf,size_t src_buf_len,int flags)4440 size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
4441 const void *pSrc_buf, size_t src_buf_len,
4442 int flags) {
4443 tdefl_output_buffer out_buf;
4444 MZ_CLEAR_OBJ(out_buf);
4445 if (!pOut_buf) return 0;
4446 out_buf.m_pBuf = (mz_uint8 *)pOut_buf;
4447 out_buf.m_capacity = out_buf_len;
4448 if (!tdefl_compress_mem_to_output(
4449 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
4450 return 0;
4451 return out_buf.m_size;
4452 }
4453
4454 #ifndef MINIZ_NO_ZLIB_APIS
4455 static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32,
4456 128, 256, 512, 768, 1500};
4457
4458 // level may actually range from [0,10] (10 is a "hidden" max level, where we
4459 // want a bit more compression and it's fine if throughput to fall off a cliff
4460 // on some files).
tdefl_create_comp_flags_from_zip_params(int level,int window_bits,int strategy)4461 mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
4462 int strategy) {
4463 mz_uint comp_flags =
4464 s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] |
4465 ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
4466 if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
4467
4468 if (!level)
4469 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
4470 else if (strategy == MZ_FILTERED)
4471 comp_flags |= TDEFL_FILTER_MATCHES;
4472 else if (strategy == MZ_HUFFMAN_ONLY)
4473 comp_flags &= ~TDEFL_MAX_PROBES_MASK;
4474 else if (strategy == MZ_FIXED)
4475 comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
4476 else if (strategy == MZ_RLE)
4477 comp_flags |= TDEFL_RLE_MATCHES;
4478
4479 return comp_flags;
4480 }
4481 #endif // MINIZ_NO_ZLIB_APIS
4482
4483 #ifdef _MSC_VER
4484 #pragma warning(push)
4485 #pragma warning(disable : 4204) // nonstandard extension used : non-constant
4486 // aggregate initializer (also supported by GNU
4487 // C and C99, so no big deal)
4488 #pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
4489 // 'int', possible loss of data
4490 #pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
4491 // 'int', possible loss of data
4492 #pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
4493 // deprecated. Instead, use the ISO C and C++
4494 // conformant name: _strdup.
4495 #endif
4496
4497 // Simple PNG writer function by Alex Evans, 2011. Released into the public
4498 // domain: https://gist.github.com/908299, more context at
4499 // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
4500 // This is actually a modification of Alex's original code so PNG files
4501 // 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)4502 void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
4503 int h, int num_chans,
4504 size_t *pLen_out,
4505 mz_uint level, mz_bool flip) {
4506 // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was
4507 // defined.
4508 static const mz_uint s_tdefl_png_num_probes[11] = {
4509 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500};
4510 tdefl_compressor *pComp =
4511 (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
4512 tdefl_output_buffer out_buf;
4513 int i, bpl = w * num_chans, y, z;
4514 mz_uint32 c;
4515 *pLen_out = 0;
4516 if (!pComp) return NULL;
4517 MZ_CLEAR_OBJ(out_buf);
4518 out_buf.m_expandable = MZ_TRUE;
4519 out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);
4520 if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) {
4521 MZ_FREE(pComp);
4522 return NULL;
4523 }
4524 // write dummy header
4525 for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
4526 // compress image data
4527 tdefl_init(
4528 pComp, tdefl_output_buffer_putter, &out_buf,
4529 s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
4530 for (y = 0; y < h; ++y) {
4531 tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);
4532 tdefl_compress_buffer(pComp,
4533 (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl,
4534 bpl, TDEFL_NO_FLUSH);
4535 }
4536 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) !=
4537 TDEFL_STATUS_DONE) {
4538 MZ_FREE(pComp);
4539 MZ_FREE(out_buf.m_pBuf);
4540 return NULL;
4541 }
4542 // write real header
4543 *pLen_out = out_buf.m_size - 41;
4544 {
4545 static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
4546 mz_uint8 pnghdr[41] = {0x89,
4547 0x50,
4548 0x4e,
4549 0x47,
4550 0x0d,
4551 0x0a,
4552 0x1a,
4553 0x0a,
4554 0x00,
4555 0x00,
4556 0x00,
4557 0x0d,
4558 0x49,
4559 0x48,
4560 0x44,
4561 0x52,
4562 0,
4563 0,
4564 (mz_uint8)(w >> 8),
4565 (mz_uint8)w,
4566 0,
4567 0,
4568 (mz_uint8)(h >> 8),
4569 (mz_uint8)h,
4570 8,
4571 chans[num_chans],
4572 0,
4573 0,
4574 0,
4575 0,
4576 0,
4577 0,
4578 0,
4579 (mz_uint8)(*pLen_out >> 24),
4580 (mz_uint8)(*pLen_out >> 16),
4581 (mz_uint8)(*pLen_out >> 8),
4582 (mz_uint8)*pLen_out,
4583 0x49,
4584 0x44,
4585 0x41,
4586 0x54};
4587 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);
4588 for (i = 0; i < 4; ++i, c <<= 8)
4589 ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);
4590 memcpy(out_buf.m_pBuf, pnghdr, 41);
4591 }
4592 // write footer (IDAT CRC-32, followed by IEND chunk)
4593 if (!tdefl_output_buffer_putter(
4594 "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) {
4595 *pLen_out = 0;
4596 MZ_FREE(pComp);
4597 MZ_FREE(out_buf.m_pBuf);
4598 return NULL;
4599 }
4600 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4,
4601 *pLen_out + 4);
4602 for (i = 0; i < 4; ++i, c <<= 8)
4603 (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);
4604 // compute final size of file, grab compressed data buffer and return
4605 *pLen_out += 57;
4606 MZ_FREE(pComp);
4607 return out_buf.m_pBuf;
4608 }
tdefl_write_image_to_png_file_in_memory(const void * pImage,int w,int h,int num_chans,size_t * pLen_out)4609 void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
4610 int num_chans, size_t *pLen_out) {
4611 // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we
4612 // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's
4613 // where #defined out)
4614 return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans,
4615 pLen_out, 6, MZ_FALSE);
4616 }
4617
4618 // ------------------- .ZIP archive reading
4619
4620 #ifndef MINIZ_NO_ARCHIVE_APIS
4621 #error "No arvhive APIs"
4622
4623 #ifdef MINIZ_NO_STDIO
4624 #define MZ_FILE void *
4625 #else
4626 #include <stdio.h>
4627 #include <sys/stat.h>
4628
4629 #if defined(_MSC_VER) || defined(__MINGW64__)
mz_fopen(const char * pFilename,const char * pMode)4630 static FILE *mz_fopen(const char *pFilename, const char *pMode) {
4631 FILE *pFile = NULL;
4632 fopen_s(&pFile, pFilename, pMode);
4633 return pFile;
4634 }
mz_freopen(const char * pPath,const char * pMode,FILE * pStream)4635 static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) {
4636 FILE *pFile = NULL;
4637 if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL;
4638 return pFile;
4639 }
4640 #ifndef MINIZ_NO_TIME
4641 #include <sys/utime.h>
4642 #endif
4643 #define MZ_FILE FILE
4644 #define MZ_FOPEN mz_fopen
4645 #define MZ_FCLOSE fclose
4646 #define MZ_FREAD fread
4647 #define MZ_FWRITE fwrite
4648 #define MZ_FTELL64 _ftelli64
4649 #define MZ_FSEEK64 _fseeki64
4650 #define MZ_FILE_STAT_STRUCT _stat
4651 #define MZ_FILE_STAT _stat
4652 #define MZ_FFLUSH fflush
4653 #define MZ_FREOPEN mz_freopen
4654 #define MZ_DELETE_FILE remove
4655 #elif defined(__MINGW32__)
4656 #ifndef MINIZ_NO_TIME
4657 #include <sys/utime.h>
4658 #endif
4659 #define MZ_FILE FILE
4660 #define MZ_FOPEN(f, m) fopen(f, m)
4661 #define MZ_FCLOSE fclose
4662 #define MZ_FREAD fread
4663 #define MZ_FWRITE fwrite
4664 #define MZ_FTELL64 ftello64
4665 #define MZ_FSEEK64 fseeko64
4666 #define MZ_FILE_STAT_STRUCT _stat
4667 #define MZ_FILE_STAT _stat
4668 #define MZ_FFLUSH fflush
4669 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4670 #define MZ_DELETE_FILE remove
4671 #elif defined(__TINYC__)
4672 #ifndef MINIZ_NO_TIME
4673 #include <sys/utime.h>
4674 #endif
4675 #define MZ_FILE FILE
4676 #define MZ_FOPEN(f, m) fopen(f, m)
4677 #define MZ_FCLOSE fclose
4678 #define MZ_FREAD fread
4679 #define MZ_FWRITE fwrite
4680 #define MZ_FTELL64 ftell
4681 #define MZ_FSEEK64 fseek
4682 #define MZ_FILE_STAT_STRUCT stat
4683 #define MZ_FILE_STAT stat
4684 #define MZ_FFLUSH fflush
4685 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4686 #define MZ_DELETE_FILE remove
4687 #elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) && _LARGEFILE64_SOURCE
4688 #ifndef MINIZ_NO_TIME
4689 #include <utime.h>
4690 #endif
4691 #define MZ_FILE FILE
4692 #define MZ_FOPEN(f, m) fopen64(f, m)
4693 #define MZ_FCLOSE fclose
4694 #define MZ_FREAD fread
4695 #define MZ_FWRITE fwrite
4696 #define MZ_FTELL64 ftello64
4697 #define MZ_FSEEK64 fseeko64
4698 #define MZ_FILE_STAT_STRUCT stat64
4699 #define MZ_FILE_STAT stat64
4700 #define MZ_FFLUSH fflush
4701 #define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
4702 #define MZ_DELETE_FILE remove
4703 #else
4704 #ifndef MINIZ_NO_TIME
4705 #include <utime.h>
4706 #endif
4707 #define MZ_FILE FILE
4708 #define MZ_FOPEN(f, m) fopen(f, m)
4709 #define MZ_FCLOSE fclose
4710 #define MZ_FREAD fread
4711 #define MZ_FWRITE fwrite
4712 #define MZ_FTELL64 ftello
4713 #define MZ_FSEEK64 fseeko
4714 #define MZ_FILE_STAT_STRUCT stat
4715 #define MZ_FILE_STAT stat
4716 #define MZ_FFLUSH fflush
4717 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4718 #define MZ_DELETE_FILE remove
4719 #endif // #ifdef _MSC_VER
4720 #endif // #ifdef MINIZ_NO_STDIO
4721
4722 #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
4723
4724 // Various ZIP archive enums. To completely avoid cross platform compiler
4725 // alignment and platform endian issues, miniz.c doesn't use structs for any of
4726 // this stuff.
4727 enum {
4728 // ZIP archive identifiers and record sizes
4729 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,
4730 MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,
4731 MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
4732 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
4733 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
4734 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
4735 // Central directory header record offsets
4736 MZ_ZIP_CDH_SIG_OFS = 0,
4737 MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
4738 MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,
4739 MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
4740 MZ_ZIP_CDH_METHOD_OFS = 10,
4741 MZ_ZIP_CDH_FILE_TIME_OFS = 12,
4742 MZ_ZIP_CDH_FILE_DATE_OFS = 14,
4743 MZ_ZIP_CDH_CRC32_OFS = 16,
4744 MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,
4745 MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,
4746 MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,
4747 MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
4748 MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,
4749 MZ_ZIP_CDH_DISK_START_OFS = 34,
4750 MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,
4751 MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,
4752 MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
4753 // Local directory header offsets
4754 MZ_ZIP_LDH_SIG_OFS = 0,
4755 MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,
4756 MZ_ZIP_LDH_BIT_FLAG_OFS = 6,
4757 MZ_ZIP_LDH_METHOD_OFS = 8,
4758 MZ_ZIP_LDH_FILE_TIME_OFS = 10,
4759 MZ_ZIP_LDH_FILE_DATE_OFS = 12,
4760 MZ_ZIP_LDH_CRC32_OFS = 14,
4761 MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,
4762 MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
4763 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,
4764 MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
4765 // End of central directory offsets
4766 MZ_ZIP_ECDH_SIG_OFS = 0,
4767 MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,
4768 MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,
4769 MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
4770 MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,
4771 MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
4772 MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
4773 MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
4774 };
4775
4776 typedef struct {
4777 void *m_p;
4778 size_t m_size, m_capacity;
4779 mz_uint m_element_size;
4780 } mz_zip_array;
4781
4782 struct mz_zip_internal_state_tag {
4783 mz_zip_array m_central_dir;
4784 mz_zip_array m_central_dir_offsets;
4785 mz_zip_array m_sorted_central_dir_offsets;
4786 MZ_FILE *m_pFile;
4787 void *m_pMem;
4788 size_t m_mem_size;
4789 size_t m_mem_capacity;
4790 };
4791
4792 #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \
4793 (array_ptr)->m_element_size = element_size
4794 #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \
4795 ((element_type *)((array_ptr)->m_p))[index]
4796
mz_zip_array_clear(mz_zip_archive * pZip,mz_zip_array * pArray)4797 static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip,
4798 mz_zip_array *pArray) {
4799 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
4800 memset(pArray, 0, sizeof(mz_zip_array));
4801 }
4802
mz_zip_array_ensure_capacity(mz_zip_archive * pZip,mz_zip_array * pArray,size_t min_new_capacity,mz_uint growing)4803 static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip,
4804 mz_zip_array *pArray,
4805 size_t min_new_capacity,
4806 mz_uint growing) {
4807 void *pNew_p;
4808 size_t new_capacity = min_new_capacity;
4809 MZ_ASSERT(pArray->m_element_size);
4810 if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE;
4811 if (growing) {
4812 new_capacity = MZ_MAX(1, pArray->m_capacity);
4813 while (new_capacity < min_new_capacity) new_capacity *= 2;
4814 }
4815 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p,
4816 pArray->m_element_size, new_capacity)))
4817 return MZ_FALSE;
4818 pArray->m_p = pNew_p;
4819 pArray->m_capacity = new_capacity;
4820 return MZ_TRUE;
4821 }
4822
mz_zip_array_reserve(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_capacity,mz_uint growing)4823 static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip,
4824 mz_zip_array *pArray,
4825 size_t new_capacity,
4826 mz_uint growing) {
4827 if (new_capacity > pArray->m_capacity) {
4828 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
4829 return MZ_FALSE;
4830 }
4831 return MZ_TRUE;
4832 }
4833
mz_zip_array_resize(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_size,mz_uint growing)4834 static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip,
4835 mz_zip_array *pArray,
4836 size_t new_size,
4837 mz_uint growing) {
4838 if (new_size > pArray->m_capacity) {
4839 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
4840 return MZ_FALSE;
4841 }
4842 pArray->m_size = new_size;
4843 return MZ_TRUE;
4844 }
4845
mz_zip_array_ensure_room(mz_zip_archive * pZip,mz_zip_array * pArray,size_t n)4846 static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip,
4847 mz_zip_array *pArray,
4848 size_t n) {
4849 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
4850 }
4851
mz_zip_array_push_back(mz_zip_archive * pZip,mz_zip_array * pArray,const void * pElements,size_t n)4852 static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip,
4853 mz_zip_array *pArray,
4854 const void *pElements,
4855 size_t n) {
4856 size_t orig_size = pArray->m_size;
4857 if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))
4858 return MZ_FALSE;
4859 memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size,
4860 pElements, n * pArray->m_element_size);
4861 return MZ_TRUE;
4862 }
4863
4864 #ifndef MINIZ_NO_TIME
mz_zip_dos_to_time_t(int dos_time,int dos_date)4865 static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) {
4866 struct tm tm;
4867 memset(&tm, 0, sizeof(tm));
4868 tm.tm_isdst = -1;
4869 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;
4870 tm.tm_mon = ((dos_date >> 5) & 15) - 1;
4871 tm.tm_mday = dos_date & 31;
4872 tm.tm_hour = (dos_time >> 11) & 31;
4873 tm.tm_min = (dos_time >> 5) & 63;
4874 tm.tm_sec = (dos_time << 1) & 62;
4875 return mktime(&tm);
4876 }
4877
mz_zip_time_to_dos_time(time_t time,mz_uint16 * pDOS_time,mz_uint16 * pDOS_date)4878 static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time,
4879 mz_uint16 *pDOS_date) {
4880 #ifdef _MSC_VER
4881 struct tm tm_struct;
4882 struct tm *tm = &tm_struct;
4883 errno_t err = localtime_s(tm, &time);
4884 if (err) {
4885 *pDOS_date = 0;
4886 *pDOS_time = 0;
4887 return;
4888 }
4889 #else
4890 struct tm *tm = localtime(&time);
4891 #endif
4892 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) +
4893 ((tm->tm_sec) >> 1));
4894 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) +
4895 ((tm->tm_mon + 1) << 5) + tm->tm_mday);
4896 }
4897 #endif
4898
4899 #ifndef MINIZ_NO_STDIO
mz_zip_get_file_modified_time(const char * pFilename,mz_uint16 * pDOS_time,mz_uint16 * pDOS_date)4900 static mz_bool mz_zip_get_file_modified_time(const char *pFilename,
4901 mz_uint16 *pDOS_time,
4902 mz_uint16 *pDOS_date) {
4903 #ifdef MINIZ_NO_TIME
4904 (void)pFilename;
4905 *pDOS_date = *pDOS_time = 0;
4906 #else
4907 struct MZ_FILE_STAT_STRUCT file_stat;
4908 // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000
4909 // bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh.
4910 if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE;
4911 mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date);
4912 #endif // #ifdef MINIZ_NO_TIME
4913 return MZ_TRUE;
4914 }
4915
4916 #ifndef MINIZ_NO_TIME
mz_zip_set_file_times(const char * pFilename,time_t access_time,time_t modified_time)4917 static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
4918 time_t modified_time) {
4919 struct utimbuf t;
4920 t.actime = access_time;
4921 t.modtime = modified_time;
4922 return !utime(pFilename, &t);
4923 }
4924 #endif // #ifndef MINIZ_NO_TIME
4925 #endif // #ifndef MINIZ_NO_STDIO
4926
mz_zip_reader_init_internal(mz_zip_archive * pZip,mz_uint32 flags)4927 static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
4928 mz_uint32 flags) {
4929 (void)flags;
4930 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
4931 return MZ_FALSE;
4932
4933 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
4934 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
4935 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
4936
4937 pZip->m_zip_mode = MZ_ZIP_MODE_READING;
4938 pZip->m_archive_size = 0;
4939 pZip->m_central_directory_file_ofs = 0;
4940 pZip->m_total_files = 0;
4941
4942 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
4943 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
4944 return MZ_FALSE;
4945 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
4946 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
4947 sizeof(mz_uint8));
4948 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
4949 sizeof(mz_uint32));
4950 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
4951 sizeof(mz_uint32));
4952 return MZ_TRUE;
4953 }
4954
4955 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)4956 mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array,
4957 const mz_zip_array *pCentral_dir_offsets,
4958 mz_uint l_index, mz_uint r_index) {
4959 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
4960 pCentral_dir_array, mz_uint8,
4961 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
4962 l_index)),
4963 *pE;
4964 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(
4965 pCentral_dir_array, mz_uint8,
4966 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
4967 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS),
4968 r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4969 mz_uint8 l = 0, r = 0;
4970 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4971 pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4972 pE = pL + MZ_MIN(l_len, r_len);
4973 while (pL < pE) {
4974 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break;
4975 pL++;
4976 pR++;
4977 }
4978 return (pL == pE) ? (l_len < r_len) : (l < r);
4979 }
4980
4981 #define MZ_SWAP_UINT32(a, b) \
4982 do { \
4983 mz_uint32 t = a; \
4984 a = b; \
4985 b = t; \
4986 } \
4987 MZ_MACRO_END
4988
4989 // Heap sort of lowercased filenames, used to help accelerate plain central
4990 // directory searches by mz_zip_reader_locate_file(). (Could also use qsort(),
4991 // but it could allocate memory.)
mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive * pZip)4992 static void mz_zip_reader_sort_central_dir_offsets_by_filename(
4993 mz_zip_archive *pZip) {
4994 mz_zip_internal_state *pState = pZip->m_pState;
4995 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
4996 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
4997 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
4998 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
4999 const int size = pZip->m_total_files;
5000 int start = (size - 2) >> 1, end;
5001 while (start >= 0) {
5002 int child, root = start;
5003 for (;;) {
5004 if ((child = (root << 1) + 1) >= size) break;
5005 child +=
5006 (((child + 1) < size) &&
5007 (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
5008 pIndices[child], pIndices[child + 1])));
5009 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
5010 pIndices[root], pIndices[child]))
5011 break;
5012 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
5013 root = child;
5014 }
5015 start--;
5016 }
5017
5018 end = size - 1;
5019 while (end > 0) {
5020 int child, root = 0;
5021 MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
5022 for (;;) {
5023 if ((child = (root << 1) + 1) >= end) break;
5024 child +=
5025 (((child + 1) < end) &&
5026 mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
5027 pIndices[child], pIndices[child + 1]));
5028 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
5029 pIndices[root], pIndices[child]))
5030 break;
5031 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
5032 root = child;
5033 }
5034 end--;
5035 }
5036 }
5037
mz_zip_reader_read_central_dir(mz_zip_archive * pZip,mz_uint32 flags)5038 static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
5039 mz_uint32 flags) {
5040 mz_uint cdir_size, num_this_disk, cdir_disk_index;
5041 mz_uint64 cdir_ofs;
5042 mz_int64 cur_file_ofs;
5043 const mz_uint8 *p;
5044 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
5045 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
5046 mz_bool sort_central_dir =
5047 ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
5048 // Basic sanity checks - reject files which are too small, and check the first
5049 // 4 bytes of the file to make sure a local header is there.
5050 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5051 return MZ_FALSE;
5052 // Find the end of central directory record by scanning the file from the end
5053 // towards the beginning.
5054 cur_file_ofs =
5055 MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
5056 for (;;) {
5057 int i,
5058 n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
5059 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
5060 return MZ_FALSE;
5061 for (i = n - 4; i >= 0; --i)
5062 if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break;
5063 if (i >= 0) {
5064 cur_file_ofs += i;
5065 break;
5066 }
5067 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
5068 (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
5069 return MZ_FALSE;
5070 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
5071 }
5072 // Read and verify the end of central directory record.
5073 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
5074 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
5075 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5076 return MZ_FALSE;
5077 if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
5078 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
5079 ((pZip->m_total_files =
5080 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
5081 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
5082 return MZ_FALSE;
5083
5084 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
5085 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
5086 if (((num_this_disk | cdir_disk_index) != 0) &&
5087 ((num_this_disk != 1) || (cdir_disk_index != 1)))
5088 return MZ_FALSE;
5089
5090 if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
5091 pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
5092 return MZ_FALSE;
5093
5094 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
5095 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE;
5096
5097 pZip->m_central_directory_file_ofs = cdir_ofs;
5098
5099 if (pZip->m_total_files) {
5100 mz_uint i, n;
5101
5102 // Read the entire central directory into a heap block, and allocate another
5103 // heap block to hold the unsorted central dir file record offsets, and
5104 // another to hold the sorted indices.
5105 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
5106 MZ_FALSE)) ||
5107 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
5108 pZip->m_total_files, MZ_FALSE)))
5109 return MZ_FALSE;
5110
5111 if (sort_central_dir) {
5112 if (!mz_zip_array_resize(pZip,
5113 &pZip->m_pState->m_sorted_central_dir_offsets,
5114 pZip->m_total_files, MZ_FALSE))
5115 return MZ_FALSE;
5116 }
5117
5118 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
5119 pZip->m_pState->m_central_dir.m_p,
5120 cdir_size) != cdir_size)
5121 return MZ_FALSE;
5122
5123 // Now create an index into the central directory file records, do some
5124 // basic sanity checking on each record, and check for zip64 entries (which
5125 // are not yet supported).
5126 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
5127 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
5128 mz_uint total_header_size, comp_size, decomp_size, disk_index;
5129 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
5130 (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
5131 return MZ_FALSE;
5132 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5133 i) =
5134 (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
5135 if (sort_central_dir)
5136 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
5137 mz_uint32, i) = i;
5138 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5139 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5140 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
5141 (decomp_size != comp_size)) ||
5142 (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
5143 (comp_size == 0xFFFFFFFF))
5144 return MZ_FALSE;
5145 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
5146 if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE;
5147 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
5148 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
5149 return MZ_FALSE;
5150 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5151 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
5152 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
5153 MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
5154 n)
5155 return MZ_FALSE;
5156 n -= total_header_size;
5157 p += total_header_size;
5158 }
5159 }
5160
5161 if (sort_central_dir)
5162 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
5163
5164 return MZ_TRUE;
5165 }
5166
mz_zip_reader_init(mz_zip_archive * pZip,mz_uint64 size,mz_uint32 flags)5167 mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
5168 mz_uint32 flags) {
5169 if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE;
5170 if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE;
5171 pZip->m_archive_size = size;
5172 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5173 mz_zip_reader_end(pZip);
5174 return MZ_FALSE;
5175 }
5176 return MZ_TRUE;
5177 }
5178
mz_zip_mem_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)5179 static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs,
5180 void *pBuf, size_t n) {
5181 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5182 size_t s = (file_ofs >= pZip->m_archive_size)
5183 ? 0
5184 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
5185 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
5186 return s;
5187 }
5188
mz_zip_reader_init_mem(mz_zip_archive * pZip,const void * pMem,size_t size,mz_uint32 flags)5189 mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
5190 size_t size, mz_uint32 flags) {
5191 if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE;
5192 pZip->m_archive_size = size;
5193 pZip->m_pRead = mz_zip_mem_read_func;
5194 pZip->m_pIO_opaque = pZip;
5195 #ifdef __cplusplus
5196 pZip->m_pState->m_pMem = const_cast<void *>(pMem);
5197 #else
5198 pZip->m_pState->m_pMem = (void *)pMem;
5199 #endif
5200 pZip->m_pState->m_mem_size = 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
5208 #ifndef MINIZ_NO_STDIO
mz_zip_file_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)5209 static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs,
5210 void *pBuf, size_t n) {
5211 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5212 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
5213 if (((mz_int64)file_ofs < 0) ||
5214 (((cur_ofs != (mz_int64)file_ofs)) &&
5215 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
5216 return 0;
5217 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
5218 }
5219
mz_zip_reader_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint32 flags)5220 mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
5221 mz_uint32 flags) {
5222 mz_uint64 file_size;
5223 MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb");
5224 if (!pFile) return MZ_FALSE;
5225 if (MZ_FSEEK64(pFile, 0, SEEK_END)) {
5226 MZ_FCLOSE(pFile);
5227 return MZ_FALSE;
5228 }
5229 file_size = MZ_FTELL64(pFile);
5230 if (!mz_zip_reader_init_internal(pZip, flags)) {
5231 MZ_FCLOSE(pFile);
5232 return MZ_FALSE;
5233 }
5234 pZip->m_pRead = mz_zip_file_read_func;
5235 pZip->m_pIO_opaque = pZip;
5236 pZip->m_pState->m_pFile = pFile;
5237 pZip->m_archive_size = file_size;
5238 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5239 mz_zip_reader_end(pZip);
5240 return MZ_FALSE;
5241 }
5242 return MZ_TRUE;
5243 }
5244 #endif // #ifndef MINIZ_NO_STDIO
5245
mz_zip_reader_get_num_files(mz_zip_archive * pZip)5246 mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) {
5247 return pZip ? pZip->m_total_files : 0;
5248 }
5249
mz_zip_reader_get_cdh(mz_zip_archive * pZip,mz_uint file_index)5250 static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(
5251 mz_zip_archive *pZip, mz_uint file_index) {
5252 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) ||
5253 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5254 return NULL;
5255 return &MZ_ZIP_ARRAY_ELEMENT(
5256 &pZip->m_pState->m_central_dir, mz_uint8,
5257 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5258 file_index));
5259 }
5260
mz_zip_reader_is_file_encrypted(mz_zip_archive * pZip,mz_uint file_index)5261 mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
5262 mz_uint file_index) {
5263 mz_uint m_bit_flag;
5264 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5265 if (!p) return MZ_FALSE;
5266 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
5267 return (m_bit_flag & 1);
5268 }
5269
mz_zip_reader_is_file_a_directory(mz_zip_archive * pZip,mz_uint file_index)5270 mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
5271 mz_uint file_index) {
5272 mz_uint filename_len, external_attr;
5273 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5274 if (!p) return MZ_FALSE;
5275
5276 // First see if the filename ends with a '/' character.
5277 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5278 if (filename_len) {
5279 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
5280 return MZ_TRUE;
5281 }
5282
5283 // Bugfix: This code was also checking if the internal attribute was non-zero,
5284 // which wasn't correct.
5285 // Most/all zip writers (hopefully) set DOS file/directory attributes in the
5286 // low 16-bits, so check for the DOS directory flag and ignore the source OS
5287 // ID in the created by field.
5288 // FIXME: Remove this check? Is it necessary - we already check the filename.
5289 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5290 if ((external_attr & 0x10) != 0) return MZ_TRUE;
5291
5292 return MZ_FALSE;
5293 }
5294
mz_zip_reader_file_stat(mz_zip_archive * pZip,mz_uint file_index,mz_zip_archive_file_stat * pStat)5295 mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
5296 mz_zip_archive_file_stat *pStat) {
5297 mz_uint n;
5298 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5299 if ((!p) || (!pStat)) return MZ_FALSE;
5300
5301 // Unpack the central directory record.
5302 pStat->m_file_index = file_index;
5303 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(
5304 &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
5305 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
5306 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
5307 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
5308 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
5309 #ifndef MINIZ_NO_TIME
5310 pStat->m_time =
5311 mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS),
5312 MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
5313 #endif
5314 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
5315 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5316 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5317 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
5318 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5319 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
5320
5321 // Copy as much of the filename and comment as possible.
5322 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5323 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
5324 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
5325 pStat->m_filename[n] = '\0';
5326
5327 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
5328 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
5329 pStat->m_comment_size = n;
5330 memcpy(pStat->m_comment,
5331 p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5332 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
5333 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
5334 n);
5335 pStat->m_comment[n] = '\0';
5336
5337 return MZ_TRUE;
5338 }
5339
mz_zip_reader_get_filename(mz_zip_archive * pZip,mz_uint file_index,char * pFilename,mz_uint filename_buf_size)5340 mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
5341 char *pFilename, mz_uint filename_buf_size) {
5342 mz_uint n;
5343 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5344 if (!p) {
5345 if (filename_buf_size) pFilename[0] = '\0';
5346 return 0;
5347 }
5348 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5349 if (filename_buf_size) {
5350 n = MZ_MIN(n, filename_buf_size - 1);
5351 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
5352 pFilename[n] = '\0';
5353 }
5354 return n + 1;
5355 }
5356
mz_zip_reader_string_equal(const char * pA,const char * pB,mz_uint len,mz_uint flags)5357 static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA,
5358 const char *pB,
5359 mz_uint len,
5360 mz_uint flags) {
5361 mz_uint i;
5362 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len);
5363 for (i = 0; i < len; ++i)
5364 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE;
5365 return MZ_TRUE;
5366 }
5367
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)5368 static MZ_FORCEINLINE int mz_zip_reader_filename_compare(
5369 const mz_zip_array *pCentral_dir_array,
5370 const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR,
5371 mz_uint r_len) {
5372 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
5373 pCentral_dir_array, mz_uint8,
5374 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
5375 l_index)),
5376 *pE;
5377 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5378 mz_uint8 l = 0, r = 0;
5379 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5380 pE = pL + MZ_MIN(l_len, r_len);
5381 while (pL < pE) {
5382 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break;
5383 pL++;
5384 pR++;
5385 }
5386 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
5387 }
5388
mz_zip_reader_locate_file_binary_search(mz_zip_archive * pZip,const char * pFilename)5389 static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip,
5390 const char *pFilename) {
5391 mz_zip_internal_state *pState = pZip->m_pState;
5392 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
5393 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
5394 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
5395 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
5396 const int size = pZip->m_total_files;
5397 const mz_uint filename_len = (mz_uint)strlen(pFilename);
5398 int l = 0, h = size - 1;
5399 while (l <= h) {
5400 int m = (l + h) >> 1, file_index = pIndices[m],
5401 comp =
5402 mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets,
5403 file_index, pFilename, filename_len);
5404 if (!comp)
5405 return file_index;
5406 else if (comp < 0)
5407 l = m + 1;
5408 else
5409 h = m - 1;
5410 }
5411 return -1;
5412 }
5413
mz_zip_reader_locate_file(mz_zip_archive * pZip,const char * pName,const char * pComment,mz_uint flags)5414 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
5415 const char *pComment, mz_uint flags) {
5416 mz_uint file_index;
5417 size_t name_len, comment_len;
5418 if ((!pZip) || (!pZip->m_pState) || (!pName) ||
5419 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5420 return -1;
5421 if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) &&
5422 (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
5423 return mz_zip_reader_locate_file_binary_search(pZip, pName);
5424 name_len = strlen(pName);
5425 if (name_len > 0xFFFF) return -1;
5426 comment_len = pComment ? strlen(pComment) : 0;
5427 if (comment_len > 0xFFFF) return -1;
5428 for (file_index = 0; file_index < pZip->m_total_files; file_index++) {
5429 const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(
5430 &pZip->m_pState->m_central_dir, mz_uint8,
5431 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5432 file_index));
5433 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5434 const char *pFilename =
5435 (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5436 if (filename_len < name_len) continue;
5437 if (comment_len) {
5438 mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS),
5439 file_comment_len =
5440 MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
5441 const char *pFile_comment = pFilename + filename_len + file_extra_len;
5442 if ((file_comment_len != comment_len) ||
5443 (!mz_zip_reader_string_equal(pComment, pFile_comment,
5444 file_comment_len, flags)))
5445 continue;
5446 }
5447 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) {
5448 int ofs = filename_len - 1;
5449 do {
5450 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') ||
5451 (pFilename[ofs] == ':'))
5452 break;
5453 } while (--ofs >= 0);
5454 ofs++;
5455 pFilename += ofs;
5456 filename_len -= ofs;
5457 }
5458 if ((filename_len == name_len) &&
5459 (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
5460 return file_index;
5461 }
5462 return -1;
5463 }
5464
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)5465 mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
5466 mz_uint file_index, void *pBuf,
5467 size_t buf_size, mz_uint flags,
5468 void *pUser_read_buf,
5469 size_t user_read_buf_size) {
5470 int status = TINFL_STATUS_DONE;
5471 mz_uint64 needed_size, cur_file_ofs, comp_remaining,
5472 out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
5473 mz_zip_archive_file_stat file_stat;
5474 void *pRead_buf;
5475 mz_uint32
5476 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5477 sizeof(mz_uint32)];
5478 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5479 tinfl_decompressor inflator;
5480
5481 if ((buf_size) && (!pBuf)) return MZ_FALSE;
5482
5483 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
5484
5485 // Empty file, or a directory (but not always a directory - I've seen odd zips
5486 // with directories that have compressed data which inflates to 0 bytes)
5487 if (!file_stat.m_comp_size) return MZ_TRUE;
5488
5489 // Entry is a subdirectory (I've seen old zips with dir entries which have
5490 // compressed deflate data which inflates to 0 bytes, but these entries claim
5491 // to uncompress to 512 bytes in the headers).
5492 // I'm torn how to handle this case - should it fail instead?
5493 if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE;
5494
5495 // Encryption and patch files are not supported.
5496 if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE;
5497
5498 // This function only supports stored and deflate.
5499 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
5500 (file_stat.m_method != MZ_DEFLATED))
5501 return MZ_FALSE;
5502
5503 // Ensure supplied output buffer is large enough.
5504 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size
5505 : file_stat.m_uncomp_size;
5506 if (buf_size < needed_size) return MZ_FALSE;
5507
5508 // Read and parse the local directory entry.
5509 cur_file_ofs = file_stat.m_local_header_ofs;
5510 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
5511 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5512 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5513 return MZ_FALSE;
5514 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5515 return MZ_FALSE;
5516
5517 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5518 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5519 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5520 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
5521 return MZ_FALSE;
5522
5523 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
5524 // The file is stored or the caller has requested the compressed data.
5525 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
5526 (size_t)needed_size) != needed_size)
5527 return MZ_FALSE;
5528 return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) ||
5529 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
5530 (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32);
5531 }
5532
5533 // Decompress the file either directly from memory or from a file input
5534 // buffer.
5535 tinfl_init(&inflator);
5536
5537 if (pZip->m_pState->m_pMem) {
5538 // Read directly from the archive in memory.
5539 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
5540 read_buf_size = read_buf_avail = file_stat.m_comp_size;
5541 comp_remaining = 0;
5542 } else if (pUser_read_buf) {
5543 // Use a user provided read buffer.
5544 if (!user_read_buf_size) return MZ_FALSE;
5545 pRead_buf = (mz_uint8 *)pUser_read_buf;
5546 read_buf_size = user_read_buf_size;
5547 read_buf_avail = 0;
5548 comp_remaining = file_stat.m_comp_size;
5549 } else {
5550 // Temporarily allocate a read buffer.
5551 read_buf_size =
5552 MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
5553 #ifdef _MSC_VER
5554 if (((0, sizeof(size_t) == sizeof(mz_uint32))) &&
5555 (read_buf_size > 0x7FFFFFFF))
5556 #else
5557 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
5558 #endif
5559 return MZ_FALSE;
5560 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5561 (size_t)read_buf_size)))
5562 return MZ_FALSE;
5563 read_buf_avail = 0;
5564 comp_remaining = file_stat.m_comp_size;
5565 }
5566
5567 do {
5568 size_t in_buf_size,
5569 out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
5570 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
5571 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5572 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5573 (size_t)read_buf_avail) != read_buf_avail) {
5574 status = TINFL_STATUS_FAILED;
5575 break;
5576 }
5577 cur_file_ofs += read_buf_avail;
5578 comp_remaining -= read_buf_avail;
5579 read_buf_ofs = 0;
5580 }
5581 in_buf_size = (size_t)read_buf_avail;
5582 status = tinfl_decompress(
5583 &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
5584 (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size,
5585 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF |
5586 (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
5587 read_buf_avail -= in_buf_size;
5588 read_buf_ofs += in_buf_size;
5589 out_buf_ofs += out_buf_size;
5590 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
5591
5592 if (status == TINFL_STATUS_DONE) {
5593 // Make sure the entire file was decompressed, and check its CRC.
5594 if ((out_buf_ofs != file_stat.m_uncomp_size) ||
5595 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
5596 (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32))
5597 status = TINFL_STATUS_FAILED;
5598 }
5599
5600 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
5601 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
5602
5603 return status == TINFL_STATUS_DONE;
5604 }
5605
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)5606 mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
5607 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
5608 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) {
5609 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5610 if (file_index < 0) return MZ_FALSE;
5611 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
5612 flags, pUser_read_buf,
5613 user_read_buf_size);
5614 }
5615
mz_zip_reader_extract_to_mem(mz_zip_archive * pZip,mz_uint file_index,void * pBuf,size_t buf_size,mz_uint flags)5616 mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
5617 void *pBuf, size_t buf_size,
5618 mz_uint flags) {
5619 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
5620 flags, NULL, 0);
5621 }
5622
mz_zip_reader_extract_file_to_mem(mz_zip_archive * pZip,const char * pFilename,void * pBuf,size_t buf_size,mz_uint flags)5623 mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
5624 const char *pFilename, void *pBuf,
5625 size_t buf_size, mz_uint flags) {
5626 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf,
5627 buf_size, flags, NULL, 0);
5628 }
5629
mz_zip_reader_extract_to_heap(mz_zip_archive * pZip,mz_uint file_index,size_t * pSize,mz_uint flags)5630 void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
5631 size_t *pSize, mz_uint flags) {
5632 mz_uint64 comp_size, uncomp_size, alloc_size;
5633 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5634 void *pBuf;
5635
5636 if (pSize) *pSize = 0;
5637 if (!p) return NULL;
5638
5639 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5640 uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5641
5642 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
5643 #ifdef _MSC_VER
5644 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
5645 #else
5646 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
5647 #endif
5648 return NULL;
5649 if (NULL ==
5650 (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
5651 return NULL;
5652
5653 if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size,
5654 flags)) {
5655 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
5656 return NULL;
5657 }
5658
5659 if (pSize) *pSize = (size_t)alloc_size;
5660 return pBuf;
5661 }
5662
mz_zip_reader_extract_file_to_heap(mz_zip_archive * pZip,const char * pFilename,size_t * pSize,mz_uint flags)5663 void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
5664 const char *pFilename, size_t *pSize,
5665 mz_uint flags) {
5666 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5667 if (file_index < 0) {
5668 if (pSize) *pSize = 0;
5669 return MZ_FALSE;
5670 }
5671 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
5672 }
5673
mz_zip_reader_extract_to_callback(mz_zip_archive * pZip,mz_uint file_index,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)5674 mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
5675 mz_uint file_index,
5676 mz_file_write_func pCallback,
5677 void *pOpaque, mz_uint flags) {
5678 int status = TINFL_STATUS_DONE;
5679 mz_uint file_crc32 = MZ_CRC32_INIT;
5680 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining,
5681 out_buf_ofs = 0, cur_file_ofs;
5682 mz_zip_archive_file_stat file_stat;
5683 void *pRead_buf = NULL;
5684 void *pWrite_buf = NULL;
5685 mz_uint32
5686 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5687 sizeof(mz_uint32)];
5688 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5689
5690 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
5691
5692 // Empty file, or a directory (but not always a directory - I've seen odd zips
5693 // with directories that have compressed data which inflates to 0 bytes)
5694 if (!file_stat.m_comp_size) return MZ_TRUE;
5695
5696 // Entry is a subdirectory (I've seen old zips with dir entries which have
5697 // compressed deflate data which inflates to 0 bytes, but these entries claim
5698 // to uncompress to 512 bytes in the headers).
5699 // I'm torn how to handle this case - should it fail instead?
5700 if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE;
5701
5702 // Encryption and patch files are not supported.
5703 if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE;
5704
5705 // This function only supports stored and deflate.
5706 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
5707 (file_stat.m_method != MZ_DEFLATED))
5708 return MZ_FALSE;
5709
5710 // Read and parse the local directory entry.
5711 cur_file_ofs = file_stat.m_local_header_ofs;
5712 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
5713 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5714 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5715 return MZ_FALSE;
5716 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5717 return MZ_FALSE;
5718
5719 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5720 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5721 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5722 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
5723 return MZ_FALSE;
5724
5725 // Decompress the file either directly from memory or from a file input
5726 // buffer.
5727 if (pZip->m_pState->m_pMem) {
5728 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
5729 read_buf_size = read_buf_avail = file_stat.m_comp_size;
5730 comp_remaining = 0;
5731 } else {
5732 read_buf_size =
5733 MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
5734 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5735 (size_t)read_buf_size)))
5736 return MZ_FALSE;
5737 read_buf_avail = 0;
5738 comp_remaining = file_stat.m_comp_size;
5739 }
5740
5741 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
5742 // The file is stored or the caller has requested the compressed data.
5743 if (pZip->m_pState->m_pMem) {
5744 #ifdef _MSC_VER
5745 if (((0, sizeof(size_t) == sizeof(mz_uint32))) &&
5746 (file_stat.m_comp_size > 0xFFFFFFFF))
5747 #else
5748 if (((sizeof(size_t) == sizeof(mz_uint32))) &&
5749 (file_stat.m_comp_size > 0xFFFFFFFF))
5750 #endif
5751 return MZ_FALSE;
5752 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5753 (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
5754 status = TINFL_STATUS_FAILED;
5755 else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
5756 file_crc32 =
5757 (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf,
5758 (size_t)file_stat.m_comp_size);
5759 cur_file_ofs += file_stat.m_comp_size;
5760 out_buf_ofs += file_stat.m_comp_size;
5761 comp_remaining = 0;
5762 } else {
5763 while (comp_remaining) {
5764 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5765 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5766 (size_t)read_buf_avail) != read_buf_avail) {
5767 status = TINFL_STATUS_FAILED;
5768 break;
5769 }
5770
5771 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
5772 file_crc32 = (mz_uint32)mz_crc32(
5773 file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
5774
5775 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5776 (size_t)read_buf_avail) != read_buf_avail) {
5777 status = TINFL_STATUS_FAILED;
5778 break;
5779 }
5780 cur_file_ofs += read_buf_avail;
5781 out_buf_ofs += read_buf_avail;
5782 comp_remaining -= read_buf_avail;
5783 }
5784 }
5785 } else {
5786 tinfl_decompressor inflator;
5787 tinfl_init(&inflator);
5788
5789 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5790 TINFL_LZ_DICT_SIZE)))
5791 status = TINFL_STATUS_FAILED;
5792 else {
5793 do {
5794 mz_uint8 *pWrite_buf_cur =
5795 (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5796 size_t in_buf_size,
5797 out_buf_size =
5798 TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5799 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
5800 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5801 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5802 (size_t)read_buf_avail) != read_buf_avail) {
5803 status = TINFL_STATUS_FAILED;
5804 break;
5805 }
5806 cur_file_ofs += read_buf_avail;
5807 comp_remaining -= read_buf_avail;
5808 read_buf_ofs = 0;
5809 }
5810
5811 in_buf_size = (size_t)read_buf_avail;
5812 status = tinfl_decompress(
5813 &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
5814 (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size,
5815 comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
5816 read_buf_avail -= in_buf_size;
5817 read_buf_ofs += in_buf_size;
5818
5819 if (out_buf_size) {
5820 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) !=
5821 out_buf_size) {
5822 status = TINFL_STATUS_FAILED;
5823 break;
5824 }
5825 file_crc32 =
5826 (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
5827 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) {
5828 status = TINFL_STATUS_FAILED;
5829 break;
5830 }
5831 }
5832 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) ||
5833 (status == TINFL_STATUS_HAS_MORE_OUTPUT));
5834 }
5835 }
5836
5837 if ((status == TINFL_STATUS_DONE) &&
5838 (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) {
5839 // Make sure the entire file was decompressed, and check its CRC.
5840 if ((out_buf_ofs != file_stat.m_uncomp_size) ||
5841 (file_crc32 != file_stat.m_crc32))
5842 status = TINFL_STATUS_FAILED;
5843 }
5844
5845 if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
5846 if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
5847
5848 return status == TINFL_STATUS_DONE;
5849 }
5850
mz_zip_reader_extract_file_to_callback(mz_zip_archive * pZip,const char * pFilename,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)5851 mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
5852 const char *pFilename,
5853 mz_file_write_func pCallback,
5854 void *pOpaque, mz_uint flags) {
5855 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5856 if (file_index < 0) return MZ_FALSE;
5857 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque,
5858 flags);
5859 }
5860
5861 #ifndef MINIZ_NO_STDIO
mz_zip_file_write_callback(void * pOpaque,mz_uint64 ofs,const void * pBuf,size_t n)5862 static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs,
5863 const void *pBuf, size_t n) {
5864 (void)ofs;
5865 return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);
5866 }
5867
mz_zip_reader_extract_to_file(mz_zip_archive * pZip,mz_uint file_index,const char * pDst_filename,mz_uint flags)5868 mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
5869 const char *pDst_filename,
5870 mz_uint flags) {
5871 mz_bool status;
5872 mz_zip_archive_file_stat file_stat;
5873 MZ_FILE *pFile;
5874 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
5875 pFile = MZ_FOPEN(pDst_filename, "wb");
5876 if (!pFile) return MZ_FALSE;
5877 status = mz_zip_reader_extract_to_callback(
5878 pZip, file_index, mz_zip_file_write_callback, pFile, flags);
5879 if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE;
5880 #ifndef MINIZ_NO_TIME
5881 if (status)
5882 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
5883 #endif
5884 return status;
5885 }
5886 #endif // #ifndef MINIZ_NO_STDIO
5887
mz_zip_reader_end(mz_zip_archive * pZip)5888 mz_bool mz_zip_reader_end(mz_zip_archive *pZip) {
5889 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
5890 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5891 return MZ_FALSE;
5892
5893 if (pZip->m_pState) {
5894 mz_zip_internal_state *pState = pZip->m_pState;
5895 pZip->m_pState = NULL;
5896 mz_zip_array_clear(pZip, &pState->m_central_dir);
5897 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
5898 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
5899
5900 #ifndef MINIZ_NO_STDIO
5901 if (pState->m_pFile) {
5902 MZ_FCLOSE(pState->m_pFile);
5903 pState->m_pFile = NULL;
5904 }
5905 #endif // #ifndef MINIZ_NO_STDIO
5906
5907 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5908 }
5909 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
5910
5911 return MZ_TRUE;
5912 }
5913
5914 #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)5915 mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
5916 const char *pArchive_filename,
5917 const char *pDst_filename,
5918 mz_uint flags) {
5919 int file_index =
5920 mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags);
5921 if (file_index < 0) return MZ_FALSE;
5922 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
5923 }
5924 #endif
5925
5926 // ------------------- .ZIP archive writing
5927
5928 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
5929
mz_write_le16(mz_uint8 * p,mz_uint16 v)5930 static void mz_write_le16(mz_uint8 *p, mz_uint16 v) {
5931 p[0] = (mz_uint8)v;
5932 p[1] = (mz_uint8)(v >> 8);
5933 }
mz_write_le32(mz_uint8 * p,mz_uint32 v)5934 static void mz_write_le32(mz_uint8 *p, mz_uint32 v) {
5935 p[0] = (mz_uint8)v;
5936 p[1] = (mz_uint8)(v >> 8);
5937 p[2] = (mz_uint8)(v >> 16);
5938 p[3] = (mz_uint8)(v >> 24);
5939 }
5940 #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
5941 #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
5942
mz_zip_writer_init(mz_zip_archive * pZip,mz_uint64 existing_size)5943 mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) {
5944 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) ||
5945 (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
5946 return MZ_FALSE;
5947
5948 if (pZip->m_file_offset_alignment) {
5949 // Ensure user specified file offset alignment is a power of 2.
5950 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
5951 return MZ_FALSE;
5952 }
5953
5954 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
5955 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
5956 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
5957
5958 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
5959 pZip->m_archive_size = existing_size;
5960 pZip->m_central_directory_file_ofs = 0;
5961 pZip->m_total_files = 0;
5962
5963 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
5964 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
5965 return MZ_FALSE;
5966 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
5967 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
5968 sizeof(mz_uint8));
5969 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
5970 sizeof(mz_uint32));
5971 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
5972 sizeof(mz_uint32));
5973 return MZ_TRUE;
5974 }
5975
mz_zip_heap_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)5976 static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs,
5977 const void *pBuf, size_t n) {
5978 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5979 mz_zip_internal_state *pState = pZip->m_pState;
5980 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
5981 #ifdef _MSC_VER
5982 if ((!n) ||
5983 ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
5984 #else
5985 if ((!n) ||
5986 ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
5987 #endif
5988 return 0;
5989 if (new_size > pState->m_mem_capacity) {
5990 void *pNew_block;
5991 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);
5992 while (new_capacity < new_size) new_capacity *= 2;
5993 if (NULL == (pNew_block = pZip->m_pRealloc(
5994 pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
5995 return 0;
5996 pState->m_pMem = pNew_block;
5997 pState->m_mem_capacity = new_capacity;
5998 }
5999 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
6000 pState->m_mem_size = (size_t)new_size;
6001 return n;
6002 }
6003
mz_zip_writer_init_heap(mz_zip_archive * pZip,size_t size_to_reserve_at_beginning,size_t initial_allocation_size)6004 mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
6005 size_t size_to_reserve_at_beginning,
6006 size_t initial_allocation_size) {
6007 pZip->m_pWrite = mz_zip_heap_write_func;
6008 pZip->m_pIO_opaque = pZip;
6009 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE;
6010 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size,
6011 size_to_reserve_at_beginning))) {
6012 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(
6013 pZip->m_pAlloc_opaque, 1, initial_allocation_size))) {
6014 mz_zip_writer_end(pZip);
6015 return MZ_FALSE;
6016 }
6017 pZip->m_pState->m_mem_capacity = initial_allocation_size;
6018 }
6019 return MZ_TRUE;
6020 }
6021
6022 #ifndef MINIZ_NO_STDIO
mz_zip_file_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)6023 static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs,
6024 const void *pBuf, size_t n) {
6025 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
6026 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
6027 if (((mz_int64)file_ofs < 0) ||
6028 (((cur_ofs != (mz_int64)file_ofs)) &&
6029 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
6030 return 0;
6031 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
6032 }
6033
mz_zip_writer_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint64 size_to_reserve_at_beginning)6034 mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
6035 mz_uint64 size_to_reserve_at_beginning) {
6036 MZ_FILE *pFile;
6037 pZip->m_pWrite = mz_zip_file_write_func;
6038 pZip->m_pIO_opaque = pZip;
6039 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE;
6040 if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) {
6041 mz_zip_writer_end(pZip);
6042 return MZ_FALSE;
6043 }
6044 pZip->m_pState->m_pFile = pFile;
6045 if (size_to_reserve_at_beginning) {
6046 mz_uint64 cur_ofs = 0;
6047 char buf[4096];
6048 MZ_CLEAR_OBJ(buf);
6049 do {
6050 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
6051 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) {
6052 mz_zip_writer_end(pZip);
6053 return MZ_FALSE;
6054 }
6055 cur_ofs += n;
6056 size_to_reserve_at_beginning -= n;
6057 } while (size_to_reserve_at_beginning);
6058 }
6059 return MZ_TRUE;
6060 }
6061 #endif // #ifndef MINIZ_NO_STDIO
6062
mz_zip_writer_init_from_reader(mz_zip_archive * pZip,const char * pFilename)6063 mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
6064 const char *pFilename) {
6065 mz_zip_internal_state *pState;
6066 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
6067 return MZ_FALSE;
6068 // No sense in trying to write to an archive that's already at the support max
6069 // size
6070 if ((pZip->m_total_files == 0xFFFF) ||
6071 ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6072 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
6073 return MZ_FALSE;
6074
6075 pState = pZip->m_pState;
6076
6077 if (pState->m_pFile) {
6078 #ifdef MINIZ_NO_STDIO
6079 pFilename;
6080 return MZ_FALSE;
6081 #else
6082 // Archive is being read from stdio - try to reopen as writable.
6083 if (pZip->m_pIO_opaque != pZip) return MZ_FALSE;
6084 if (!pFilename) return MZ_FALSE;
6085 pZip->m_pWrite = mz_zip_file_write_func;
6086 if (NULL ==
6087 (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) {
6088 // The mz_zip_archive is now in a bogus state because pState->m_pFile is
6089 // NULL, so just close it.
6090 mz_zip_reader_end(pZip);
6091 return MZ_FALSE;
6092 }
6093 #endif // #ifdef MINIZ_NO_STDIO
6094 } else if (pState->m_pMem) {
6095 // Archive lives in a memory block. Assume it's from the heap that we can
6096 // resize using the realloc callback.
6097 if (pZip->m_pIO_opaque != pZip) return MZ_FALSE;
6098 pState->m_mem_capacity = pState->m_mem_size;
6099 pZip->m_pWrite = mz_zip_heap_write_func;
6100 }
6101 // Archive is being read via a user provided read function - make sure the
6102 // user has specified a write function too.
6103 else if (!pZip->m_pWrite)
6104 return MZ_FALSE;
6105
6106 // Start writing new files at the archive's current central directory
6107 // location.
6108 pZip->m_archive_size = pZip->m_central_directory_file_ofs;
6109 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
6110 pZip->m_central_directory_file_ofs = 0;
6111
6112 return MZ_TRUE;
6113 }
6114
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)6115 mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
6116 const void *pBuf, size_t buf_size,
6117 mz_uint level_and_flags) {
6118 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0,
6119 level_and_flags, 0, 0);
6120 }
6121
6122 typedef struct {
6123 mz_zip_archive *m_pZip;
6124 mz_uint64 m_cur_archive_file_ofs;
6125 mz_uint64 m_comp_size;
6126 } mz_zip_writer_add_state;
6127
mz_zip_writer_add_put_buf_callback(const void * pBuf,int len,void * pUser)6128 static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len,
6129 void *pUser) {
6130 mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
6131 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque,
6132 pState->m_cur_archive_file_ofs, pBuf,
6133 len) != len)
6134 return MZ_FALSE;
6135 pState->m_cur_archive_file_ofs += len;
6136 pState->m_comp_size += len;
6137 return MZ_TRUE;
6138 }
6139
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)6140 static mz_bool mz_zip_writer_create_local_dir_header(
6141 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
6142 mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
6143 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
6144 mz_uint16 dos_time, mz_uint16 dos_date) {
6145 (void)pZip;
6146 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
6147 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
6148 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
6149 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
6150 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
6151 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
6152 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
6153 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
6154 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size);
6155 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
6156 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
6157 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
6158 return MZ_TRUE;
6159 }
6160
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)6161 static mz_bool mz_zip_writer_create_central_dir_header(
6162 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
6163 mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size,
6164 mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method,
6165 mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
6166 mz_uint64 local_header_ofs, mz_uint32 ext_attributes) {
6167 (void)pZip;
6168 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
6169 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
6170 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
6171 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
6172 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
6173 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
6174 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
6175 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
6176 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size);
6177 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
6178 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
6179 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
6180 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
6181 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
6182 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs);
6183 return MZ_TRUE;
6184 }
6185
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)6186 static mz_bool mz_zip_writer_add_to_central_dir(
6187 mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,
6188 const void *pExtra, mz_uint16 extra_size, const void *pComment,
6189 mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
6190 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
6191 mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs,
6192 mz_uint32 ext_attributes) {
6193 mz_zip_internal_state *pState = pZip->m_pState;
6194 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
6195 size_t orig_central_dir_size = pState->m_central_dir.m_size;
6196 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6197
6198 // No zip64 support yet
6199 if ((local_header_ofs > 0xFFFFFFFF) ||
6200 (((mz_uint64)pState->m_central_dir.m_size +
6201 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size +
6202 comment_size) > 0xFFFFFFFF))
6203 return MZ_FALSE;
6204
6205 if (!mz_zip_writer_create_central_dir_header(
6206 pZip, central_dir_header, filename_size, extra_size, comment_size,
6207 uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time,
6208 dos_date, local_header_ofs, ext_attributes))
6209 return MZ_FALSE;
6210
6211 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header,
6212 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
6213 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename,
6214 filename_size)) ||
6215 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra,
6216 extra_size)) ||
6217 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment,
6218 comment_size)) ||
6219 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets,
6220 ¢ral_dir_ofs, 1))) {
6221 // Try to push the central directory array back into its original state.
6222 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6223 MZ_FALSE);
6224 return MZ_FALSE;
6225 }
6226
6227 return MZ_TRUE;
6228 }
6229
mz_zip_writer_validate_archive_name(const char * pArchive_name)6230 static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) {
6231 // Basic ZIP archive filename validity checks: Valid filenames cannot start
6232 // with a forward slash, cannot contain a drive letter, and cannot use
6233 // DOS-style backward slashes.
6234 if (*pArchive_name == '/') return MZ_FALSE;
6235 while (*pArchive_name) {
6236 if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE;
6237 pArchive_name++;
6238 }
6239 return MZ_TRUE;
6240 }
6241
mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive * pZip)6242 static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(
6243 mz_zip_archive *pZip) {
6244 mz_uint32 n;
6245 if (!pZip->m_file_offset_alignment) return 0;
6246 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
6247 return (pZip->m_file_offset_alignment - n) &
6248 (pZip->m_file_offset_alignment - 1);
6249 }
6250
mz_zip_writer_write_zeros(mz_zip_archive * pZip,mz_uint64 cur_file_ofs,mz_uint32 n)6251 static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip,
6252 mz_uint64 cur_file_ofs, mz_uint32 n) {
6253 char buf[4096];
6254 memset(buf, 0, MZ_MIN(sizeof(buf), n));
6255 while (n) {
6256 mz_uint32 s = MZ_MIN(sizeof(buf), n);
6257 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
6258 return MZ_FALSE;
6259 cur_file_ofs += s;
6260 n -= s;
6261 }
6262 return MZ_TRUE;
6263 }
6264
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)6265 mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
6266 const char *pArchive_name, const void *pBuf,
6267 size_t buf_size, const void *pComment,
6268 mz_uint16 comment_size,
6269 mz_uint level_and_flags, mz_uint64 uncomp_size,
6270 mz_uint32 uncomp_crc32) {
6271 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
6272 mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
6273 mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
6274 cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
6275 size_t archive_name_size;
6276 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6277 tdefl_compressor *pComp = NULL;
6278 mz_bool store_data_uncompressed;
6279 mz_zip_internal_state *pState;
6280
6281 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
6282 level = level_and_flags & 0xF;
6283 store_data_uncompressed =
6284 ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
6285
6286 if ((!pZip) || (!pZip->m_pState) ||
6287 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) ||
6288 (!pArchive_name) || ((comment_size) && (!pComment)) ||
6289 (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION))
6290 return MZ_FALSE;
6291
6292 pState = pZip->m_pState;
6293
6294 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
6295 return MZ_FALSE;
6296 // No zip64 support yet
6297 if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE;
6298 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
6299
6300 #ifndef MINIZ_NO_TIME
6301 {
6302 time_t cur_time;
6303 time(&cur_time);
6304 mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date);
6305 }
6306 #endif // #ifndef MINIZ_NO_TIME
6307
6308 archive_name_size = strlen(pArchive_name);
6309 if (archive_name_size > 0xFFFF) return MZ_FALSE;
6310
6311 num_alignment_padding_bytes =
6312 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6313
6314 // no zip64 support yet
6315 if ((pZip->m_total_files == 0xFFFF) ||
6316 ((pZip->m_archive_size + num_alignment_padding_bytes +
6317 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6318 comment_size + archive_name_size) > 0xFFFFFFFF))
6319 return MZ_FALSE;
6320
6321 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) {
6322 // Set DOS Subdirectory attribute bit.
6323 ext_attributes |= 0x10;
6324 // Subdirectories cannot contain data.
6325 if ((buf_size) || (uncomp_size)) return MZ_FALSE;
6326 }
6327
6328 // Try to do any allocations before writing to the archive, so if an
6329 // allocation fails the file remains unmodified. (A good idea if we're doing
6330 // an in-place modification.)
6331 if ((!mz_zip_array_ensure_room(
6332 pZip, &pState->m_central_dir,
6333 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) ||
6334 (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
6335 return MZ_FALSE;
6336
6337 if ((!store_data_uncompressed) && (buf_size)) {
6338 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(
6339 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
6340 return MZ_FALSE;
6341 }
6342
6343 if (!mz_zip_writer_write_zeros(
6344 pZip, cur_archive_file_ofs,
6345 num_alignment_padding_bytes + sizeof(local_dir_header))) {
6346 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6347 return MZ_FALSE;
6348 }
6349 local_dir_header_ofs += num_alignment_padding_bytes;
6350 if (pZip->m_file_offset_alignment) {
6351 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6352 0);
6353 }
6354 cur_archive_file_ofs +=
6355 num_alignment_padding_bytes + sizeof(local_dir_header);
6356
6357 MZ_CLEAR_OBJ(local_dir_header);
6358 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6359 archive_name_size) != archive_name_size) {
6360 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6361 return MZ_FALSE;
6362 }
6363 cur_archive_file_ofs += archive_name_size;
6364
6365 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
6366 uncomp_crc32 =
6367 (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
6368 uncomp_size = buf_size;
6369 if (uncomp_size <= 3) {
6370 level = 0;
6371 store_data_uncompressed = MZ_TRUE;
6372 }
6373 }
6374
6375 if (store_data_uncompressed) {
6376 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf,
6377 buf_size) != buf_size) {
6378 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6379 return MZ_FALSE;
6380 }
6381
6382 cur_archive_file_ofs += buf_size;
6383 comp_size = buf_size;
6384
6385 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED;
6386 } else if (buf_size) {
6387 mz_zip_writer_add_state state;
6388
6389 state.m_pZip = pZip;
6390 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6391 state.m_comp_size = 0;
6392
6393 if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
6394 tdefl_create_comp_flags_from_zip_params(
6395 level, -15, MZ_DEFAULT_STRATEGY)) !=
6396 TDEFL_STATUS_OKAY) ||
6397 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) !=
6398 TDEFL_STATUS_DONE)) {
6399 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6400 return MZ_FALSE;
6401 }
6402
6403 comp_size = state.m_comp_size;
6404 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6405
6406 method = MZ_DEFLATED;
6407 }
6408
6409 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6410 pComp = NULL;
6411
6412 // no zip64 support yet
6413 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
6414 return MZ_FALSE;
6415
6416 if (!mz_zip_writer_create_local_dir_header(
6417 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
6418 comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
6419 return MZ_FALSE;
6420
6421 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
6422 sizeof(local_dir_header)) != sizeof(local_dir_header))
6423 return MZ_FALSE;
6424
6425 if (!mz_zip_writer_add_to_central_dir(
6426 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
6427 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
6428 dos_time, dos_date, local_dir_header_ofs, ext_attributes))
6429 return MZ_FALSE;
6430
6431 pZip->m_total_files++;
6432 pZip->m_archive_size = cur_archive_file_ofs;
6433
6434 return MZ_TRUE;
6435 }
6436
6437 #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)6438 mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
6439 const char *pSrc_filename, const void *pComment,
6440 mz_uint16 comment_size,
6441 mz_uint level_and_flags) {
6442 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
6443 mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
6444 mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
6445 cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0,
6446 comp_size = 0;
6447 size_t archive_name_size;
6448 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6449 MZ_FILE *pSrc_file = NULL;
6450
6451 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
6452 level = level_and_flags & 0xF;
6453
6454 if ((!pZip) || (!pZip->m_pState) ||
6455 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) ||
6456 ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
6457 return MZ_FALSE;
6458 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE;
6459 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
6460
6461 archive_name_size = strlen(pArchive_name);
6462 if (archive_name_size > 0xFFFF) return MZ_FALSE;
6463
6464 num_alignment_padding_bytes =
6465 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6466
6467 // no zip64 support yet
6468 if ((pZip->m_total_files == 0xFFFF) ||
6469 ((pZip->m_archive_size + num_alignment_padding_bytes +
6470 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6471 comment_size + archive_name_size) > 0xFFFFFFFF))
6472 return MZ_FALSE;
6473
6474 if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date))
6475 return MZ_FALSE;
6476
6477 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
6478 if (!pSrc_file) return MZ_FALSE;
6479 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
6480 uncomp_size = MZ_FTELL64(pSrc_file);
6481 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
6482
6483 if (uncomp_size > 0xFFFFFFFF) {
6484 // No zip64 support yet
6485 MZ_FCLOSE(pSrc_file);
6486 return MZ_FALSE;
6487 }
6488 if (uncomp_size <= 3) level = 0;
6489
6490 if (!mz_zip_writer_write_zeros(
6491 pZip, cur_archive_file_ofs,
6492 num_alignment_padding_bytes + sizeof(local_dir_header))) {
6493 MZ_FCLOSE(pSrc_file);
6494 return MZ_FALSE;
6495 }
6496 local_dir_header_ofs += num_alignment_padding_bytes;
6497 if (pZip->m_file_offset_alignment) {
6498 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6499 0);
6500 }
6501 cur_archive_file_ofs +=
6502 num_alignment_padding_bytes + sizeof(local_dir_header);
6503
6504 MZ_CLEAR_OBJ(local_dir_header);
6505 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6506 archive_name_size) != archive_name_size) {
6507 MZ_FCLOSE(pSrc_file);
6508 return MZ_FALSE;
6509 }
6510 cur_archive_file_ofs += archive_name_size;
6511
6512 if (uncomp_size) {
6513 mz_uint64 uncomp_remaining = uncomp_size;
6514 void *pRead_buf =
6515 pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
6516 if (!pRead_buf) {
6517 MZ_FCLOSE(pSrc_file);
6518 return MZ_FALSE;
6519 }
6520
6521 if (!level) {
6522 while (uncomp_remaining) {
6523 mz_uint n =
6524 (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
6525 if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) ||
6526 (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf,
6527 n) != n)) {
6528 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6529 MZ_FCLOSE(pSrc_file);
6530 return MZ_FALSE;
6531 }
6532 uncomp_crc32 =
6533 (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
6534 uncomp_remaining -= n;
6535 cur_archive_file_ofs += n;
6536 }
6537 comp_size = uncomp_size;
6538 } else {
6539 mz_bool result = MZ_FALSE;
6540 mz_zip_writer_add_state state;
6541 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(
6542 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
6543 if (!pComp) {
6544 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6545 MZ_FCLOSE(pSrc_file);
6546 return MZ_FALSE;
6547 }
6548
6549 state.m_pZip = pZip;
6550 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6551 state.m_comp_size = 0;
6552
6553 if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
6554 tdefl_create_comp_flags_from_zip_params(
6555 level, -15, MZ_DEFAULT_STRATEGY)) !=
6556 TDEFL_STATUS_OKAY) {
6557 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6558 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6559 MZ_FCLOSE(pSrc_file);
6560 return MZ_FALSE;
6561 }
6562
6563 for (;;) {
6564 size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining,
6565 (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
6566 tdefl_status status;
6567
6568 if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
6569 break;
6570
6571 uncomp_crc32 = (mz_uint32)mz_crc32(
6572 uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
6573 uncomp_remaining -= in_buf_size;
6574
6575 status = tdefl_compress_buffer(
6576 pComp, pRead_buf, in_buf_size,
6577 uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH);
6578 if (status == TDEFL_STATUS_DONE) {
6579 result = MZ_TRUE;
6580 break;
6581 } else if (status != TDEFL_STATUS_OKAY)
6582 break;
6583 }
6584
6585 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6586
6587 if (!result) {
6588 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6589 MZ_FCLOSE(pSrc_file);
6590 return MZ_FALSE;
6591 }
6592
6593 comp_size = state.m_comp_size;
6594 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6595
6596 method = MZ_DEFLATED;
6597 }
6598
6599 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6600 }
6601
6602 MZ_FCLOSE(pSrc_file);
6603 pSrc_file = NULL;
6604
6605 // no zip64 support yet
6606 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
6607 return MZ_FALSE;
6608
6609 if (!mz_zip_writer_create_local_dir_header(
6610 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
6611 comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
6612 return MZ_FALSE;
6613
6614 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
6615 sizeof(local_dir_header)) != sizeof(local_dir_header))
6616 return MZ_FALSE;
6617
6618 if (!mz_zip_writer_add_to_central_dir(
6619 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
6620 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
6621 dos_time, dos_date, local_dir_header_ofs, ext_attributes))
6622 return MZ_FALSE;
6623
6624 pZip->m_total_files++;
6625 pZip->m_archive_size = cur_archive_file_ofs;
6626
6627 return MZ_TRUE;
6628 }
6629 #endif // #ifndef MINIZ_NO_STDIO
6630
mz_zip_writer_add_from_zip_reader(mz_zip_archive * pZip,mz_zip_archive * pSource_zip,mz_uint file_index)6631 mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
6632 mz_zip_archive *pSource_zip,
6633 mz_uint file_index) {
6634 mz_uint n, bit_flags, num_alignment_padding_bytes;
6635 mz_uint64 comp_bytes_remaining, local_dir_header_ofs;
6636 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
6637 mz_uint32
6638 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
6639 sizeof(mz_uint32)];
6640 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
6641 mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6642 size_t orig_central_dir_size;
6643 mz_zip_internal_state *pState;
6644 void *pBuf;
6645 const mz_uint8 *pSrc_central_header;
6646
6647 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
6648 return MZ_FALSE;
6649 if (NULL ==
6650 (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index)))
6651 return MZ_FALSE;
6652 pState = pZip->m_pState;
6653
6654 num_alignment_padding_bytes =
6655 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6656
6657 // no zip64 support yet
6658 if ((pZip->m_total_files == 0xFFFF) ||
6659 ((pZip->m_archive_size + num_alignment_padding_bytes +
6660 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) >
6661 0xFFFFFFFF))
6662 return MZ_FALSE;
6663
6664 cur_src_file_ofs =
6665 MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
6666 cur_dst_file_ofs = pZip->m_archive_size;
6667
6668 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
6669 pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6670 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6671 return MZ_FALSE;
6672 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
6673 return MZ_FALSE;
6674 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
6675
6676 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs,
6677 num_alignment_padding_bytes))
6678 return MZ_FALSE;
6679 cur_dst_file_ofs += num_alignment_padding_bytes;
6680 local_dir_header_ofs = cur_dst_file_ofs;
6681 if (pZip->m_file_offset_alignment) {
6682 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6683 0);
6684 }
6685
6686 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header,
6687 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6688 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6689 return MZ_FALSE;
6690 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
6691
6692 n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
6693 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
6694 comp_bytes_remaining =
6695 n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
6696
6697 if (NULL == (pBuf = pZip->m_pAlloc(
6698 pZip->m_pAlloc_opaque, 1,
6699 (size_t)MZ_MAX(sizeof(mz_uint32) * 4,
6700 MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE,
6701 comp_bytes_remaining)))))
6702 return MZ_FALSE;
6703
6704 while (comp_bytes_remaining) {
6705 n = (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining);
6706 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
6707 n) != n) {
6708 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6709 return MZ_FALSE;
6710 }
6711 cur_src_file_ofs += n;
6712
6713 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
6714 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6715 return MZ_FALSE;
6716 }
6717 cur_dst_file_ofs += n;
6718
6719 comp_bytes_remaining -= n;
6720 }
6721
6722 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
6723 if (bit_flags & 8) {
6724 // Copy data descriptor
6725 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
6726 sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) {
6727 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6728 return MZ_FALSE;
6729 }
6730
6731 n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3);
6732 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
6733 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6734 return MZ_FALSE;
6735 }
6736
6737 cur_src_file_ofs += n;
6738 cur_dst_file_ofs += n;
6739 }
6740 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6741
6742 // no zip64 support yet
6743 if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE;
6744
6745 orig_central_dir_size = pState->m_central_dir.m_size;
6746
6747 memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
6748 MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
6749 local_dir_header_ofs);
6750 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header,
6751 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
6752 return MZ_FALSE;
6753
6754 n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
6755 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
6756 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
6757 if (!mz_zip_array_push_back(
6758 pZip, &pState->m_central_dir,
6759 pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) {
6760 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6761 MZ_FALSE);
6762 return MZ_FALSE;
6763 }
6764
6765 if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE;
6766 n = (mz_uint32)orig_central_dir_size;
6767 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) {
6768 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6769 MZ_FALSE);
6770 return MZ_FALSE;
6771 }
6772
6773 pZip->m_total_files++;
6774 pZip->m_archive_size = cur_dst_file_ofs;
6775
6776 return MZ_TRUE;
6777 }
6778
mz_zip_writer_finalize_archive(mz_zip_archive * pZip)6779 mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) {
6780 mz_zip_internal_state *pState;
6781 mz_uint64 central_dir_ofs, central_dir_size;
6782 mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE];
6783
6784 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
6785 return MZ_FALSE;
6786
6787 pState = pZip->m_pState;
6788
6789 // no zip64 support yet
6790 if ((pZip->m_total_files > 0xFFFF) ||
6791 ((pZip->m_archive_size + pState->m_central_dir.m_size +
6792 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
6793 return MZ_FALSE;
6794
6795 central_dir_ofs = 0;
6796 central_dir_size = 0;
6797 if (pZip->m_total_files) {
6798 // Write central directory
6799 central_dir_ofs = pZip->m_archive_size;
6800 central_dir_size = pState->m_central_dir.m_size;
6801 pZip->m_central_directory_file_ofs = central_dir_ofs;
6802 if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs,
6803 pState->m_central_dir.m_p,
6804 (size_t)central_dir_size) != central_dir_size)
6805 return MZ_FALSE;
6806 pZip->m_archive_size += central_dir_size;
6807 }
6808
6809 // Write end of central directory record
6810 MZ_CLEAR_OBJ(hdr);
6811 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS,
6812 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
6813 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS,
6814 pZip->m_total_files);
6815 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
6816 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size);
6817 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs);
6818
6819 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
6820 sizeof(hdr)) != sizeof(hdr))
6821 return MZ_FALSE;
6822 #ifndef MINIZ_NO_STDIO
6823 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE;
6824 #endif // #ifndef MINIZ_NO_STDIO
6825
6826 pZip->m_archive_size += sizeof(hdr);
6827
6828 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
6829 return MZ_TRUE;
6830 }
6831
mz_zip_writer_finalize_heap_archive(mz_zip_archive * pZip,void ** pBuf,size_t * pSize)6832 mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
6833 size_t *pSize) {
6834 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE;
6835 if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE;
6836 if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE;
6837
6838 *pBuf = pZip->m_pState->m_pMem;
6839 *pSize = pZip->m_pState->m_mem_size;
6840 pZip->m_pState->m_pMem = NULL;
6841 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
6842 return MZ_TRUE;
6843 }
6844
mz_zip_writer_end(mz_zip_archive * pZip)6845 mz_bool mz_zip_writer_end(mz_zip_archive *pZip) {
6846 mz_zip_internal_state *pState;
6847 mz_bool status = MZ_TRUE;
6848 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
6849 ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) &&
6850 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))
6851 return MZ_FALSE;
6852
6853 pState = pZip->m_pState;
6854 pZip->m_pState = NULL;
6855 mz_zip_array_clear(pZip, &pState->m_central_dir);
6856 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
6857 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
6858
6859 #ifndef MINIZ_NO_STDIO
6860 if (pState->m_pFile) {
6861 MZ_FCLOSE(pState->m_pFile);
6862 pState->m_pFile = NULL;
6863 }
6864 #endif // #ifndef MINIZ_NO_STDIO
6865
6866 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
6867 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
6868 pState->m_pMem = NULL;
6869 }
6870
6871 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
6872 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
6873 return status;
6874 }
6875
6876 #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)6877 mz_bool mz_zip_add_mem_to_archive_file_in_place(
6878 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
6879 size_t buf_size, const void *pComment, mz_uint16 comment_size,
6880 mz_uint level_and_flags) {
6881 mz_bool status, created_new_archive = MZ_FALSE;
6882 mz_zip_archive zip_archive;
6883 struct MZ_FILE_STAT_STRUCT file_stat;
6884 MZ_CLEAR_OBJ(zip_archive);
6885 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
6886 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) ||
6887 ((comment_size) && (!pComment)) ||
6888 ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
6889 return MZ_FALSE;
6890 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
6891 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) {
6892 // Create a new archive.
6893 if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0))
6894 return MZ_FALSE;
6895 created_new_archive = MZ_TRUE;
6896 } else {
6897 // Append to an existing archive.
6898 if (!mz_zip_reader_init_file(
6899 &zip_archive, pZip_filename,
6900 level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
6901 return MZ_FALSE;
6902 if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) {
6903 mz_zip_reader_end(&zip_archive);
6904 return MZ_FALSE;
6905 }
6906 }
6907 status =
6908 mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size,
6909 pComment, comment_size, level_and_flags, 0, 0);
6910 // Always finalize, even if adding failed for some reason, so we have a valid
6911 // central directory. (This may not always succeed, but we can try.)
6912 if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE;
6913 if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE;
6914 if ((!status) && (created_new_archive)) {
6915 // It's a new archive and something went wrong, so just delete it.
6916 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
6917 (void)ignoredStatus;
6918 }
6919 return status;
6920 }
6921
mz_zip_extract_archive_file_to_heap(const char * pZip_filename,const char * pArchive_name,size_t * pSize,mz_uint flags)6922 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
6923 const char *pArchive_name,
6924 size_t *pSize, mz_uint flags) {
6925 int file_index;
6926 mz_zip_archive zip_archive;
6927 void *p = NULL;
6928
6929 if (pSize) *pSize = 0;
6930
6931 if ((!pZip_filename) || (!pArchive_name)) return NULL;
6932
6933 MZ_CLEAR_OBJ(zip_archive);
6934 if (!mz_zip_reader_init_file(
6935 &zip_archive, pZip_filename,
6936 flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
6937 return NULL;
6938
6939 if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL,
6940 flags)) >= 0)
6941 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
6942
6943 mz_zip_reader_end(&zip_archive);
6944 return p;
6945 }
6946
6947 #endif // #ifndef MINIZ_NO_STDIO
6948
6949 #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
6950
6951 #endif // #ifndef MINIZ_NO_ARCHIVE_APIS
6952
6953 #ifdef __cplusplus
6954 }
6955 #endif
6956
6957 #ifdef _MSC_VER
6958 #pragma warning(pop)
6959 #endif
6960
6961 #endif // MINIZ_HEADER_FILE_ONLY
6962
6963 /*
6964 This is free and unencumbered software released into the public domain.
6965
6966 Anyone is free to copy, modify, publish, use, compile, sell, or
6967 distribute this software, either in source code form or as a compiled
6968 binary, for any purpose, commercial or non-commercial, and by any
6969 means.
6970
6971 In jurisdictions that recognize copyright laws, the author or authors
6972 of this software dedicate any and all copyright interest in the
6973 software to the public domain. We make this dedication for the benefit
6974 of the public at large and to the detriment of our heirs and
6975 successors. We intend this dedication to be an overt act of
6976 relinquishment in perpetuity of all present and future rights to this
6977 software under copyright law.
6978
6979 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
6980 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
6981 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
6982 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
6983 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
6984 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
6985 OTHER DEALINGS IN THE SOFTWARE.
6986
6987 For more information, please refer to <http://unlicense.org/>
6988 */
6989
6990 // ---------------------- end of miniz ----------------------------------------
6991
6992 #ifdef __clang__
6993 #pragma clang diagnostic pop
6994 #endif
6995
6996 } // namespace miniz
6997 #else
6998
6999 // Reuse MINIZ_LITTE_ENDIAN macro
7000
7001 #if defined(__sparcv9)
7002 // Big endian
7003 #else
7004 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
7005 // Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
7006 #define MINIZ_LITTLE_ENDIAN 1
7007 #endif
7008 #endif
7009
7010 #endif // TINYEXR_USE_MINIZ
7011
7012 // static bool IsBigEndian(void) {
7013 // union {
7014 // unsigned int i;
7015 // char c[4];
7016 // } bint = {0x01020304};
7017 //
7018 // return bint.c[0] == 1;
7019 //}
7020
SetErrorMessage(const std::string & msg,const char ** err)7021 static void SetErrorMessage(const std::string &msg, const char **err) {
7022 if (err) {
7023 #ifdef _WIN32
7024 (*err) = _strdup(msg.c_str());
7025 #else
7026 (*err) = strdup(msg.c_str());
7027 #endif
7028 }
7029 }
7030
7031 static const int kEXRVersionSize = 8;
7032
cpy2(unsigned short * dst_val,const unsigned short * src_val)7033 static void cpy2(unsigned short *dst_val, const unsigned short *src_val) {
7034 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7035 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7036
7037 dst[0] = src[0];
7038 dst[1] = src[1];
7039 }
7040
swap2(unsigned short * val)7041 static void swap2(unsigned short *val) {
7042 #ifdef MINIZ_LITTLE_ENDIAN
7043 (void)val;
7044 #else
7045 unsigned short tmp = *val;
7046 unsigned char *dst = reinterpret_cast<unsigned char *>(val);
7047 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
7048
7049 dst[0] = src[1];
7050 dst[1] = src[0];
7051 #endif
7052 }
7053
7054 #ifdef __clang__
7055 #pragma clang diagnostic push
7056 #pragma clang diagnostic ignored "-Wunused-function"
7057 #endif
7058
7059 #ifdef __GNUC__
7060 #pragma GCC diagnostic push
7061 #pragma GCC diagnostic ignored "-Wunused-function"
7062 #endif
cpy4(int * dst_val,const int * src_val)7063 static void cpy4(int *dst_val, const int *src_val) {
7064 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7065 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7066
7067 dst[0] = src[0];
7068 dst[1] = src[1];
7069 dst[2] = src[2];
7070 dst[3] = src[3];
7071 }
7072
cpy4(unsigned int * dst_val,const unsigned int * src_val)7073 static void cpy4(unsigned int *dst_val, const unsigned int *src_val) {
7074 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7075 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7076
7077 dst[0] = src[0];
7078 dst[1] = src[1];
7079 dst[2] = src[2];
7080 dst[3] = src[3];
7081 }
7082
cpy4(float * dst_val,const float * src_val)7083 static void cpy4(float *dst_val, const float *src_val) {
7084 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7085 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7086
7087 dst[0] = src[0];
7088 dst[1] = src[1];
7089 dst[2] = src[2];
7090 dst[3] = src[3];
7091 }
7092 #ifdef __clang__
7093 #pragma clang diagnostic pop
7094 #endif
7095
7096 #ifdef __GNUC__
7097 #pragma GCC diagnostic pop
7098 #endif
7099
swap4(unsigned int * val)7100 static void swap4(unsigned int *val) {
7101 #ifdef MINIZ_LITTLE_ENDIAN
7102 (void)val;
7103 #else
7104 unsigned int tmp = *val;
7105 unsigned char *dst = reinterpret_cast<unsigned char *>(val);
7106 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
7107
7108 dst[0] = src[3];
7109 dst[1] = src[2];
7110 dst[2] = src[1];
7111 dst[3] = src[0];
7112 #endif
7113 }
7114
7115 #if 0
7116 static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) {
7117 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7118 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7119
7120 dst[0] = src[0];
7121 dst[1] = src[1];
7122 dst[2] = src[2];
7123 dst[3] = src[3];
7124 dst[4] = src[4];
7125 dst[5] = src[5];
7126 dst[6] = src[6];
7127 dst[7] = src[7];
7128 }
7129 #endif
7130
swap8(tinyexr::tinyexr_uint64 * val)7131 static void swap8(tinyexr::tinyexr_uint64 *val) {
7132 #ifdef MINIZ_LITTLE_ENDIAN
7133 (void)val;
7134 #else
7135 tinyexr::tinyexr_uint64 tmp = (*val);
7136 unsigned char *dst = reinterpret_cast<unsigned char *>(val);
7137 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
7138
7139 dst[0] = src[7];
7140 dst[1] = src[6];
7141 dst[2] = src[5];
7142 dst[3] = src[4];
7143 dst[4] = src[3];
7144 dst[5] = src[2];
7145 dst[6] = src[1];
7146 dst[7] = src[0];
7147 #endif
7148 }
7149
7150 // https://gist.github.com/rygorous/2156668
7151 // Reuse MINIZ_LITTLE_ENDIAN flag from miniz.
7152 union FP32 {
7153 unsigned int u;
7154 float f;
7155 struct {
7156 #if MINIZ_LITTLE_ENDIAN
7157 unsigned int Mantissa : 23;
7158 unsigned int Exponent : 8;
7159 unsigned int Sign : 1;
7160 #else
7161 unsigned int Sign : 1;
7162 unsigned int Exponent : 8;
7163 unsigned int Mantissa : 23;
7164 #endif
7165 } s;
7166 };
7167
7168 #ifdef __clang__
7169 #pragma clang diagnostic push
7170 #pragma clang diagnostic ignored "-Wpadded"
7171 #endif
7172
7173 union FP16 {
7174 unsigned short u;
7175 struct {
7176 #if MINIZ_LITTLE_ENDIAN
7177 unsigned int Mantissa : 10;
7178 unsigned int Exponent : 5;
7179 unsigned int Sign : 1;
7180 #else
7181 unsigned int Sign : 1;
7182 unsigned int Exponent : 5;
7183 unsigned int Mantissa : 10;
7184 #endif
7185 } s;
7186 };
7187
7188 #ifdef __clang__
7189 #pragma clang diagnostic pop
7190 #endif
7191
half_to_float(FP16 h)7192 static FP32 half_to_float(FP16 h) {
7193 static const FP32 magic = {113 << 23};
7194 static const unsigned int shifted_exp = 0x7c00
7195 << 13; // exponent mask after shift
7196 FP32 o;
7197
7198 o.u = (h.u & 0x7fffU) << 13U; // exponent/mantissa bits
7199 unsigned int exp_ = shifted_exp & o.u; // just the exponent
7200 o.u += (127 - 15) << 23; // exponent adjust
7201
7202 // handle exponent special cases
7203 if (exp_ == shifted_exp) // Inf/NaN?
7204 o.u += (128 - 16) << 23; // extra exp adjust
7205 else if (exp_ == 0) // Zero/Denormal?
7206 {
7207 o.u += 1 << 23; // extra exp adjust
7208 o.f -= magic.f; // renormalize
7209 }
7210
7211 o.u |= (h.u & 0x8000U) << 16U; // sign bit
7212 return o;
7213 }
7214
float_to_half_full(FP32 f)7215 static FP16 float_to_half_full(FP32 f) {
7216 FP16 o = {0};
7217
7218 // Based on ISPC reference code (with minor modifications)
7219 if (f.s.Exponent == 0) // Signed zero/denormal (which will underflow)
7220 o.s.Exponent = 0;
7221 else if (f.s.Exponent == 255) // Inf or NaN (all exponent bits set)
7222 {
7223 o.s.Exponent = 31;
7224 o.s.Mantissa = f.s.Mantissa ? 0x200 : 0; // NaN->qNaN and Inf->Inf
7225 } else // Normalized number
7226 {
7227 // Exponent unbias the single, then bias the halfp
7228 int newexp = f.s.Exponent - 127 + 15;
7229 if (newexp >= 31) // Overflow, return signed infinity
7230 o.s.Exponent = 31;
7231 else if (newexp <= 0) // Underflow
7232 {
7233 if ((14 - newexp) <= 24) // Mantissa might be non-zero
7234 {
7235 unsigned int mant = f.s.Mantissa | 0x800000; // Hidden 1 bit
7236 o.s.Mantissa = mant >> (14 - newexp);
7237 if ((mant >> (13 - newexp)) & 1) // Check for rounding
7238 o.u++; // Round, might overflow into exp bit, but this is OK
7239 }
7240 } else {
7241 o.s.Exponent = static_cast<unsigned int>(newexp);
7242 o.s.Mantissa = f.s.Mantissa >> 13;
7243 if (f.s.Mantissa & 0x1000) // Check for rounding
7244 o.u++; // Round, might overflow to inf, this is OK
7245 }
7246 }
7247
7248 o.s.Sign = f.s.Sign;
7249 return o;
7250 }
7251
7252 // NOTE: From OpenEXR code
7253 // #define IMF_INCREASING_Y 0
7254 // #define IMF_DECREASING_Y 1
7255 // #define IMF_RAMDOM_Y 2
7256 //
7257 // #define IMF_NO_COMPRESSION 0
7258 // #define IMF_RLE_COMPRESSION 1
7259 // #define IMF_ZIPS_COMPRESSION 2
7260 // #define IMF_ZIP_COMPRESSION 3
7261 // #define IMF_PIZ_COMPRESSION 4
7262 // #define IMF_PXR24_COMPRESSION 5
7263 // #define IMF_B44_COMPRESSION 6
7264 // #define IMF_B44A_COMPRESSION 7
7265
7266 #ifdef __clang__
7267 #pragma clang diagnostic push
7268
7269 #if __has_warning("-Wzero-as-null-pointer-constant")
7270 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
7271 #endif
7272
7273 #endif
7274
ReadString(std::string * s,const char * ptr,size_t len)7275 static const char *ReadString(std::string *s, const char *ptr, size_t len) {
7276 // Read untile NULL(\0).
7277 const char *p = ptr;
7278 const char *q = ptr;
7279 while ((size_t(q - ptr) < len) && (*q) != 0) {
7280 q++;
7281 }
7282
7283 if (size_t(q - ptr) >= len) {
7284 (*s) = std::string();
7285 return NULL;
7286 }
7287
7288 (*s) = std::string(p, q);
7289
7290 return q + 1; // skip '\0'
7291 }
7292
ReadAttribute(std::string * name,std::string * type,std::vector<unsigned char> * data,size_t * marker_size,const char * marker,size_t size)7293 static bool ReadAttribute(std::string *name, std::string *type,
7294 std::vector<unsigned char> *data, size_t *marker_size,
7295 const char *marker, size_t size) {
7296 size_t name_len = strnlen(marker, size);
7297 if (name_len == size) {
7298 // String does not have a terminating character.
7299 return false;
7300 }
7301 *name = std::string(marker, name_len);
7302
7303 marker += name_len + 1;
7304 size -= name_len + 1;
7305
7306 size_t type_len = strnlen(marker, size);
7307 if (type_len == size) {
7308 return false;
7309 }
7310 *type = std::string(marker, type_len);
7311
7312 marker += type_len + 1;
7313 size -= type_len + 1;
7314
7315 if (size < sizeof(uint32_t)) {
7316 return false;
7317 }
7318
7319 uint32_t data_len;
7320 memcpy(&data_len, marker, sizeof(uint32_t));
7321 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
7322
7323 if (data_len == 0) {
7324 if ((*type).compare("string") == 0) {
7325 // Accept empty string attribute.
7326
7327 marker += sizeof(uint32_t);
7328 size -= sizeof(uint32_t);
7329
7330 *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t);
7331
7332 data->resize(1);
7333 (*data)[0] = '\0';
7334
7335 return true;
7336 } else {
7337 return false;
7338 }
7339 }
7340
7341 marker += sizeof(uint32_t);
7342 size -= sizeof(uint32_t);
7343
7344 if (size < data_len) {
7345 return false;
7346 }
7347
7348 data->resize(static_cast<size_t>(data_len));
7349 memcpy(&data->at(0), marker, static_cast<size_t>(data_len));
7350
7351 *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t) + data_len;
7352 return true;
7353 }
7354
WriteAttributeToMemory(std::vector<unsigned char> * out,const char * name,const char * type,const unsigned char * data,int len)7355 static void WriteAttributeToMemory(std::vector<unsigned char> *out,
7356 const char *name, const char *type,
7357 const unsigned char *data, int len) {
7358 out->insert(out->end(), name, name + strlen(name) + 1);
7359 out->insert(out->end(), type, type + strlen(type) + 1);
7360
7361 int outLen = len;
7362 tinyexr::swap4(reinterpret_cast<unsigned int *>(&outLen));
7363 out->insert(out->end(), reinterpret_cast<unsigned char *>(&outLen),
7364 reinterpret_cast<unsigned char *>(&outLen) + sizeof(int));
7365 out->insert(out->end(), data, data + len);
7366 }
7367
7368 struct ChannelInfo {
7369 std::string name; // less than 255 bytes long
7370 int pixel_type;
7371 int x_sampling;
7372 int y_sampling;
7373 unsigned char p_linear;
7374 unsigned char pad[3];
7375 };
7376
7377 struct HeaderInfo {
7378 std::vector<tinyexr::ChannelInfo> channels;
7379 std::vector<EXRAttribute> attributes;
7380
7381 int data_window[4];
7382 int line_order;
7383 int display_window[4];
7384 float screen_window_center[2];
7385 float screen_window_width;
7386 float pixel_aspect_ratio;
7387
7388 int chunk_count;
7389
7390 // Tiled format
7391 int tile_size_x;
7392 int tile_size_y;
7393 int tile_level_mode;
7394 int tile_rounding_mode;
7395
7396 unsigned int header_len;
7397
7398 int compression_type;
7399
clearHeaderInfo7400 void clear() {
7401 channels.clear();
7402 attributes.clear();
7403
7404 data_window[0] = 0;
7405 data_window[1] = 0;
7406 data_window[2] = 0;
7407 data_window[3] = 0;
7408 line_order = 0;
7409 display_window[0] = 0;
7410 display_window[1] = 0;
7411 display_window[2] = 0;
7412 display_window[3] = 0;
7413 screen_window_center[0] = 0.0f;
7414 screen_window_center[1] = 0.0f;
7415 screen_window_width = 0.0f;
7416 pixel_aspect_ratio = 0.0f;
7417
7418 chunk_count = 0;
7419
7420 // Tiled format
7421 tile_size_x = 0;
7422 tile_size_y = 0;
7423 tile_level_mode = 0;
7424 tile_rounding_mode = 0;
7425
7426 header_len = 0;
7427 compression_type = 0;
7428 }
7429 };
7430
ReadChannelInfo(std::vector<ChannelInfo> & channels,const std::vector<unsigned char> & data)7431 static bool ReadChannelInfo(std::vector<ChannelInfo> &channels,
7432 const std::vector<unsigned char> &data) {
7433 const char *p = reinterpret_cast<const char *>(&data.at(0));
7434
7435 for (;;) {
7436 if ((*p) == 0) {
7437 break;
7438 }
7439 ChannelInfo info;
7440
7441 tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) -
7442 (p - reinterpret_cast<const char *>(data.data()));
7443 if (data_len < 0) {
7444 return false;
7445 }
7446
7447 p = ReadString(&info.name, p, size_t(data_len));
7448 if ((p == NULL) && (info.name.empty())) {
7449 // Buffer overrun. Issue #51.
7450 return false;
7451 }
7452
7453 const unsigned char *data_end =
7454 reinterpret_cast<const unsigned char *>(p) + 16;
7455 if (data_end >= (data.data() + data.size())) {
7456 return false;
7457 }
7458
7459 memcpy(&info.pixel_type, p, sizeof(int));
7460 p += 4;
7461 info.p_linear = static_cast<unsigned char>(p[0]); // uchar
7462 p += 1 + 3; // reserved: uchar[3]
7463 memcpy(&info.x_sampling, p, sizeof(int)); // int
7464 p += 4;
7465 memcpy(&info.y_sampling, p, sizeof(int)); // int
7466 p += 4;
7467
7468 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.pixel_type));
7469 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.x_sampling));
7470 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.y_sampling));
7471
7472 channels.push_back(info);
7473 }
7474
7475 return true;
7476 }
7477
WriteChannelInfo(std::vector<unsigned char> & data,const std::vector<ChannelInfo> & channels)7478 static void WriteChannelInfo(std::vector<unsigned char> &data,
7479 const std::vector<ChannelInfo> &channels) {
7480 size_t sz = 0;
7481
7482 // Calculate total size.
7483 for (size_t c = 0; c < channels.size(); c++) {
7484 sz += strlen(channels[c].name.c_str()) + 1; // +1 for \0
7485 sz += 16; // 4 * int
7486 }
7487 data.resize(sz + 1);
7488
7489 unsigned char *p = &data.at(0);
7490
7491 for (size_t c = 0; c < channels.size(); c++) {
7492 memcpy(p, channels[c].name.c_str(), strlen(channels[c].name.c_str()));
7493 p += strlen(channels[c].name.c_str());
7494 (*p) = '\0';
7495 p++;
7496
7497 int pixel_type = channels[c].pixel_type;
7498 int x_sampling = channels[c].x_sampling;
7499 int y_sampling = channels[c].y_sampling;
7500 tinyexr::swap4(reinterpret_cast<unsigned int *>(&pixel_type));
7501 tinyexr::swap4(reinterpret_cast<unsigned int *>(&x_sampling));
7502 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y_sampling));
7503
7504 memcpy(p, &pixel_type, sizeof(int));
7505 p += sizeof(int);
7506
7507 (*p) = channels[c].p_linear;
7508 p += 4;
7509
7510 memcpy(p, &x_sampling, sizeof(int));
7511 p += sizeof(int);
7512
7513 memcpy(p, &y_sampling, sizeof(int));
7514 p += sizeof(int);
7515 }
7516
7517 (*p) = '\0';
7518 }
7519
CompressZip(unsigned char * dst,tinyexr::tinyexr_uint64 & compressedSize,const unsigned char * src,unsigned long src_size)7520 static void CompressZip(unsigned char *dst,
7521 tinyexr::tinyexr_uint64 &compressedSize,
7522 const unsigned char *src, unsigned long src_size) {
7523 std::vector<unsigned char> tmpBuf(src_size);
7524
7525 //
7526 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7527 // ImfZipCompressor.cpp
7528 //
7529
7530 //
7531 // Reorder the pixel data.
7532 //
7533
7534 const char *srcPtr = reinterpret_cast<const char *>(src);
7535
7536 {
7537 char *t1 = reinterpret_cast<char *>(&tmpBuf.at(0));
7538 char *t2 = reinterpret_cast<char *>(&tmpBuf.at(0)) + (src_size + 1) / 2;
7539 const char *stop = srcPtr + src_size;
7540
7541 for (;;) {
7542 if (srcPtr < stop)
7543 *(t1++) = *(srcPtr++);
7544 else
7545 break;
7546
7547 if (srcPtr < stop)
7548 *(t2++) = *(srcPtr++);
7549 else
7550 break;
7551 }
7552 }
7553
7554 //
7555 // Predictor.
7556 //
7557
7558 {
7559 unsigned char *t = &tmpBuf.at(0) + 1;
7560 unsigned char *stop = &tmpBuf.at(0) + src_size;
7561 int p = t[-1];
7562
7563 while (t < stop) {
7564 int d = int(t[0]) - p + (128 + 256);
7565 p = t[0];
7566 t[0] = static_cast<unsigned char>(d);
7567 ++t;
7568 }
7569 }
7570
7571 #if TINYEXR_USE_MINIZ
7572 //
7573 // Compress the data using miniz
7574 //
7575
7576 miniz::mz_ulong outSize = miniz::mz_compressBound(src_size);
7577 int ret = miniz::mz_compress(
7578 dst, &outSize, static_cast<const unsigned char *>(&tmpBuf.at(0)),
7579 src_size);
7580 TEXR_ASSERT(ret == miniz::MZ_OK);
7581 (void)ret;
7582
7583 compressedSize = outSize;
7584 #else
7585 uLong outSize = compressBound(static_cast<uLong>(src_size));
7586 int ret = compress(dst, &outSize, static_cast<const Bytef *>(&tmpBuf.at(0)),
7587 src_size);
7588 TEXR_ASSERT(ret == Z_OK);
7589
7590 compressedSize = outSize;
7591 #endif
7592
7593 // Use uncompressed data when compressed data is larger than uncompressed.
7594 // (Issue 40)
7595 if (compressedSize >= src_size) {
7596 compressedSize = src_size;
7597 memcpy(dst, src, src_size);
7598 }
7599 }
7600
DecompressZip(unsigned char * dst,unsigned long * uncompressed_size,const unsigned char * src,unsigned long src_size)7601 static bool DecompressZip(unsigned char *dst,
7602 unsigned long *uncompressed_size /* inout */,
7603 const unsigned char *src, unsigned long src_size) {
7604 if ((*uncompressed_size) == src_size) {
7605 // Data is not compressed(Issue 40).
7606 memcpy(dst, src, src_size);
7607 return true;
7608 }
7609 std::vector<unsigned char> tmpBuf(*uncompressed_size);
7610
7611 #if TINYEXR_USE_MINIZ
7612 int ret =
7613 miniz::mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
7614 if (miniz::MZ_OK != ret) {
7615 return false;
7616 }
7617 #else
7618 int ret = uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
7619 if (Z_OK != ret) {
7620 return false;
7621 }
7622 #endif
7623
7624 //
7625 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7626 // ImfZipCompressor.cpp
7627 //
7628
7629 // Predictor.
7630 {
7631 unsigned char *t = &tmpBuf.at(0) + 1;
7632 unsigned char *stop = &tmpBuf.at(0) + (*uncompressed_size);
7633
7634 while (t < stop) {
7635 int d = int(t[-1]) + int(t[0]) - 128;
7636 t[0] = static_cast<unsigned char>(d);
7637 ++t;
7638 }
7639 }
7640
7641 // Reorder the pixel data.
7642 {
7643 const char *t1 = reinterpret_cast<const char *>(&tmpBuf.at(0));
7644 const char *t2 = reinterpret_cast<const char *>(&tmpBuf.at(0)) +
7645 (*uncompressed_size + 1) / 2;
7646 char *s = reinterpret_cast<char *>(dst);
7647 char *stop = s + (*uncompressed_size);
7648
7649 for (;;) {
7650 if (s < stop)
7651 *(s++) = *(t1++);
7652 else
7653 break;
7654
7655 if (s < stop)
7656 *(s++) = *(t2++);
7657 else
7658 break;
7659 }
7660 }
7661
7662 return true;
7663 }
7664
7665 // RLE code from OpenEXR --------------------------------------
7666
7667 #ifdef __clang__
7668 #pragma clang diagnostic push
7669 #pragma clang diagnostic ignored "-Wsign-conversion"
7670 #if __has_warning("-Wextra-semi-stmt")
7671 #pragma clang diagnostic ignored "-Wextra-semi-stmt"
7672 #endif
7673 #endif
7674
7675 #ifdef _MSC_VER
7676 #pragma warning(push)
7677 #pragma warning(disable : 4204) // nonstandard extension used : non-constant
7678 // aggregate initializer (also supported by GNU
7679 // C and C99, so no big deal)
7680 #pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
7681 // 'int', possible loss of data
7682 #pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
7683 // 'int', possible loss of data
7684 #pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
7685 // deprecated. Instead, use the ISO C and C++
7686 // conformant name: _strdup.
7687 #endif
7688
7689 const int MIN_RUN_LENGTH = 3;
7690 const int MAX_RUN_LENGTH = 127;
7691
7692 //
7693 // Compress an array of bytes, using run-length encoding,
7694 // and return the length of the compressed data.
7695 //
7696
rleCompress(int inLength,const char in[],signed char out[])7697 static int rleCompress(int inLength, const char in[], signed char out[]) {
7698 const char *inEnd = in + inLength;
7699 const char *runStart = in;
7700 const char *runEnd = in + 1;
7701 signed char *outWrite = out;
7702
7703 while (runStart < inEnd) {
7704 while (runEnd < inEnd && *runStart == *runEnd &&
7705 runEnd - runStart - 1 < MAX_RUN_LENGTH) {
7706 ++runEnd;
7707 }
7708
7709 if (runEnd - runStart >= MIN_RUN_LENGTH) {
7710 //
7711 // Compressable run
7712 //
7713
7714 *outWrite++ = static_cast<char>(runEnd - runStart) - 1;
7715 *outWrite++ = *(reinterpret_cast<const signed char *>(runStart));
7716 runStart = runEnd;
7717 } else {
7718 //
7719 // Uncompressable run
7720 //
7721
7722 while (runEnd < inEnd &&
7723 ((runEnd + 1 >= inEnd || *runEnd != *(runEnd + 1)) ||
7724 (runEnd + 2 >= inEnd || *(runEnd + 1) != *(runEnd + 2))) &&
7725 runEnd - runStart < MAX_RUN_LENGTH) {
7726 ++runEnd;
7727 }
7728
7729 *outWrite++ = static_cast<char>(runStart - runEnd);
7730
7731 while (runStart < runEnd) {
7732 *outWrite++ = *(reinterpret_cast<const signed char *>(runStart++));
7733 }
7734 }
7735
7736 ++runEnd;
7737 }
7738
7739 return static_cast<int>(outWrite - out);
7740 }
7741
7742 //
7743 // Uncompress an array of bytes compressed with rleCompress().
7744 // Returns the length of the oncompressed data, or 0 if the
7745 // length of the uncompressed data would be more than maxLength.
7746 //
7747
rleUncompress(int inLength,int maxLength,const signed char in[],char out[])7748 static int rleUncompress(int inLength, int maxLength, const signed char in[],
7749 char out[]) {
7750 char *outStart = out;
7751
7752 while (inLength > 0) {
7753 if (*in < 0) {
7754 int count = -(static_cast<int>(*in++));
7755 inLength -= count + 1;
7756
7757 // Fixes #116: Add bounds check to in buffer.
7758 if ((0 > (maxLength -= count)) || (inLength < 0)) return 0;
7759
7760 memcpy(out, in, count);
7761 out += count;
7762 in += count;
7763 } else {
7764 int count = *in++;
7765 inLength -= 2;
7766
7767 if (0 > (maxLength -= count + 1)) return 0;
7768
7769 memset(out, *reinterpret_cast<const char *>(in), count + 1);
7770 out += count + 1;
7771
7772 in++;
7773 }
7774 }
7775
7776 return static_cast<int>(out - outStart);
7777 }
7778
7779 #ifdef __clang__
7780 #pragma clang diagnostic pop
7781 #endif
7782
7783 // End of RLE code from OpenEXR -----------------------------------
7784
CompressRle(unsigned char * dst,tinyexr::tinyexr_uint64 & compressedSize,const unsigned char * src,unsigned long src_size)7785 static void CompressRle(unsigned char *dst,
7786 tinyexr::tinyexr_uint64 &compressedSize,
7787 const unsigned char *src, unsigned long src_size) {
7788 std::vector<unsigned char> tmpBuf(src_size);
7789
7790 //
7791 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7792 // ImfRleCompressor.cpp
7793 //
7794
7795 //
7796 // Reorder the pixel data.
7797 //
7798
7799 const char *srcPtr = reinterpret_cast<const char *>(src);
7800
7801 {
7802 char *t1 = reinterpret_cast<char *>(&tmpBuf.at(0));
7803 char *t2 = reinterpret_cast<char *>(&tmpBuf.at(0)) + (src_size + 1) / 2;
7804 const char *stop = srcPtr + src_size;
7805
7806 for (;;) {
7807 if (srcPtr < stop)
7808 *(t1++) = *(srcPtr++);
7809 else
7810 break;
7811
7812 if (srcPtr < stop)
7813 *(t2++) = *(srcPtr++);
7814 else
7815 break;
7816 }
7817 }
7818
7819 //
7820 // Predictor.
7821 //
7822
7823 {
7824 unsigned char *t = &tmpBuf.at(0) + 1;
7825 unsigned char *stop = &tmpBuf.at(0) + src_size;
7826 int p = t[-1];
7827
7828 while (t < stop) {
7829 int d = int(t[0]) - p + (128 + 256);
7830 p = t[0];
7831 t[0] = static_cast<unsigned char>(d);
7832 ++t;
7833 }
7834 }
7835
7836 // outSize will be (srcSiz * 3) / 2 at max.
7837 int outSize = rleCompress(static_cast<int>(src_size),
7838 reinterpret_cast<const char *>(&tmpBuf.at(0)),
7839 reinterpret_cast<signed char *>(dst));
7840 TEXR_ASSERT(outSize > 0);
7841
7842 compressedSize = static_cast<tinyexr::tinyexr_uint64>(outSize);
7843
7844 // Use uncompressed data when compressed data is larger than uncompressed.
7845 // (Issue 40)
7846 if (compressedSize >= src_size) {
7847 compressedSize = src_size;
7848 memcpy(dst, src, src_size);
7849 }
7850 }
7851
DecompressRle(unsigned char * dst,const unsigned long uncompressed_size,const unsigned char * src,unsigned long src_size)7852 static bool DecompressRle(unsigned char *dst,
7853 const unsigned long uncompressed_size,
7854 const unsigned char *src, unsigned long src_size) {
7855 if (uncompressed_size == src_size) {
7856 // Data is not compressed(Issue 40).
7857 memcpy(dst, src, src_size);
7858 return true;
7859 }
7860
7861 // Workaround for issue #112.
7862 // TODO(syoyo): Add more robust out-of-bounds check in `rleUncompress`.
7863 if (src_size <= 2) {
7864 return false;
7865 }
7866
7867 std::vector<unsigned char> tmpBuf(uncompressed_size);
7868
7869 int ret = rleUncompress(static_cast<int>(src_size),
7870 static_cast<int>(uncompressed_size),
7871 reinterpret_cast<const signed char *>(src),
7872 reinterpret_cast<char *>(&tmpBuf.at(0)));
7873 if (ret != static_cast<int>(uncompressed_size)) {
7874 return false;
7875 }
7876
7877 //
7878 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7879 // ImfRleCompressor.cpp
7880 //
7881
7882 // Predictor.
7883 {
7884 unsigned char *t = &tmpBuf.at(0) + 1;
7885 unsigned char *stop = &tmpBuf.at(0) + uncompressed_size;
7886
7887 while (t < stop) {
7888 int d = int(t[-1]) + int(t[0]) - 128;
7889 t[0] = static_cast<unsigned char>(d);
7890 ++t;
7891 }
7892 }
7893
7894 // Reorder the pixel data.
7895 {
7896 const char *t1 = reinterpret_cast<const char *>(&tmpBuf.at(0));
7897 const char *t2 = reinterpret_cast<const char *>(&tmpBuf.at(0)) +
7898 (uncompressed_size + 1) / 2;
7899 char *s = reinterpret_cast<char *>(dst);
7900 char *stop = s + uncompressed_size;
7901
7902 for (;;) {
7903 if (s < stop)
7904 *(s++) = *(t1++);
7905 else
7906 break;
7907
7908 if (s < stop)
7909 *(s++) = *(t2++);
7910 else
7911 break;
7912 }
7913 }
7914
7915 return true;
7916 }
7917
7918 #if TINYEXR_USE_PIZ
7919
7920 #ifdef __clang__
7921 #pragma clang diagnostic push
7922 #pragma clang diagnostic ignored "-Wc++11-long-long"
7923 #pragma clang diagnostic ignored "-Wold-style-cast"
7924 #pragma clang diagnostic ignored "-Wpadded"
7925 #pragma clang diagnostic ignored "-Wsign-conversion"
7926 #pragma clang diagnostic ignored "-Wc++11-extensions"
7927 #pragma clang diagnostic ignored "-Wconversion"
7928 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
7929
7930 #if __has_warning("-Wcast-qual")
7931 #pragma clang diagnostic ignored "-Wcast-qual"
7932 #endif
7933
7934 #if __has_warning("-Wextra-semi-stmt")
7935 #pragma clang diagnostic ignored "-Wextra-semi-stmt"
7936 #endif
7937
7938 #endif
7939
7940 //
7941 // PIZ compress/uncompress, based on OpenEXR's ImfPizCompressor.cpp
7942 //
7943 // -----------------------------------------------------------------
7944 // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
7945 // Digital Ltd. LLC)
7946 // (3 clause BSD license)
7947 //
7948
7949 struct PIZChannelData {
7950 unsigned short *start;
7951 unsigned short *end;
7952 int nx;
7953 int ny;
7954 int ys;
7955 int size;
7956 };
7957
7958 //-----------------------------------------------------------------------------
7959 //
7960 // 16-bit Haar Wavelet encoding and decoding
7961 //
7962 // The source code in this file is derived from the encoding
7963 // and decoding routines written by Christian Rouet for his
7964 // PIZ image file format.
7965 //
7966 //-----------------------------------------------------------------------------
7967
7968 //
7969 // Wavelet basis functions without modulo arithmetic; they produce
7970 // the best compression ratios when the wavelet-transformed data are
7971 // Huffman-encoded, but the wavelet transform works only for 14-bit
7972 // data (untransformed data values must be less than (1 << 14)).
7973 //
7974
wenc14(unsigned short a,unsigned short b,unsigned short & l,unsigned short & h)7975 inline void wenc14(unsigned short a, unsigned short b, unsigned short &l,
7976 unsigned short &h) {
7977 short as = static_cast<short>(a);
7978 short bs = static_cast<short>(b);
7979
7980 short ms = (as + bs) >> 1;
7981 short ds = as - bs;
7982
7983 l = static_cast<unsigned short>(ms);
7984 h = static_cast<unsigned short>(ds);
7985 }
7986
wdec14(unsigned short l,unsigned short h,unsigned short & a,unsigned short & b)7987 inline void wdec14(unsigned short l, unsigned short h, unsigned short &a,
7988 unsigned short &b) {
7989 short ls = static_cast<short>(l);
7990 short hs = static_cast<short>(h);
7991
7992 int hi = hs;
7993 int ai = ls + (hi & 1) + (hi >> 1);
7994
7995 short as = static_cast<short>(ai);
7996 short bs = static_cast<short>(ai - hi);
7997
7998 a = static_cast<unsigned short>(as);
7999 b = static_cast<unsigned short>(bs);
8000 }
8001
8002 //
8003 // Wavelet basis functions with modulo arithmetic; they work with full
8004 // 16-bit data, but Huffman-encoding the wavelet-transformed data doesn't
8005 // compress the data quite as well.
8006 //
8007
8008 const int NBITS = 16;
8009 const int A_OFFSET = 1 << (NBITS - 1);
8010 const int M_OFFSET = 1 << (NBITS - 1);
8011 const int MOD_MASK = (1 << NBITS) - 1;
8012
wenc16(unsigned short a,unsigned short b,unsigned short & l,unsigned short & h)8013 inline void wenc16(unsigned short a, unsigned short b, unsigned short &l,
8014 unsigned short &h) {
8015 int ao = (a + A_OFFSET) & MOD_MASK;
8016 int m = ((ao + b) >> 1);
8017 int d = ao - b;
8018
8019 if (d < 0) m = (m + M_OFFSET) & MOD_MASK;
8020
8021 d &= MOD_MASK;
8022
8023 l = static_cast<unsigned short>(m);
8024 h = static_cast<unsigned short>(d);
8025 }
8026
wdec16(unsigned short l,unsigned short h,unsigned short & a,unsigned short & b)8027 inline void wdec16(unsigned short l, unsigned short h, unsigned short &a,
8028 unsigned short &b) {
8029 int m = l;
8030 int d = h;
8031 int bb = (m - (d >> 1)) & MOD_MASK;
8032 int aa = (d + bb - A_OFFSET) & MOD_MASK;
8033 b = static_cast<unsigned short>(bb);
8034 a = static_cast<unsigned short>(aa);
8035 }
8036
8037 //
8038 // 2D Wavelet encoding:
8039 //
8040
wav2Encode(unsigned short * in,int nx,int ox,int ny,int oy,unsigned short mx)8041 static void wav2Encode(
8042 unsigned short *in, // io: values are transformed in place
8043 int nx, // i : x size
8044 int ox, // i : x offset
8045 int ny, // i : y size
8046 int oy, // i : y offset
8047 unsigned short mx) // i : maximum in[x][y] value
8048 {
8049 bool w14 = (mx < (1 << 14));
8050 int n = (nx > ny) ? ny : nx;
8051 int p = 1; // == 1 << level
8052 int p2 = 2; // == 1 << (level+1)
8053
8054 //
8055 // Hierachical loop on smaller dimension n
8056 //
8057
8058 while (p2 <= n) {
8059 unsigned short *py = in;
8060 unsigned short *ey = in + oy * (ny - p2);
8061 int oy1 = oy * p;
8062 int oy2 = oy * p2;
8063 int ox1 = ox * p;
8064 int ox2 = ox * p2;
8065 unsigned short i00, i01, i10, i11;
8066
8067 //
8068 // Y loop
8069 //
8070
8071 for (; py <= ey; py += oy2) {
8072 unsigned short *px = py;
8073 unsigned short *ex = py + ox * (nx - p2);
8074
8075 //
8076 // X loop
8077 //
8078
8079 for (; px <= ex; px += ox2) {
8080 unsigned short *p01 = px + ox1;
8081 unsigned short *p10 = px + oy1;
8082 unsigned short *p11 = p10 + ox1;
8083
8084 //
8085 // 2D wavelet encoding
8086 //
8087
8088 if (w14) {
8089 wenc14(*px, *p01, i00, i01);
8090 wenc14(*p10, *p11, i10, i11);
8091 wenc14(i00, i10, *px, *p10);
8092 wenc14(i01, i11, *p01, *p11);
8093 } else {
8094 wenc16(*px, *p01, i00, i01);
8095 wenc16(*p10, *p11, i10, i11);
8096 wenc16(i00, i10, *px, *p10);
8097 wenc16(i01, i11, *p01, *p11);
8098 }
8099 }
8100
8101 //
8102 // Encode (1D) odd column (still in Y loop)
8103 //
8104
8105 if (nx & p) {
8106 unsigned short *p10 = px + oy1;
8107
8108 if (w14)
8109 wenc14(*px, *p10, i00, *p10);
8110 else
8111 wenc16(*px, *p10, i00, *p10);
8112
8113 *px = i00;
8114 }
8115 }
8116
8117 //
8118 // Encode (1D) odd line (must loop in X)
8119 //
8120
8121 if (ny & p) {
8122 unsigned short *px = py;
8123 unsigned short *ex = py + ox * (nx - p2);
8124
8125 for (; px <= ex; px += ox2) {
8126 unsigned short *p01 = px + ox1;
8127
8128 if (w14)
8129 wenc14(*px, *p01, i00, *p01);
8130 else
8131 wenc16(*px, *p01, i00, *p01);
8132
8133 *px = i00;
8134 }
8135 }
8136
8137 //
8138 // Next level
8139 //
8140
8141 p = p2;
8142 p2 <<= 1;
8143 }
8144 }
8145
8146 //
8147 // 2D Wavelet decoding:
8148 //
8149
wav2Decode(unsigned short * in,int nx,int ox,int ny,int oy,unsigned short mx)8150 static void wav2Decode(
8151 unsigned short *in, // io: values are transformed in place
8152 int nx, // i : x size
8153 int ox, // i : x offset
8154 int ny, // i : y size
8155 int oy, // i : y offset
8156 unsigned short mx) // i : maximum in[x][y] value
8157 {
8158 bool w14 = (mx < (1 << 14));
8159 int n = (nx > ny) ? ny : nx;
8160 int p = 1;
8161 int p2;
8162
8163 //
8164 // Search max level
8165 //
8166
8167 while (p <= n) p <<= 1;
8168
8169 p >>= 1;
8170 p2 = p;
8171 p >>= 1;
8172
8173 //
8174 // Hierarchical loop on smaller dimension n
8175 //
8176
8177 while (p >= 1) {
8178 unsigned short *py = in;
8179 unsigned short *ey = in + oy * (ny - p2);
8180 int oy1 = oy * p;
8181 int oy2 = oy * p2;
8182 int ox1 = ox * p;
8183 int ox2 = ox * p2;
8184 unsigned short i00, i01, i10, i11;
8185
8186 //
8187 // Y loop
8188 //
8189
8190 for (; py <= ey; py += oy2) {
8191 unsigned short *px = py;
8192 unsigned short *ex = py + ox * (nx - p2);
8193
8194 //
8195 // X loop
8196 //
8197
8198 for (; px <= ex; px += ox2) {
8199 unsigned short *p01 = px + ox1;
8200 unsigned short *p10 = px + oy1;
8201 unsigned short *p11 = p10 + ox1;
8202
8203 //
8204 // 2D wavelet decoding
8205 //
8206
8207 if (w14) {
8208 wdec14(*px, *p10, i00, i10);
8209 wdec14(*p01, *p11, i01, i11);
8210 wdec14(i00, i01, *px, *p01);
8211 wdec14(i10, i11, *p10, *p11);
8212 } else {
8213 wdec16(*px, *p10, i00, i10);
8214 wdec16(*p01, *p11, i01, i11);
8215 wdec16(i00, i01, *px, *p01);
8216 wdec16(i10, i11, *p10, *p11);
8217 }
8218 }
8219
8220 //
8221 // Decode (1D) odd column (still in Y loop)
8222 //
8223
8224 if (nx & p) {
8225 unsigned short *p10 = px + oy1;
8226
8227 if (w14)
8228 wdec14(*px, *p10, i00, *p10);
8229 else
8230 wdec16(*px, *p10, i00, *p10);
8231
8232 *px = i00;
8233 }
8234 }
8235
8236 //
8237 // Decode (1D) odd line (must loop in X)
8238 //
8239
8240 if (ny & p) {
8241 unsigned short *px = py;
8242 unsigned short *ex = py + ox * (nx - p2);
8243
8244 for (; px <= ex; px += ox2) {
8245 unsigned short *p01 = px + ox1;
8246
8247 if (w14)
8248 wdec14(*px, *p01, i00, *p01);
8249 else
8250 wdec16(*px, *p01, i00, *p01);
8251
8252 *px = i00;
8253 }
8254 }
8255
8256 //
8257 // Next level
8258 //
8259
8260 p2 = p;
8261 p >>= 1;
8262 }
8263 }
8264
8265 //-----------------------------------------------------------------------------
8266 //
8267 // 16-bit Huffman compression and decompression.
8268 //
8269 // The source code in this file is derived from the 8-bit
8270 // Huffman compression and decompression routines written
8271 // by Christian Rouet for his PIZ image file format.
8272 //
8273 //-----------------------------------------------------------------------------
8274
8275 // Adds some modification for tinyexr.
8276
8277 const int HUF_ENCBITS = 16; // literal (value) bit length
8278 const int HUF_DECBITS = 14; // decoding bit size (>= 8)
8279
8280 const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1; // encoding table size
8281 const int HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size
8282 const int HUF_DECMASK = HUF_DECSIZE - 1;
8283
8284 struct HufDec { // short code long code
8285 //-------------------------------
8286 int len : 8; // code length 0
8287 int lit : 24; // lit p size
8288 int *p; // 0 lits
8289 };
8290
hufLength(long long code)8291 inline long long hufLength(long long code) { return code & 63; }
8292
hufCode(long long code)8293 inline long long hufCode(long long code) { return code >> 6; }
8294
outputBits(int nBits,long long bits,long long & c,int & lc,char * & out)8295 inline void outputBits(int nBits, long long bits, long long &c, int &lc,
8296 char *&out) {
8297 c <<= nBits;
8298 lc += nBits;
8299
8300 c |= bits;
8301
8302 while (lc >= 8) *out++ = static_cast<char>((c >> (lc -= 8)));
8303 }
8304
getBits(int nBits,long long & c,int & lc,const char * & in)8305 inline long long getBits(int nBits, long long &c, int &lc, const char *&in) {
8306 while (lc < nBits) {
8307 c = (c << 8) | *(reinterpret_cast<const unsigned char *>(in++));
8308 lc += 8;
8309 }
8310
8311 lc -= nBits;
8312 return (c >> lc) & ((1 << nBits) - 1);
8313 }
8314
8315 //
8316 // ENCODING TABLE BUILDING & (UN)PACKING
8317 //
8318
8319 //
8320 // Build a "canonical" Huffman code table:
8321 // - for each (uncompressed) symbol, hcode contains the length
8322 // of the corresponding code (in the compressed data)
8323 // - canonical codes are computed and stored in hcode
8324 // - the rules for constructing canonical codes are as follows:
8325 // * shorter codes (if filled with zeroes to the right)
8326 // have a numerically higher value than longer codes
8327 // * for codes with the same length, numerical values
8328 // increase with numerical symbol values
8329 // - because the canonical code table can be constructed from
8330 // symbol lengths alone, the code table can be transmitted
8331 // without sending the actual code values
8332 // - see http://www.compressconsult.com/huffman/
8333 //
8334
hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE])8335 static void hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE]) {
8336 long long n[59];
8337
8338 //
8339 // For each i from 0 through 58, count the
8340 // number of different codes of length i, and
8341 // store the count in n[i].
8342 //
8343
8344 for (int i = 0; i <= 58; ++i) n[i] = 0;
8345
8346 for (int i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1;
8347
8348 //
8349 // For each i from 58 through 1, compute the
8350 // numerically lowest code with length i, and
8351 // store that code in n[i].
8352 //
8353
8354 long long c = 0;
8355
8356 for (int i = 58; i > 0; --i) {
8357 long long nc = ((c + n[i]) >> 1);
8358 n[i] = c;
8359 c = nc;
8360 }
8361
8362 //
8363 // hcode[i] contains the length, l, of the
8364 // code for symbol i. Assign the next available
8365 // code of length l to the symbol and store both
8366 // l and the code in hcode[i].
8367 //
8368
8369 for (int i = 0; i < HUF_ENCSIZE; ++i) {
8370 int l = static_cast<int>(hcode[i]);
8371
8372 if (l > 0) hcode[i] = l | (n[l]++ << 6);
8373 }
8374 }
8375
8376 //
8377 // Compute Huffman codes (based on frq input) and store them in frq:
8378 // - code structure is : [63:lsb - 6:msb] | [5-0: bit length];
8379 // - max code length is 58 bits;
8380 // - codes outside the range [im-iM] have a null length (unused values);
8381 // - original frequencies are destroyed;
8382 // - encoding tables are used by hufEncode() and hufBuildDecTable();
8383 //
8384
8385 struct FHeapCompare {
operatorFHeapCompare8386 bool operator()(long long *a, long long *b) { return *a > *b; }
8387 };
8388
hufBuildEncTable(long long * frq,int * im,int * iM)8389 static void hufBuildEncTable(
8390 long long *frq, // io: input frequencies [HUF_ENCSIZE], output table
8391 int *im, // o: min frq index
8392 int *iM) // o: max frq index
8393 {
8394 //
8395 // This function assumes that when it is called, array frq
8396 // indicates the frequency of all possible symbols in the data
8397 // that are to be Huffman-encoded. (frq[i] contains the number
8398 // of occurrences of symbol i in the data.)
8399 //
8400 // The loop below does three things:
8401 //
8402 // 1) Finds the minimum and maximum indices that point
8403 // to non-zero entries in frq:
8404 //
8405 // frq[im] != 0, and frq[i] == 0 for all i < im
8406 // frq[iM] != 0, and frq[i] == 0 for all i > iM
8407 //
8408 // 2) Fills array fHeap with pointers to all non-zero
8409 // entries in frq.
8410 //
8411 // 3) Initializes array hlink such that hlink[i] == i
8412 // for all array entries.
8413 //
8414
8415 std::vector<int> hlink(HUF_ENCSIZE);
8416 std::vector<long long *> fHeap(HUF_ENCSIZE);
8417
8418 *im = 0;
8419
8420 while (!frq[*im]) (*im)++;
8421
8422 int nf = 0;
8423
8424 for (int i = *im; i < HUF_ENCSIZE; i++) {
8425 hlink[i] = i;
8426
8427 if (frq[i]) {
8428 fHeap[nf] = &frq[i];
8429 nf++;
8430 *iM = i;
8431 }
8432 }
8433
8434 //
8435 // Add a pseudo-symbol, with a frequency count of 1, to frq;
8436 // adjust the fHeap and hlink array accordingly. Function
8437 // hufEncode() uses the pseudo-symbol for run-length encoding.
8438 //
8439
8440 (*iM)++;
8441 frq[*iM] = 1;
8442 fHeap[nf] = &frq[*iM];
8443 nf++;
8444
8445 //
8446 // Build an array, scode, such that scode[i] contains the number
8447 // of bits assigned to symbol i. Conceptually this is done by
8448 // constructing a tree whose leaves are the symbols with non-zero
8449 // frequency:
8450 //
8451 // Make a heap that contains all symbols with a non-zero frequency,
8452 // with the least frequent symbol on top.
8453 //
8454 // Repeat until only one symbol is left on the heap:
8455 //
8456 // Take the two least frequent symbols off the top of the heap.
8457 // Create a new node that has first two nodes as children, and
8458 // whose frequency is the sum of the frequencies of the first
8459 // two nodes. Put the new node back into the heap.
8460 //
8461 // The last node left on the heap is the root of the tree. For each
8462 // leaf node, the distance between the root and the leaf is the length
8463 // of the code for the corresponding symbol.
8464 //
8465 // The loop below doesn't actually build the tree; instead we compute
8466 // the distances of the leaves from the root on the fly. When a new
8467 // node is added to the heap, then that node's descendants are linked
8468 // into a single linear list that starts at the new node, and the code
8469 // lengths of the descendants (that is, their distance from the root
8470 // of the tree) are incremented by one.
8471 //
8472
8473 std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8474
8475 std::vector<long long> scode(HUF_ENCSIZE);
8476 memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE);
8477
8478 while (nf > 1) {
8479 //
8480 // Find the indices, mm and m, of the two smallest non-zero frq
8481 // values in fHeap, add the smallest frq to the second-smallest
8482 // frq, and remove the smallest frq value from fHeap.
8483 //
8484
8485 int mm = fHeap[0] - frq;
8486 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8487 --nf;
8488
8489 int m = fHeap[0] - frq;
8490 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8491
8492 frq[m] += frq[mm];
8493 std::push_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8494
8495 //
8496 // The entries in scode are linked into lists with the
8497 // entries in hlink serving as "next" pointers and with
8498 // the end of a list marked by hlink[j] == j.
8499 //
8500 // Traverse the lists that start at scode[m] and scode[mm].
8501 // For each element visited, increment the length of the
8502 // corresponding code by one bit. (If we visit scode[j]
8503 // during the traversal, then the code for symbol j becomes
8504 // one bit longer.)
8505 //
8506 // Merge the lists that start at scode[m] and scode[mm]
8507 // into a single list that starts at scode[m].
8508 //
8509
8510 //
8511 // Add a bit to all codes in the first list.
8512 //
8513
8514 for (int j = m;; j = hlink[j]) {
8515 scode[j]++;
8516
8517 TEXR_ASSERT(scode[j] <= 58);
8518
8519 if (hlink[j] == j) {
8520 //
8521 // Merge the two lists.
8522 //
8523
8524 hlink[j] = mm;
8525 break;
8526 }
8527 }
8528
8529 //
8530 // Add a bit to all codes in the second list
8531 //
8532
8533 for (int j = mm;; j = hlink[j]) {
8534 scode[j]++;
8535
8536 TEXR_ASSERT(scode[j] <= 58);
8537
8538 if (hlink[j] == j) break;
8539 }
8540 }
8541
8542 //
8543 // Build a canonical Huffman code table, replacing the code
8544 // lengths in scode with (code, code length) pairs. Copy the
8545 // code table from scode into frq.
8546 //
8547
8548 hufCanonicalCodeTable(scode.data());
8549 memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE);
8550 }
8551
8552 //
8553 // Pack an encoding table:
8554 // - only code lengths, not actual codes, are stored
8555 // - runs of zeroes are compressed as follows:
8556 //
8557 // unpacked packed
8558 // --------------------------------
8559 // 1 zero 0 (6 bits)
8560 // 2 zeroes 59
8561 // 3 zeroes 60
8562 // 4 zeroes 61
8563 // 5 zeroes 62
8564 // n zeroes (6 or more) 63 n-6 (6 + 8 bits)
8565 //
8566
8567 const int SHORT_ZEROCODE_RUN = 59;
8568 const int LONG_ZEROCODE_RUN = 63;
8569 const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
8570 const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN;
8571
hufPackEncTable(const long long * hcode,int im,int iM,char ** pcode)8572 static void hufPackEncTable(
8573 const long long *hcode, // i : encoding table [HUF_ENCSIZE]
8574 int im, // i : min hcode index
8575 int iM, // i : max hcode index
8576 char **pcode) // o: ptr to packed table (updated)
8577 {
8578 char *p = *pcode;
8579 long long c = 0;
8580 int lc = 0;
8581
8582 for (; im <= iM; im++) {
8583 int l = hufLength(hcode[im]);
8584
8585 if (l == 0) {
8586 int zerun = 1;
8587
8588 while ((im < iM) && (zerun < LONGEST_LONG_RUN)) {
8589 if (hufLength(hcode[im + 1]) > 0) break;
8590 im++;
8591 zerun++;
8592 }
8593
8594 if (zerun >= 2) {
8595 if (zerun >= SHORTEST_LONG_RUN) {
8596 outputBits(6, LONG_ZEROCODE_RUN, c, lc, p);
8597 outputBits(8, zerun - SHORTEST_LONG_RUN, c, lc, p);
8598 } else {
8599 outputBits(6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p);
8600 }
8601 continue;
8602 }
8603 }
8604
8605 outputBits(6, l, c, lc, p);
8606 }
8607
8608 if (lc > 0) *p++ = (unsigned char)(c << (8 - lc));
8609
8610 *pcode = p;
8611 }
8612
8613 //
8614 // Unpack an encoding table packed by hufPackEncTable():
8615 //
8616
hufUnpackEncTable(const char ** pcode,int ni,int im,int iM,long long * hcode)8617 static bool hufUnpackEncTable(
8618 const char **pcode, // io: ptr to packed table (updated)
8619 int ni, // i : input size (in bytes)
8620 int im, // i : min hcode index
8621 int iM, // i : max hcode index
8622 long long *hcode) // o: encoding table [HUF_ENCSIZE]
8623 {
8624 memset(hcode, 0, sizeof(long long) * HUF_ENCSIZE);
8625
8626 const char *p = *pcode;
8627 long long c = 0;
8628 int lc = 0;
8629
8630 for (; im <= iM; im++) {
8631 if (p - *pcode >= ni) {
8632 return false;
8633 }
8634
8635 long long l = hcode[im] = getBits(6, c, lc, p); // code length
8636
8637 if (l == (long long)LONG_ZEROCODE_RUN) {
8638 if (p - *pcode > ni) {
8639 return false;
8640 }
8641
8642 int zerun = getBits(8, c, lc, p) + SHORTEST_LONG_RUN;
8643
8644 if (im + zerun > iM + 1) {
8645 return false;
8646 }
8647
8648 while (zerun--) hcode[im++] = 0;
8649
8650 im--;
8651 } else if (l >= (long long)SHORT_ZEROCODE_RUN) {
8652 int zerun = l - SHORT_ZEROCODE_RUN + 2;
8653
8654 if (im + zerun > iM + 1) {
8655 return false;
8656 }
8657
8658 while (zerun--) hcode[im++] = 0;
8659
8660 im--;
8661 }
8662 }
8663
8664 *pcode = const_cast<char *>(p);
8665
8666 hufCanonicalCodeTable(hcode);
8667
8668 return true;
8669 }
8670
8671 //
8672 // DECODING TABLE BUILDING
8673 //
8674
8675 //
8676 // Clear a newly allocated decoding table so that it contains only zeroes.
8677 //
8678
hufClearDecTable(HufDec * hdecod)8679 static void hufClearDecTable(HufDec *hdecod) // io: (allocated by caller)
8680 // decoding table [HUF_DECSIZE]
8681 {
8682 for (int i = 0; i < HUF_DECSIZE; i++) {
8683 hdecod[i].len = 0;
8684 hdecod[i].lit = 0;
8685 hdecod[i].p = NULL;
8686 }
8687 // memset(hdecod, 0, sizeof(HufDec) * HUF_DECSIZE);
8688 }
8689
8690 //
8691 // Build a decoding hash table based on the encoding table hcode:
8692 // - short codes (<= HUF_DECBITS) are resolved with a single table access;
8693 // - long code entry allocations are not optimized, because long codes are
8694 // unfrequent;
8695 // - decoding tables are used by hufDecode();
8696 //
8697
hufBuildDecTable(const long long * hcode,int im,int iM,HufDec * hdecod)8698 static bool hufBuildDecTable(const long long *hcode, // i : encoding table
8699 int im, // i : min index in hcode
8700 int iM, // i : max index in hcode
8701 HufDec *hdecod) // o: (allocated by caller)
8702 // decoding table [HUF_DECSIZE]
8703 {
8704 //
8705 // Init hashtable & loop on all codes.
8706 // Assumes that hufClearDecTable(hdecod) has already been called.
8707 //
8708
8709 for (; im <= iM; im++) {
8710 long long c = hufCode(hcode[im]);
8711 int l = hufLength(hcode[im]);
8712
8713 if (c >> l) {
8714 //
8715 // Error: c is supposed to be an l-bit code,
8716 // but c contains a value that is greater
8717 // than the largest l-bit number.
8718 //
8719
8720 // invalidTableEntry();
8721 return false;
8722 }
8723
8724 if (l > HUF_DECBITS) {
8725 //
8726 // Long code: add a secondary entry
8727 //
8728
8729 HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
8730
8731 if (pl->len) {
8732 //
8733 // Error: a short code has already
8734 // been stored in table entry *pl.
8735 //
8736
8737 // invalidTableEntry();
8738 return false;
8739 }
8740
8741 pl->lit++;
8742
8743 if (pl->p) {
8744 int *p = pl->p;
8745 pl->p = new int[pl->lit];
8746
8747 for (int i = 0; i < pl->lit - 1; ++i) pl->p[i] = p[i];
8748
8749 delete[] p;
8750 } else {
8751 pl->p = new int[1];
8752 }
8753
8754 pl->p[pl->lit - 1] = im;
8755 } else if (l) {
8756 //
8757 // Short code: init all primary entries
8758 //
8759
8760 HufDec *pl = hdecod + (c << (HUF_DECBITS - l));
8761
8762 for (long long i = 1ULL << (HUF_DECBITS - l); i > 0; i--, pl++) {
8763 if (pl->len || pl->p) {
8764 //
8765 // Error: a short code or a long code has
8766 // already been stored in table entry *pl.
8767 //
8768
8769 // invalidTableEntry();
8770 return false;
8771 }
8772
8773 pl->len = l;
8774 pl->lit = im;
8775 }
8776 }
8777 }
8778
8779 return true;
8780 }
8781
8782 //
8783 // Free the long code entries of a decoding table built by hufBuildDecTable()
8784 //
8785
hufFreeDecTable(HufDec * hdecod)8786 static void hufFreeDecTable(HufDec *hdecod) // io: Decoding table
8787 {
8788 for (int i = 0; i < HUF_DECSIZE; i++) {
8789 if (hdecod[i].p) {
8790 delete[] hdecod[i].p;
8791 hdecod[i].p = 0;
8792 }
8793 }
8794 }
8795
8796 //
8797 // ENCODING
8798 //
8799
outputCode(long long code,long long & c,int & lc,char * & out)8800 inline void outputCode(long long code, long long &c, int &lc, char *&out) {
8801 outputBits(hufLength(code), hufCode(code), c, lc, out);
8802 }
8803
sendCode(long long sCode,int runCount,long long runCode,long long & c,int & lc,char * & out)8804 inline void sendCode(long long sCode, int runCount, long long runCode,
8805 long long &c, int &lc, char *&out) {
8806 //
8807 // Output a run of runCount instances of the symbol sCount.
8808 // Output the symbols explicitly, or if that is shorter, output
8809 // the sCode symbol once followed by a runCode symbol and runCount
8810 // expressed as an 8-bit number.
8811 //
8812
8813 if (hufLength(sCode) + hufLength(runCode) + 8 < hufLength(sCode) * runCount) {
8814 outputCode(sCode, c, lc, out);
8815 outputCode(runCode, c, lc, out);
8816 outputBits(8, runCount, c, lc, out);
8817 } else {
8818 while (runCount-- >= 0) outputCode(sCode, c, lc, out);
8819 }
8820 }
8821
8822 //
8823 // Encode (compress) ni values based on the Huffman encoding table hcode:
8824 //
8825
hufEncode(const long long * hcode,const unsigned short * in,const int ni,int rlc,char * out)8826 static int hufEncode // return: output size (in bits)
8827 (const long long *hcode, // i : encoding table
8828 const unsigned short *in, // i : uncompressed input buffer
8829 const int ni, // i : input buffer size (in bytes)
8830 int rlc, // i : rl code
8831 char *out) // o: compressed output buffer
8832 {
8833 char *outStart = out;
8834 long long c = 0; // bits not yet written to out
8835 int lc = 0; // number of valid bits in c (LSB)
8836 int s = in[0];
8837 int cs = 0;
8838
8839 //
8840 // Loop on input values
8841 //
8842
8843 for (int i = 1; i < ni; i++) {
8844 //
8845 // Count same values or send code
8846 //
8847
8848 if (s == in[i] && cs < 255) {
8849 cs++;
8850 } else {
8851 sendCode(hcode[s], cs, hcode[rlc], c, lc, out);
8852 cs = 0;
8853 }
8854
8855 s = in[i];
8856 }
8857
8858 //
8859 // Send remaining code
8860 //
8861
8862 sendCode(hcode[s], cs, hcode[rlc], c, lc, out);
8863
8864 if (lc) *out = (c << (8 - lc)) & 0xff;
8865
8866 return (out - outStart) * 8 + lc;
8867 }
8868
8869 //
8870 // DECODING
8871 //
8872
8873 //
8874 // In order to force the compiler to inline them,
8875 // getChar() and getCode() are implemented as macros
8876 // instead of "inline" functions.
8877 //
8878
8879 #define getChar(c, lc, in) \
8880 { \
8881 c = (c << 8) | *(unsigned char *)(in++); \
8882 lc += 8; \
8883 }
8884
8885 #if 0
8886 #define getCode(po, rlc, c, lc, in, out, ob, oe) \
8887 { \
8888 if (po == rlc) { \
8889 if (lc < 8) getChar(c, lc, in); \
8890 \
8891 lc -= 8; \
8892 \
8893 unsigned char cs = (c >> lc); \
8894 \
8895 if (out + cs > oe) return false; \
8896 \
8897 /* TinyEXR issue 78 */ \
8898 unsigned short s = out[-1]; \
8899 \
8900 while (cs-- > 0) *out++ = s; \
8901 } else if (out < oe) { \
8902 *out++ = po; \
8903 } else { \
8904 return false; \
8905 } \
8906 }
8907 #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)8908 static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in,
8909 const char *in_end, unsigned short *&out,
8910 const unsigned short *ob, const unsigned short *oe) {
8911 (void)ob;
8912 if (po == rlc) {
8913 if (lc < 8) {
8914 /* TinyEXR issue 78 */
8915 if ((in + 1) >= in_end) {
8916 return false;
8917 }
8918
8919 getChar(c, lc, in);
8920 }
8921
8922 lc -= 8;
8923
8924 unsigned char cs = (c >> lc);
8925
8926 if (out + cs > oe) return false;
8927
8928 // Bounds check for safety
8929 // Issue 100.
8930 if ((out - 1) < ob) return false;
8931 unsigned short s = out[-1];
8932
8933 while (cs-- > 0) *out++ = s;
8934 } else if (out < oe) {
8935 *out++ = po;
8936 } else {
8937 return false;
8938 }
8939 return true;
8940 }
8941 #endif
8942
8943 //
8944 // Decode (uncompress) ni bits based on encoding & decoding tables:
8945 //
8946
hufDecode(const long long * hcode,const HufDec * hdecod,const char * in,int ni,int rlc,int no,unsigned short * out)8947 static bool hufDecode(const long long *hcode, // i : encoding table
8948 const HufDec *hdecod, // i : decoding table
8949 const char *in, // i : compressed input buffer
8950 int ni, // i : input size (in bits)
8951 int rlc, // i : run-length code
8952 int no, // i : expected output size (in bytes)
8953 unsigned short *out) // o: uncompressed output buffer
8954 {
8955 long long c = 0;
8956 int lc = 0;
8957 unsigned short *outb = out; // begin
8958 unsigned short *oe = out + no; // end
8959 const char *ie = in + (ni + 7) / 8; // input byte size
8960
8961 //
8962 // Loop on input bytes
8963 //
8964
8965 while (in < ie) {
8966 getChar(c, lc, in);
8967
8968 //
8969 // Access decoding table
8970 //
8971
8972 while (lc >= HUF_DECBITS) {
8973 const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK];
8974
8975 if (pl.len) {
8976 //
8977 // Get short code
8978 //
8979
8980 lc -= pl.len;
8981 // std::cout << "lit = " << pl.lit << std::endl;
8982 // std::cout << "rlc = " << rlc << std::endl;
8983 // std::cout << "c = " << c << std::endl;
8984 // std::cout << "lc = " << lc << std::endl;
8985 // std::cout << "in = " << in << std::endl;
8986 // std::cout << "out = " << out << std::endl;
8987 // std::cout << "oe = " << oe << std::endl;
8988 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
8989 return false;
8990 }
8991 } else {
8992 if (!pl.p) {
8993 return false;
8994 }
8995 // invalidCode(); // wrong code
8996
8997 //
8998 // Search long code
8999 //
9000
9001 int j;
9002
9003 for (j = 0; j < pl.lit; j++) {
9004 int l = hufLength(hcode[pl.p[j]]);
9005
9006 while (lc < l && in < ie) // get more bits
9007 getChar(c, lc, in);
9008
9009 if (lc >= l) {
9010 if (hufCode(hcode[pl.p[j]]) ==
9011 ((c >> (lc - l)) & (((long long)(1) << l) - 1))) {
9012 //
9013 // Found : get long code
9014 //
9015
9016 lc -= l;
9017 if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) {
9018 return false;
9019 }
9020 break;
9021 }
9022 }
9023 }
9024
9025 if (j == pl.lit) {
9026 return false;
9027 // invalidCode(); // Not found
9028 }
9029 }
9030 }
9031 }
9032
9033 //
9034 // Get remaining (short) codes
9035 //
9036
9037 int i = (8 - ni) & 7;
9038 c >>= i;
9039 lc -= i;
9040
9041 while (lc > 0) {
9042 const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
9043
9044 if (pl.len) {
9045 lc -= pl.len;
9046 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
9047 return false;
9048 }
9049 } else {
9050 return false;
9051 // invalidCode(); // wrong (long) code
9052 }
9053 }
9054
9055 if (out - outb != no) {
9056 return false;
9057 }
9058 // notEnoughData ();
9059
9060 return true;
9061 }
9062
countFrequencies(std::vector<long long> & freq,const unsigned short data[],int n)9063 static void countFrequencies(std::vector<long long> &freq,
9064 const unsigned short data[/*n*/], int n) {
9065 for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0;
9066
9067 for (int i = 0; i < n; ++i) ++freq[data[i]];
9068 }
9069
writeUInt(char buf[4],unsigned int i)9070 static void writeUInt(char buf[4], unsigned int i) {
9071 unsigned char *b = (unsigned char *)buf;
9072
9073 b[0] = i;
9074 b[1] = i >> 8;
9075 b[2] = i >> 16;
9076 b[3] = i >> 24;
9077 }
9078
readUInt(const char buf[4])9079 static unsigned int readUInt(const char buf[4]) {
9080 const unsigned char *b = (const unsigned char *)buf;
9081
9082 return (b[0] & 0x000000ff) | ((b[1] << 8) & 0x0000ff00) |
9083 ((b[2] << 16) & 0x00ff0000) | ((b[3] << 24) & 0xff000000);
9084 }
9085
9086 //
9087 // EXTERNAL INTERFACE
9088 //
9089
hufCompress(const unsigned short raw[],int nRaw,char compressed[])9090 static int hufCompress(const unsigned short raw[], int nRaw,
9091 char compressed[]) {
9092 if (nRaw == 0) return 0;
9093
9094 std::vector<long long> freq(HUF_ENCSIZE);
9095
9096 countFrequencies(freq, raw, nRaw);
9097
9098 int im = 0;
9099 int iM = 0;
9100 hufBuildEncTable(freq.data(), &im, &iM);
9101
9102 char *tableStart = compressed + 20;
9103 char *tableEnd = tableStart;
9104 hufPackEncTable(freq.data(), im, iM, &tableEnd);
9105 int tableLength = tableEnd - tableStart;
9106
9107 char *dataStart = tableEnd;
9108 int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart);
9109 int data_length = (nBits + 7) / 8;
9110
9111 writeUInt(compressed, im);
9112 writeUInt(compressed + 4, iM);
9113 writeUInt(compressed + 8, tableLength);
9114 writeUInt(compressed + 12, nBits);
9115 writeUInt(compressed + 16, 0); // room for future extensions
9116
9117 return dataStart + data_length - compressed;
9118 }
9119
hufUncompress(const char compressed[],int nCompressed,std::vector<unsigned short> * raw)9120 static bool hufUncompress(const char compressed[], int nCompressed,
9121 std::vector<unsigned short> *raw) {
9122 if (nCompressed == 0) {
9123 if (raw->size() != 0) return false;
9124
9125 return false;
9126 }
9127
9128 int im = readUInt(compressed);
9129 int iM = readUInt(compressed + 4);
9130 // int tableLength = readUInt (compressed + 8);
9131 int nBits = readUInt(compressed + 12);
9132
9133 if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) return false;
9134
9135 const char *ptr = compressed + 20;
9136
9137 //
9138 // Fast decoder needs at least 2x64-bits of compressed data, and
9139 // needs to be run-able on this platform. Otherwise, fall back
9140 // to the original decoder
9141 //
9142
9143 // if (FastHufDecoder::enabled() && nBits > 128)
9144 //{
9145 // FastHufDecoder fhd (ptr, nCompressed - (ptr - compressed), im, iM, iM);
9146 // fhd.decode ((unsigned char*)ptr, nBits, raw, nRaw);
9147 //}
9148 // else
9149 {
9150 std::vector<long long> freq(HUF_ENCSIZE);
9151 std::vector<HufDec> hdec(HUF_DECSIZE);
9152
9153 hufClearDecTable(&hdec.at(0));
9154
9155 hufUnpackEncTable(&ptr, nCompressed - (ptr - compressed), im, iM,
9156 &freq.at(0));
9157
9158 {
9159 if (nBits > 8 * (nCompressed - (ptr - compressed))) {
9160 return false;
9161 }
9162
9163 hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0));
9164 hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(),
9165 raw->data());
9166 }
9167 // catch (...)
9168 //{
9169 // hufFreeDecTable (hdec);
9170 // throw;
9171 //}
9172
9173 hufFreeDecTable(&hdec.at(0));
9174 }
9175
9176 return true;
9177 }
9178
9179 //
9180 // Functions to compress the range of values in the pixel data
9181 //
9182
9183 const int USHORT_RANGE = (1 << 16);
9184 const int BITMAP_SIZE = (USHORT_RANGE >> 3);
9185
bitmapFromData(const unsigned short data[],int nData,unsigned char bitmap[BITMAP_SIZE],unsigned short & minNonZero,unsigned short & maxNonZero)9186 static void bitmapFromData(const unsigned short data[/*nData*/], int nData,
9187 unsigned char bitmap[BITMAP_SIZE],
9188 unsigned short &minNonZero,
9189 unsigned short &maxNonZero) {
9190 for (int i = 0; i < BITMAP_SIZE; ++i) bitmap[i] = 0;
9191
9192 for (int i = 0; i < nData; ++i) bitmap[data[i] >> 3] |= (1 << (data[i] & 7));
9193
9194 bitmap[0] &= ~1; // zero is not explicitly stored in
9195 // the bitmap; we assume that the
9196 // data always contain zeroes
9197 minNonZero = BITMAP_SIZE - 1;
9198 maxNonZero = 0;
9199
9200 for (int i = 0; i < BITMAP_SIZE; ++i) {
9201 if (bitmap[i]) {
9202 if (minNonZero > i) minNonZero = i;
9203 if (maxNonZero < i) maxNonZero = i;
9204 }
9205 }
9206 }
9207
forwardLutFromBitmap(const unsigned char bitmap[BITMAP_SIZE],unsigned short lut[USHORT_RANGE])9208 static unsigned short forwardLutFromBitmap(
9209 const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) {
9210 int k = 0;
9211
9212 for (int i = 0; i < USHORT_RANGE; ++i) {
9213 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
9214 lut[i] = k++;
9215 else
9216 lut[i] = 0;
9217 }
9218
9219 return k - 1; // maximum value stored in lut[],
9220 } // i.e. number of ones in bitmap minus 1
9221
reverseLutFromBitmap(const unsigned char bitmap[BITMAP_SIZE],unsigned short lut[USHORT_RANGE])9222 static unsigned short reverseLutFromBitmap(
9223 const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) {
9224 int k = 0;
9225
9226 for (int i = 0; i < USHORT_RANGE; ++i) {
9227 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) lut[k++] = i;
9228 }
9229
9230 int n = k - 1;
9231
9232 while (k < USHORT_RANGE) lut[k++] = 0;
9233
9234 return n; // maximum k where lut[k] is non-zero,
9235 } // i.e. number of ones in bitmap minus 1
9236
applyLut(const unsigned short lut[USHORT_RANGE],unsigned short data[],int nData)9237 static void applyLut(const unsigned short lut[USHORT_RANGE],
9238 unsigned short data[/*nData*/], int nData) {
9239 for (int i = 0; i < nData; ++i) data[i] = lut[data[i]];
9240 }
9241
9242 #ifdef __clang__
9243 #pragma clang diagnostic pop
9244 #endif // __clang__
9245
9246 #ifdef _MSC_VER
9247 #pragma warning(pop)
9248 #endif
9249
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)9250 static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
9251 const unsigned char *inPtr, size_t inSize,
9252 const std::vector<ChannelInfo> &channelInfo,
9253 int data_width, int num_lines) {
9254 std::vector<unsigned char> bitmap(BITMAP_SIZE);
9255 unsigned short minNonZero;
9256 unsigned short maxNonZero;
9257
9258 #if !MINIZ_LITTLE_ENDIAN
9259 // @todo { PIZ compression on BigEndian architecture. }
9260 TEXR_ASSERT(0);
9261 return false;
9262 #endif
9263
9264 // Assume `inSize` is multiple of 2 or 4.
9265 std::vector<unsigned short> tmpBuffer(inSize / sizeof(unsigned short));
9266
9267 std::vector<PIZChannelData> channelData(channelInfo.size());
9268 unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
9269
9270 for (size_t c = 0; c < channelData.size(); c++) {
9271 PIZChannelData &cd = channelData[c];
9272
9273 cd.start = tmpBufferEnd;
9274 cd.end = cd.start;
9275
9276 cd.nx = data_width;
9277 cd.ny = num_lines;
9278 // cd.ys = c.channel().ySampling;
9279
9280 size_t pixelSize = sizeof(int); // UINT and FLOAT
9281 if (channelInfo[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9282 pixelSize = sizeof(short);
9283 }
9284
9285 cd.size = static_cast<int>(pixelSize / sizeof(short));
9286
9287 tmpBufferEnd += cd.nx * cd.ny * cd.size;
9288 }
9289
9290 const unsigned char *ptr = inPtr;
9291 for (int y = 0; y < num_lines; ++y) {
9292 for (size_t i = 0; i < channelData.size(); ++i) {
9293 PIZChannelData &cd = channelData[i];
9294
9295 // if (modp (y, cd.ys) != 0)
9296 // continue;
9297
9298 size_t n = static_cast<size_t>(cd.nx * cd.size);
9299 memcpy(cd.end, ptr, n * sizeof(unsigned short));
9300 ptr += n * sizeof(unsigned short);
9301 cd.end += n;
9302 }
9303 }
9304
9305 bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()),
9306 bitmap.data(), minNonZero, maxNonZero);
9307
9308 std::vector<unsigned short> lut(USHORT_RANGE);
9309 unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data());
9310 applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()));
9311
9312 //
9313 // Store range compression info in _outBuffer
9314 //
9315
9316 char *buf = reinterpret_cast<char *>(outPtr);
9317
9318 memcpy(buf, &minNonZero, sizeof(unsigned short));
9319 buf += sizeof(unsigned short);
9320 memcpy(buf, &maxNonZero, sizeof(unsigned short));
9321 buf += sizeof(unsigned short);
9322
9323 if (minNonZero <= maxNonZero) {
9324 memcpy(buf, reinterpret_cast<char *>(&bitmap[0] + minNonZero),
9325 maxNonZero - minNonZero + 1);
9326 buf += maxNonZero - minNonZero + 1;
9327 }
9328
9329 //
9330 // Apply wavelet encoding
9331 //
9332
9333 for (size_t i = 0; i < channelData.size(); ++i) {
9334 PIZChannelData &cd = channelData[i];
9335
9336 for (int j = 0; j < cd.size; ++j) {
9337 wav2Encode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size,
9338 maxValue);
9339 }
9340 }
9341
9342 //
9343 // Apply Huffman encoding; append the result to _outBuffer
9344 //
9345
9346 // length header(4byte), then huff data. Initialize length header with zero,
9347 // then later fill it by `length`.
9348 char *lengthPtr = buf;
9349 int zero = 0;
9350 memcpy(buf, &zero, sizeof(int));
9351 buf += sizeof(int);
9352
9353 int length =
9354 hufCompress(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), buf);
9355 memcpy(lengthPtr, &length, sizeof(int));
9356
9357 (*outSize) = static_cast<unsigned int>(
9358 (reinterpret_cast<unsigned char *>(buf) - outPtr) +
9359 static_cast<unsigned int>(length));
9360
9361 // Use uncompressed data when compressed data is larger than uncompressed.
9362 // (Issue 40)
9363 if ((*outSize) >= inSize) {
9364 (*outSize) = static_cast<unsigned int>(inSize);
9365 memcpy(outPtr, inPtr, inSize);
9366 }
9367 return true;
9368 }
9369
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)9370 static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
9371 size_t tmpBufSize, size_t inLen, int num_channels,
9372 const EXRChannelInfo *channels, int data_width,
9373 int num_lines) {
9374 if (inLen == tmpBufSize) {
9375 // Data is not compressed(Issue 40).
9376 memcpy(outPtr, inPtr, inLen);
9377 return true;
9378 }
9379
9380 std::vector<unsigned char> bitmap(BITMAP_SIZE);
9381 unsigned short minNonZero;
9382 unsigned short maxNonZero;
9383
9384 #if !MINIZ_LITTLE_ENDIAN
9385 // @todo { PIZ compression on BigEndian architecture. }
9386 TEXR_ASSERT(0);
9387 return false;
9388 #endif
9389
9390 memset(bitmap.data(), 0, BITMAP_SIZE);
9391
9392 const unsigned char *ptr = inPtr;
9393 // minNonZero = *(reinterpret_cast<const unsigned short *>(ptr));
9394 tinyexr::cpy2(&minNonZero, reinterpret_cast<const unsigned short *>(ptr));
9395 // maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2));
9396 tinyexr::cpy2(&maxNonZero, reinterpret_cast<const unsigned short *>(ptr + 2));
9397 ptr += 4;
9398
9399 if (maxNonZero >= BITMAP_SIZE) {
9400 return false;
9401 }
9402
9403 if (minNonZero <= maxNonZero) {
9404 memcpy(reinterpret_cast<char *>(&bitmap[0] + minNonZero), ptr,
9405 maxNonZero - minNonZero + 1);
9406 ptr += maxNonZero - minNonZero + 1;
9407 }
9408
9409 std::vector<unsigned short> lut(USHORT_RANGE);
9410 memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE);
9411 unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data());
9412
9413 //
9414 // Huffman decoding
9415 //
9416
9417 int length;
9418
9419 // length = *(reinterpret_cast<const int *>(ptr));
9420 tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr));
9421 ptr += sizeof(int);
9422
9423 if (size_t((ptr - inPtr) + length) > inLen) {
9424 return false;
9425 }
9426
9427 std::vector<unsigned short> tmpBuffer(tmpBufSize);
9428 hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer);
9429
9430 //
9431 // Wavelet decoding
9432 //
9433
9434 std::vector<PIZChannelData> channelData(static_cast<size_t>(num_channels));
9435
9436 unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
9437
9438 for (size_t i = 0; i < static_cast<size_t>(num_channels); ++i) {
9439 const EXRChannelInfo &chan = channels[i];
9440
9441 size_t pixelSize = sizeof(int); // UINT and FLOAT
9442 if (chan.pixel_type == TINYEXR_PIXELTYPE_HALF) {
9443 pixelSize = sizeof(short);
9444 }
9445
9446 channelData[i].start = tmpBufferEnd;
9447 channelData[i].end = channelData[i].start;
9448 channelData[i].nx = data_width;
9449 channelData[i].ny = num_lines;
9450 // channelData[i].ys = 1;
9451 channelData[i].size = static_cast<int>(pixelSize / sizeof(short));
9452
9453 tmpBufferEnd += channelData[i].nx * channelData[i].ny * channelData[i].size;
9454 }
9455
9456 for (size_t i = 0; i < channelData.size(); ++i) {
9457 PIZChannelData &cd = channelData[i];
9458
9459 for (int j = 0; j < cd.size; ++j) {
9460 wav2Decode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size,
9461 maxValue);
9462 }
9463 }
9464
9465 //
9466 // Expand the pixel data to their original range
9467 //
9468
9469 applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBufSize));
9470
9471 for (int y = 0; y < num_lines; y++) {
9472 for (size_t i = 0; i < channelData.size(); ++i) {
9473 PIZChannelData &cd = channelData[i];
9474
9475 // if (modp (y, cd.ys) != 0)
9476 // continue;
9477
9478 size_t n = static_cast<size_t>(cd.nx * cd.size);
9479 memcpy(outPtr, cd.end, static_cast<size_t>(n * sizeof(unsigned short)));
9480 outPtr += n * sizeof(unsigned short);
9481 cd.end += n;
9482 }
9483 }
9484
9485 return true;
9486 }
9487 #endif // TINYEXR_USE_PIZ
9488
9489 #if TINYEXR_USE_ZFP
9490 struct ZFPCompressionParam {
9491 double rate;
9492 int precision;
9493 double tolerance;
9494 int type; // TINYEXR_ZFP_COMPRESSIONTYPE_*
9495
ZFPCompressionParamZFPCompressionParam9496 ZFPCompressionParam() {
9497 type = TINYEXR_ZFP_COMPRESSIONTYPE_RATE;
9498 rate = 2.0;
9499 precision = 0;
9500 tolerance = 0.0f;
9501 }
9502 };
9503
FindZFPCompressionParam(ZFPCompressionParam * param,const EXRAttribute * attributes,int num_attributes)9504 bool FindZFPCompressionParam(ZFPCompressionParam *param,
9505 const EXRAttribute *attributes,
9506 int num_attributes) {
9507 bool foundType = false;
9508
9509 for (int i = 0; i < num_attributes; i++) {
9510 if ((strcmp(attributes[i].name, "zfpCompressionType") == 0) &&
9511 (attributes[i].size == 1)) {
9512 param->type = static_cast<int>(attributes[i].value[0]);
9513
9514 foundType = true;
9515 }
9516 }
9517
9518 if (!foundType) {
9519 return false;
9520 }
9521
9522 if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
9523 for (int i = 0; i < num_attributes; i++) {
9524 if ((strcmp(attributes[i].name, "zfpCompressionRate") == 0) &&
9525 (attributes[i].size == 8)) {
9526 param->rate = *(reinterpret_cast<double *>(attributes[i].value));
9527 return true;
9528 }
9529 }
9530 } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
9531 for (int i = 0; i < num_attributes; i++) {
9532 if ((strcmp(attributes[i].name, "zfpCompressionPrecision") == 0) &&
9533 (attributes[i].size == 4)) {
9534 param->rate = *(reinterpret_cast<int *>(attributes[i].value));
9535 return true;
9536 }
9537 }
9538 } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
9539 for (int i = 0; i < num_attributes; i++) {
9540 if ((strcmp(attributes[i].name, "zfpCompressionTolerance") == 0) &&
9541 (attributes[i].size == 8)) {
9542 param->tolerance = *(reinterpret_cast<double *>(attributes[i].value));
9543 return true;
9544 }
9545 }
9546 } else {
9547 TEXR_ASSERT(0);
9548 }
9549
9550 return false;
9551 }
9552
9553 // 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)9554 static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
9555 int num_channels, const unsigned char *src,
9556 unsigned long src_size,
9557 const ZFPCompressionParam ¶m) {
9558 size_t uncompressed_size = dst_width * dst_num_lines * num_channels;
9559
9560 if (uncompressed_size == src_size) {
9561 // Data is not compressed(Issue 40).
9562 memcpy(dst, src, src_size);
9563 }
9564
9565 zfp_stream *zfp = NULL;
9566 zfp_field *field = NULL;
9567
9568 TEXR_ASSERT((dst_width % 4) == 0);
9569 TEXR_ASSERT((dst_num_lines % 4) == 0);
9570
9571 if ((dst_width & 3U) || (dst_num_lines & 3U)) {
9572 return false;
9573 }
9574
9575 field =
9576 zfp_field_2d(reinterpret_cast<void *>(const_cast<unsigned char *>(src)),
9577 zfp_type_float, dst_width, dst_num_lines * num_channels);
9578 zfp = zfp_stream_open(NULL);
9579
9580 if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
9581 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimention */ 2,
9582 /* write random access */ 0);
9583 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
9584 zfp_stream_set_precision(zfp, param.precision, zfp_type_float);
9585 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
9586 zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float);
9587 } else {
9588 TEXR_ASSERT(0);
9589 }
9590
9591 size_t buf_size = zfp_stream_maximum_size(zfp, field);
9592 std::vector<unsigned char> buf(buf_size);
9593 memcpy(&buf.at(0), src, src_size);
9594
9595 bitstream *stream = stream_open(&buf.at(0), buf_size);
9596 zfp_stream_set_bit_stream(zfp, stream);
9597 zfp_stream_rewind(zfp);
9598
9599 size_t image_size = dst_width * dst_num_lines;
9600
9601 for (int c = 0; c < num_channels; c++) {
9602 // decompress 4x4 pixel block.
9603 for (int y = 0; y < dst_num_lines; y += 4) {
9604 for (int x = 0; x < dst_width; x += 4) {
9605 float fblock[16];
9606 zfp_decode_block_float_2(zfp, fblock);
9607 for (int j = 0; j < 4; j++) {
9608 for (int i = 0; i < 4; i++) {
9609 dst[c * image_size + ((y + j) * dst_width + (x + i))] =
9610 fblock[j * 4 + i];
9611 }
9612 }
9613 }
9614 }
9615 }
9616
9617 zfp_field_free(field);
9618 zfp_stream_close(zfp);
9619 stream_close(stream);
9620
9621 return true;
9622 }
9623
9624 // 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)9625 bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
9626 const float *inPtr, int width, int num_lines, int num_channels,
9627 const ZFPCompressionParam ¶m) {
9628 zfp_stream *zfp = NULL;
9629 zfp_field *field = NULL;
9630
9631 TEXR_ASSERT((width % 4) == 0);
9632 TEXR_ASSERT((num_lines % 4) == 0);
9633
9634 if ((width & 3U) || (num_lines & 3U)) {
9635 return false;
9636 }
9637
9638 // create input array.
9639 field = zfp_field_2d(reinterpret_cast<void *>(const_cast<float *>(inPtr)),
9640 zfp_type_float, width, num_lines * num_channels);
9641
9642 zfp = zfp_stream_open(NULL);
9643
9644 if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
9645 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0);
9646 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
9647 zfp_stream_set_precision(zfp, param.precision, zfp_type_float);
9648 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
9649 zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float);
9650 } else {
9651 TEXR_ASSERT(0);
9652 }
9653
9654 size_t buf_size = zfp_stream_maximum_size(zfp, field);
9655
9656 outBuf->resize(buf_size);
9657
9658 bitstream *stream = stream_open(&outBuf->at(0), buf_size);
9659 zfp_stream_set_bit_stream(zfp, stream);
9660 zfp_field_free(field);
9661
9662 size_t image_size = width * num_lines;
9663
9664 for (int c = 0; c < num_channels; c++) {
9665 // compress 4x4 pixel block.
9666 for (int y = 0; y < num_lines; y += 4) {
9667 for (int x = 0; x < width; x += 4) {
9668 float fblock[16];
9669 for (int j = 0; j < 4; j++) {
9670 for (int i = 0; i < 4; i++) {
9671 fblock[j * 4 + i] =
9672 inPtr[c * image_size + ((y + j) * width + (x + i))];
9673 }
9674 }
9675 zfp_encode_block_float_2(zfp, fblock);
9676 }
9677 }
9678 }
9679
9680 zfp_stream_flush(zfp);
9681 (*outSize) = zfp_stream_compressed_size(zfp);
9682
9683 zfp_stream_close(zfp);
9684
9685 return true;
9686 }
9687
9688 #endif
9689
9690 //
9691 // -----------------------------------------------------------------
9692 //
9693
9694 // 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)9695 static bool DecodePixelData(/* out */ unsigned char **out_images,
9696 const int *requested_pixel_types,
9697 const unsigned char *data_ptr, size_t data_len,
9698 int compression_type, int line_order, int width,
9699 int height, int x_stride, int y, int line_no,
9700 int num_lines, size_t pixel_data_size,
9701 size_t num_attributes,
9702 const EXRAttribute *attributes, size_t num_channels,
9703 const EXRChannelInfo *channels,
9704 const std::vector<size_t> &channel_offset_list) {
9705 if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ
9706 #if TINYEXR_USE_PIZ
9707 if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) {
9708 // Invalid input #90
9709 return false;
9710 }
9711
9712 // Allocate original data size.
9713 std::vector<unsigned char> outBuf(static_cast<size_t>(
9714 static_cast<size_t>(width * num_lines) * pixel_data_size));
9715 size_t tmpBufLen = outBuf.size();
9716
9717 bool ret = tinyexr::DecompressPiz(
9718 reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen,
9719 data_len, static_cast<int>(num_channels), channels, width, num_lines);
9720
9721 if (!ret) {
9722 return false;
9723 }
9724
9725 // For PIZ_COMPRESSION:
9726 // pixel sample data for channel 0 for scanline 0
9727 // pixel sample data for channel 1 for scanline 0
9728 // pixel sample data for channel ... for scanline 0
9729 // pixel sample data for channel n for scanline 0
9730 // pixel sample data for channel 0 for scanline 1
9731 // pixel sample data for channel 1 for scanline 1
9732 // pixel sample data for channel ... for scanline 1
9733 // pixel sample data for channel n for scanline 1
9734 // ...
9735 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
9736 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9737 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9738 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
9739 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9740 channel_offset_list[c] * static_cast<size_t>(width)));
9741 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9742 FP16 hf;
9743
9744 // hf.u = line_ptr[u];
9745 // use `cpy` to avoid unaligned memory access when compiler's
9746 // optimization is on.
9747 tinyexr::cpy2(&(hf.u), line_ptr + u);
9748
9749 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
9750
9751 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
9752 unsigned short *image =
9753 reinterpret_cast<unsigned short **>(out_images)[c];
9754 if (line_order == 0) {
9755 image += (static_cast<size_t>(line_no) + v) *
9756 static_cast<size_t>(x_stride) +
9757 u;
9758 } else {
9759 image += static_cast<size_t>(
9760 (height - 1 - (line_no + static_cast<int>(v)))) *
9761 static_cast<size_t>(x_stride) +
9762 u;
9763 }
9764 *image = hf.u;
9765 } else { // HALF -> FLOAT
9766 FP32 f32 = half_to_float(hf);
9767 float *image = reinterpret_cast<float **>(out_images)[c];
9768 size_t offset = 0;
9769 if (line_order == 0) {
9770 offset = (static_cast<size_t>(line_no) + v) *
9771 static_cast<size_t>(x_stride) +
9772 u;
9773 } else {
9774 offset = static_cast<size_t>(
9775 (height - 1 - (line_no + static_cast<int>(v)))) *
9776 static_cast<size_t>(x_stride) +
9777 u;
9778 }
9779 image += offset;
9780 *image = f32.f;
9781 }
9782 }
9783 }
9784 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
9785 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
9786
9787 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9788 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
9789 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9790 channel_offset_list[c] * static_cast<size_t>(width)));
9791 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9792 unsigned int val;
9793 // val = line_ptr[u];
9794 tinyexr::cpy4(&val, line_ptr + u);
9795
9796 tinyexr::swap4(&val);
9797
9798 unsigned int *image =
9799 reinterpret_cast<unsigned int **>(out_images)[c];
9800 if (line_order == 0) {
9801 image += (static_cast<size_t>(line_no) + v) *
9802 static_cast<size_t>(x_stride) +
9803 u;
9804 } else {
9805 image += static_cast<size_t>(
9806 (height - 1 - (line_no + static_cast<int>(v)))) *
9807 static_cast<size_t>(x_stride) +
9808 u;
9809 }
9810 *image = val;
9811 }
9812 }
9813 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
9814 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
9815 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9816 const float *line_ptr = reinterpret_cast<float *>(&outBuf.at(
9817 v * pixel_data_size * static_cast<size_t>(x_stride) +
9818 channel_offset_list[c] * static_cast<size_t>(x_stride)));
9819 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9820 float val;
9821 // val = line_ptr[u];
9822 tinyexr::cpy4(&val, line_ptr + u);
9823
9824 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
9825
9826 float *image = reinterpret_cast<float **>(out_images)[c];
9827 if (line_order == 0) {
9828 image += (static_cast<size_t>(line_no) + v) *
9829 static_cast<size_t>(x_stride) +
9830 u;
9831 } else {
9832 image += static_cast<size_t>(
9833 (height - 1 - (line_no + static_cast<int>(v)))) *
9834 static_cast<size_t>(x_stride) +
9835 u;
9836 }
9837 *image = val;
9838 }
9839 }
9840 } else {
9841 TEXR_ASSERT(0);
9842 }
9843 }
9844 #else
9845 TEXR_ASSERT(0 && "PIZ is enabled in this build");
9846 return false;
9847 #endif
9848
9849 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS ||
9850 compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
9851 // Allocate original data size.
9852 std::vector<unsigned char> outBuf(static_cast<size_t>(width) *
9853 static_cast<size_t>(num_lines) *
9854 pixel_data_size);
9855
9856 unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
9857 TEXR_ASSERT(dstLen > 0);
9858 if (!tinyexr::DecompressZip(
9859 reinterpret_cast<unsigned char *>(&outBuf.at(0)), &dstLen, data_ptr,
9860 static_cast<unsigned long>(data_len))) {
9861 return false;
9862 }
9863
9864 // For ZIP_COMPRESSION:
9865 // pixel sample data for channel 0 for scanline 0
9866 // pixel sample data for channel 1 for scanline 0
9867 // pixel sample data for channel ... for scanline 0
9868 // pixel sample data for channel n for scanline 0
9869 // pixel sample data for channel 0 for scanline 1
9870 // pixel sample data for channel 1 for scanline 1
9871 // pixel sample data for channel ... for scanline 1
9872 // pixel sample data for channel n for scanline 1
9873 // ...
9874 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
9875 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9876 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9877 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
9878 &outBuf.at(v * static_cast<size_t>(pixel_data_size) *
9879 static_cast<size_t>(width) +
9880 channel_offset_list[c] * static_cast<size_t>(width)));
9881 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9882 tinyexr::FP16 hf;
9883
9884 // hf.u = line_ptr[u];
9885 tinyexr::cpy2(&(hf.u), line_ptr + u);
9886
9887 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
9888
9889 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
9890 unsigned short *image =
9891 reinterpret_cast<unsigned short **>(out_images)[c];
9892 if (line_order == 0) {
9893 image += (static_cast<size_t>(line_no) + v) *
9894 static_cast<size_t>(x_stride) +
9895 u;
9896 } else {
9897 image += (static_cast<size_t>(height) - 1U -
9898 (static_cast<size_t>(line_no) + v)) *
9899 static_cast<size_t>(x_stride) +
9900 u;
9901 }
9902 *image = hf.u;
9903 } else { // HALF -> FLOAT
9904 tinyexr::FP32 f32 = half_to_float(hf);
9905 float *image = reinterpret_cast<float **>(out_images)[c];
9906 size_t offset = 0;
9907 if (line_order == 0) {
9908 offset = (static_cast<size_t>(line_no) + v) *
9909 static_cast<size_t>(x_stride) +
9910 u;
9911 } else {
9912 offset = (static_cast<size_t>(height) - 1U -
9913 (static_cast<size_t>(line_no) + v)) *
9914 static_cast<size_t>(x_stride) +
9915 u;
9916 }
9917 image += offset;
9918
9919 *image = f32.f;
9920 }
9921 }
9922 }
9923 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
9924 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
9925
9926 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9927 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
9928 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9929 channel_offset_list[c] * static_cast<size_t>(width)));
9930 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9931 unsigned int val;
9932 // val = line_ptr[u];
9933 tinyexr::cpy4(&val, line_ptr + u);
9934
9935 tinyexr::swap4(&val);
9936
9937 unsigned int *image =
9938 reinterpret_cast<unsigned int **>(out_images)[c];
9939 if (line_order == 0) {
9940 image += (static_cast<size_t>(line_no) + v) *
9941 static_cast<size_t>(x_stride) +
9942 u;
9943 } else {
9944 image += (static_cast<size_t>(height) - 1U -
9945 (static_cast<size_t>(line_no) + v)) *
9946 static_cast<size_t>(x_stride) +
9947 u;
9948 }
9949 *image = val;
9950 }
9951 }
9952 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
9953 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
9954 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9955 const float *line_ptr = reinterpret_cast<float *>(
9956 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9957 channel_offset_list[c] * static_cast<size_t>(width)));
9958 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9959 float val;
9960 // val = line_ptr[u];
9961 tinyexr::cpy4(&val, line_ptr + u);
9962
9963 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
9964
9965 float *image = reinterpret_cast<float **>(out_images)[c];
9966 if (line_order == 0) {
9967 image += (static_cast<size_t>(line_no) + v) *
9968 static_cast<size_t>(x_stride) +
9969 u;
9970 } else {
9971 image += (static_cast<size_t>(height) - 1U -
9972 (static_cast<size_t>(line_no) + v)) *
9973 static_cast<size_t>(x_stride) +
9974 u;
9975 }
9976 *image = val;
9977 }
9978 }
9979 } else {
9980 TEXR_ASSERT(0);
9981 return false;
9982 }
9983 }
9984 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) {
9985 // Allocate original data size.
9986 std::vector<unsigned char> outBuf(static_cast<size_t>(width) *
9987 static_cast<size_t>(num_lines) *
9988 pixel_data_size);
9989
9990 unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
9991 if (dstLen == 0) {
9992 return false;
9993 }
9994
9995 if (!tinyexr::DecompressRle(
9996 reinterpret_cast<unsigned char *>(&outBuf.at(0)), dstLen, data_ptr,
9997 static_cast<unsigned long>(data_len))) {
9998 return false;
9999 }
10000
10001 // For RLE_COMPRESSION:
10002 // pixel sample data for channel 0 for scanline 0
10003 // pixel sample data for channel 1 for scanline 0
10004 // pixel sample data for channel ... for scanline 0
10005 // pixel sample data for channel n for scanline 0
10006 // pixel sample data for channel 0 for scanline 1
10007 // pixel sample data for channel 1 for scanline 1
10008 // pixel sample data for channel ... for scanline 1
10009 // pixel sample data for channel n for scanline 1
10010 // ...
10011 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10012 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10013 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10014 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
10015 &outBuf.at(v * static_cast<size_t>(pixel_data_size) *
10016 static_cast<size_t>(width) +
10017 channel_offset_list[c] * static_cast<size_t>(width)));
10018 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10019 tinyexr::FP16 hf;
10020
10021 // hf.u = line_ptr[u];
10022 tinyexr::cpy2(&(hf.u), line_ptr + u);
10023
10024 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
10025
10026 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
10027 unsigned short *image =
10028 reinterpret_cast<unsigned short **>(out_images)[c];
10029 if (line_order == 0) {
10030 image += (static_cast<size_t>(line_no) + v) *
10031 static_cast<size_t>(x_stride) +
10032 u;
10033 } else {
10034 image += (static_cast<size_t>(height) - 1U -
10035 (static_cast<size_t>(line_no) + v)) *
10036 static_cast<size_t>(x_stride) +
10037 u;
10038 }
10039 *image = hf.u;
10040 } else { // HALF -> FLOAT
10041 tinyexr::FP32 f32 = half_to_float(hf);
10042 float *image = reinterpret_cast<float **>(out_images)[c];
10043 if (line_order == 0) {
10044 image += (static_cast<size_t>(line_no) + v) *
10045 static_cast<size_t>(x_stride) +
10046 u;
10047 } else {
10048 image += (static_cast<size_t>(height) - 1U -
10049 (static_cast<size_t>(line_no) + v)) *
10050 static_cast<size_t>(x_stride) +
10051 u;
10052 }
10053 *image = f32.f;
10054 }
10055 }
10056 }
10057 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10058 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
10059
10060 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10061 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
10062 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
10063 channel_offset_list[c] * static_cast<size_t>(width)));
10064 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10065 unsigned int val;
10066 // val = line_ptr[u];
10067 tinyexr::cpy4(&val, line_ptr + u);
10068
10069 tinyexr::swap4(&val);
10070
10071 unsigned int *image =
10072 reinterpret_cast<unsigned int **>(out_images)[c];
10073 if (line_order == 0) {
10074 image += (static_cast<size_t>(line_no) + v) *
10075 static_cast<size_t>(x_stride) +
10076 u;
10077 } else {
10078 image += (static_cast<size_t>(height) - 1U -
10079 (static_cast<size_t>(line_no) + v)) *
10080 static_cast<size_t>(x_stride) +
10081 u;
10082 }
10083 *image = val;
10084 }
10085 }
10086 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10087 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
10088 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10089 const float *line_ptr = reinterpret_cast<float *>(
10090 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
10091 channel_offset_list[c] * static_cast<size_t>(width)));
10092 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10093 float val;
10094 // val = line_ptr[u];
10095 tinyexr::cpy4(&val, line_ptr + u);
10096
10097 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10098
10099 float *image = reinterpret_cast<float **>(out_images)[c];
10100 if (line_order == 0) {
10101 image += (static_cast<size_t>(line_no) + v) *
10102 static_cast<size_t>(x_stride) +
10103 u;
10104 } else {
10105 image += (static_cast<size_t>(height) - 1U -
10106 (static_cast<size_t>(line_no) + v)) *
10107 static_cast<size_t>(x_stride) +
10108 u;
10109 }
10110 *image = val;
10111 }
10112 }
10113 } else {
10114 TEXR_ASSERT(0);
10115 return false;
10116 }
10117 }
10118 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
10119 #if TINYEXR_USE_ZFP
10120 tinyexr::ZFPCompressionParam zfp_compression_param;
10121 if (!FindZFPCompressionParam(&zfp_compression_param, attributes,
10122 num_attributes)) {
10123 TEXR_ASSERT(0);
10124 return false;
10125 }
10126
10127 // Allocate original data size.
10128 std::vector<unsigned char> outBuf(static_cast<size_t>(width) *
10129 static_cast<size_t>(num_lines) *
10130 pixel_data_size);
10131
10132 unsigned long dstLen = outBuf.size();
10133 TEXR_ASSERT(dstLen > 0);
10134 tinyexr::DecompressZfp(reinterpret_cast<float *>(&outBuf.at(0)), width,
10135 num_lines, num_channels, data_ptr,
10136 static_cast<unsigned long>(data_len),
10137 zfp_compression_param);
10138
10139 // For ZFP_COMPRESSION:
10140 // pixel sample data for channel 0 for scanline 0
10141 // pixel sample data for channel 1 for scanline 0
10142 // pixel sample data for channel ... for scanline 0
10143 // pixel sample data for channel n for scanline 0
10144 // pixel sample data for channel 0 for scanline 1
10145 // pixel sample data for channel 1 for scanline 1
10146 // pixel sample data for channel ... for scanline 1
10147 // pixel sample data for channel n for scanline 1
10148 // ...
10149 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10150 TEXR_ASSERT(channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT);
10151 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10152 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
10153 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10154 const float *line_ptr = reinterpret_cast<float *>(
10155 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
10156 channel_offset_list[c] * static_cast<size_t>(width)));
10157 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10158 float val;
10159 tinyexr::cpy4(&val, line_ptr + u);
10160
10161 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10162
10163 float *image = reinterpret_cast<float **>(out_images)[c];
10164 if (line_order == 0) {
10165 image += (static_cast<size_t>(line_no) + v) *
10166 static_cast<size_t>(x_stride) +
10167 u;
10168 } else {
10169 image += (static_cast<size_t>(height) - 1U -
10170 (static_cast<size_t>(line_no) + v)) *
10171 static_cast<size_t>(x_stride) +
10172 u;
10173 }
10174 *image = val;
10175 }
10176 }
10177 } else {
10178 TEXR_ASSERT(0);
10179 return false;
10180 }
10181 }
10182 #else
10183 (void)attributes;
10184 (void)num_attributes;
10185 (void)num_channels;
10186 TEXR_ASSERT(0);
10187 return false;
10188 #endif
10189 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
10190 for (size_t c = 0; c < num_channels; c++) {
10191 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10192 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10193 const unsigned short *line_ptr =
10194 reinterpret_cast<const unsigned short *>(
10195 data_ptr + v * pixel_data_size * size_t(width) +
10196 channel_offset_list[c] * static_cast<size_t>(width));
10197
10198 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
10199 unsigned short *outLine =
10200 reinterpret_cast<unsigned short *>(out_images[c]);
10201 if (line_order == 0) {
10202 outLine += (size_t(y) + v) * size_t(x_stride);
10203 } else {
10204 outLine +=
10205 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10206 }
10207
10208 for (int u = 0; u < width; u++) {
10209 tinyexr::FP16 hf;
10210
10211 // hf.u = line_ptr[u];
10212 tinyexr::cpy2(&(hf.u), line_ptr + u);
10213
10214 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
10215
10216 outLine[u] = hf.u;
10217 }
10218 } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
10219 float *outLine = reinterpret_cast<float *>(out_images[c]);
10220 if (line_order == 0) {
10221 outLine += (size_t(y) + v) * size_t(x_stride);
10222 } else {
10223 outLine +=
10224 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10225 }
10226
10227 if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
10228 (data_ptr + data_len)) {
10229 // Insufficient data size
10230 return false;
10231 }
10232
10233 for (int u = 0; u < width; u++) {
10234 tinyexr::FP16 hf;
10235
10236 // address may not be aliged. use byte-wise copy for safety.#76
10237 // hf.u = line_ptr[u];
10238 tinyexr::cpy2(&(hf.u), line_ptr + u);
10239
10240 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
10241
10242 tinyexr::FP32 f32 = half_to_float(hf);
10243
10244 outLine[u] = f32.f;
10245 }
10246 } else {
10247 TEXR_ASSERT(0);
10248 return false;
10249 }
10250 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10251 const float *line_ptr = reinterpret_cast<const float *>(
10252 data_ptr + v * pixel_data_size * size_t(width) +
10253 channel_offset_list[c] * static_cast<size_t>(width));
10254
10255 float *outLine = reinterpret_cast<float *>(out_images[c]);
10256 if (line_order == 0) {
10257 outLine += (size_t(y) + v) * size_t(x_stride);
10258 } else {
10259 outLine +=
10260 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10261 }
10262
10263 if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
10264 (data_ptr + data_len)) {
10265 // Insufficient data size
10266 return false;
10267 }
10268
10269 for (int u = 0; u < width; u++) {
10270 float val;
10271 tinyexr::cpy4(&val, line_ptr + u);
10272
10273 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10274
10275 outLine[u] = val;
10276 }
10277 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10278 const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>(
10279 data_ptr + v * pixel_data_size * size_t(width) +
10280 channel_offset_list[c] * static_cast<size_t>(width));
10281
10282 unsigned int *outLine =
10283 reinterpret_cast<unsigned int *>(out_images[c]);
10284 if (line_order == 0) {
10285 outLine += (size_t(y) + v) * size_t(x_stride);
10286 } else {
10287 outLine +=
10288 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10289 }
10290
10291 for (int u = 0; u < width; u++) {
10292 if (reinterpret_cast<const unsigned char *>(line_ptr + u) >=
10293 (data_ptr + data_len)) {
10294 // Corrupsed data?
10295 return false;
10296 }
10297
10298 unsigned int val;
10299 tinyexr::cpy4(&val, line_ptr + u);
10300
10301 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10302
10303 outLine[u] = val;
10304 }
10305 }
10306 }
10307 }
10308 }
10309
10310 return true;
10311 }
10312
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)10313 static bool DecodeTiledPixelData(
10314 unsigned char **out_images, int *width, int *height,
10315 const int *requested_pixel_types, const unsigned char *data_ptr,
10316 size_t data_len, int compression_type, int line_order, int data_width,
10317 int data_height, int tile_offset_x, int tile_offset_y, int tile_size_x,
10318 int tile_size_y, size_t pixel_data_size, size_t num_attributes,
10319 const EXRAttribute *attributes, size_t num_channels,
10320 const EXRChannelInfo *channels,
10321 const std::vector<size_t> &channel_offset_list) {
10322 TEXR_ASSERT(tile_offset_x * tile_size_x < data_width);
10323 TEXR_ASSERT(tile_offset_y * tile_size_y < data_height);
10324
10325 // Compute actual image size in a tile.
10326 if ((tile_offset_x + 1) * tile_size_x >= data_width) {
10327 (*width) = data_width - (tile_offset_x * tile_size_x);
10328 } else {
10329 (*width) = tile_size_x;
10330 }
10331
10332 if ((tile_offset_y + 1) * tile_size_y >= data_height) {
10333 (*height) = data_height - (tile_offset_y * tile_size_y);
10334 } else {
10335 (*height) = tile_size_y;
10336 }
10337
10338 // Image size = tile size.
10339 return DecodePixelData(out_images, requested_pixel_types, data_ptr, data_len,
10340 compression_type, line_order, (*width), tile_size_y,
10341 /* stride */ tile_size_x, /* y */ 0, /* line_no */ 0,
10342 (*height), pixel_data_size, num_attributes, attributes,
10343 num_channels, channels, channel_offset_list);
10344 }
10345
ComputeChannelLayout(std::vector<size_t> * channel_offset_list,int * pixel_data_size,size_t * channel_offset,int num_channels,const EXRChannelInfo * channels)10346 static bool ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
10347 int *pixel_data_size, size_t *channel_offset,
10348 int num_channels,
10349 const EXRChannelInfo *channels) {
10350 channel_offset_list->resize(static_cast<size_t>(num_channels));
10351
10352 (*pixel_data_size) = 0;
10353 (*channel_offset) = 0;
10354
10355 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10356 (*channel_offset_list)[c] = (*channel_offset);
10357 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10358 (*pixel_data_size) += sizeof(unsigned short);
10359 (*channel_offset) += sizeof(unsigned short);
10360 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10361 (*pixel_data_size) += sizeof(float);
10362 (*channel_offset) += sizeof(float);
10363 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10364 (*pixel_data_size) += sizeof(unsigned int);
10365 (*channel_offset) += sizeof(unsigned int);
10366 } else {
10367 // ???
10368 return false;
10369 }
10370 }
10371 return true;
10372 }
10373
AllocateImage(int num_channels,const EXRChannelInfo * channels,const int * requested_pixel_types,int data_width,int data_height)10374 static unsigned char **AllocateImage(int num_channels,
10375 const EXRChannelInfo *channels,
10376 const int *requested_pixel_types,
10377 int data_width, int data_height) {
10378 unsigned char **images =
10379 reinterpret_cast<unsigned char **>(static_cast<float **>(
10380 malloc(sizeof(float *) * static_cast<size_t>(num_channels))));
10381
10382 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10383 size_t data_len =
10384 static_cast<size_t>(data_width) * static_cast<size_t>(data_height);
10385 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10386 // pixel_data_size += sizeof(unsigned short);
10387 // channel_offset += sizeof(unsigned short);
10388 // Alloc internal image for half type.
10389 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
10390 images[c] =
10391 reinterpret_cast<unsigned char *>(static_cast<unsigned short *>(
10392 malloc(sizeof(unsigned short) * data_len)));
10393 } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
10394 images[c] = reinterpret_cast<unsigned char *>(
10395 static_cast<float *>(malloc(sizeof(float) * data_len)));
10396 } else {
10397 TEXR_ASSERT(0);
10398 }
10399 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10400 // pixel_data_size += sizeof(float);
10401 // channel_offset += sizeof(float);
10402 images[c] = reinterpret_cast<unsigned char *>(
10403 static_cast<float *>(malloc(sizeof(float) * data_len)));
10404 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10405 // pixel_data_size += sizeof(unsigned int);
10406 // channel_offset += sizeof(unsigned int);
10407 images[c] = reinterpret_cast<unsigned char *>(
10408 static_cast<unsigned int *>(malloc(sizeof(unsigned int) * data_len)));
10409 } else {
10410 TEXR_ASSERT(0);
10411 }
10412 }
10413
10414 return images;
10415 }
10416
ParseEXRHeader(HeaderInfo * info,bool * empty_header,const EXRVersion * version,std::string * err,const unsigned char * buf,size_t size)10417 static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
10418 const EXRVersion *version, std::string *err,
10419 const unsigned char *buf, size_t size) {
10420 const char *marker = reinterpret_cast<const char *>(&buf[0]);
10421
10422 if (empty_header) {
10423 (*empty_header) = false;
10424 }
10425
10426 if (version->multipart) {
10427 if (size > 0 && marker[0] == '\0') {
10428 // End of header list.
10429 if (empty_header) {
10430 (*empty_header) = true;
10431 }
10432 return TINYEXR_SUCCESS;
10433 }
10434 }
10435
10436 // According to the spec, the header of every OpenEXR file must contain at
10437 // least the following attributes:
10438 //
10439 // channels chlist
10440 // compression compression
10441 // dataWindow box2i
10442 // displayWindow box2i
10443 // lineOrder lineOrder
10444 // pixelAspectRatio float
10445 // screenWindowCenter v2f
10446 // screenWindowWidth float
10447 bool has_channels = false;
10448 bool has_compression = false;
10449 bool has_data_window = false;
10450 bool has_display_window = false;
10451 bool has_line_order = false;
10452 bool has_pixel_aspect_ratio = false;
10453 bool has_screen_window_center = false;
10454 bool has_screen_window_width = false;
10455
10456 info->data_window[0] = 0;
10457 info->data_window[1] = 0;
10458 info->data_window[2] = 0;
10459 info->data_window[3] = 0;
10460 info->line_order = 0; // @fixme
10461 info->display_window[0] = 0;
10462 info->display_window[1] = 0;
10463 info->display_window[2] = 0;
10464 info->display_window[3] = 0;
10465 info->screen_window_center[0] = 0.0f;
10466 info->screen_window_center[1] = 0.0f;
10467 info->screen_window_width = -1.0f;
10468 info->pixel_aspect_ratio = -1.0f;
10469
10470 info->tile_size_x = -1;
10471 info->tile_size_y = -1;
10472 info->tile_level_mode = -1;
10473 info->tile_rounding_mode = -1;
10474
10475 info->attributes.clear();
10476
10477 // Read attributes
10478 size_t orig_size = size;
10479 for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) {
10480 if (0 == size) {
10481 if (err) {
10482 (*err) += "Insufficient data size for attributes.\n";
10483 }
10484 return TINYEXR_ERROR_INVALID_DATA;
10485 } else if (marker[0] == '\0') {
10486 size--;
10487 break;
10488 }
10489
10490 std::string attr_name;
10491 std::string attr_type;
10492 std::vector<unsigned char> data;
10493 size_t marker_size;
10494 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
10495 marker, size)) {
10496 if (err) {
10497 (*err) += "Failed to read attribute.\n";
10498 }
10499 return TINYEXR_ERROR_INVALID_DATA;
10500 }
10501 marker += marker_size;
10502 size -= marker_size;
10503
10504 if (version->tiled && attr_name.compare("tiles") == 0) {
10505 unsigned int x_size, y_size;
10506 unsigned char tile_mode;
10507 TEXR_ASSERT(data.size() == 9);
10508 memcpy(&x_size, &data.at(0), sizeof(int));
10509 memcpy(&y_size, &data.at(4), sizeof(int));
10510 tile_mode = data[8];
10511 tinyexr::swap4(&x_size);
10512 tinyexr::swap4(&y_size);
10513
10514 info->tile_size_x = static_cast<int>(x_size);
10515 info->tile_size_y = static_cast<int>(y_size);
10516
10517 // mode = levelMode + roundingMode * 16
10518 info->tile_level_mode = tile_mode & 0x3;
10519 info->tile_rounding_mode = (tile_mode >> 4) & 0x1;
10520
10521 } else if (attr_name.compare("compression") == 0) {
10522 bool ok = false;
10523 if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) {
10524 ok = true;
10525 }
10526
10527 if (data[0] == TINYEXR_COMPRESSIONTYPE_PIZ) {
10528 #if TINYEXR_USE_PIZ
10529 ok = true;
10530 #else
10531 if (err) {
10532 (*err) = "PIZ compression is not supported.";
10533 }
10534 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
10535 #endif
10536 }
10537
10538 if (data[0] == TINYEXR_COMPRESSIONTYPE_ZFP) {
10539 #if TINYEXR_USE_ZFP
10540 ok = true;
10541 #else
10542 if (err) {
10543 (*err) = "ZFP compression is not supported.";
10544 }
10545 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
10546 #endif
10547 }
10548
10549 if (!ok) {
10550 if (err) {
10551 (*err) = "Unknown compression type.";
10552 }
10553 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
10554 }
10555
10556 info->compression_type = static_cast<int>(data[0]);
10557 has_compression = true;
10558
10559 } else if (attr_name.compare("channels") == 0) {
10560 // name: zero-terminated string, from 1 to 255 bytes long
10561 // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2
10562 // pLinear: unsigned char, possible values are 0 and 1
10563 // reserved: three chars, should be zero
10564 // xSampling: int
10565 // ySampling: int
10566
10567 if (!ReadChannelInfo(info->channels, data)) {
10568 if (err) {
10569 (*err) += "Failed to parse channel info.\n";
10570 }
10571 return TINYEXR_ERROR_INVALID_DATA;
10572 }
10573
10574 if (info->channels.size() < 1) {
10575 if (err) {
10576 (*err) += "# of channels is zero.\n";
10577 }
10578 return TINYEXR_ERROR_INVALID_DATA;
10579 }
10580
10581 has_channels = true;
10582
10583 } else if (attr_name.compare("dataWindow") == 0) {
10584 if (data.size() >= 16) {
10585 memcpy(&info->data_window[0], &data.at(0), sizeof(int));
10586 memcpy(&info->data_window[1], &data.at(4), sizeof(int));
10587 memcpy(&info->data_window[2], &data.at(8), sizeof(int));
10588 memcpy(&info->data_window[3], &data.at(12), sizeof(int));
10589 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[0]));
10590 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[1]));
10591 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[2]));
10592 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[3]));
10593 has_data_window = true;
10594 }
10595 } else if (attr_name.compare("displayWindow") == 0) {
10596 if (data.size() >= 16) {
10597 memcpy(&info->display_window[0], &data.at(0), sizeof(int));
10598 memcpy(&info->display_window[1], &data.at(4), sizeof(int));
10599 memcpy(&info->display_window[2], &data.at(8), sizeof(int));
10600 memcpy(&info->display_window[3], &data.at(12), sizeof(int));
10601 tinyexr::swap4(
10602 reinterpret_cast<unsigned int *>(&info->display_window[0]));
10603 tinyexr::swap4(
10604 reinterpret_cast<unsigned int *>(&info->display_window[1]));
10605 tinyexr::swap4(
10606 reinterpret_cast<unsigned int *>(&info->display_window[2]));
10607 tinyexr::swap4(
10608 reinterpret_cast<unsigned int *>(&info->display_window[3]));
10609
10610 has_display_window = true;
10611 }
10612 } else if (attr_name.compare("lineOrder") == 0) {
10613 if (data.size() >= 1) {
10614 info->line_order = static_cast<int>(data[0]);
10615 has_line_order = true;
10616 }
10617 } else if (attr_name.compare("pixelAspectRatio") == 0) {
10618 if (data.size() >= sizeof(float)) {
10619 memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float));
10620 tinyexr::swap4(
10621 reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio));
10622 has_pixel_aspect_ratio = true;
10623 }
10624 } else if (attr_name.compare("screenWindowCenter") == 0) {
10625 if (data.size() >= 8) {
10626 memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float));
10627 memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float));
10628 tinyexr::swap4(
10629 reinterpret_cast<unsigned int *>(&info->screen_window_center[0]));
10630 tinyexr::swap4(
10631 reinterpret_cast<unsigned int *>(&info->screen_window_center[1]));
10632 has_screen_window_center = true;
10633 }
10634 } else if (attr_name.compare("screenWindowWidth") == 0) {
10635 if (data.size() >= sizeof(float)) {
10636 memcpy(&info->screen_window_width, &data.at(0), sizeof(float));
10637 tinyexr::swap4(
10638 reinterpret_cast<unsigned int *>(&info->screen_window_width));
10639
10640 has_screen_window_width = true;
10641 }
10642 } else if (attr_name.compare("chunkCount") == 0) {
10643 if (data.size() >= sizeof(int)) {
10644 memcpy(&info->chunk_count, &data.at(0), sizeof(int));
10645 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count));
10646 }
10647 } else {
10648 // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES)
10649 if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
10650 EXRAttribute attrib;
10651 #ifdef _MSC_VER
10652 strncpy_s(attrib.name, attr_name.c_str(), 255);
10653 strncpy_s(attrib.type, attr_type.c_str(), 255);
10654 #else
10655 strncpy(attrib.name, attr_name.c_str(), 255);
10656 strncpy(attrib.type, attr_type.c_str(), 255);
10657 #endif
10658 attrib.name[255] = '\0';
10659 attrib.type[255] = '\0';
10660 attrib.size = static_cast<int>(data.size());
10661 attrib.value = static_cast<unsigned char *>(malloc(data.size()));
10662 memcpy(reinterpret_cast<char *>(attrib.value), &data.at(0),
10663 data.size());
10664 info->attributes.push_back(attrib);
10665 }
10666 }
10667 }
10668
10669 // Check if required attributes exist
10670 {
10671 std::stringstream ss_err;
10672
10673 if (!has_compression) {
10674 ss_err << "\"compression\" attribute not found in the header."
10675 << std::endl;
10676 }
10677
10678 if (!has_channels) {
10679 ss_err << "\"channels\" attribute not found in the header." << std::endl;
10680 }
10681
10682 if (!has_line_order) {
10683 ss_err << "\"lineOrder\" attribute not found in the header." << std::endl;
10684 }
10685
10686 if (!has_display_window) {
10687 ss_err << "\"displayWindow\" attribute not found in the header."
10688 << std::endl;
10689 }
10690
10691 if (!has_data_window) {
10692 ss_err << "\"dataWindow\" attribute not found in the header or invalid."
10693 << std::endl;
10694 }
10695
10696 if (!has_pixel_aspect_ratio) {
10697 ss_err << "\"pixelAspectRatio\" attribute not found in the header."
10698 << std::endl;
10699 }
10700
10701 if (!has_screen_window_width) {
10702 ss_err << "\"screenWindowWidth\" attribute not found in the header."
10703 << std::endl;
10704 }
10705
10706 if (!has_screen_window_center) {
10707 ss_err << "\"screenWindowCenter\" attribute not found in the header."
10708 << std::endl;
10709 }
10710
10711 if (!(ss_err.str().empty())) {
10712 if (err) {
10713 (*err) += ss_err.str();
10714 }
10715 return TINYEXR_ERROR_INVALID_HEADER;
10716 }
10717 }
10718
10719 info->header_len = static_cast<unsigned int>(orig_size - size);
10720
10721 return TINYEXR_SUCCESS;
10722 }
10723
10724 // C++ HeaderInfo to C EXRHeader conversion.
ConvertHeader(EXRHeader * exr_header,const HeaderInfo & info)10725 static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
10726 exr_header->pixel_aspect_ratio = info.pixel_aspect_ratio;
10727 exr_header->screen_window_center[0] = info.screen_window_center[0];
10728 exr_header->screen_window_center[1] = info.screen_window_center[1];
10729 exr_header->screen_window_width = info.screen_window_width;
10730 exr_header->chunk_count = info.chunk_count;
10731 exr_header->display_window[0] = info.display_window[0];
10732 exr_header->display_window[1] = info.display_window[1];
10733 exr_header->display_window[2] = info.display_window[2];
10734 exr_header->display_window[3] = info.display_window[3];
10735 exr_header->data_window[0] = info.data_window[0];
10736 exr_header->data_window[1] = info.data_window[1];
10737 exr_header->data_window[2] = info.data_window[2];
10738 exr_header->data_window[3] = info.data_window[3];
10739 exr_header->line_order = info.line_order;
10740 exr_header->compression_type = info.compression_type;
10741
10742 exr_header->tile_size_x = info.tile_size_x;
10743 exr_header->tile_size_y = info.tile_size_y;
10744 exr_header->tile_level_mode = info.tile_level_mode;
10745 exr_header->tile_rounding_mode = info.tile_rounding_mode;
10746
10747 exr_header->num_channels = static_cast<int>(info.channels.size());
10748
10749 exr_header->channels = static_cast<EXRChannelInfo *>(malloc(
10750 sizeof(EXRChannelInfo) * static_cast<size_t>(exr_header->num_channels)));
10751 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
10752 #ifdef _MSC_VER
10753 strncpy_s(exr_header->channels[c].name, info.channels[c].name.c_str(), 255);
10754 #else
10755 strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255);
10756 #endif
10757 // manually add '\0' for safety.
10758 exr_header->channels[c].name[255] = '\0';
10759
10760 exr_header->channels[c].pixel_type = info.channels[c].pixel_type;
10761 exr_header->channels[c].p_linear = info.channels[c].p_linear;
10762 exr_header->channels[c].x_sampling = info.channels[c].x_sampling;
10763 exr_header->channels[c].y_sampling = info.channels[c].y_sampling;
10764 }
10765
10766 exr_header->pixel_types = static_cast<int *>(
10767 malloc(sizeof(int) * static_cast<size_t>(exr_header->num_channels)));
10768 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
10769 exr_header->pixel_types[c] = info.channels[c].pixel_type;
10770 }
10771
10772 // Initially fill with values of `pixel_types`
10773 exr_header->requested_pixel_types = static_cast<int *>(
10774 malloc(sizeof(int) * static_cast<size_t>(exr_header->num_channels)));
10775 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
10776 exr_header->requested_pixel_types[c] = info.channels[c].pixel_type;
10777 }
10778
10779 exr_header->num_custom_attributes = static_cast<int>(info.attributes.size());
10780
10781 if (exr_header->num_custom_attributes > 0) {
10782 // TODO(syoyo): Report warning when # of attributes exceeds
10783 // `TINYEXR_MAX_CUSTOM_ATTRIBUTES`
10784 if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
10785 exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES;
10786 }
10787
10788 exr_header->custom_attributes = static_cast<EXRAttribute *>(malloc(
10789 sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes)));
10790
10791 for (size_t i = 0; i < info.attributes.size(); i++) {
10792 memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name,
10793 256);
10794 memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type,
10795 256);
10796 exr_header->custom_attributes[i].size = info.attributes[i].size;
10797 // Just copy poiner
10798 exr_header->custom_attributes[i].value = info.attributes[i].value;
10799 }
10800
10801 } else {
10802 exr_header->custom_attributes = NULL;
10803 }
10804
10805 exr_header->header_len = info.header_len;
10806 }
10807
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)10808 static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
10809 const std::vector<tinyexr::tinyexr_uint64> &offsets,
10810 const unsigned char *head, const size_t size,
10811 std::string *err) {
10812 int num_channels = exr_header->num_channels;
10813
10814 int num_scanline_blocks = 1;
10815 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
10816 num_scanline_blocks = 16;
10817 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
10818 num_scanline_blocks = 32;
10819 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
10820 num_scanline_blocks = 16;
10821 }
10822
10823 int data_width = exr_header->data_window[2] - exr_header->data_window[0] + 1;
10824 int data_height = exr_header->data_window[3] - exr_header->data_window[1] + 1;
10825
10826 if ((data_width < 0) || (data_height < 0)) {
10827 if (err) {
10828 std::stringstream ss;
10829 ss << "Invalid data width or data height: " << data_width << ", "
10830 << data_height << std::endl;
10831 (*err) += ss.str();
10832 }
10833 return TINYEXR_ERROR_INVALID_DATA;
10834 }
10835
10836 // Do not allow too large data_width and data_height. header invalid?
10837 {
10838 const int threshold = 1024 * 8192; // heuristics
10839 if ((data_width > threshold) || (data_height > threshold)) {
10840 if (err) {
10841 std::stringstream ss;
10842 ss << "data_with or data_height too large. data_width: " << data_width
10843 << ", "
10844 << "data_height = " << data_height << std::endl;
10845 (*err) += ss.str();
10846 }
10847 return TINYEXR_ERROR_INVALID_DATA;
10848 }
10849 }
10850
10851 size_t num_blocks = offsets.size();
10852
10853 std::vector<size_t> channel_offset_list;
10854 int pixel_data_size = 0;
10855 size_t channel_offset = 0;
10856 if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size,
10857 &channel_offset, num_channels,
10858 exr_header->channels)) {
10859 if (err) {
10860 (*err) += "Failed to compute channel layout.\n";
10861 }
10862 return TINYEXR_ERROR_INVALID_DATA;
10863 }
10864
10865 bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety.
10866
10867 if (exr_header->tiled) {
10868 // value check
10869 if (exr_header->tile_size_x < 0) {
10870 if (err) {
10871 std::stringstream ss;
10872 ss << "Invalid tile size x : " << exr_header->tile_size_x << "\n";
10873 (*err) += ss.str();
10874 }
10875 return TINYEXR_ERROR_INVALID_HEADER;
10876 }
10877
10878 if (exr_header->tile_size_y < 0) {
10879 if (err) {
10880 std::stringstream ss;
10881 ss << "Invalid tile size y : " << exr_header->tile_size_y << "\n";
10882 (*err) += ss.str();
10883 }
10884 return TINYEXR_ERROR_INVALID_HEADER;
10885 }
10886
10887 size_t num_tiles = offsets.size(); // = # of blocks
10888
10889 exr_image->tiles = static_cast<EXRTile *>(
10890 calloc(sizeof(EXRTile), static_cast<size_t>(num_tiles)));
10891
10892 int err_code = TINYEXR_SUCCESS;
10893
10894 #if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0)
10895
10896 std::vector<std::thread> workers;
10897 std::atomic<size_t> tile_count(0);
10898
10899 int num_threads = std::max(1, int(std::thread::hardware_concurrency()));
10900 if (num_threads > int(num_tiles)) {
10901 num_threads = int(num_tiles);
10902 }
10903
10904 for (int t = 0; t < num_threads; t++) {
10905 workers.emplace_back(std::thread([&]() {
10906 size_t tile_idx = 0;
10907 while ((tile_idx = tile_count++) < num_tiles) {
10908
10909 #else
10910 for (size_t tile_idx = 0; tile_idx < num_tiles; tile_idx++) {
10911 #endif
10912 // Allocate memory for each tile.
10913 exr_image->tiles[tile_idx].images = tinyexr::AllocateImage(
10914 num_channels, exr_header->channels,
10915 exr_header->requested_pixel_types, exr_header->tile_size_x,
10916 exr_header->tile_size_y);
10917
10918 // 16 byte: tile coordinates
10919 // 4 byte : data size
10920 // ~ : data(uncompressed or compressed)
10921 if (offsets[tile_idx] + sizeof(int) * 5 > size) {
10922 // TODO(LTE): atomic
10923 if (err) {
10924 (*err) += "Insufficient data size.\n";
10925 }
10926 err_code = TINYEXR_ERROR_INVALID_DATA;
10927 break;
10928 }
10929
10930 size_t data_size =
10931 size_t(size - (offsets[tile_idx] + sizeof(int) * 5));
10932 const unsigned char *data_ptr =
10933 reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]);
10934
10935 int tile_coordinates[4];
10936 memcpy(tile_coordinates, data_ptr, sizeof(int) * 4);
10937 tinyexr::swap4(
10938 reinterpret_cast<unsigned int *>(&tile_coordinates[0]));
10939 tinyexr::swap4(
10940 reinterpret_cast<unsigned int *>(&tile_coordinates[1]));
10941 tinyexr::swap4(
10942 reinterpret_cast<unsigned int *>(&tile_coordinates[2]));
10943 tinyexr::swap4(
10944 reinterpret_cast<unsigned int *>(&tile_coordinates[3]));
10945
10946 // @todo{ LoD }
10947 if (tile_coordinates[2] != 0) {
10948 err_code = TINYEXR_ERROR_UNSUPPORTED_FEATURE;
10949 break;
10950 }
10951 if (tile_coordinates[3] != 0) {
10952 err_code = TINYEXR_ERROR_UNSUPPORTED_FEATURE;
10953 break;
10954 }
10955
10956 int data_len;
10957 memcpy(&data_len, data_ptr + 16,
10958 sizeof(int)); // 16 = sizeof(tile_coordinates)
10959 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
10960
10961 if (data_len < 4 || size_t(data_len) > data_size) {
10962 // TODO(LTE): atomic
10963 if (err) {
10964 (*err) += "Insufficient data length.\n";
10965 }
10966 err_code = TINYEXR_ERROR_INVALID_DATA;
10967 break;
10968 }
10969
10970 // Move to data addr: 20 = 16 + 4;
10971 data_ptr += 20;
10972
10973 bool ret = tinyexr::DecodeTiledPixelData(
10974 exr_image->tiles[tile_idx].images,
10975 &(exr_image->tiles[tile_idx].width),
10976 &(exr_image->tiles[tile_idx].height),
10977 exr_header->requested_pixel_types, data_ptr,
10978 static_cast<size_t>(data_len), exr_header->compression_type,
10979 exr_header->line_order, data_width, data_height,
10980 tile_coordinates[0], tile_coordinates[1], exr_header->tile_size_x,
10981 exr_header->tile_size_y, static_cast<size_t>(pixel_data_size),
10982 static_cast<size_t>(exr_header->num_custom_attributes),
10983 exr_header->custom_attributes,
10984 static_cast<size_t>(exr_header->num_channels),
10985 exr_header->channels, channel_offset_list);
10986
10987 if (!ret) {
10988 // TODO(LTE): atomic
10989 if (err) {
10990 (*err) += "Failed to decode tile data.\n";
10991 }
10992 err_code = TINYEXR_ERROR_INVALID_DATA;
10993 }
10994
10995 exr_image->tiles[tile_idx].offset_x = tile_coordinates[0];
10996 exr_image->tiles[tile_idx].offset_y = tile_coordinates[1];
10997 exr_image->tiles[tile_idx].level_x = tile_coordinates[2];
10998 exr_image->tiles[tile_idx].level_y = tile_coordinates[3];
10999
11000 #if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0)
11001 }
11002 }));
11003 } // num_thread loop
11004
11005 for (auto &t : workers) {
11006 t.join();
11007 }
11008
11009 #else
11010 }
11011 #endif
11012
11013 if (err_code != TINYEXR_SUCCESS) {
11014 return err_code;
11015 }
11016
11017 exr_image->num_tiles = static_cast<int>(num_tiles);
11018 } else { // scanline format
11019
11020 // Don't allow too large image(256GB * pixel_data_size or more). Workaround
11021 // for #104.
11022 size_t total_data_len =
11023 size_t(data_width) * size_t(data_height) * size_t(num_channels);
11024 const bool total_data_len_overflown =
11025 sizeof(void *) == 8 ? (total_data_len >= 0x4000000000) : false;
11026 if ((total_data_len == 0) || total_data_len_overflown) {
11027 if (err) {
11028 std::stringstream ss;
11029 ss << "Image data size is zero or too large: width = " << data_width
11030 << ", height = " << data_height << ", channels = " << num_channels
11031 << std::endl;
11032 (*err) += ss.str();
11033 }
11034 return TINYEXR_ERROR_INVALID_DATA;
11035 }
11036
11037 exr_image->images = tinyexr::AllocateImage(
11038 num_channels, exr_header->channels, exr_header->requested_pixel_types,
11039 data_width, data_height);
11040
11041 #if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0)
11042 std::vector<std::thread> workers;
11043 std::atomic<int> y_count(0);
11044
11045 int num_threads = std::max(1, int(std::thread::hardware_concurrency()));
11046 if (num_threads > int(num_blocks)) {
11047 num_threads = int(num_blocks);
11048 }
11049
11050 for (int t = 0; t < num_threads; t++) {
11051 workers.emplace_back(std::thread([&]() {
11052 int y = 0;
11053 while ((y = y_count++) < int(num_blocks)) {
11054
11055 #else
11056
11057 #if TINYEXR_USE_OPENMP
11058 #pragma omp parallel for
11059 #endif
11060 for (int y = 0; y < static_cast<int>(num_blocks); y++) {
11061
11062 #endif
11063 size_t y_idx = static_cast<size_t>(y);
11064
11065 if (offsets[y_idx] + sizeof(int) * 2 > size) {
11066 invalid_data = true;
11067 } else {
11068 // 4 byte: scan line
11069 // 4 byte: data size
11070 // ~ : pixel data(uncompressed or compressed)
11071 size_t data_size =
11072 size_t(size - (offsets[y_idx] + sizeof(int) * 2));
11073 const unsigned char *data_ptr =
11074 reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
11075
11076 int line_no;
11077 memcpy(&line_no, data_ptr, sizeof(int));
11078 int data_len;
11079 memcpy(&data_len, data_ptr + 4, sizeof(int));
11080 tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
11081 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
11082
11083 if (size_t(data_len) > data_size) {
11084 invalid_data = true;
11085
11086 } else if ((line_no > (2 << 20)) || (line_no < -(2 << 20))) {
11087 // Too large value. Assume this is invalid
11088 // 2**20 = 1048576 = heuristic value.
11089 invalid_data = true;
11090 } else if (data_len == 0) {
11091 // TODO(syoyo): May be ok to raise the threshold for example
11092 // `data_len < 4`
11093 invalid_data = true;
11094 } else {
11095 // line_no may be negative.
11096 int end_line_no = (std::min)(line_no + num_scanline_blocks,
11097 (exr_header->data_window[3] + 1));
11098
11099 int num_lines = end_line_no - line_no;
11100
11101 if (num_lines <= 0) {
11102 invalid_data = true;
11103 } else {
11104 // Move to data addr: 8 = 4 + 4;
11105 data_ptr += 8;
11106
11107 // Adjust line_no with data_window.bmin.y
11108
11109 // overflow check
11110 tinyexr_int64 lno =
11111 static_cast<tinyexr_int64>(line_no) -
11112 static_cast<tinyexr_int64>(exr_header->data_window[1]);
11113 if (lno > std::numeric_limits<int>::max()) {
11114 line_no = -1; // invalid
11115 } else if (lno < -std::numeric_limits<int>::max()) {
11116 line_no = -1; // invalid
11117 } else {
11118 line_no -= exr_header->data_window[1];
11119 }
11120
11121 if (line_no < 0) {
11122 invalid_data = true;
11123 } else {
11124 if (!tinyexr::DecodePixelData(
11125 exr_image->images, exr_header->requested_pixel_types,
11126 data_ptr, static_cast<size_t>(data_len),
11127 exr_header->compression_type, exr_header->line_order,
11128 data_width, data_height, data_width, y, line_no,
11129 num_lines, static_cast<size_t>(pixel_data_size),
11130 static_cast<size_t>(
11131 exr_header->num_custom_attributes),
11132 exr_header->custom_attributes,
11133 static_cast<size_t>(exr_header->num_channels),
11134 exr_header->channels, channel_offset_list)) {
11135 invalid_data = true;
11136 }
11137 }
11138 }
11139 }
11140 }
11141
11142 #if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0)
11143 }
11144 }));
11145 }
11146
11147 for (auto &t : workers) {
11148 t.join();
11149 }
11150 #else
11151 } // omp parallel
11152 #endif
11153 }
11154
11155 if (invalid_data) {
11156 if (err) {
11157 std::stringstream ss;
11158 (*err) += "Invalid data found when decoding pixels.\n";
11159 }
11160 return TINYEXR_ERROR_INVALID_DATA;
11161 }
11162
11163 // Overwrite `pixel_type` with `requested_pixel_type`.
11164 {
11165 for (int c = 0; c < exr_header->num_channels; c++) {
11166 exr_header->pixel_types[c] = exr_header->requested_pixel_types[c];
11167 }
11168 }
11169
11170 {
11171 exr_image->num_channels = num_channels;
11172
11173 exr_image->width = data_width;
11174 exr_image->height = data_height;
11175 }
11176
11177 return TINYEXR_SUCCESS;
11178 }
11179
ReconstructLineOffsets(std::vector<tinyexr::tinyexr_uint64> * offsets,size_t n,const unsigned char * head,const unsigned char * marker,const size_t size)11180 static bool ReconstructLineOffsets(
11181 std::vector<tinyexr::tinyexr_uint64> *offsets, size_t n,
11182 const unsigned char *head, const unsigned char *marker, const size_t size) {
11183 TEXR_ASSERT(head < marker);
11184 TEXR_ASSERT(offsets->size() == n);
11185
11186 for (size_t i = 0; i < n; i++) {
11187 size_t offset = static_cast<size_t>(marker - head);
11188 // Offset should not exceed whole EXR file/data size.
11189 if ((offset + sizeof(tinyexr::tinyexr_uint64)) >= size) {
11190 return false;
11191 }
11192
11193 int y;
11194 unsigned int data_len;
11195
11196 memcpy(&y, marker, sizeof(int));
11197 memcpy(&data_len, marker + 4, sizeof(unsigned int));
11198
11199 if (data_len >= size) {
11200 return false;
11201 }
11202
11203 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y));
11204 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
11205
11206 (*offsets)[i] = offset;
11207
11208 marker += data_len + 8; // 8 = 4 bytes(y) + 4 bytes(data_len)
11209 }
11210
11211 return true;
11212 }
11213
DecodeEXRImage(EXRImage * exr_image,const EXRHeader * exr_header,const unsigned char * head,const unsigned char * marker,const size_t size,const char ** err)11214 static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
11215 const unsigned char *head,
11216 const unsigned char *marker, const size_t size,
11217 const char **err) {
11218 if (exr_image == NULL || exr_header == NULL || head == NULL ||
11219 marker == NULL || (size <= tinyexr::kEXRVersionSize)) {
11220 tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err);
11221 return TINYEXR_ERROR_INVALID_ARGUMENT;
11222 }
11223
11224 int num_scanline_blocks = 1;
11225 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
11226 num_scanline_blocks = 16;
11227 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
11228 num_scanline_blocks = 32;
11229 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
11230 num_scanline_blocks = 16;
11231 }
11232
11233 int data_width = exr_header->data_window[2] - exr_header->data_window[0];
11234 if (data_width >= std::numeric_limits<int>::max()) {
11235 // Issue 63
11236 tinyexr::SetErrorMessage("Invalid data width value", err);
11237 return TINYEXR_ERROR_INVALID_DATA;
11238 }
11239 data_width++;
11240
11241 int data_height = exr_header->data_window[3] - exr_header->data_window[1];
11242 if (data_height >= std::numeric_limits<int>::max()) {
11243 tinyexr::SetErrorMessage("Invalid data height value", err);
11244 return TINYEXR_ERROR_INVALID_DATA;
11245 }
11246 data_height++;
11247
11248 if ((data_width < 0) || (data_height < 0)) {
11249 tinyexr::SetErrorMessage("data width or data height is negative.", err);
11250 return TINYEXR_ERROR_INVALID_DATA;
11251 }
11252
11253 // Do not allow too large data_width and data_height. header invalid?
11254 {
11255 const int threshold = 1024 * 8192; // heuristics
11256 if (data_width > threshold) {
11257 tinyexr::SetErrorMessage("data width too large.", err);
11258 return TINYEXR_ERROR_INVALID_DATA;
11259 }
11260 if (data_height > threshold) {
11261 tinyexr::SetErrorMessage("data height too large.", err);
11262 return TINYEXR_ERROR_INVALID_DATA;
11263 }
11264 }
11265
11266 // Read offset tables.
11267 size_t num_blocks = 0;
11268
11269 if (exr_header->chunk_count > 0) {
11270 // Use `chunkCount` attribute.
11271 num_blocks = static_cast<size_t>(exr_header->chunk_count);
11272 } else if (exr_header->tiled) {
11273 // @todo { LoD }
11274 size_t num_x_tiles = static_cast<size_t>(data_width) /
11275 static_cast<size_t>(exr_header->tile_size_x);
11276 if (num_x_tiles * static_cast<size_t>(exr_header->tile_size_x) <
11277 static_cast<size_t>(data_width)) {
11278 num_x_tiles++;
11279 }
11280 size_t num_y_tiles = static_cast<size_t>(data_height) /
11281 static_cast<size_t>(exr_header->tile_size_y);
11282 if (num_y_tiles * static_cast<size_t>(exr_header->tile_size_y) <
11283 static_cast<size_t>(data_height)) {
11284 num_y_tiles++;
11285 }
11286
11287 num_blocks = num_x_tiles * num_y_tiles;
11288 } else {
11289 num_blocks = static_cast<size_t>(data_height) /
11290 static_cast<size_t>(num_scanline_blocks);
11291 if (num_blocks * static_cast<size_t>(num_scanline_blocks) <
11292 static_cast<size_t>(data_height)) {
11293 num_blocks++;
11294 }
11295 }
11296
11297 std::vector<tinyexr::tinyexr_uint64> offsets(num_blocks);
11298
11299 for (size_t y = 0; y < num_blocks; y++) {
11300 tinyexr::tinyexr_uint64 offset;
11301 // Issue #81
11302 if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) {
11303 tinyexr::SetErrorMessage("Insufficient data size in offset table.", err);
11304 return TINYEXR_ERROR_INVALID_DATA;
11305 }
11306
11307 memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64));
11308 tinyexr::swap8(&offset);
11309 if (offset >= size) {
11310 tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err);
11311 return TINYEXR_ERROR_INVALID_DATA;
11312 }
11313 marker += sizeof(tinyexr::tinyexr_uint64); // = 8
11314 offsets[y] = offset;
11315 }
11316
11317 // If line offsets are invalid, we try to reconstruct it.
11318 // See OpenEXR/IlmImf/ImfScanLineInputFile.cpp::readLineOffsets() for details.
11319 for (size_t y = 0; y < num_blocks; y++) {
11320 if (offsets[y] <= 0) {
11321 // TODO(syoyo) Report as warning?
11322 // if (err) {
11323 // stringstream ss;
11324 // ss << "Incomplete lineOffsets." << std::endl;
11325 // (*err) += ss.str();
11326 //}
11327 bool ret =
11328 ReconstructLineOffsets(&offsets, num_blocks, head, marker, size);
11329 if (ret) {
11330 // OK
11331 break;
11332 } else {
11333 tinyexr::SetErrorMessage(
11334 "Cannot reconstruct lineOffset table in DecodeEXRImage.", err);
11335 return TINYEXR_ERROR_INVALID_DATA;
11336 }
11337 }
11338 }
11339
11340 {
11341 std::string e;
11342 int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e);
11343
11344 if (ret != TINYEXR_SUCCESS) {
11345 if (!e.empty()) {
11346 tinyexr::SetErrorMessage(e, err);
11347 }
11348
11349 #if 1
11350 FreeEXRImage(exr_image);
11351 #else
11352 // release memory(if exists)
11353 if ((exr_header->num_channels > 0) && exr_image && exr_image->images) {
11354 for (size_t c = 0; c < size_t(exr_header->num_channels); c++) {
11355 if (exr_image->images[c]) {
11356 free(exr_image->images[c]);
11357 exr_image->images[c] = NULL;
11358 }
11359 }
11360 free(exr_image->images);
11361 exr_image->images = NULL;
11362 }
11363 #endif
11364 }
11365
11366 return ret;
11367 }
11368 }
11369
GetLayers(const EXRHeader & exr_header,std::vector<std::string> & layer_names)11370 static void GetLayers(const EXRHeader& exr_header, std::vector<std::string>& layer_names) {
11371 // Naive implementation
11372 // Group channels by layers
11373 // go over all channel names, split by periods
11374 // collect unique names
11375 layer_names.clear();
11376 for (int c = 0; c < exr_header.num_channels; c++) {
11377 std::string full_name(exr_header.channels[c].name);
11378 const size_t pos = full_name.find_last_of('.');
11379 if (pos != std::string::npos && pos != 0 && pos + 1 < full_name.size()) {
11380 full_name.erase(pos);
11381 if (std::find(layer_names.begin(), layer_names.end(), full_name) == layer_names.end())
11382 layer_names.push_back(full_name);
11383 }
11384 }
11385 }
11386
11387 struct LayerChannel {
LayerChannelLayerChannel11388 explicit LayerChannel (size_t i, std::string n)
11389 : index(i)
11390 , name(n)
11391 {}
11392 size_t index;
11393 std::string name;
11394 };
11395
ChannelsInLayer(const EXRHeader & exr_header,const std::string layer_name,std::vector<LayerChannel> & channels)11396 static void ChannelsInLayer(const EXRHeader& exr_header, const std::string layer_name, std::vector<LayerChannel>& channels) {
11397 channels.clear();
11398 for (int c = 0; c < exr_header.num_channels; c++) {
11399 std::string ch_name(exr_header.channels[c].name);
11400 if (layer_name.empty()) {
11401 const size_t pos = ch_name.find_last_of('.');
11402 if (pos != std::string::npos && pos < ch_name.size()) {
11403 ch_name = ch_name.substr(pos + 1);
11404 }
11405 } else {
11406 const size_t pos = ch_name.find(layer_name + '.');
11407 if (pos == std::string::npos)
11408 continue;
11409 if (pos == 0) {
11410 ch_name = ch_name.substr(layer_name.size() + 1);
11411 }
11412 }
11413 LayerChannel ch(size_t(c), ch_name);
11414 channels.push_back(ch);
11415 }
11416 }
11417
11418 } // namespace tinyexr
11419
EXRLayers(const char * filename,const char ** layer_names[],int * num_layers,const char ** err)11420 int EXRLayers(const char *filename, const char **layer_names[], int *num_layers, const char **err) {
11421 EXRVersion exr_version;
11422 EXRHeader exr_header;
11423 InitEXRHeader(&exr_header);
11424
11425 {
11426 int ret = ParseEXRVersionFromFile(&exr_version, filename);
11427 if (ret != TINYEXR_SUCCESS) {
11428 tinyexr::SetErrorMessage("Invalid EXR header.", err);
11429 return ret;
11430 }
11431
11432 if (exr_version.multipart || exr_version.non_image) {
11433 tinyexr::SetErrorMessage(
11434 "Loading multipart or DeepImage is not supported in LoadEXR() API",
11435 err);
11436 return TINYEXR_ERROR_INVALID_DATA; // @fixme.
11437 }
11438 }
11439
11440 int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err);
11441 if (ret != TINYEXR_SUCCESS) {
11442 FreeEXRHeader(&exr_header);
11443 return ret;
11444 }
11445
11446 std::vector<std::string> layer_vec;
11447 tinyexr::GetLayers(exr_header, layer_vec);
11448
11449 (*num_layers) = int(layer_vec.size());
11450 (*layer_names) = static_cast<const char **>(
11451 malloc(sizeof(const char *) * static_cast<size_t>(layer_vec.size())));
11452 for (size_t c = 0; c < static_cast<size_t>(layer_vec.size()); c++) {
11453 #ifdef _MSC_VER
11454 (*layer_names)[c] = _strdup(layer_vec[c].c_str());
11455 #else
11456 (*layer_names)[c] = strdup(layer_vec[c].c_str());
11457 #endif
11458 }
11459
11460 FreeEXRHeader(&exr_header);
11461 return TINYEXR_SUCCESS;
11462 }
11463
LoadEXR(float ** out_rgba,int * width,int * height,const char * filename,const char ** err)11464 int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
11465 const char **err) {
11466 return LoadEXRWithLayer(out_rgba, width, height, filename, /* layername */NULL, err);
11467 }
11468
LoadEXRWithLayer(float ** out_rgba,int * width,int * height,const char * filename,const char * layername,const char ** err)11469 int LoadEXRWithLayer(float **out_rgba, int *width, int *height, const char *filename, const char *layername,
11470 const char **err) {
11471 if (out_rgba == NULL) {
11472 tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err);
11473 return TINYEXR_ERROR_INVALID_ARGUMENT;
11474 }
11475
11476 EXRVersion exr_version;
11477 EXRImage exr_image;
11478 EXRHeader exr_header;
11479 InitEXRHeader(&exr_header);
11480 InitEXRImage(&exr_image);
11481
11482 {
11483 int ret = ParseEXRVersionFromFile(&exr_version, filename);
11484 if (ret != TINYEXR_SUCCESS) {
11485 std::stringstream ss;
11486 ss << "Failed to open EXR file or read version info from EXR file. code(" << ret << ")";
11487 tinyexr::SetErrorMessage(ss.str(), err);
11488 return ret;
11489 }
11490
11491 if (exr_version.multipart || exr_version.non_image) {
11492 tinyexr::SetErrorMessage(
11493 "Loading multipart or DeepImage is not supported in LoadEXR() API",
11494 err);
11495 return TINYEXR_ERROR_INVALID_DATA; // @fixme.
11496 }
11497 }
11498
11499 {
11500 int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err);
11501 if (ret != TINYEXR_SUCCESS) {
11502 FreeEXRHeader(&exr_header);
11503 return ret;
11504 }
11505 }
11506
11507 // Read HALF channel as FLOAT.
11508 for (int i = 0; i < exr_header.num_channels; i++) {
11509 if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
11510 exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
11511 }
11512 }
11513
11514 // TODO: Probably limit loading to layers (channels) selected by layer index
11515 {
11516 int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err);
11517 if (ret != TINYEXR_SUCCESS) {
11518 FreeEXRHeader(&exr_header);
11519 return ret;
11520 }
11521 }
11522
11523 // RGBA
11524 int idxR = -1;
11525 int idxG = -1;
11526 int idxB = -1;
11527 int idxA = -1;
11528
11529 std::vector<std::string> layer_names;
11530 tinyexr::GetLayers(exr_header, layer_names);
11531
11532 std::vector<tinyexr::LayerChannel> channels;
11533 tinyexr::ChannelsInLayer(exr_header, layername == NULL ? "" : std::string(layername), channels);
11534
11535 if (channels.size() < 1) {
11536 tinyexr::SetErrorMessage("Layer Not Found", err);
11537 FreeEXRHeader(&exr_header);
11538 FreeEXRImage(&exr_image);
11539 return TINYEXR_ERROR_LAYER_NOT_FOUND;
11540 }
11541
11542 size_t ch_count = channels.size() < 4 ? channels.size() : 4;
11543 for (size_t c = 0; c < ch_count; c++) {
11544 const tinyexr::LayerChannel &ch = channels[c];
11545
11546 if (ch.name == "R") {
11547 idxR = int(ch.index);
11548 }
11549 else if (ch.name == "G") {
11550 idxG = int(ch.index);
11551 }
11552 else if (ch.name == "B") {
11553 idxB = int(ch.index);
11554 }
11555 else if (ch.name == "A") {
11556 idxA = int(ch.index);
11557 }
11558 }
11559
11560 if (channels.size() == 1) {
11561 int chIdx = int(channels.front().index);
11562 // Grayscale channel only.
11563
11564 (*out_rgba) = reinterpret_cast<float *>(
11565 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11566 static_cast<size_t>(exr_image.height)));
11567
11568 if (exr_header.tiled) {
11569 for (int it = 0; it < exr_image.num_tiles; it++) {
11570 for (int j = 0; j < exr_header.tile_size_y; j++) {
11571 for (int i = 0; i < exr_header.tile_size_x; i++) {
11572 const int ii =
11573 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11574 const int jj =
11575 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11576 const int idx = ii + jj * exr_image.width;
11577
11578 // out of region check.
11579 if (ii >= exr_image.width) {
11580 continue;
11581 }
11582 if (jj >= exr_image.height) {
11583 continue;
11584 }
11585 const int srcIdx = i + j * exr_header.tile_size_x;
11586 unsigned char **src = exr_image.tiles[it].images;
11587 (*out_rgba)[4 * idx + 0] =
11588 reinterpret_cast<float **>(src)[chIdx][srcIdx];
11589 (*out_rgba)[4 * idx + 1] =
11590 reinterpret_cast<float **>(src)[chIdx][srcIdx];
11591 (*out_rgba)[4 * idx + 2] =
11592 reinterpret_cast<float **>(src)[chIdx][srcIdx];
11593 (*out_rgba)[4 * idx + 3] =
11594 reinterpret_cast<float **>(src)[chIdx][srcIdx];
11595 }
11596 }
11597 }
11598 } else {
11599 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11600 const float val = reinterpret_cast<float **>(exr_image.images)[chIdx][i];
11601 (*out_rgba)[4 * i + 0] = val;
11602 (*out_rgba)[4 * i + 1] = val;
11603 (*out_rgba)[4 * i + 2] = val;
11604 (*out_rgba)[4 * i + 3] = val;
11605 }
11606 }
11607 } else {
11608 // Assume RGB(A)
11609
11610 if (idxR == -1) {
11611 tinyexr::SetErrorMessage("R channel not found", err);
11612
11613 FreeEXRHeader(&exr_header);
11614 FreeEXRImage(&exr_image);
11615 return TINYEXR_ERROR_INVALID_DATA;
11616 }
11617
11618 if (idxG == -1) {
11619 tinyexr::SetErrorMessage("G channel not found", err);
11620 FreeEXRHeader(&exr_header);
11621 FreeEXRImage(&exr_image);
11622 return TINYEXR_ERROR_INVALID_DATA;
11623 }
11624
11625 if (idxB == -1) {
11626 tinyexr::SetErrorMessage("B channel not found", err);
11627 FreeEXRHeader(&exr_header);
11628 FreeEXRImage(&exr_image);
11629 return TINYEXR_ERROR_INVALID_DATA;
11630 }
11631
11632 (*out_rgba) = reinterpret_cast<float *>(
11633 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11634 static_cast<size_t>(exr_image.height)));
11635 if (exr_header.tiled) {
11636 for (int it = 0; it < exr_image.num_tiles; it++) {
11637 for (int j = 0; j < exr_header.tile_size_y; j++) {
11638 for (int i = 0; i < exr_header.tile_size_x; i++) {
11639 const int ii =
11640 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11641 const int jj =
11642 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11643 const int idx = ii + jj * exr_image.width;
11644
11645 // out of region check.
11646 if (ii >= exr_image.width) {
11647 continue;
11648 }
11649 if (jj >= exr_image.height) {
11650 continue;
11651 }
11652 const int srcIdx = i + j * exr_header.tile_size_x;
11653 unsigned char **src = exr_image.tiles[it].images;
11654 (*out_rgba)[4 * idx + 0] =
11655 reinterpret_cast<float **>(src)[idxR][srcIdx];
11656 (*out_rgba)[4 * idx + 1] =
11657 reinterpret_cast<float **>(src)[idxG][srcIdx];
11658 (*out_rgba)[4 * idx + 2] =
11659 reinterpret_cast<float **>(src)[idxB][srcIdx];
11660 if (idxA != -1) {
11661 (*out_rgba)[4 * idx + 3] =
11662 reinterpret_cast<float **>(src)[idxA][srcIdx];
11663 } else {
11664 (*out_rgba)[4 * idx + 3] = 1.0;
11665 }
11666 }
11667 }
11668 }
11669 } else {
11670 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11671 (*out_rgba)[4 * i + 0] =
11672 reinterpret_cast<float **>(exr_image.images)[idxR][i];
11673 (*out_rgba)[4 * i + 1] =
11674 reinterpret_cast<float **>(exr_image.images)[idxG][i];
11675 (*out_rgba)[4 * i + 2] =
11676 reinterpret_cast<float **>(exr_image.images)[idxB][i];
11677 if (idxA != -1) {
11678 (*out_rgba)[4 * i + 3] =
11679 reinterpret_cast<float **>(exr_image.images)[idxA][i];
11680 } else {
11681 (*out_rgba)[4 * i + 3] = 1.0;
11682 }
11683 }
11684 }
11685 }
11686
11687 (*width) = exr_image.width;
11688 (*height) = exr_image.height;
11689
11690 FreeEXRHeader(&exr_header);
11691 FreeEXRImage(&exr_image);
11692
11693 return TINYEXR_SUCCESS;
11694 }
11695
IsEXR(const char * filename)11696 int IsEXR(const char *filename) {
11697 EXRVersion exr_version;
11698
11699 int ret = ParseEXRVersionFromFile(&exr_version, filename);
11700 if (ret != TINYEXR_SUCCESS) {
11701 return ret;
11702 }
11703
11704 return TINYEXR_SUCCESS;
11705 }
11706
ParseEXRHeaderFromMemory(EXRHeader * exr_header,const EXRVersion * version,const unsigned char * memory,size_t size,const char ** err)11707 int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
11708 const unsigned char *memory, size_t size,
11709 const char **err) {
11710 if (memory == NULL || exr_header == NULL) {
11711 tinyexr::SetErrorMessage(
11712 "Invalid argument. `memory` or `exr_header` argument is null in "
11713 "ParseEXRHeaderFromMemory()",
11714 err);
11715
11716 // Invalid argument
11717 return TINYEXR_ERROR_INVALID_ARGUMENT;
11718 }
11719
11720 if (size < tinyexr::kEXRVersionSize) {
11721 tinyexr::SetErrorMessage("Insufficient header/data size.\n", err);
11722 return TINYEXR_ERROR_INVALID_DATA;
11723 }
11724
11725 const unsigned char *marker = memory + tinyexr::kEXRVersionSize;
11726 size_t marker_size = size - tinyexr::kEXRVersionSize;
11727
11728 tinyexr::HeaderInfo info;
11729 info.clear();
11730
11731 std::string err_str;
11732 int ret = ParseEXRHeader(&info, NULL, version, &err_str, marker, marker_size);
11733
11734 if (ret != TINYEXR_SUCCESS) {
11735 if (err && !err_str.empty()) {
11736 tinyexr::SetErrorMessage(err_str, err);
11737 }
11738 }
11739
11740 ConvertHeader(exr_header, info);
11741
11742 // transfoer `tiled` from version.
11743 exr_header->tiled = version->tiled;
11744
11745 return ret;
11746 }
11747
LoadEXRFromMemory(float ** out_rgba,int * width,int * height,const unsigned char * memory,size_t size,const char ** err)11748 int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
11749 const unsigned char *memory, size_t size,
11750 const char **err) {
11751 if (out_rgba == NULL || memory == NULL) {
11752 tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err);
11753 return TINYEXR_ERROR_INVALID_ARGUMENT;
11754 }
11755
11756 EXRVersion exr_version;
11757 EXRImage exr_image;
11758 EXRHeader exr_header;
11759
11760 InitEXRHeader(&exr_header);
11761
11762 int ret = ParseEXRVersionFromMemory(&exr_version, memory, size);
11763 if (ret != TINYEXR_SUCCESS) {
11764 std::stringstream ss;
11765 ss << "Failed to parse EXR version. code(" << ret << ")";
11766 tinyexr::SetErrorMessage(ss.str(), err);
11767 return ret;
11768 }
11769
11770 ret = ParseEXRHeaderFromMemory(&exr_header, &exr_version, memory, size, err);
11771 if (ret != TINYEXR_SUCCESS) {
11772 return ret;
11773 }
11774
11775 // Read HALF channel as FLOAT.
11776 for (int i = 0; i < exr_header.num_channels; i++) {
11777 if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
11778 exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
11779 }
11780 }
11781
11782 InitEXRImage(&exr_image);
11783 ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err);
11784 if (ret != TINYEXR_SUCCESS) {
11785 return ret;
11786 }
11787
11788 // RGBA
11789 int idxR = -1;
11790 int idxG = -1;
11791 int idxB = -1;
11792 int idxA = -1;
11793 for (int c = 0; c < exr_header.num_channels; c++) {
11794 if (strcmp(exr_header.channels[c].name, "R") == 0) {
11795 idxR = c;
11796 } else if (strcmp(exr_header.channels[c].name, "G") == 0) {
11797 idxG = c;
11798 } else if (strcmp(exr_header.channels[c].name, "B") == 0) {
11799 idxB = c;
11800 } else if (strcmp(exr_header.channels[c].name, "A") == 0) {
11801 idxA = c;
11802 }
11803 }
11804
11805 // TODO(syoyo): Refactor removing same code as used in LoadEXR().
11806 if (exr_header.num_channels == 1) {
11807 // Grayscale channel only.
11808
11809 (*out_rgba) = reinterpret_cast<float *>(
11810 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11811 static_cast<size_t>(exr_image.height)));
11812
11813 if (exr_header.tiled) {
11814 for (int it = 0; it < exr_image.num_tiles; it++) {
11815 for (int j = 0; j < exr_header.tile_size_y; j++) {
11816 for (int i = 0; i < exr_header.tile_size_x; i++) {
11817 const int ii =
11818 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11819 const int jj =
11820 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11821 const int idx = ii + jj * exr_image.width;
11822
11823 // out of region check.
11824 if (ii >= exr_image.width) {
11825 continue;
11826 }
11827 if (jj >= exr_image.height) {
11828 continue;
11829 }
11830 const int srcIdx = i + j * exr_header.tile_size_x;
11831 unsigned char **src = exr_image.tiles[it].images;
11832 (*out_rgba)[4 * idx + 0] =
11833 reinterpret_cast<float **>(src)[0][srcIdx];
11834 (*out_rgba)[4 * idx + 1] =
11835 reinterpret_cast<float **>(src)[0][srcIdx];
11836 (*out_rgba)[4 * idx + 2] =
11837 reinterpret_cast<float **>(src)[0][srcIdx];
11838 (*out_rgba)[4 * idx + 3] =
11839 reinterpret_cast<float **>(src)[0][srcIdx];
11840 }
11841 }
11842 }
11843 } else {
11844 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11845 const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
11846 (*out_rgba)[4 * i + 0] = val;
11847 (*out_rgba)[4 * i + 1] = val;
11848 (*out_rgba)[4 * i + 2] = val;
11849 (*out_rgba)[4 * i + 3] = val;
11850 }
11851 }
11852
11853 } else {
11854 // TODO(syoyo): Support non RGBA image.
11855
11856 if (idxR == -1) {
11857 tinyexr::SetErrorMessage("R channel not found", err);
11858
11859 // @todo { free exr_image }
11860 return TINYEXR_ERROR_INVALID_DATA;
11861 }
11862
11863 if (idxG == -1) {
11864 tinyexr::SetErrorMessage("G channel not found", err);
11865 // @todo { free exr_image }
11866 return TINYEXR_ERROR_INVALID_DATA;
11867 }
11868
11869 if (idxB == -1) {
11870 tinyexr::SetErrorMessage("B channel not found", err);
11871 // @todo { free exr_image }
11872 return TINYEXR_ERROR_INVALID_DATA;
11873 }
11874
11875 (*out_rgba) = reinterpret_cast<float *>(
11876 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11877 static_cast<size_t>(exr_image.height)));
11878
11879 if (exr_header.tiled) {
11880 for (int it = 0; it < exr_image.num_tiles; it++) {
11881 for (int j = 0; j < exr_header.tile_size_y; j++)
11882 for (int i = 0; i < exr_header.tile_size_x; i++) {
11883 const int ii =
11884 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11885 const int jj =
11886 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11887 const int idx = ii + jj * exr_image.width;
11888
11889 // out of region check.
11890 if (ii >= exr_image.width) {
11891 continue;
11892 }
11893 if (jj >= exr_image.height) {
11894 continue;
11895 }
11896 const int srcIdx = i + j * exr_header.tile_size_x;
11897 unsigned char **src = exr_image.tiles[it].images;
11898 (*out_rgba)[4 * idx + 0] =
11899 reinterpret_cast<float **>(src)[idxR][srcIdx];
11900 (*out_rgba)[4 * idx + 1] =
11901 reinterpret_cast<float **>(src)[idxG][srcIdx];
11902 (*out_rgba)[4 * idx + 2] =
11903 reinterpret_cast<float **>(src)[idxB][srcIdx];
11904 if (idxA != -1) {
11905 (*out_rgba)[4 * idx + 3] =
11906 reinterpret_cast<float **>(src)[idxA][srcIdx];
11907 } else {
11908 (*out_rgba)[4 * idx + 3] = 1.0;
11909 }
11910 }
11911 }
11912 } else {
11913 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11914 (*out_rgba)[4 * i + 0] =
11915 reinterpret_cast<float **>(exr_image.images)[idxR][i];
11916 (*out_rgba)[4 * i + 1] =
11917 reinterpret_cast<float **>(exr_image.images)[idxG][i];
11918 (*out_rgba)[4 * i + 2] =
11919 reinterpret_cast<float **>(exr_image.images)[idxB][i];
11920 if (idxA != -1) {
11921 (*out_rgba)[4 * i + 3] =
11922 reinterpret_cast<float **>(exr_image.images)[idxA][i];
11923 } else {
11924 (*out_rgba)[4 * i + 3] = 1.0;
11925 }
11926 }
11927 }
11928 }
11929
11930 (*width) = exr_image.width;
11931 (*height) = exr_image.height;
11932
11933 FreeEXRHeader(&exr_header);
11934 FreeEXRImage(&exr_image);
11935
11936 return TINYEXR_SUCCESS;
11937 }
11938
LoadEXRImageFromFile(EXRImage * exr_image,const EXRHeader * exr_header,const char * filename,const char ** err)11939 int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
11940 const char *filename, const char **err) {
11941 if (exr_image == NULL) {
11942 tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err);
11943 return TINYEXR_ERROR_INVALID_ARGUMENT;
11944 }
11945
11946 #ifdef _WIN32
11947 FILE *fp = NULL;
11948 fopen_s(&fp, filename, "rb");
11949 #else
11950 FILE *fp = fopen(filename, "rb");
11951 #endif
11952 if (!fp) {
11953 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
11954 return TINYEXR_ERROR_CANT_OPEN_FILE;
11955 }
11956
11957 size_t filesize;
11958 // Compute size
11959 fseek(fp, 0, SEEK_END);
11960 filesize = static_cast<size_t>(ftell(fp));
11961 fseek(fp, 0, SEEK_SET);
11962
11963 if (filesize < 16) {
11964 fclose(fp);
11965 tinyexr::SetErrorMessage("File size too short " + std::string(filename),
11966 err);
11967 return TINYEXR_ERROR_INVALID_FILE;
11968 }
11969
11970 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
11971 {
11972 size_t ret;
11973 ret = fread(&buf[0], 1, filesize, fp);
11974 TEXR_ASSERT(ret == filesize);
11975 fclose(fp);
11976 (void)ret;
11977 }
11978
11979 return LoadEXRImageFromMemory(exr_image, exr_header, &buf.at(0), filesize,
11980 err);
11981 }
11982
LoadEXRImageFromMemory(EXRImage * exr_image,const EXRHeader * exr_header,const unsigned char * memory,const size_t size,const char ** err)11983 int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header,
11984 const unsigned char *memory, const size_t size,
11985 const char **err) {
11986 if (exr_image == NULL || memory == NULL ||
11987 (size < tinyexr::kEXRVersionSize)) {
11988 tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory",
11989 err);
11990 return TINYEXR_ERROR_INVALID_ARGUMENT;
11991 }
11992
11993 if (exr_header->header_len == 0) {
11994 tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
11995 return TINYEXR_ERROR_INVALID_ARGUMENT;
11996 }
11997
11998 const unsigned char *head = memory;
11999 const unsigned char *marker = reinterpret_cast<const unsigned char *>(
12000 memory + exr_header->header_len +
12001 8); // +8 for magic number + version header.
12002 return tinyexr::DecodeEXRImage(exr_image, exr_header, head, marker, size,
12003 err);
12004 }
12005
SaveEXRImageToMemory(const EXRImage * exr_image,const EXRHeader * exr_header,unsigned char ** memory_out,const char ** err)12006 size_t SaveEXRImageToMemory(const EXRImage *exr_image,
12007 const EXRHeader *exr_header,
12008 unsigned char **memory_out, const char **err) {
12009 if (exr_image == NULL || memory_out == NULL ||
12010 exr_header->compression_type < 0) {
12011 tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err);
12012 return 0;
12013 }
12014
12015 #if !TINYEXR_USE_PIZ
12016 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
12017 tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
12018 err);
12019 return 0;
12020 }
12021 #endif
12022
12023 #if !TINYEXR_USE_ZFP
12024 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
12025 tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
12026 err);
12027 return 0;
12028 }
12029 #endif
12030
12031 #if TINYEXR_USE_ZFP
12032 for (size_t i = 0; i < static_cast<size_t>(exr_header->num_channels); i++) {
12033 if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) {
12034 tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression",
12035 err);
12036 return 0;
12037 }
12038 }
12039 #endif
12040
12041 std::vector<unsigned char> memory;
12042
12043 // Header
12044 {
12045 const char header[] = {0x76, 0x2f, 0x31, 0x01};
12046 memory.insert(memory.end(), header, header + 4);
12047 }
12048
12049 // Version, scanline.
12050 {
12051 char marker[] = {2, 0, 0, 0};
12052 /* @todo
12053 if (exr_header->tiled) {
12054 marker[1] |= 0x2;
12055 }
12056 if (exr_header->long_name) {
12057 marker[1] |= 0x4;
12058 }
12059 if (exr_header->non_image) {
12060 marker[1] |= 0x8;
12061 }
12062 if (exr_header->multipart) {
12063 marker[1] |= 0x10;
12064 }
12065 */
12066 memory.insert(memory.end(), marker, marker + 4);
12067 }
12068
12069 int num_scanlines = 1;
12070 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
12071 num_scanlines = 16;
12072 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
12073 num_scanlines = 32;
12074 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
12075 num_scanlines = 16;
12076 }
12077
12078 // Write attributes.
12079 std::vector<tinyexr::ChannelInfo> channels;
12080 {
12081 std::vector<unsigned char> data;
12082
12083 for (int c = 0; c < exr_header->num_channels; c++) {
12084 tinyexr::ChannelInfo info;
12085 info.p_linear = 0;
12086 info.pixel_type = exr_header->requested_pixel_types[c];
12087 info.x_sampling = 1;
12088 info.y_sampling = 1;
12089 info.name = std::string(exr_header->channels[c].name);
12090 channels.push_back(info);
12091 }
12092
12093 tinyexr::WriteChannelInfo(data, channels);
12094
12095 tinyexr::WriteAttributeToMemory(&memory, "channels", "chlist", &data.at(0),
12096 static_cast<int>(data.size()));
12097 }
12098
12099 {
12100 int comp = exr_header->compression_type;
12101 tinyexr::swap4(reinterpret_cast<unsigned int *>(&comp));
12102 tinyexr::WriteAttributeToMemory(
12103 &memory, "compression", "compression",
12104 reinterpret_cast<const unsigned char *>(&comp), 1);
12105 }
12106
12107 {
12108 int data[4] = {0, 0, exr_image->width - 1, exr_image->height - 1};
12109 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[0]));
12110 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[1]));
12111 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[2]));
12112 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[3]));
12113 tinyexr::WriteAttributeToMemory(
12114 &memory, "dataWindow", "box2i",
12115 reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4);
12116 tinyexr::WriteAttributeToMemory(
12117 &memory, "displayWindow", "box2i",
12118 reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4);
12119 }
12120
12121 {
12122 unsigned char line_order = 0; // @fixme { read line_order from EXRHeader }
12123 tinyexr::WriteAttributeToMemory(&memory, "lineOrder", "lineOrder",
12124 &line_order, 1);
12125 }
12126
12127 {
12128 float aspectRatio = 1.0f;
12129 tinyexr::swap4(reinterpret_cast<unsigned int *>(&aspectRatio));
12130 tinyexr::WriteAttributeToMemory(
12131 &memory, "pixelAspectRatio", "float",
12132 reinterpret_cast<const unsigned char *>(&aspectRatio), sizeof(float));
12133 }
12134
12135 {
12136 float center[2] = {0.0f, 0.0f};
12137 tinyexr::swap4(reinterpret_cast<unsigned int *>(¢er[0]));
12138 tinyexr::swap4(reinterpret_cast<unsigned int *>(¢er[1]));
12139 tinyexr::WriteAttributeToMemory(
12140 &memory, "screenWindowCenter", "v2f",
12141 reinterpret_cast<const unsigned char *>(center), 2 * sizeof(float));
12142 }
12143
12144 {
12145 float w = static_cast<float>(exr_image->width);
12146 tinyexr::swap4(reinterpret_cast<unsigned int *>(&w));
12147 tinyexr::WriteAttributeToMemory(&memory, "screenWindowWidth", "float",
12148 reinterpret_cast<const unsigned char *>(&w),
12149 sizeof(float));
12150 }
12151
12152 // Custom attributes
12153 if (exr_header->num_custom_attributes > 0) {
12154 for (int i = 0; i < exr_header->num_custom_attributes; i++) {
12155 tinyexr::WriteAttributeToMemory(
12156 &memory, exr_header->custom_attributes[i].name,
12157 exr_header->custom_attributes[i].type,
12158 reinterpret_cast<const unsigned char *>(
12159 exr_header->custom_attributes[i].value),
12160 exr_header->custom_attributes[i].size);
12161 }
12162 }
12163
12164 { // end of header
12165 unsigned char e = 0;
12166 memory.push_back(e);
12167 }
12168
12169 int num_blocks = exr_image->height / num_scanlines;
12170 if (num_blocks * num_scanlines < exr_image->height) {
12171 num_blocks++;
12172 }
12173
12174 std::vector<tinyexr::tinyexr_uint64> offsets(static_cast<size_t>(num_blocks));
12175
12176 size_t headerSize = memory.size();
12177 tinyexr::tinyexr_uint64 offset =
12178 headerSize +
12179 static_cast<size_t>(num_blocks) *
12180 sizeof(
12181 tinyexr::tinyexr_int64); // sizeof(header) + sizeof(offsetTable)
12182
12183 std::vector<std::vector<unsigned char> > data_list(
12184 static_cast<size_t>(num_blocks));
12185 std::vector<size_t> channel_offset_list(
12186 static_cast<size_t>(exr_header->num_channels));
12187
12188 int pixel_data_size = 0;
12189 size_t channel_offset = 0;
12190 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
12191 channel_offset_list[c] = channel_offset;
12192 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
12193 pixel_data_size += sizeof(unsigned short);
12194 channel_offset += sizeof(unsigned short);
12195 } else if (exr_header->requested_pixel_types[c] ==
12196 TINYEXR_PIXELTYPE_FLOAT) {
12197 pixel_data_size += sizeof(float);
12198 channel_offset += sizeof(float);
12199 } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
12200 pixel_data_size += sizeof(unsigned int);
12201 channel_offset += sizeof(unsigned int);
12202 } else {
12203 TEXR_ASSERT(0);
12204 }
12205 }
12206
12207 #if TINYEXR_USE_ZFP
12208 tinyexr::ZFPCompressionParam zfp_compression_param;
12209
12210 // Use ZFP compression parameter from custom attributes(if such a parameter
12211 // exists)
12212 {
12213 bool ret = tinyexr::FindZFPCompressionParam(
12214 &zfp_compression_param, exr_header->custom_attributes,
12215 exr_header->num_custom_attributes);
12216
12217 if (!ret) {
12218 // Use predefined compression parameter.
12219 zfp_compression_param.type = 0;
12220 zfp_compression_param.rate = 2;
12221 }
12222 }
12223 #endif
12224
12225 // TOOD(LTE): C++11 thread
12226
12227 // Use signed int since some OpenMP compiler doesn't allow unsigned type for
12228 // `parallel for`
12229 #if TINYEXR_USE_OPENMP
12230 #pragma omp parallel for
12231 #endif
12232 for (int i = 0; i < num_blocks; i++) {
12233 size_t ii = static_cast<size_t>(i);
12234 int start_y = num_scanlines * i;
12235 int endY = (std::min)(num_scanlines * (i + 1), exr_image->height);
12236 int h = endY - start_y;
12237
12238 std::vector<unsigned char> buf(
12239 static_cast<size_t>(exr_image->width * h * pixel_data_size));
12240
12241 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
12242 if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
12243 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
12244 for (int y = 0; y < h; y++) {
12245 // Assume increasing Y
12246 float *line_ptr = reinterpret_cast<float *>(&buf.at(
12247 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
12248 channel_offset_list[c] *
12249 static_cast<size_t>(exr_image->width)));
12250 for (int x = 0; x < exr_image->width; x++) {
12251 tinyexr::FP16 h16;
12252 h16.u = reinterpret_cast<unsigned short **>(
12253 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12254
12255 tinyexr::FP32 f32 = half_to_float(h16);
12256
12257 tinyexr::swap4(reinterpret_cast<unsigned int *>(&f32.f));
12258
12259 // line_ptr[x] = f32.f;
12260 tinyexr::cpy4(line_ptr + x, &(f32.f));
12261 }
12262 }
12263 } else if (exr_header->requested_pixel_types[c] ==
12264 TINYEXR_PIXELTYPE_HALF) {
12265 for (int y = 0; y < h; y++) {
12266 // Assume increasing Y
12267 unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
12268 &buf.at(static_cast<size_t>(pixel_data_size * y *
12269 exr_image->width) +
12270 channel_offset_list[c] *
12271 static_cast<size_t>(exr_image->width)));
12272 for (int x = 0; x < exr_image->width; x++) {
12273 unsigned short val = reinterpret_cast<unsigned short **>(
12274 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12275
12276 tinyexr::swap2(&val);
12277
12278 // line_ptr[x] = val;
12279 tinyexr::cpy2(line_ptr + x, &val);
12280 }
12281 }
12282 } else {
12283 TEXR_ASSERT(0);
12284 }
12285
12286 } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
12287 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
12288 for (int y = 0; y < h; y++) {
12289 // Assume increasing Y
12290 unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
12291 &buf.at(static_cast<size_t>(pixel_data_size * y *
12292 exr_image->width) +
12293 channel_offset_list[c] *
12294 static_cast<size_t>(exr_image->width)));
12295 for (int x = 0; x < exr_image->width; x++) {
12296 tinyexr::FP32 f32;
12297 f32.f = reinterpret_cast<float **>(
12298 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12299
12300 tinyexr::FP16 h16;
12301 h16 = float_to_half_full(f32);
12302
12303 tinyexr::swap2(reinterpret_cast<unsigned short *>(&h16.u));
12304
12305 // line_ptr[x] = h16.u;
12306 tinyexr::cpy2(line_ptr + x, &(h16.u));
12307 }
12308 }
12309 } else if (exr_header->requested_pixel_types[c] ==
12310 TINYEXR_PIXELTYPE_FLOAT) {
12311 for (int y = 0; y < h; y++) {
12312 // Assume increasing Y
12313 float *line_ptr = reinterpret_cast<float *>(&buf.at(
12314 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
12315 channel_offset_list[c] *
12316 static_cast<size_t>(exr_image->width)));
12317 for (int x = 0; x < exr_image->width; x++) {
12318 float val = reinterpret_cast<float **>(
12319 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12320
12321 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
12322
12323 // line_ptr[x] = val;
12324 tinyexr::cpy4(line_ptr + x, &val);
12325 }
12326 }
12327 } else {
12328 TEXR_ASSERT(0);
12329 }
12330 } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
12331 for (int y = 0; y < h; y++) {
12332 // Assume increasing Y
12333 unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
12334 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
12335 channel_offset_list[c] * static_cast<size_t>(exr_image->width)));
12336 for (int x = 0; x < exr_image->width; x++) {
12337 unsigned int val = reinterpret_cast<unsigned int **>(
12338 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12339
12340 tinyexr::swap4(&val);
12341
12342 // line_ptr[x] = val;
12343 tinyexr::cpy4(line_ptr + x, &val);
12344 }
12345 }
12346 }
12347 }
12348
12349 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
12350 // 4 byte: scan line
12351 // 4 byte: data size
12352 // ~ : pixel data(uncompressed)
12353 std::vector<unsigned char> header(8);
12354 unsigned int data_len = static_cast<unsigned int>(buf.size());
12355 memcpy(&header.at(0), &start_y, sizeof(int));
12356 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12357
12358 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12359 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12360
12361 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12362 data_list[ii].insert(data_list[ii].end(), buf.begin(),
12363 buf.begin() + data_len);
12364
12365 } else if ((exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
12366 (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) {
12367 #if TINYEXR_USE_MINIZ
12368 std::vector<unsigned char> block(tinyexr::miniz::mz_compressBound(
12369 static_cast<unsigned long>(buf.size())));
12370 #else
12371 std::vector<unsigned char> block(
12372 compressBound(static_cast<uLong>(buf.size())));
12373 #endif
12374 tinyexr::tinyexr_uint64 outSize = block.size();
12375
12376 tinyexr::CompressZip(&block.at(0), outSize,
12377 reinterpret_cast<const unsigned char *>(&buf.at(0)),
12378 static_cast<unsigned long>(buf.size()));
12379
12380 // 4 byte: scan line
12381 // 4 byte: data size
12382 // ~ : pixel data(compressed)
12383 std::vector<unsigned char> header(8);
12384 unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
12385 memcpy(&header.at(0), &start_y, sizeof(int));
12386 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12387
12388 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12389 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12390
12391 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12392 data_list[ii].insert(data_list[ii].end(), block.begin(),
12393 block.begin() + data_len);
12394
12395 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_RLE) {
12396 // (buf.size() * 3) / 2 would be enough.
12397 std::vector<unsigned char> block((buf.size() * 3) / 2);
12398
12399 tinyexr::tinyexr_uint64 outSize = block.size();
12400
12401 tinyexr::CompressRle(&block.at(0), outSize,
12402 reinterpret_cast<const unsigned char *>(&buf.at(0)),
12403 static_cast<unsigned long>(buf.size()));
12404
12405 // 4 byte: scan line
12406 // 4 byte: data size
12407 // ~ : pixel data(compressed)
12408 std::vector<unsigned char> header(8);
12409 unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
12410 memcpy(&header.at(0), &start_y, sizeof(int));
12411 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12412
12413 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12414 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12415
12416 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12417 data_list[ii].insert(data_list[ii].end(), block.begin(),
12418 block.begin() + data_len);
12419
12420 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
12421 #if TINYEXR_USE_PIZ
12422 unsigned int bufLen =
12423 8192 + static_cast<unsigned int>(
12424 2 * static_cast<unsigned int>(
12425 buf.size())); // @fixme { compute good bound. }
12426 std::vector<unsigned char> block(bufLen);
12427 unsigned int outSize = static_cast<unsigned int>(block.size());
12428
12429 CompressPiz(&block.at(0), &outSize,
12430 reinterpret_cast<const unsigned char *>(&buf.at(0)),
12431 buf.size(), channels, exr_image->width, h);
12432
12433 // 4 byte: scan line
12434 // 4 byte: data size
12435 // ~ : pixel data(compressed)
12436 std::vector<unsigned char> header(8);
12437 unsigned int data_len = outSize;
12438 memcpy(&header.at(0), &start_y, sizeof(int));
12439 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12440
12441 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12442 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12443
12444 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12445 data_list[ii].insert(data_list[ii].end(), block.begin(),
12446 block.begin() + data_len);
12447
12448 #else
12449 TEXR_ASSERT(0);
12450 #endif
12451 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
12452 #if TINYEXR_USE_ZFP
12453 std::vector<unsigned char> block;
12454 unsigned int outSize;
12455
12456 tinyexr::CompressZfp(
12457 &block, &outSize, reinterpret_cast<const float *>(&buf.at(0)),
12458 exr_image->width, h, exr_header->num_channels, zfp_compression_param);
12459
12460 // 4 byte: scan line
12461 // 4 byte: data size
12462 // ~ : pixel data(compressed)
12463 std::vector<unsigned char> header(8);
12464 unsigned int data_len = outSize;
12465 memcpy(&header.at(0), &start_y, sizeof(int));
12466 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12467
12468 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12469 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12470
12471 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12472 data_list[ii].insert(data_list[ii].end(), block.begin(),
12473 block.begin() + data_len);
12474
12475 #else
12476 TEXR_ASSERT(0);
12477 #endif
12478 } else {
12479 TEXR_ASSERT(0);
12480 }
12481 } // omp parallel
12482
12483 for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
12484 offsets[i] = offset;
12485 tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offsets[i]));
12486 offset += data_list[i].size();
12487 }
12488
12489 size_t totalSize = static_cast<size_t>(offset);
12490 {
12491 memory.insert(
12492 memory.end(), reinterpret_cast<unsigned char *>(&offsets.at(0)),
12493 reinterpret_cast<unsigned char *>(&offsets.at(0)) +
12494 sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(num_blocks));
12495 }
12496
12497 if (memory.size() == 0) {
12498 tinyexr::SetErrorMessage("Output memory size is zero", err);
12499 return 0;
12500 }
12501
12502 (*memory_out) = static_cast<unsigned char *>(malloc(totalSize));
12503 memcpy((*memory_out), &memory.at(0), memory.size());
12504 unsigned char *memory_ptr = *memory_out + memory.size();
12505
12506 for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
12507 memcpy(memory_ptr, &data_list[i].at(0), data_list[i].size());
12508 memory_ptr += data_list[i].size();
12509 }
12510
12511 return totalSize; // OK
12512 }
12513
SaveEXRImageToFile(const EXRImage * exr_image,const EXRHeader * exr_header,const char * filename,const char ** err)12514 int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
12515 const char *filename, const char **err) {
12516 if (exr_image == NULL || filename == NULL ||
12517 exr_header->compression_type < 0) {
12518 tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err);
12519 return TINYEXR_ERROR_INVALID_ARGUMENT;
12520 }
12521
12522 #if !TINYEXR_USE_PIZ
12523 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
12524 tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
12525 err);
12526 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
12527 }
12528 #endif
12529
12530 #if !TINYEXR_USE_ZFP
12531 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
12532 tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
12533 err);
12534 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
12535 }
12536 #endif
12537
12538 #ifdef _WIN32
12539 FILE *fp = NULL;
12540 fopen_s(&fp, filename, "wb");
12541 #else
12542 FILE *fp = fopen(filename, "wb");
12543 #endif
12544 if (!fp) {
12545 tinyexr::SetErrorMessage("Cannot write a file", err);
12546 return TINYEXR_ERROR_CANT_WRITE_FILE;
12547 }
12548
12549 unsigned char *mem = NULL;
12550 size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err);
12551 if (mem_size == 0) {
12552 fclose(fp);
12553 return TINYEXR_ERROR_SERIALZATION_FAILED;
12554 }
12555
12556 size_t written_size = 0;
12557 if ((mem_size > 0) && mem) {
12558 written_size = fwrite(mem, 1, mem_size, fp);
12559 }
12560 free(mem);
12561
12562 fclose(fp);
12563
12564 if (written_size != mem_size) {
12565 tinyexr::SetErrorMessage("Cannot write a file", err);
12566 return TINYEXR_ERROR_CANT_WRITE_FILE;
12567 }
12568
12569 return TINYEXR_SUCCESS;
12570 }
12571
LoadDeepEXR(DeepImage * deep_image,const char * filename,const char ** err)12572 int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
12573 if (deep_image == NULL) {
12574 tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err);
12575 return TINYEXR_ERROR_INVALID_ARGUMENT;
12576 }
12577
12578 #ifdef _MSC_VER
12579 FILE *fp = NULL;
12580 errno_t errcode = fopen_s(&fp, filename, "rb");
12581 if ((0 != errcode) || (!fp)) {
12582 tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
12583 err);
12584 return TINYEXR_ERROR_CANT_OPEN_FILE;
12585 }
12586 #else
12587 FILE *fp = fopen(filename, "rb");
12588 if (!fp) {
12589 tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
12590 err);
12591 return TINYEXR_ERROR_CANT_OPEN_FILE;
12592 }
12593 #endif
12594
12595 size_t filesize;
12596 // Compute size
12597 fseek(fp, 0, SEEK_END);
12598 filesize = static_cast<size_t>(ftell(fp));
12599 fseek(fp, 0, SEEK_SET);
12600
12601 if (filesize == 0) {
12602 fclose(fp);
12603 tinyexr::SetErrorMessage("File size is zero : " + std::string(filename),
12604 err);
12605 return TINYEXR_ERROR_INVALID_FILE;
12606 }
12607
12608 std::vector<char> buf(filesize); // @todo { use mmap }
12609 {
12610 size_t ret;
12611 ret = fread(&buf[0], 1, filesize, fp);
12612 TEXR_ASSERT(ret == filesize);
12613 (void)ret;
12614 }
12615 fclose(fp);
12616
12617 const char *head = &buf[0];
12618 const char *marker = &buf[0];
12619
12620 // Header check.
12621 {
12622 const char header[] = {0x76, 0x2f, 0x31, 0x01};
12623
12624 if (memcmp(marker, header, 4) != 0) {
12625 tinyexr::SetErrorMessage("Invalid magic number", err);
12626 return TINYEXR_ERROR_INVALID_MAGIC_NUMBER;
12627 }
12628 marker += 4;
12629 }
12630
12631 // Version, scanline.
12632 {
12633 // ver 2.0, scanline, deep bit on(0x800)
12634 // must be [2, 0, 0, 0]
12635 if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) {
12636 tinyexr::SetErrorMessage("Unsupported version or scanline", err);
12637 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
12638 }
12639
12640 marker += 4;
12641 }
12642
12643 int dx = -1;
12644 int dy = -1;
12645 int dw = -1;
12646 int dh = -1;
12647 int num_scanline_blocks = 1; // 16 for ZIP compression.
12648 int compression_type = -1;
12649 int num_channels = -1;
12650 std::vector<tinyexr::ChannelInfo> channels;
12651
12652 // Read attributes
12653 size_t size = filesize - tinyexr::kEXRVersionSize;
12654 for (;;) {
12655 if (0 == size) {
12656 return TINYEXR_ERROR_INVALID_DATA;
12657 } else if (marker[0] == '\0') {
12658 marker++;
12659 size--;
12660 break;
12661 }
12662
12663 std::string attr_name;
12664 std::string attr_type;
12665 std::vector<unsigned char> data;
12666 size_t marker_size;
12667 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
12668 marker, size)) {
12669 std::stringstream ss;
12670 ss << "Failed to parse attribute\n";
12671 tinyexr::SetErrorMessage(ss.str(), err);
12672 return TINYEXR_ERROR_INVALID_DATA;
12673 }
12674 marker += marker_size;
12675 size -= marker_size;
12676
12677 if (attr_name.compare("compression") == 0) {
12678 compression_type = data[0];
12679 if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) {
12680 std::stringstream ss;
12681 ss << "Unsupported compression type : " << compression_type;
12682 tinyexr::SetErrorMessage(ss.str(), err);
12683 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
12684 }
12685
12686 if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
12687 num_scanline_blocks = 16;
12688 }
12689
12690 } else if (attr_name.compare("channels") == 0) {
12691 // name: zero-terminated string, from 1 to 255 bytes long
12692 // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2
12693 // pLinear: unsigned char, possible values are 0 and 1
12694 // reserved: three chars, should be zero
12695 // xSampling: int
12696 // ySampling: int
12697
12698 if (!tinyexr::ReadChannelInfo(channels, data)) {
12699 tinyexr::SetErrorMessage("Failed to parse channel info", err);
12700 return TINYEXR_ERROR_INVALID_DATA;
12701 }
12702
12703 num_channels = static_cast<int>(channels.size());
12704
12705 if (num_channels < 1) {
12706 tinyexr::SetErrorMessage("Invalid channels format", err);
12707 return TINYEXR_ERROR_INVALID_DATA;
12708 }
12709
12710 } else if (attr_name.compare("dataWindow") == 0) {
12711 memcpy(&dx, &data.at(0), sizeof(int));
12712 memcpy(&dy, &data.at(4), sizeof(int));
12713 memcpy(&dw, &data.at(8), sizeof(int));
12714 memcpy(&dh, &data.at(12), sizeof(int));
12715 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dx));
12716 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dy));
12717 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dw));
12718 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dh));
12719
12720 } else if (attr_name.compare("displayWindow") == 0) {
12721 int x;
12722 int y;
12723 int w;
12724 int h;
12725 memcpy(&x, &data.at(0), sizeof(int));
12726 memcpy(&y, &data.at(4), sizeof(int));
12727 memcpy(&w, &data.at(8), sizeof(int));
12728 memcpy(&h, &data.at(12), sizeof(int));
12729 tinyexr::swap4(reinterpret_cast<unsigned int *>(&x));
12730 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y));
12731 tinyexr::swap4(reinterpret_cast<unsigned int *>(&w));
12732 tinyexr::swap4(reinterpret_cast<unsigned int *>(&h));
12733 }
12734 }
12735
12736 TEXR_ASSERT(dx >= 0);
12737 TEXR_ASSERT(dy >= 0);
12738 TEXR_ASSERT(dw >= 0);
12739 TEXR_ASSERT(dh >= 0);
12740 TEXR_ASSERT(num_channels >= 1);
12741
12742 int data_width = dw - dx + 1;
12743 int data_height = dh - dy + 1;
12744
12745 std::vector<float> image(
12746 static_cast<size_t>(data_width * data_height * 4)); // 4 = RGBA
12747
12748 // Read offset tables.
12749 int num_blocks = data_height / num_scanline_blocks;
12750 if (num_blocks * num_scanline_blocks < data_height) {
12751 num_blocks++;
12752 }
12753
12754 std::vector<tinyexr::tinyexr_int64> offsets(static_cast<size_t>(num_blocks));
12755
12756 for (size_t y = 0; y < static_cast<size_t>(num_blocks); y++) {
12757 tinyexr::tinyexr_int64 offset;
12758 memcpy(&offset, marker, sizeof(tinyexr::tinyexr_int64));
12759 tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offset));
12760 marker += sizeof(tinyexr::tinyexr_int64); // = 8
12761 offsets[y] = offset;
12762 }
12763
12764 #if TINYEXR_USE_PIZ
12765 if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) ||
12766 (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) ||
12767 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
12768 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) ||
12769 (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ)) {
12770 #else
12771 if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) ||
12772 (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) ||
12773 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
12774 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) {
12775 #endif
12776 // OK
12777 } else {
12778 tinyexr::SetErrorMessage("Unsupported compression format", err);
12779 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
12780 }
12781
12782 deep_image->image = static_cast<float ***>(
12783 malloc(sizeof(float **) * static_cast<size_t>(num_channels)));
12784 for (int c = 0; c < num_channels; c++) {
12785 deep_image->image[c] = static_cast<float **>(
12786 malloc(sizeof(float *) * static_cast<size_t>(data_height)));
12787 for (int y = 0; y < data_height; y++) {
12788 }
12789 }
12790
12791 deep_image->offset_table = static_cast<int **>(
12792 malloc(sizeof(int *) * static_cast<size_t>(data_height)));
12793 for (int y = 0; y < data_height; y++) {
12794 deep_image->offset_table[y] = static_cast<int *>(
12795 malloc(sizeof(int) * static_cast<size_t>(data_width)));
12796 }
12797
12798 for (size_t y = 0; y < static_cast<size_t>(num_blocks); y++) {
12799 const unsigned char *data_ptr =
12800 reinterpret_cast<const unsigned char *>(head + offsets[y]);
12801
12802 // int: y coordinate
12803 // int64: packed size of pixel offset table
12804 // int64: packed size of sample data
12805 // int64: unpacked size of sample data
12806 // compressed pixel offset table
12807 // compressed sample data
12808 int line_no;
12809 tinyexr::tinyexr_int64 packedOffsetTableSize;
12810 tinyexr::tinyexr_int64 packedSampleDataSize;
12811 tinyexr::tinyexr_int64 unpackedSampleDataSize;
12812 memcpy(&line_no, data_ptr, sizeof(int));
12813 memcpy(&packedOffsetTableSize, data_ptr + 4,
12814 sizeof(tinyexr::tinyexr_int64));
12815 memcpy(&packedSampleDataSize, data_ptr + 12,
12816 sizeof(tinyexr::tinyexr_int64));
12817 memcpy(&unpackedSampleDataSize, data_ptr + 20,
12818 sizeof(tinyexr::tinyexr_int64));
12819
12820 tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
12821 tinyexr::swap8(
12822 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&packedOffsetTableSize));
12823 tinyexr::swap8(
12824 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&packedSampleDataSize));
12825 tinyexr::swap8(
12826 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&unpackedSampleDataSize));
12827
12828 std::vector<int> pixelOffsetTable(static_cast<size_t>(data_width));
12829
12830 // decode pixel offset table.
12831 {
12832 unsigned long dstLen =
12833 static_cast<unsigned long>(pixelOffsetTable.size() * sizeof(int));
12834 if (!tinyexr::DecompressZip(
12835 reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)),
12836 &dstLen, data_ptr + 28,
12837 static_cast<unsigned long>(packedOffsetTableSize))) {
12838 return false;
12839 }
12840
12841 TEXR_ASSERT(dstLen == pixelOffsetTable.size() * sizeof(int));
12842 for (size_t i = 0; i < static_cast<size_t>(data_width); i++) {
12843 deep_image->offset_table[y][i] = pixelOffsetTable[i];
12844 }
12845 }
12846
12847 std::vector<unsigned char> sample_data(
12848 static_cast<size_t>(unpackedSampleDataSize));
12849
12850 // decode sample data.
12851 {
12852 unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize);
12853 if (dstLen) {
12854 if (!tinyexr::DecompressZip(
12855 reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen,
12856 data_ptr + 28 + packedOffsetTableSize,
12857 static_cast<unsigned long>(packedSampleDataSize))) {
12858 return false;
12859 }
12860 TEXR_ASSERT(dstLen == static_cast<unsigned long>(unpackedSampleDataSize));
12861 }
12862 }
12863
12864 // decode sample
12865 int sampleSize = -1;
12866 std::vector<int> channel_offset_list(static_cast<size_t>(num_channels));
12867 {
12868 int channel_offset = 0;
12869 for (size_t i = 0; i < static_cast<size_t>(num_channels); i++) {
12870 channel_offset_list[i] = channel_offset;
12871 if (channels[i].pixel_type == TINYEXR_PIXELTYPE_UINT) { // UINT
12872 channel_offset += 4;
12873 } else if (channels[i].pixel_type == TINYEXR_PIXELTYPE_HALF) { // half
12874 channel_offset += 2;
12875 } else if (channels[i].pixel_type ==
12876 TINYEXR_PIXELTYPE_FLOAT) { // float
12877 channel_offset += 4;
12878 } else {
12879 TEXR_ASSERT(0);
12880 }
12881 }
12882 sampleSize = channel_offset;
12883 }
12884 TEXR_ASSERT(sampleSize >= 2);
12885
12886 TEXR_ASSERT(static_cast<size_t>(
12887 pixelOffsetTable[static_cast<size_t>(data_width - 1)] *
12888 sampleSize) == sample_data.size());
12889 int samples_per_line = static_cast<int>(sample_data.size()) / sampleSize;
12890
12891 //
12892 // Alloc memory
12893 //
12894
12895 //
12896 // pixel data is stored as image[channels][pixel_samples]
12897 //
12898 {
12899 tinyexr::tinyexr_uint64 data_offset = 0;
12900 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
12901 deep_image->image[c][y] = static_cast<float *>(
12902 malloc(sizeof(float) * static_cast<size_t>(samples_per_line)));
12903
12904 if (channels[c].pixel_type == 0) { // UINT
12905 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
12906 unsigned int ui;
12907 unsigned int *src_ptr = reinterpret_cast<unsigned int *>(
12908 &sample_data.at(size_t(data_offset) + x * sizeof(int)));
12909 tinyexr::cpy4(&ui, src_ptr);
12910 deep_image->image[c][y][x] = static_cast<float>(ui); // @fixme
12911 }
12912 data_offset +=
12913 sizeof(unsigned int) * static_cast<size_t>(samples_per_line);
12914 } else if (channels[c].pixel_type == 1) { // half
12915 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
12916 tinyexr::FP16 f16;
12917 const unsigned short *src_ptr = reinterpret_cast<unsigned short *>(
12918 &sample_data.at(size_t(data_offset) + x * sizeof(short)));
12919 tinyexr::cpy2(&(f16.u), src_ptr);
12920 tinyexr::FP32 f32 = half_to_float(f16);
12921 deep_image->image[c][y][x] = f32.f;
12922 }
12923 data_offset += sizeof(short) * static_cast<size_t>(samples_per_line);
12924 } else { // float
12925 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
12926 float f;
12927 const float *src_ptr = reinterpret_cast<float *>(
12928 &sample_data.at(size_t(data_offset) + x * sizeof(float)));
12929 tinyexr::cpy4(&f, src_ptr);
12930 deep_image->image[c][y][x] = f;
12931 }
12932 data_offset += sizeof(float) * static_cast<size_t>(samples_per_line);
12933 }
12934 }
12935 }
12936 } // y
12937
12938 deep_image->width = data_width;
12939 deep_image->height = data_height;
12940
12941 deep_image->channel_names = static_cast<const char **>(
12942 malloc(sizeof(const char *) * static_cast<size_t>(num_channels)));
12943 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
12944 #ifdef _WIN32
12945 deep_image->channel_names[c] = _strdup(channels[c].name.c_str());
12946 #else
12947 deep_image->channel_names[c] = strdup(channels[c].name.c_str());
12948 #endif
12949 }
12950 deep_image->num_channels = num_channels;
12951
12952 return TINYEXR_SUCCESS;
12953 }
12954
12955 void InitEXRImage(EXRImage *exr_image) {
12956 if (exr_image == NULL) {
12957 return;
12958 }
12959
12960 exr_image->width = 0;
12961 exr_image->height = 0;
12962 exr_image->num_channels = 0;
12963
12964 exr_image->images = NULL;
12965 exr_image->tiles = NULL;
12966
12967 exr_image->num_tiles = 0;
12968 }
12969
12970 void FreeEXRErrorMessage(const char *msg) {
12971 if (msg) {
12972 free(reinterpret_cast<void *>(const_cast<char *>(msg)));
12973 }
12974 return;
12975 }
12976
12977 void InitEXRHeader(EXRHeader *exr_header) {
12978 if (exr_header == NULL) {
12979 return;
12980 }
12981
12982 memset(exr_header, 0, sizeof(EXRHeader));
12983 }
12984
12985 int FreeEXRHeader(EXRHeader *exr_header) {
12986 if (exr_header == NULL) {
12987 return TINYEXR_ERROR_INVALID_ARGUMENT;
12988 }
12989
12990 if (exr_header->channels) {
12991 free(exr_header->channels);
12992 }
12993
12994 if (exr_header->pixel_types) {
12995 free(exr_header->pixel_types);
12996 }
12997
12998 if (exr_header->requested_pixel_types) {
12999 free(exr_header->requested_pixel_types);
13000 }
13001
13002 for (int i = 0; i < exr_header->num_custom_attributes; i++) {
13003 if (exr_header->custom_attributes[i].value) {
13004 free(exr_header->custom_attributes[i].value);
13005 }
13006 }
13007
13008 if (exr_header->custom_attributes) {
13009 free(exr_header->custom_attributes);
13010 }
13011
13012 return TINYEXR_SUCCESS;
13013 }
13014
13015 int FreeEXRImage(EXRImage *exr_image) {
13016 if (exr_image == NULL) {
13017 return TINYEXR_ERROR_INVALID_ARGUMENT;
13018 }
13019
13020 for (int i = 0; i < exr_image->num_channels; i++) {
13021 if (exr_image->images && exr_image->images[i]) {
13022 free(exr_image->images[i]);
13023 }
13024 }
13025
13026 if (exr_image->images) {
13027 free(exr_image->images);
13028 }
13029
13030 if (exr_image->tiles) {
13031 for (int tid = 0; tid < exr_image->num_tiles; tid++) {
13032 for (int i = 0; i < exr_image->num_channels; i++) {
13033 if (exr_image->tiles[tid].images && exr_image->tiles[tid].images[i]) {
13034 free(exr_image->tiles[tid].images[i]);
13035 }
13036 }
13037 if (exr_image->tiles[tid].images) {
13038 free(exr_image->tiles[tid].images);
13039 }
13040 }
13041 free(exr_image->tiles);
13042 }
13043
13044 return TINYEXR_SUCCESS;
13045 }
13046
13047 int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
13048 const char *filename, const char **err) {
13049 if (exr_header == NULL || exr_version == NULL || filename == NULL) {
13050 tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile",
13051 err);
13052 return TINYEXR_ERROR_INVALID_ARGUMENT;
13053 }
13054
13055 #ifdef _WIN32
13056 FILE *fp = NULL;
13057 fopen_s(&fp, filename, "rb");
13058 #else
13059 FILE *fp = fopen(filename, "rb");
13060 #endif
13061 if (!fp) {
13062 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
13063 return TINYEXR_ERROR_CANT_OPEN_FILE;
13064 }
13065
13066 size_t filesize;
13067 // Compute size
13068 fseek(fp, 0, SEEK_END);
13069 filesize = static_cast<size_t>(ftell(fp));
13070 fseek(fp, 0, SEEK_SET);
13071
13072 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
13073 {
13074 size_t ret;
13075 ret = fread(&buf[0], 1, filesize, fp);
13076 TEXR_ASSERT(ret == filesize);
13077 fclose(fp);
13078
13079 if (ret != filesize) {
13080 tinyexr::SetErrorMessage("fread() error on " + std::string(filename),
13081 err);
13082 return TINYEXR_ERROR_INVALID_FILE;
13083 }
13084 }
13085
13086 return ParseEXRHeaderFromMemory(exr_header, exr_version, &buf.at(0), filesize,
13087 err);
13088 }
13089
13090 int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
13091 int *num_headers,
13092 const EXRVersion *exr_version,
13093 const unsigned char *memory, size_t size,
13094 const char **err) {
13095 if (memory == NULL || exr_headers == NULL || num_headers == NULL ||
13096 exr_version == NULL) {
13097 // Invalid argument
13098 tinyexr::SetErrorMessage(
13099 "Invalid argument for ParseEXRMultipartHeaderFromMemory", err);
13100 return TINYEXR_ERROR_INVALID_ARGUMENT;
13101 }
13102
13103 if (size < tinyexr::kEXRVersionSize) {
13104 tinyexr::SetErrorMessage("Data size too short", err);
13105 return TINYEXR_ERROR_INVALID_DATA;
13106 }
13107
13108 const unsigned char *marker = memory + tinyexr::kEXRVersionSize;
13109 size_t marker_size = size - tinyexr::kEXRVersionSize;
13110
13111 std::vector<tinyexr::HeaderInfo> infos;
13112
13113 for (;;) {
13114 tinyexr::HeaderInfo info;
13115 info.clear();
13116
13117 std::string err_str;
13118 bool empty_header = false;
13119 int ret = ParseEXRHeader(&info, &empty_header, exr_version, &err_str,
13120 marker, marker_size);
13121
13122 if (ret != TINYEXR_SUCCESS) {
13123 tinyexr::SetErrorMessage(err_str, err);
13124 return ret;
13125 }
13126
13127 if (empty_header) {
13128 marker += 1; // skip '\0'
13129 break;
13130 }
13131
13132 // `chunkCount` must exist in the header.
13133 if (info.chunk_count == 0) {
13134 tinyexr::SetErrorMessage(
13135 "`chunkCount' attribute is not found in the header.", err);
13136 return TINYEXR_ERROR_INVALID_DATA;
13137 }
13138
13139 infos.push_back(info);
13140
13141 // move to next header.
13142 marker += info.header_len;
13143 size -= info.header_len;
13144 }
13145
13146 // allocate memory for EXRHeader and create array of EXRHeader pointers.
13147 (*exr_headers) =
13148 static_cast<EXRHeader **>(malloc(sizeof(EXRHeader *) * infos.size()));
13149 for (size_t i = 0; i < infos.size(); i++) {
13150 EXRHeader *exr_header = static_cast<EXRHeader *>(malloc(sizeof(EXRHeader)));
13151
13152 ConvertHeader(exr_header, infos[i]);
13153
13154 // transfoer `tiled` from version.
13155 exr_header->tiled = exr_version->tiled;
13156
13157 (*exr_headers)[i] = exr_header;
13158 }
13159
13160 (*num_headers) = static_cast<int>(infos.size());
13161
13162 return TINYEXR_SUCCESS;
13163 }
13164
13165 int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
13166 const EXRVersion *exr_version,
13167 const char *filename, const char **err) {
13168 if (exr_headers == NULL || num_headers == NULL || exr_version == NULL ||
13169 filename == NULL) {
13170 tinyexr::SetErrorMessage(
13171 "Invalid argument for ParseEXRMultipartHeaderFromFile()", err);
13172 return TINYEXR_ERROR_INVALID_ARGUMENT;
13173 }
13174
13175 #ifdef _WIN32
13176 FILE *fp = NULL;
13177 fopen_s(&fp, filename, "rb");
13178 #else
13179 FILE *fp = fopen(filename, "rb");
13180 #endif
13181 if (!fp) {
13182 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
13183 return TINYEXR_ERROR_CANT_OPEN_FILE;
13184 }
13185
13186 size_t filesize;
13187 // Compute size
13188 fseek(fp, 0, SEEK_END);
13189 filesize = static_cast<size_t>(ftell(fp));
13190 fseek(fp, 0, SEEK_SET);
13191
13192 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
13193 {
13194 size_t ret;
13195 ret = fread(&buf[0], 1, filesize, fp);
13196 TEXR_ASSERT(ret == filesize);
13197 fclose(fp);
13198
13199 if (ret != filesize) {
13200 tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err);
13201 return TINYEXR_ERROR_INVALID_FILE;
13202 }
13203 }
13204
13205 return ParseEXRMultipartHeaderFromMemory(
13206 exr_headers, num_headers, exr_version, &buf.at(0), filesize, err);
13207 }
13208
13209 int ParseEXRVersionFromMemory(EXRVersion *version, const unsigned char *memory,
13210 size_t size) {
13211 if (version == NULL || memory == NULL) {
13212 return TINYEXR_ERROR_INVALID_ARGUMENT;
13213 }
13214
13215 if (size < tinyexr::kEXRVersionSize) {
13216 return TINYEXR_ERROR_INVALID_DATA;
13217 }
13218
13219 const unsigned char *marker = memory;
13220
13221 // Header check.
13222 {
13223 const char header[] = {0x76, 0x2f, 0x31, 0x01};
13224
13225 if (memcmp(marker, header, 4) != 0) {
13226 return TINYEXR_ERROR_INVALID_MAGIC_NUMBER;
13227 }
13228 marker += 4;
13229 }
13230
13231 version->tiled = false;
13232 version->long_name = false;
13233 version->non_image = false;
13234 version->multipart = false;
13235
13236 // Parse version header.
13237 {
13238 // must be 2
13239 if (marker[0] != 2) {
13240 return TINYEXR_ERROR_INVALID_EXR_VERSION;
13241 }
13242
13243 version->version = 2;
13244
13245 if (marker[1] & 0x2) { // 9th bit
13246 version->tiled = true;
13247 }
13248 if (marker[1] & 0x4) { // 10th bit
13249 version->long_name = true;
13250 }
13251 if (marker[1] & 0x8) { // 11th bit
13252 version->non_image = true; // (deep image)
13253 }
13254 if (marker[1] & 0x10) { // 12th bit
13255 version->multipart = true;
13256 }
13257 }
13258
13259 return TINYEXR_SUCCESS;
13260 }
13261
13262 int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) {
13263 if (filename == NULL) {
13264 return TINYEXR_ERROR_INVALID_ARGUMENT;
13265 }
13266
13267 #ifdef _WIN32
13268 FILE *fp = NULL;
13269 fopen_s(&fp, filename, "rb");
13270 #else
13271 FILE *fp = fopen(filename, "rb");
13272 #endif
13273 if (!fp) {
13274 return TINYEXR_ERROR_CANT_OPEN_FILE;
13275 }
13276
13277 size_t file_size;
13278 // Compute size
13279 fseek(fp, 0, SEEK_END);
13280 file_size = static_cast<size_t>(ftell(fp));
13281 fseek(fp, 0, SEEK_SET);
13282
13283 if (file_size < tinyexr::kEXRVersionSize) {
13284 fclose(fp);
13285 return TINYEXR_ERROR_INVALID_FILE;
13286 }
13287
13288 unsigned char buf[tinyexr::kEXRVersionSize];
13289 size_t ret = fread(&buf[0], 1, tinyexr::kEXRVersionSize, fp);
13290 fclose(fp);
13291
13292 if (ret != tinyexr::kEXRVersionSize) {
13293 return TINYEXR_ERROR_INVALID_FILE;
13294 }
13295
13296 return ParseEXRVersionFromMemory(version, buf, tinyexr::kEXRVersionSize);
13297 }
13298
13299 int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
13300 const EXRHeader **exr_headers,
13301 unsigned int num_parts,
13302 const unsigned char *memory,
13303 const size_t size, const char **err) {
13304 if (exr_images == NULL || exr_headers == NULL || num_parts == 0 ||
13305 memory == NULL || (size <= tinyexr::kEXRVersionSize)) {
13306 tinyexr::SetErrorMessage(
13307 "Invalid argument for LoadEXRMultipartImageFromMemory()", err);
13308 return TINYEXR_ERROR_INVALID_ARGUMENT;
13309 }
13310
13311 // compute total header size.
13312 size_t total_header_size = 0;
13313 for (unsigned int i = 0; i < num_parts; i++) {
13314 if (exr_headers[i]->header_len == 0) {
13315 tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
13316 return TINYEXR_ERROR_INVALID_ARGUMENT;
13317 }
13318
13319 total_header_size += exr_headers[i]->header_len;
13320 }
13321
13322 const char *marker = reinterpret_cast<const char *>(
13323 memory + total_header_size + 4 +
13324 4); // +8 for magic number and version header.
13325
13326 marker += 1; // Skip empty header.
13327
13328 // NOTE 1:
13329 // In multipart image, There is 'part number' before chunk data.
13330 // 4 byte : part number
13331 // 4+ : chunk
13332 //
13333 // NOTE 2:
13334 // EXR spec says 'part number' is 'unsigned long' but actually this is
13335 // 'unsigned int(4 bytes)' in OpenEXR implementation...
13336 // http://www.openexr.com/openexrfilelayout.pdf
13337
13338 // Load chunk offset table.
13339 std::vector<std::vector<tinyexr::tinyexr_uint64> > chunk_offset_table_list;
13340 for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
13341 std::vector<tinyexr::tinyexr_uint64> offset_table(
13342 static_cast<size_t>(exr_headers[i]->chunk_count));
13343
13344 for (size_t c = 0; c < offset_table.size(); c++) {
13345 tinyexr::tinyexr_uint64 offset;
13346 memcpy(&offset, marker, 8);
13347 tinyexr::swap8(&offset);
13348
13349 if (offset >= size) {
13350 tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.",
13351 err);
13352 return TINYEXR_ERROR_INVALID_DATA;
13353 }
13354
13355 offset_table[c] = offset + 4; // +4 to skip 'part number'
13356 marker += 8;
13357 }
13358
13359 chunk_offset_table_list.push_back(offset_table);
13360 }
13361
13362 // Decode image.
13363 for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
13364 std::vector<tinyexr::tinyexr_uint64> &offset_table =
13365 chunk_offset_table_list[i];
13366
13367 // First check 'part number' is identitical to 'i'
13368 for (size_t c = 0; c < offset_table.size(); c++) {
13369 const unsigned char *part_number_addr =
13370 memory + offset_table[c] - 4; // -4 to move to 'part number' field.
13371 unsigned int part_no;
13372 memcpy(&part_no, part_number_addr, sizeof(unsigned int)); // 4
13373 tinyexr::swap4(&part_no);
13374
13375 if (part_no != i) {
13376 tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.",
13377 err);
13378 return TINYEXR_ERROR_INVALID_DATA;
13379 }
13380 }
13381
13382 std::string e;
13383 int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
13384 memory, size, &e);
13385 if (ret != TINYEXR_SUCCESS) {
13386 if (!e.empty()) {
13387 tinyexr::SetErrorMessage(e, err);
13388 }
13389 return ret;
13390 }
13391 }
13392
13393 return TINYEXR_SUCCESS;
13394 }
13395
13396 int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
13397 const EXRHeader **exr_headers,
13398 unsigned int num_parts, const char *filename,
13399 const char **err) {
13400 if (exr_images == NULL || exr_headers == NULL || num_parts == 0) {
13401 tinyexr::SetErrorMessage(
13402 "Invalid argument for LoadEXRMultipartImageFromFile", err);
13403 return TINYEXR_ERROR_INVALID_ARGUMENT;
13404 }
13405
13406 #ifdef _WIN32
13407 FILE *fp = NULL;
13408 fopen_s(&fp, filename, "rb");
13409 #else
13410 FILE *fp = fopen(filename, "rb");
13411 #endif
13412 if (!fp) {
13413 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
13414 return TINYEXR_ERROR_CANT_OPEN_FILE;
13415 }
13416
13417 size_t filesize;
13418 // Compute size
13419 fseek(fp, 0, SEEK_END);
13420 filesize = static_cast<size_t>(ftell(fp));
13421 fseek(fp, 0, SEEK_SET);
13422
13423 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
13424 {
13425 size_t ret;
13426 ret = fread(&buf[0], 1, filesize, fp);
13427 TEXR_ASSERT(ret == filesize);
13428 fclose(fp);
13429 (void)ret;
13430 }
13431
13432 return LoadEXRMultipartImageFromMemory(exr_images, exr_headers, num_parts,
13433 &buf.at(0), filesize, err);
13434 }
13435
13436 int SaveEXR(const float *data, int width, int height, int components,
13437 const int save_as_fp16, const char *outfilename, const char **err) {
13438 if ((components == 1) || components == 3 || components == 4) {
13439 // OK
13440 } else {
13441 std::stringstream ss;
13442 ss << "Unsupported component value : " << components << std::endl;
13443
13444 tinyexr::SetErrorMessage(ss.str(), err);
13445 return TINYEXR_ERROR_INVALID_ARGUMENT;
13446 }
13447
13448 EXRHeader header;
13449 InitEXRHeader(&header);
13450
13451 if ((width < 16) && (height < 16)) {
13452 // No compression for small image.
13453 header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE;
13454 } else {
13455 header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP;
13456 }
13457
13458 EXRImage image;
13459 InitEXRImage(&image);
13460
13461 image.num_channels = components;
13462
13463 std::vector<float> images[4];
13464
13465 if (components == 1) {
13466 images[0].resize(static_cast<size_t>(width * height));
13467 memcpy(images[0].data(), data, sizeof(float) * size_t(width * height));
13468 } else {
13469 images[0].resize(static_cast<size_t>(width * height));
13470 images[1].resize(static_cast<size_t>(width * height));
13471 images[2].resize(static_cast<size_t>(width * height));
13472 images[3].resize(static_cast<size_t>(width * height));
13473
13474 // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers
13475 for (size_t i = 0; i < static_cast<size_t>(width * height); i++) {
13476 images[0][i] = data[static_cast<size_t>(components) * i + 0];
13477 images[1][i] = data[static_cast<size_t>(components) * i + 1];
13478 images[2][i] = data[static_cast<size_t>(components) * i + 2];
13479 if (components == 4) {
13480 images[3][i] = data[static_cast<size_t>(components) * i + 3];
13481 }
13482 }
13483 }
13484
13485 float *image_ptr[4] = {0, 0, 0, 0};
13486 if (components == 4) {
13487 image_ptr[0] = &(images[3].at(0)); // A
13488 image_ptr[1] = &(images[2].at(0)); // B
13489 image_ptr[2] = &(images[1].at(0)); // G
13490 image_ptr[3] = &(images[0].at(0)); // R
13491 } else if (components == 3) {
13492 image_ptr[0] = &(images[2].at(0)); // B
13493 image_ptr[1] = &(images[1].at(0)); // G
13494 image_ptr[2] = &(images[0].at(0)); // R
13495 } else if (components == 1) {
13496 image_ptr[0] = &(images[0].at(0)); // A
13497 }
13498
13499 image.images = reinterpret_cast<unsigned char **>(image_ptr);
13500 image.width = width;
13501 image.height = height;
13502
13503 header.num_channels = components;
13504 header.channels = static_cast<EXRChannelInfo *>(malloc(
13505 sizeof(EXRChannelInfo) * static_cast<size_t>(header.num_channels)));
13506 // Must be (A)BGR order, since most of EXR viewers expect this channel order.
13507 if (components == 4) {
13508 #ifdef _MSC_VER
13509 strncpy_s(header.channels[0].name, "A", 255);
13510 strncpy_s(header.channels[1].name, "B", 255);
13511 strncpy_s(header.channels[2].name, "G", 255);
13512 strncpy_s(header.channels[3].name, "R", 255);
13513 #else
13514 strncpy(header.channels[0].name, "A", 255);
13515 strncpy(header.channels[1].name, "B", 255);
13516 strncpy(header.channels[2].name, "G", 255);
13517 strncpy(header.channels[3].name, "R", 255);
13518 #endif
13519 header.channels[0].name[strlen("A")] = '\0';
13520 header.channels[1].name[strlen("B")] = '\0';
13521 header.channels[2].name[strlen("G")] = '\0';
13522 header.channels[3].name[strlen("R")] = '\0';
13523 } else if (components == 3) {
13524 #ifdef _MSC_VER
13525 strncpy_s(header.channels[0].name, "B", 255);
13526 strncpy_s(header.channels[1].name, "G", 255);
13527 strncpy_s(header.channels[2].name, "R", 255);
13528 #else
13529 strncpy(header.channels[0].name, "B", 255);
13530 strncpy(header.channels[1].name, "G", 255);
13531 strncpy(header.channels[2].name, "R", 255);
13532 #endif
13533 header.channels[0].name[strlen("B")] = '\0';
13534 header.channels[1].name[strlen("G")] = '\0';
13535 header.channels[2].name[strlen("R")] = '\0';
13536 } else {
13537 #ifdef _MSC_VER
13538 strncpy_s(header.channels[0].name, "A", 255);
13539 #else
13540 strncpy(header.channels[0].name, "A", 255);
13541 #endif
13542 header.channels[0].name[strlen("A")] = '\0';
13543 }
13544
13545 header.pixel_types = static_cast<int *>(
13546 malloc(sizeof(int) * static_cast<size_t>(header.num_channels)));
13547 header.requested_pixel_types = static_cast<int *>(
13548 malloc(sizeof(int) * static_cast<size_t>(header.num_channels)));
13549 for (int i = 0; i < header.num_channels; i++) {
13550 header.pixel_types[i] =
13551 TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
13552
13553 if (save_as_fp16 > 0) {
13554 header.requested_pixel_types[i] =
13555 TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format
13556 } else {
13557 header.requested_pixel_types[i] =
13558 TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e.
13559 // no precision reduction)
13560 }
13561 }
13562
13563 int ret = SaveEXRImageToFile(&image, &header, outfilename, err);
13564 if (ret != TINYEXR_SUCCESS) {
13565 return ret;
13566 }
13567
13568 free(header.channels);
13569 free(header.pixel_types);
13570 free(header.requested_pixel_types);
13571
13572 return ret;
13573 }
13574
13575 #ifdef __clang__
13576 // zero-as-null-ppinter-constant
13577 #pragma clang diagnostic pop
13578 #endif
13579
13580 #endif // TINYEXR_IMPLEMENTATION_DEIFNED
13581 #endif // TINYEXR_IMPLEMENTATION
13582