1/*
2Copyright (c) 2014 - 2019, Syoyo Fujita and many contributors.
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON 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
25SOFTWARE, 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
89extern "C" {
90#endif
91
92// Use embedded miniz or not to decode ZIP format pixel. Linking with zlib
93// required if this flas is 0.
94#ifndef TINYEXR_USE_MINIZ
95#define TINYEXR_USE_MINIZ (1)
96#endif
97
98// Disable PIZ comporession when applying cpplint.
99#ifndef TINYEXR_USE_PIZ
100#define TINYEXR_USE_PIZ (1)
101#endif
102
103#ifndef TINYEXR_USE_ZFP
104#define TINYEXR_USE_ZFP (0) // TinyEXR extension.
105// http://computation.llnl.gov/projects/floating-point-compression
106#endif
107
108#define TINYEXR_SUCCESS (0)
109#define TINYEXR_ERROR_INVALID_MAGIC_NUMBER (-1)
110#define TINYEXR_ERROR_INVALID_EXR_VERSION (-2)
111#define TINYEXR_ERROR_INVALID_ARGUMENT (-3)
112#define TINYEXR_ERROR_INVALID_DATA (-4)
113#define TINYEXR_ERROR_INVALID_FILE (-5)
114#define TINYEXR_ERROR_INVALID_PARAMETER (-5)
115#define TINYEXR_ERROR_CANT_OPEN_FILE (-6)
116#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-7)
117#define TINYEXR_ERROR_INVALID_HEADER (-8)
118#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-9)
119#define TINYEXR_ERROR_CANT_WRITE_FILE (-10)
120#define TINYEXR_ERROR_SERIALZATION_FAILED (-11)
121
122// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf }
123
124// pixel type: possible values are: UINT = 0 HALF = 1 FLOAT = 2
125#define TINYEXR_PIXELTYPE_UINT (0)
126#define TINYEXR_PIXELTYPE_HALF (1)
127#define TINYEXR_PIXELTYPE_FLOAT (2)
128
129#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024)
130#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128)
131
132#define TINYEXR_COMPRESSIONTYPE_NONE (0)
133#define TINYEXR_COMPRESSIONTYPE_RLE (1)
134#define TINYEXR_COMPRESSIONTYPE_ZIPS (2)
135#define TINYEXR_COMPRESSIONTYPE_ZIP (3)
136#define TINYEXR_COMPRESSIONTYPE_PIZ (4)
137#define TINYEXR_COMPRESSIONTYPE_ZFP (128) // TinyEXR extension
138
139#define TINYEXR_ZFP_COMPRESSIONTYPE_RATE (0)
140#define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION (1)
141#define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY (2)
142
143#define TINYEXR_TILE_ONE_LEVEL (0)
144#define TINYEXR_TILE_MIPMAP_LEVELS (1)
145#define TINYEXR_TILE_RIPMAP_LEVELS (2)
146
147#define TINYEXR_TILE_ROUND_DOWN (0)
148#define TINYEXR_TILE_ROUND_UP (1)
149
150typedef struct _EXRVersion {
151 int version; // this must be 2
152 int tiled; // tile format image
153 int long_name; // long name attribute
154 int non_image; // deep image(EXR 2.0)
155 int multipart; // multi-part(EXR 2.0)
156} EXRVersion;
157
158typedef struct _EXRAttribute {
159 char name[256]; // name and type are up to 255 chars long.
160 char type[256];
161 unsigned char *value; // uint8_t*
162 int size;
163 int pad0;
164} EXRAttribute;
165
166typedef struct _EXRChannelInfo {
167 char name[256]; // less than 255 bytes long
168 int pixel_type;
169 int x_sampling;
170 int y_sampling;
171 unsigned char p_linear;
172 unsigned char pad[3];
173} EXRChannelInfo;
174
175typedef struct _EXRTile {
176 int offset_x;
177 int offset_y;
178 int level_x;
179 int level_y;
180
181 int width; // actual width in a tile.
182 int height; // actual height int a tile.
183
184 unsigned char **images; // image[channels][pixels]
185} EXRTile;
186
187typedef struct _EXRHeader {
188 float pixel_aspect_ratio;
189 int line_order;
190 int data_window[4];
191 int display_window[4];
192 float screen_window_center[2];
193 float screen_window_width;
194
195 int chunk_count;
196
197 // Properties for tiled format(`tiledesc`).
198 int tiled;
199 int tile_size_x;
200 int tile_size_y;
201 int tile_level_mode;
202 int tile_rounding_mode;
203
204 int long_name;
205 int non_image;
206 int multipart;
207 unsigned int header_len;
208
209 // Custom attributes(exludes required attributes(e.g. `channels`,
210 // `compression`, etc)
211 int num_custom_attributes;
212 EXRAttribute *custom_attributes; // array of EXRAttribute. size =
213 // `num_custom_attributes`.
214
215 EXRChannelInfo *channels; // [num_channels]
216
217 int *pixel_types; // Loaded pixel type(TINYEXR_PIXELTYPE_*) of `images` for
218 // each channel. This is overwritten with `requested_pixel_types` when
219 // loading.
220 int num_channels;
221
222 int compression_type; // compression type(TINYEXR_COMPRESSIONTYPE_*)
223 int *requested_pixel_types; // Filled initially by
224 // ParseEXRHeaderFrom(Meomory|File), then users
225 // can edit it(only valid for HALF pixel type
226 // channel)
227
228} EXRHeader;
229
230typedef struct _EXRMultiPartHeader {
231 int num_headers;
232 EXRHeader *headers;
233
234} EXRMultiPartHeader;
235
236typedef struct _EXRImage {
237 EXRTile *tiles; // Tiled pixel data. The application must reconstruct image
238 // from tiles manually. NULL if scanline format.
239 unsigned char **images; // image[channels][pixels]. NULL if tiled format.
240
241 int width;
242 int height;
243 int num_channels;
244
245 // Properties for tile format.
246 int num_tiles;
247
248} EXRImage;
249
250typedef struct _EXRMultiPartImage {
251 int num_images;
252 EXRImage *images;
253
254} EXRMultiPartImage;
255
256typedef struct _DeepImage {
257 const char **channel_names;
258 float ***image; // image[channels][scanlines][samples]
259 int **offset_table; // offset_table[scanline][offsets]
260 int num_channels;
261 int width;
262 int height;
263 int pad0;
264} DeepImage;
265
266// @deprecated { to be removed. }
267// Loads single-frame OpenEXR image. Assume EXR image contains A(single channel
268// alpha) or RGB(A) channels.
269// Application must free image data as returned by `out_rgba`
270// Result image format is: float x RGBA x width x hight
271// Returns negative value and may set error string in `err` when there's an
272// error
273extern int LoadEXR(float **out_rgba, int *width, int *height,
274 const char *filename, const char **err);
275
276// @deprecated { to be removed. }
277// Simple wrapper API for ParseEXRHeaderFromFile.
278// checking given file is a EXR file(by just look up header)
279// @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for
280// others
281extern int IsEXR(const char *filename);
282
283// @deprecated { to be removed. }
284// Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels.
285// components must be 1(Grayscale), 3(RGB) or 4(RGBA).
286// Input image format is: `float x width x height`, or `float x RGB(A) x width x
287// hight`
288// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero
289// value.
290// Save image as fp32(FLOAT) format when `save_as_fp16` is 0.
291// Use ZIP compression by default.
292// Returns negative value and may set error string in `err` when there's an
293// error
294extern int SaveEXR(const float *data, const int width, const int height,
295 const int components, const int save_as_fp16,
296 const char *filename, const char **err);
297
298// Initialize EXRHeader struct
299extern void InitEXRHeader(EXRHeader *exr_header);
300
301// Initialize EXRImage struct
302extern void InitEXRImage(EXRImage *exr_image);
303
304// Free's internal data of EXRHeader struct
305extern int FreeEXRHeader(EXRHeader *exr_header);
306
307// Free's internal data of EXRImage struct
308extern int FreeEXRImage(EXRImage *exr_image);
309
310// Free's error message
311extern void FreeEXRErrorMessage(const char *msg);
312
313// Parse EXR version header of a file.
314extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename);
315
316// Parse EXR version header from memory-mapped EXR data.
317extern int ParseEXRVersionFromMemory(EXRVersion *version,
318 const unsigned char *memory, size_t size);
319
320// Parse single-part OpenEXR header from a file and initialize `EXRHeader`.
321// When there was an error message, Application must free `err` with
322// FreeEXRErrorMessage()
323extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version,
324 const char *filename, const char **err);
325
326// Parse single-part OpenEXR header from a memory and initialize `EXRHeader`.
327// When there was an error message, Application must free `err` with
328// FreeEXRErrorMessage()
329extern int ParseEXRHeaderFromMemory(EXRHeader *header,
330 const EXRVersion *version,
331 const unsigned char *memory, size_t size,
332 const char **err);
333
334// Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*`
335// array.
336// When there was an error message, Application must free `err` with
337// FreeEXRErrorMessage()
338extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
339 int *num_headers,
340 const EXRVersion *version,
341 const char *filename,
342 const char **err);
343
344// Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*`
345// array
346// When there was an error message, Application must free `err` with
347// FreeEXRErrorMessage()
348extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
349 int *num_headers,
350 const EXRVersion *version,
351 const unsigned char *memory,
352 size_t size, const char **err);
353
354// Loads single-part OpenEXR image from a file.
355// Application must setup `ParseEXRHeaderFromFile` before calling this function.
356// Application can free EXRImage using `FreeEXRImage`
357// Returns negative value and may set error string in `err` when there's an
358// error
359// When there was an error message, Application must free `err` with
360// FreeEXRErrorMessage()
361extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
362 const char *filename, const char **err);
363
364// Loads single-part OpenEXR image from a memory.
365// Application must setup `EXRHeader` with
366// `ParseEXRHeaderFromMemory` before calling this function.
367// Application can free EXRImage using `FreeEXRImage`
368// Returns negative value and may set error string in `err` when there's an
369// error
370// When there was an error message, Application must free `err` with
371// FreeEXRErrorMessage()
372extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
373 const unsigned char *memory,
374 const size_t size, const char **err);
375
376// Loads multi-part OpenEXR image from a file.
377// Application must setup `ParseEXRMultipartHeaderFromFile` before calling this
378// function.
379// Application can free EXRImage using `FreeEXRImage`
380// Returns negative value and may set error string in `err` when there's an
381// error
382// When there was an error message, Application must free `err` with
383// FreeEXRErrorMessage()
384extern int LoadEXRMultipartImageFromFile(EXRImage *images,
385 const EXRHeader **headers,
386 unsigned int num_parts,
387 const char *filename,
388 const char **err);
389
390// Loads multi-part OpenEXR image from a memory.
391// Application must setup `EXRHeader*` array with
392// `ParseEXRMultipartHeaderFromMemory` before calling this function.
393// Application can free EXRImage using `FreeEXRImage`
394// Returns negative value and may set error string in `err` when there's an
395// error
396// When there was an error message, Application must free `err` with
397// FreeEXRErrorMessage()
398extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
399 const EXRHeader **headers,
400 unsigned int num_parts,
401 const unsigned char *memory,
402 const size_t size, const char **err);
403
404// Saves multi-channel, single-frame OpenEXR image to a file.
405// Returns negative value and may set error string in `err` when there's an
406// error
407// When there was an error message, Application must free `err` with
408// FreeEXRErrorMessage()
409extern int SaveEXRImageToFile(const EXRImage *image,
410 const EXRHeader *exr_header, const char *filename,
411 const char **err);
412
413// Saves multi-channel, single-frame OpenEXR image to a memory.
414// Image is compressed using EXRImage.compression value.
415// Return the number of bytes if success.
416// Return zero and will set error string in `err` when there's an
417// error.
418// When there was an error message, Application must free `err` with
419// FreeEXRErrorMessage()
420extern size_t SaveEXRImageToMemory(const EXRImage *image,
421 const EXRHeader *exr_header,
422 unsigned char **memory, const char **err);
423
424// Loads single-frame OpenEXR deep image.
425// Application must free memory of variables in DeepImage(image, offset_table)
426// Returns negative value and may set error string in `err` when there's an
427// error
428// When there was an error message, Application must free `err` with
429// FreeEXRErrorMessage()
430extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
431 const char **err);
432
433// NOT YET IMPLEMENTED:
434// Saves single-frame OpenEXR deep image.
435// Returns negative value and may set error string in `err` when there's an
436// error
437// extern int SaveDeepEXR(const DeepImage *in_image, const char *filename,
438// const char **err);
439
440// NOT YET IMPLEMENTED:
441// Loads multi-part OpenEXR deep image.
442// Application must free memory of variables in DeepImage(image, offset_table)
443// extern int LoadMultiPartDeepEXR(DeepImage **out_image, int num_parts, const
444// char *filename,
445// const char **err);
446
447// For emscripten.
448// Loads single-frame OpenEXR image from memory. Assume EXR image contains
449// RGB(A) channels.
450// Returns negative value and may set error string in `err` when there's an
451// error
452// When there was an error message, Application must free `err` with
453// FreeEXRErrorMessage()
454extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
455 const unsigned char *memory, size_t size,
456 const char **err);
457
458#ifdef __cplusplus
459}
460#endif
461
462#endif // TINYEXR_H_
463
464#ifdef TINYEXR_IMPLEMENTATION
465#ifndef TINYEXR_IMPLEMENTATION_DEIFNED
466#define TINYEXR_IMPLEMENTATION_DEIFNED
467
468#include <algorithm>
469#include <cassert>
470#include <cstdio>
471#include <cstdlib>
472#include <cstring>
473#include <sstream>
474
475// #include <iostream> // debug
476
477#include <limits>
478#include <string>
479#include <vector>
480
481#if __cplusplus > 199711L
482// C++11
483#include <cstdint>
484#endif // __cplusplus > 199711L
485
486#ifdef _OPENMP
487#include <omp.h>
488#endif
489
490#if TINYEXR_USE_MINIZ
491#else
492// Issue #46. Please include your own zlib-compatible API header before
493// including `tinyexr.h`
494//#include "zlib.h"
495#endif
496
497#if TINYEXR_USE_ZFP
498#include "zfp.h"
499#endif
500
501namespace tinyexr {
502
503#if __cplusplus > 199711L
504// C++11
505typedef uint64_t tinyexr_uint64;
506typedef int64_t tinyexr_int64;
507#else
508// Although `long long` is not a standard type pre C++11, assume it is defined
509// as a compiler's extension.
510#ifdef __clang__
511#pragma clang diagnostic push
512#pragma clang diagnostic ignored "-Wc++11-long-long"
513#endif
514typedef unsigned long long tinyexr_uint64;
515typedef long long tinyexr_int64;
516#ifdef __clang__
517#pragma clang diagnostic pop
518#endif
519#endif
520
521#if TINYEXR_USE_MINIZ
522
523namespace miniz {
524
525#ifdef __clang__
526#pragma clang diagnostic push
527#pragma clang diagnostic ignored "-Wc++11-long-long"
528#pragma clang diagnostic ignored "-Wold-style-cast"
529#pragma clang diagnostic ignored "-Wpadded"
530#pragma clang diagnostic ignored "-Wsign-conversion"
531#pragma clang diagnostic ignored "-Wc++11-extensions"
532#pragma clang diagnostic ignored "-Wconversion"
533#pragma clang diagnostic ignored "-Wunused-function"
534#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
535#pragma clang diagnostic ignored "-Wundef"
536
537#if __has_warning("-Wcomma")
538#pragma clang diagnostic ignored "-Wcomma"
539#endif
540
541#if __has_warning("-Wmacro-redefined")
542#pragma clang diagnostic ignored "-Wmacro-redefined"
543#endif
544
545#if __has_warning("-Wcast-qual")
546#pragma clang diagnostic ignored "-Wcast-qual"
547#endif
548
549#if __has_warning("-Wzero-as-null-pointer-constant")
550#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
551#endif
552
553#if __has_warning("-Wtautological-constant-compare")
554#pragma clang diagnostic ignored "-Wtautological-constant-compare"
555#endif
556
557#endif
558
559/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
560 reading/writing/appending, PNG writing
561 See "unlicense" statement at the end of this file.
562 Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013
563 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951:
564 http://www.ietf.org/rfc/rfc1951.txt
565
566 Most API's defined in miniz.c are optional. For example, to disable the
567 archive related functions just define
568 MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO
569 (see the list below for more macros).
570
571 * Change History
572 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major
573 release with Zip64 support (almost there!):
574 - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug
575 (thanks kahmyong.moon@hp.com) which could cause locate files to not find
576 files. This bug
577 would only have occured in earlier versions if you explicitly used this
578 flag, OR if you used mz_zip_extract_archive_file_to_heap() or
579 mz_zip_add_mem_to_archive_file_in_place()
580 (which used this flag). If you can't switch to v1.15 but want to fix
581 this bug, just remove the uses of this flag from both helper funcs (and of
582 course don't use the flag).
583 - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when
584 pUser_read_buf is not NULL and compressed size is > uncompressed size
585 - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract
586 compressed data from directory entries, to account for weird zipfiles which
587 contain zero-size compressed data on dir entries.
588 Hopefully this fix won't cause any issues on weird zip archives,
589 because it assumes the low 16-bits of zip external attributes are DOS
590 attributes (which I believe they always are in practice).
591 - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the
592 internal attributes, just the filename and external attributes
593 - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed
594 - Added cmake support for Linux builds which builds all the examples,
595 tested with clang v3.3 and gcc v4.6.
596 - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti
597 - Merged MZ_FORCEINLINE fix from hdeanclark
598 - Fix <time.h> include before config #ifdef, thanks emil.brink
599 - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping
600 (super useful for OpenGL apps), and explicit control over the compression
601 level (so you can
602 set it to 1 for real-time compression).
603 - Merged in some compiler fixes from paulharris's github repro.
604 - Retested this build under Windows (VS 2010, including static analysis),
605 tcc 0.9.26, gcc v4.6 and clang v3.3.
606 - Added example6.c, which dumps an image of the mandelbrot set to a PNG
607 file.
608 - Modified example2 to help test the
609 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more.
610 - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix
611 possible src file fclose() leak if alignment bytes+local header file write
612 faiiled
613 - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader():
614 Was pushing the wrong central dir header offset, appears harmless in this
615 release, but it became a problem in the zip64 branch
616 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE,
617 #include <time.h> (thanks fermtect).
618 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix
619 mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit.
620 - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and
621 re-ran a randomized regression test on ~500k files.
622 - Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
623 - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze
624 (static analysis) option and fixed all warnings (except for the silly
625 "Use of the comma-operator in a tested expression.." analysis warning,
626 which I purposely use to work around a MSVC compiler warning).
627 - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and
628 tested Linux executables. The codeblocks workspace is compatible with
629 Linux+Win32/x64.
630 - Added miniz_tester solution/project, which is a useful little app
631 derived from LZHAM's tester app that I use as part of the regression test.
632 - Ran miniz.c and tinfl.c through another series of regression testing on
633 ~500,000 files and archives.
634 - Modified example5.c so it purposely disables a bunch of high-level
635 functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the
636 MINIZ_NO_STDIO bug report.)
637 - Fix ftell() usage in examples so they exit with an error on files which
638 are too large (a limitation of the examples, not miniz itself).
639 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple
640 minor level_and_flags issues in the archive API's.
641 level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce
642 Dawson <bruced@valvesoftware.com> for the feedback/bug report.
643 5/28/11 v1.11 - Added statement from unlicense.org
644 5/27/11 v1.10 - Substantial compressor optimizations:
645 - Level 1 is now ~4x faster than before. The L1 compressor's throughput
646 now varies between 70-110MB/sec. on a
647 - Core i7 (actual throughput varies depending on the type of data, and x64
648 vs. x86).
649 - Improved baseline L2-L9 compression perf. Also, greatly improved
650 compression perf. issues on some file types.
651 - Refactored the compression code for better readability and
652 maintainability.
653 - Added level 10 compression level (L10 has slightly better ratio than
654 level 9, but could have a potentially large
655 drop in throughput on some files).
656 5/15/11 v1.09 - Initial stable release.
657
658 * Low-level Deflate/Inflate implementation notes:
659
660 Compression: Use the "tdefl" API's. The compressor supports raw, static,
661 and dynamic blocks, lazy or
662 greedy parsing, match length filtering, RLE-only, and Huffman-only streams.
663 It performs and compresses
664 approximately as well as zlib.
665
666 Decompression: Use the "tinfl" API's. The entire decompressor is
667 implemented as a single function
668 coroutine: see tinfl_decompress(). It supports decompression into a 32KB
669 (or larger power of 2) wrapping buffer, or into a memory
670 block large enough to hold the entire file.
671
672 The low-level tdefl/tinfl API's do not make any use of dynamic memory
673 allocation.
674
675 * zlib-style API notes:
676
677 miniz.c implements a fairly large subset of zlib. There's enough
678 functionality present for it to be a drop-in
679 zlib replacement in many apps:
680 The z_stream struct, optional memory allocation callbacks
681 deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
682 inflateInit/inflateInit2/inflate/inflateEnd
683 compress, compress2, compressBound, uncompress
684 CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly
685 routines.
686 Supports raw deflate streams or standard zlib streams with adler-32
687 checking.
688
689 Limitations:
690 The callback API's are not implemented yet. No support for gzip headers or
691 zlib static dictionaries.
692 I've tried to closely emulate zlib's various flavors of stream flushing
693 and return status codes, but
694 there are no guarantees that miniz.c pulls this off perfectly.
695
696 * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function,
697 originally written by
698 Alex Evans. Supports 1-4 bytes/pixel images.
699
700 * ZIP archive API notes:
701
702 The ZIP archive API's where designed with simplicity and efficiency in
703 mind, with just enough abstraction to
704 get the job done with minimal fuss. There are simple API's to retrieve file
705 information, read files from
706 existing archives, create new archives, append new files to existing
707 archives, or clone archive data from
708 one archive to another. It supports archives located in memory or the heap,
709 on disk (using stdio.h),
710 or you can specify custom file read/write callbacks.
711
712 - Archive reading: Just call this function to read a single file from a
713 disk archive:
714
715 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const
716 char *pArchive_name,
717 size_t *pSize, mz_uint zip_flags);
718
719 For more complex cases, use the "mz_zip_reader" functions. Upon opening an
720 archive, the entire central
721 directory is located and read as-is into memory, and subsequent file access
722 only occurs when reading individual files.
723
724 - Archives file scanning: The simple way is to use this function to scan a
725 loaded archive for a specific file:
726
727 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
728 const char *pComment, mz_uint flags);
729
730 The locate operation can optionally check file comments too, which (as one
731 example) can be used to identify
732 multiple versions of the same file in an archive. This function uses a
733 simple linear search through the central
734 directory, so it's not very fast.
735
736 Alternately, you can iterate through all the files in an archive (using
737 mz_zip_reader_get_num_files()) and
738 retrieve detailed info on each file by calling mz_zip_reader_file_stat().
739
740 - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer
741 immediately writes compressed file data
742 to disk and builds an exact image of the central directory in memory. The
743 central directory image is written
744 all at once at the end of the archive file when the archive is finalized.
745
746 The archive writer can optionally align each file's local header and file
747 data to any power of 2 alignment,
748 which can be useful when the archive will be read from optical media. Also,
749 the writer supports placing
750 arbitrary data blobs at the very beginning of ZIP archives. Archives
751 written using either feature are still
752 readable by any ZIP tool.
753
754 - Archive appending: The simple way to add a single file to an archive is
755 to call this function:
756
757 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename,
758 const char *pArchive_name,
759 const void *pBuf, size_t buf_size, const void *pComment, mz_uint16
760 comment_size, mz_uint level_and_flags);
761
762 The archive will be created if it doesn't already exist, otherwise it'll be
763 appended to.
764 Note the appending is done in-place and is not an atomic operation, so if
765 something goes wrong
766 during the operation it's possible the archive could be left without a
767 central directory (although the local
768 file headers and file data will be fine, so the archive will be
769 recoverable).
770
771 For more complex archive modification scenarios:
772 1. The safest way is to use a mz_zip_reader to read the existing archive,
773 cloning only those bits you want to
774 preserve into a new archive using using the
775 mz_zip_writer_add_from_zip_reader() function (which compiles the
776 compressed file data as-is). When you're done, delete the old archive and
777 rename the newly written archive, and
778 you're done. This is safe but requires a bunch of temporary disk space or
779 heap memory.
780
781 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using
782 mz_zip_writer_init_from_reader(),
783 append new files as needed, then finalize the archive which will write an
784 updated central directory to the
785 original archive. (This is basically what
786 mz_zip_add_mem_to_archive_file_in_place() does.) There's a
787 possibility that the archive's central directory could be lost with this
788 method if anything goes wrong, though.
789
790 - ZIP archive support limitations:
791 No zip64 or spanning support. Extraction functions can only handle
792 unencrypted, stored or deflated files.
793 Requires streams capable of seeking.
794
795 * This is a header file library, like stb_image.c. To get only a header file,
796 either cut and paste the
797 below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then
798 include miniz.c from it.
799
800 * Important: For best perf. be sure to customize the below macros for your
801 target platform:
802 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
803 #define MINIZ_LITTLE_ENDIAN 1
804 #define MINIZ_HAS_64BIT_REGISTERS 1
805
806 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before
807 including miniz.c to ensure miniz
808 uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be
809 able to process large files
810 (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).
811*/
812
813#ifndef MINIZ_HEADER_INCLUDED
814#define MINIZ_HEADER_INCLUDED
815
816//#include <stdlib.h>
817
818// Defines to completely disable specific portions of miniz.c:
819// If all macros here are defined the only functionality remaining will be
820// CRC-32, adler-32, tinfl, and tdefl.
821
822// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on
823// stdio for file I/O.
824//#define MINIZ_NO_STDIO
825
826// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able
827// to get the current time, or
828// get/set file times, and the C run-time funcs that get/set times won't be
829// called.
830// The current downside is the times written to your archives will be from 1979.
831#define MINIZ_NO_TIME
832
833// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
834#define MINIZ_NO_ARCHIVE_APIS
835
836// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive
837// API's.
838//#define MINIZ_NO_ARCHIVE_WRITING_APIS
839
840// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression
841// API's.
842//#define MINIZ_NO_ZLIB_APIS
843
844// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent
845// conflicts against stock zlib.
846//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
847
848// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
849// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom
850// user alloc/free/realloc
851// callbacks to the zlib and archive API's, and a few stand-alone helper API's
852// which don't provide custom user
853// functions (such as tdefl_compress_mem_to_heap() and
854// tinfl_decompress_mem_to_heap()) won't work.
855//#define MINIZ_NO_MALLOC
856
857#if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
858// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc
859// on Linux
860#define MINIZ_NO_TIME
861#endif
862
863#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
864//#include <time.h>
865#endif
866
867#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
868 defined(__i386) || defined(__i486__) || defined(__i486) || \
869 defined(i386) || defined(__ia64__) || defined(__x86_64__)
870// MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
871#define MINIZ_X86_OR_X64_CPU 1
872#endif
873
874#if defined(__sparcv9)
875// Big endian
876#else
877#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
878// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
879#define MINIZ_LITTLE_ENDIAN 1
880#endif
881#endif
882
883#if MINIZ_X86_OR_X64_CPU
884// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
885// integer loads and stores from unaligned addresses.
886//#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
887#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES \
888 0 // disable to suppress compiler warnings
889#endif
890
891#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \
892 defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \
893 defined(__x86_64__)
894// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are
895// reasonably fast (and don't involve compiler generated calls to helper
896// functions).
897#define MINIZ_HAS_64BIT_REGISTERS 1
898#endif
899
900#ifdef __cplusplus
901extern "C" {
902#endif
903
904// ------------------- zlib-style API Definitions.
905
906// For more compatibility with zlib, miniz.c uses unsigned long for some
907// parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits!
908typedef unsigned long mz_ulong;
909
910// mz_free() internally uses the MZ_FREE() macro (which by default calls free()
911// unless you've modified the MZ_MALLOC macro) to release a block allocated from
912// the heap.
913void mz_free(void *p);
914
915#define MZ_ADLER32_INIT (1)
916// mz_adler32() returns the initial adler-32 value to use when called with
917// ptr==NULL.
918mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
919
920#define MZ_CRC32_INIT (0)
921// mz_crc32() returns the initial CRC-32 value to use when called with
922// ptr==NULL.
923mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
924
925// Compression strategies.
926enum {
927 MZ_DEFAULT_STRATEGY = 0,
928 MZ_FILTERED = 1,
929 MZ_HUFFMAN_ONLY = 2,
930 MZ_RLE = 3,
931 MZ_FIXED = 4
932};
933
934// Method
935#define MZ_DEFLATED 8
936
937#ifndef MINIZ_NO_ZLIB_APIS
938
939// Heap allocation callbacks.
940// Note that mz_alloc_func parameter types purpsosely differ from zlib's:
941// items/size is size_t, not unsigned long.
942typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
943typedef void (*mz_free_func)(void *opaque, void *address);
944typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items,
945 size_t size);
946
947#define MZ_VERSION "9.1.15"
948#define MZ_VERNUM 0x91F0
949#define MZ_VER_MAJOR 9
950#define MZ_VER_MINOR 1
951#define MZ_VER_REVISION 15
952#define MZ_VER_SUBREVISION 0
953
954// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The
955// other values are for advanced use (refer to the zlib docs).
956enum {
957 MZ_NO_FLUSH = 0,
958 MZ_PARTIAL_FLUSH = 1,
959 MZ_SYNC_FLUSH = 2,
960 MZ_FULL_FLUSH = 3,
961 MZ_FINISH = 4,
962 MZ_BLOCK = 5
963};
964
965// Return status codes. MZ_PARAM_ERROR is non-standard.
966enum {
967 MZ_OK = 0,
968 MZ_STREAM_END = 1,
969 MZ_NEED_DICT = 2,
970 MZ_ERRNO = -1,
971 MZ_STREAM_ERROR = -2,
972 MZ_DATA_ERROR = -3,
973 MZ_MEM_ERROR = -4,
974 MZ_BUF_ERROR = -5,
975 MZ_VERSION_ERROR = -6,
976 MZ_PARAM_ERROR = -10000
977};
978
979// Compression levels: 0-9 are the standard zlib-style levels, 10 is best
980// possible compression (not zlib compatible, and may be very slow),
981// MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
982enum {
983 MZ_NO_COMPRESSION = 0,
984 MZ_BEST_SPEED = 1,
985 MZ_BEST_COMPRESSION = 9,
986 MZ_UBER_COMPRESSION = 10,
987 MZ_DEFAULT_LEVEL = 6,
988 MZ_DEFAULT_COMPRESSION = -1
989};
990
991// Window bits
992#define MZ_DEFAULT_WINDOW_BITS 15
993
994struct mz_internal_state;
995
996// Compression/decompression stream struct.
997typedef struct mz_stream_s {
998 const unsigned char *next_in; // pointer to next byte to read
999 unsigned int avail_in; // number of bytes available at next_in
1000 mz_ulong total_in; // total number of bytes consumed so far
1001
1002 unsigned char *next_out; // pointer to next byte to write
1003 unsigned int avail_out; // number of bytes that can be written to next_out
1004 mz_ulong total_out; // total number of bytes produced so far
1005
1006 char *msg; // error msg (unused)
1007 struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
1008
1009 mz_alloc_func
1010 zalloc; // optional heap allocation function (defaults to malloc)
1011 mz_free_func zfree; // optional heap free function (defaults to free)
1012 void *opaque; // heap alloc function user pointer
1013
1014 int data_type; // data_type (unused)
1015 mz_ulong adler; // adler32 of the source or uncompressed data
1016 mz_ulong reserved; // not used
1017} mz_stream;
1018
1019typedef mz_stream *mz_streamp;
1020
1021// Returns the version string of miniz.c.
1022const char *mz_version(void);
1023
1024// mz_deflateInit() initializes a compressor with default options:
1025// Parameters:
1026// pStream must point to an initialized mz_stream struct.
1027// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
1028// level 1 enables a specially optimized compression function that's been
1029// optimized purely for performance, not ratio.
1030// (This special func. is currently only enabled when
1031// MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.)
1032// Return values:
1033// MZ_OK on success.
1034// MZ_STREAM_ERROR if the stream is bogus.
1035// MZ_PARAM_ERROR if the input parameters are bogus.
1036// MZ_MEM_ERROR on out of memory.
1037int mz_deflateInit(mz_streamp pStream, int level);
1038
1039// mz_deflateInit2() is like mz_deflate(), except with more control:
1040// Additional parameters:
1041// method must be MZ_DEFLATED
1042// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with
1043// zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no
1044// header or footer)
1045// mem_level must be between [1, 9] (it's checked but ignored by miniz.c)
1046int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
1047 int mem_level, int strategy);
1048
1049// Quickly resets a compressor without having to reallocate anything. Same as
1050// calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2().
1051int mz_deflateReset(mz_streamp pStream);
1052
1053// mz_deflate() compresses the input to output, consuming as much of the input
1054// and producing as much output as possible.
1055// Parameters:
1056// pStream is the stream to read from and write to. You must initialize/update
1057// the next_in, avail_in, next_out, and avail_out members.
1058// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or
1059// MZ_FINISH.
1060// Return values:
1061// MZ_OK on success (when flushing, or if more input is needed but not
1062// available, and/or there's more output to be written but the output buffer
1063// is full).
1064// MZ_STREAM_END if all input has been consumed and all output bytes have been
1065// written. Don't call mz_deflate() on the stream anymore.
1066// MZ_STREAM_ERROR if the stream is bogus.
1067// MZ_PARAM_ERROR if one of the parameters is invalid.
1068// MZ_BUF_ERROR if no forward progress is possible because the input and/or
1069// output buffers are empty. (Fill up the input buffer or free up some output
1070// space and try again.)
1071int mz_deflate(mz_streamp pStream, int flush);
1072
1073// mz_deflateEnd() deinitializes a compressor:
1074// Return values:
1075// MZ_OK on success.
1076// MZ_STREAM_ERROR if the stream is bogus.
1077int mz_deflateEnd(mz_streamp pStream);
1078
1079// mz_deflateBound() returns a (very) conservative upper bound on the amount of
1080// data that could be generated by deflate(), assuming flush is set to only
1081// MZ_NO_FLUSH or MZ_FINISH.
1082mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
1083
1084// Single-call compression functions mz_compress() and mz_compress2():
1085// Returns MZ_OK on success, or one of the error codes from mz_deflate() on
1086// failure.
1087int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
1088 const unsigned char *pSource, mz_ulong source_len);
1089int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
1090 const unsigned char *pSource, mz_ulong source_len, int level);
1091
1092// mz_compressBound() returns a (very) conservative upper bound on the amount of
1093// data that could be generated by calling mz_compress().
1094mz_ulong mz_compressBound(mz_ulong source_len);
1095
1096// Initializes a decompressor.
1097int mz_inflateInit(mz_streamp pStream);
1098
1099// mz_inflateInit2() is like mz_inflateInit() with an additional option that
1100// controls the window size and whether or not the stream has been wrapped with
1101// a zlib header/footer:
1102// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or
1103// -MZ_DEFAULT_WINDOW_BITS (raw deflate).
1104int mz_inflateInit2(mz_streamp pStream, int window_bits);
1105
1106// Decompresses the input stream to the output, consuming only as much of the
1107// input as needed, and writing as much to the output as possible.
1108// Parameters:
1109// pStream is the stream to read from and write to. You must initialize/update
1110// the next_in, avail_in, next_out, and avail_out members.
1111// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH.
1112// On the first call, if flush is MZ_FINISH it's assumed the input and output
1113// buffers are both sized large enough to decompress the entire stream in a
1114// single call (this is slightly faster).
1115// MZ_FINISH implies that there are no more source bytes available beside
1116// what's already in the input buffer, and that the output buffer is large
1117// enough to hold the rest of the decompressed data.
1118// Return values:
1119// MZ_OK on success. Either more input is needed but not available, and/or
1120// there's more output to be written but the output buffer is full.
1121// MZ_STREAM_END if all needed input has been consumed and all output bytes
1122// have been written. For zlib streams, the adler-32 of the decompressed data
1123// has also been verified.
1124// MZ_STREAM_ERROR if the stream is bogus.
1125// MZ_DATA_ERROR if the deflate stream is invalid.
1126// MZ_PARAM_ERROR if one of the parameters is invalid.
1127// MZ_BUF_ERROR if no forward progress is possible because the input buffer is
1128// empty but the inflater needs more input to continue, or if the output
1129// buffer is not large enough. Call mz_inflate() again
1130// with more input data, or with more room in the output buffer (except when
1131// using single call decompression, described above).
1132int mz_inflate(mz_streamp pStream, int flush);
1133
1134// Deinitializes a decompressor.
1135int mz_inflateEnd(mz_streamp pStream);
1136
1137// Single-call decompression.
1138// Returns MZ_OK on success, or one of the error codes from mz_inflate() on
1139// failure.
1140int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
1141 const unsigned char *pSource, mz_ulong source_len);
1142
1143// Returns a string description of the specified error code, or NULL if the
1144// error code is invalid.
1145const char *mz_error(int err);
1146
1147// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used
1148// as a drop-in replacement for the subset of zlib that miniz.c supports.
1149// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you
1150// use zlib in the same project.
1151#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
1152typedef unsigned char Byte;
1153typedef unsigned int uInt;
1154typedef mz_ulong uLong;
1155typedef Byte Bytef;
1156typedef uInt uIntf;
1157typedef char charf;
1158typedef int intf;
1159typedef void *voidpf;
1160typedef uLong uLongf;
1161typedef void *voidp;
1162typedef void *const voidpc;
1163#define Z_NULL 0
1164#define Z_NO_FLUSH MZ_NO_FLUSH
1165#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
1166#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
1167#define Z_FULL_FLUSH MZ_FULL_FLUSH
1168#define Z_FINISH MZ_FINISH
1169#define Z_BLOCK MZ_BLOCK
1170#define Z_OK MZ_OK
1171#define Z_STREAM_END MZ_STREAM_END
1172#define Z_NEED_DICT MZ_NEED_DICT
1173#define Z_ERRNO MZ_ERRNO
1174#define Z_STREAM_ERROR MZ_STREAM_ERROR
1175#define Z_DATA_ERROR MZ_DATA_ERROR
1176#define Z_MEM_ERROR MZ_MEM_ERROR
1177#define Z_BUF_ERROR MZ_BUF_ERROR
1178#define Z_VERSION_ERROR MZ_VERSION_ERROR
1179#define Z_PARAM_ERROR MZ_PARAM_ERROR
1180#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
1181#define Z_BEST_SPEED MZ_BEST_SPEED
1182#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
1183#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
1184#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
1185#define Z_FILTERED MZ_FILTERED
1186#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
1187#define Z_RLE MZ_RLE
1188#define Z_FIXED MZ_FIXED
1189#define Z_DEFLATED MZ_DEFLATED
1190#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
1191#define alloc_func mz_alloc_func
1192#define free_func mz_free_func
1193#define internal_state mz_internal_state
1194#define z_stream mz_stream
1195#define deflateInit mz_deflateInit
1196#define deflateInit2 mz_deflateInit2
1197#define deflateReset mz_deflateReset
1198#define deflate mz_deflate
1199#define deflateEnd mz_deflateEnd
1200#define deflateBound mz_deflateBound
1201#define compress mz_compress
1202#define compress2 mz_compress2
1203#define compressBound mz_compressBound
1204#define inflateInit mz_inflateInit
1205#define inflateInit2 mz_inflateInit2
1206#define inflate mz_inflate
1207#define inflateEnd mz_inflateEnd
1208#define uncompress mz_uncompress
1209#define crc32 mz_crc32
1210#define adler32 mz_adler32
1211#define MAX_WBITS 15
1212#define MAX_MEM_LEVEL 9
1213#define zError mz_error
1214#define ZLIB_VERSION MZ_VERSION
1215#define ZLIB_VERNUM MZ_VERNUM
1216#define ZLIB_VER_MAJOR MZ_VER_MAJOR
1217#define ZLIB_VER_MINOR MZ_VER_MINOR
1218#define ZLIB_VER_REVISION MZ_VER_REVISION
1219#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
1220#define zlibVersion mz_version
1221#define zlib_version mz_version()
1222#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
1223
1224#endif // MINIZ_NO_ZLIB_APIS
1225
1226// ------------------- Types and macros
1227
1228typedef unsigned char mz_uint8;
1229typedef signed short mz_int16;
1230typedef unsigned short mz_uint16;
1231typedef unsigned int mz_uint32;
1232typedef unsigned int mz_uint;
1233typedef long long mz_int64;
1234typedef unsigned long long mz_uint64;
1235typedef int mz_bool;
1236
1237#define MZ_FALSE (0)
1238#define MZ_TRUE (1)
1239
1240// An attempt to work around MSVC's spammy "warning C4127: conditional
1241// expression is constant" message.
1242#ifdef _MSC_VER
1243#define MZ_MACRO_END while (0, 0)
1244#else
1245#define MZ_MACRO_END while (0)
1246#endif
1247
1248// ------------------- ZIP archive reading/writing
1249
1250#ifndef MINIZ_NO_ARCHIVE_APIS
1251
1252enum {
1253 MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
1254 MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
1255 MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
1256};
1257
1258typedef struct {
1259 mz_uint32 m_file_index;
1260 mz_uint32 m_central_dir_ofs;
1261 mz_uint16 m_version_made_by;
1262 mz_uint16 m_version_needed;
1263 mz_uint16 m_bit_flag;
1264 mz_uint16 m_method;
1265#ifndef MINIZ_NO_TIME
1266 time_t m_time;
1267#endif
1268 mz_uint32 m_crc32;
1269 mz_uint64 m_comp_size;
1270 mz_uint64 m_uncomp_size;
1271 mz_uint16 m_internal_attr;
1272 mz_uint32 m_external_attr;
1273 mz_uint64 m_local_header_ofs;
1274 mz_uint32 m_comment_size;
1275 char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
1276 char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
1277} mz_zip_archive_file_stat;
1278
1279typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
1280 void *pBuf, size_t n);
1281typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
1282 const void *pBuf, size_t n);
1283
1284struct mz_zip_internal_state_tag;
1285typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
1286
1287typedef enum {
1288 MZ_ZIP_MODE_INVALID = 0,
1289 MZ_ZIP_MODE_READING = 1,
1290 MZ_ZIP_MODE_WRITING = 2,
1291 MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
1292} mz_zip_mode;
1293
1294typedef struct mz_zip_archive_tag {
1295 mz_uint64 m_archive_size;
1296 mz_uint64 m_central_directory_file_ofs;
1297 mz_uint m_total_files;
1298 mz_zip_mode m_zip_mode;
1299
1300 mz_uint m_file_offset_alignment;
1301
1302 mz_alloc_func m_pAlloc;
1303 mz_free_func m_pFree;
1304 mz_realloc_func m_pRealloc;
1305 void *m_pAlloc_opaque;
1306
1307 mz_file_read_func m_pRead;
1308 mz_file_write_func m_pWrite;
1309 void *m_pIO_opaque;
1310
1311 mz_zip_internal_state *m_pState;
1312
1313} mz_zip_archive;
1314
1315typedef enum {
1316 MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
1317 MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
1318 MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
1319 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
1320} mz_zip_flags;
1321
1322// ZIP archive reading
1323
1324// Inits a ZIP archive reader.
1325// These functions read and validate the archive's central directory.
1326mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
1327 mz_uint32 flags);
1328mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
1329 size_t size, mz_uint32 flags);
1330
1331#ifndef MINIZ_NO_STDIO
1332mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
1333 mz_uint32 flags);
1334#endif
1335
1336// Returns the total number of files in the archive.
1337mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
1338
1339// Returns detailed information about an archive file entry.
1340mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
1341 mz_zip_archive_file_stat *pStat);
1342
1343// Determines if an archive file entry is a directory entry.
1344mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
1345 mz_uint file_index);
1346mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
1347 mz_uint file_index);
1348
1349// Retrieves the filename of an archive file entry.
1350// Returns the number of bytes written to pFilename, or if filename_buf_size is
1351// 0 this function returns the number of bytes needed to fully store the
1352// filename.
1353mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
1354 char *pFilename, mz_uint filename_buf_size);
1355
1356// Attempts to locates a file in the archive's central directory.
1357// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
1358// Returns -1 if the file cannot be found.
1359int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
1360 const char *pComment, mz_uint flags);
1361
1362// Extracts a archive file to a memory buffer using no memory allocation.
1363mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
1364 mz_uint file_index, void *pBuf,
1365 size_t buf_size, mz_uint flags,
1366 void *pUser_read_buf,
1367 size_t user_read_buf_size);
1368mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
1369 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
1370 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
1371
1372// Extracts a archive file to a memory buffer.
1373mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
1374 void *pBuf, size_t buf_size,
1375 mz_uint flags);
1376mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
1377 const char *pFilename, void *pBuf,
1378 size_t buf_size, mz_uint flags);
1379
1380// Extracts a archive file to a dynamically allocated heap buffer.
1381void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
1382 size_t *pSize, mz_uint flags);
1383void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
1384 const char *pFilename, size_t *pSize,
1385 mz_uint flags);
1386
1387// Extracts a archive file using a callback function to output the file's data.
1388mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
1389 mz_uint file_index,
1390 mz_file_write_func pCallback,
1391 void *pOpaque, mz_uint flags);
1392mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
1393 const char *pFilename,
1394 mz_file_write_func pCallback,
1395 void *pOpaque, mz_uint flags);
1396
1397#ifndef MINIZ_NO_STDIO
1398// Extracts a archive file to a disk file and sets its last accessed and
1399// modified times.
1400// This function only extracts files, not archive directory records.
1401mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
1402 const char *pDst_filename, mz_uint flags);
1403mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
1404 const char *pArchive_filename,
1405 const char *pDst_filename,
1406 mz_uint flags);
1407#endif
1408
1409// Ends archive reading, freeing all allocations, and closing the input archive
1410// file if mz_zip_reader_init_file() was used.
1411mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
1412
1413// ZIP archive writing
1414
1415#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
1416
1417// Inits a ZIP archive writer.
1418mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
1419mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
1420 size_t size_to_reserve_at_beginning,
1421 size_t initial_allocation_size);
1422
1423#ifndef MINIZ_NO_STDIO
1424mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
1425 mz_uint64 size_to_reserve_at_beginning);
1426#endif
1427
1428// Converts a ZIP archive reader object into a writer object, to allow efficient
1429// in-place file appends to occur on an existing archive.
1430// For archives opened using mz_zip_reader_init_file, pFilename must be the
1431// archive's filename so it can be reopened for writing. If the file can't be
1432// reopened, mz_zip_reader_end() will be called.
1433// For archives opened using mz_zip_reader_init_mem, the memory block must be
1434// growable using the realloc callback (which defaults to realloc unless you've
1435// overridden it).
1436// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's
1437// user provided m_pWrite function cannot be NULL.
1438// Note: In-place archive modification is not recommended unless you know what
1439// you're doing, because if execution stops or something goes wrong before
1440// the archive is finalized the file's central directory will be hosed.
1441mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
1442 const char *pFilename);
1443
1444// Adds the contents of a memory buffer to an archive. These functions record
1445// the current local time into the archive.
1446// To add a directory entry, call this method with an archive name ending in a
1447// forwardslash with empty buffer.
1448// level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1449// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1450// just set to MZ_DEFAULT_COMPRESSION.
1451mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
1452 const void *pBuf, size_t buf_size,
1453 mz_uint level_and_flags);
1454mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
1455 const char *pArchive_name, const void *pBuf,
1456 size_t buf_size, const void *pComment,
1457 mz_uint16 comment_size,
1458 mz_uint level_and_flags, mz_uint64 uncomp_size,
1459 mz_uint32 uncomp_crc32);
1460
1461#ifndef MINIZ_NO_STDIO
1462// Adds the contents of a disk file to an archive. This function also records
1463// the disk file's modified time into the archive.
1464// level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1465// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1466// just set to MZ_DEFAULT_COMPRESSION.
1467mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
1468 const char *pSrc_filename, const void *pComment,
1469 mz_uint16 comment_size, mz_uint level_and_flags);
1470#endif
1471
1472// Adds a file to an archive by fully cloning the data from another archive.
1473// This function fully clones the source file's compressed data (no
1474// recompression), along with its full filename, extra data, and comment fields.
1475mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
1476 mz_zip_archive *pSource_zip,
1477 mz_uint file_index);
1478
1479// Finalizes the archive by writing the central directory records followed by
1480// the end of central directory record.
1481// After an archive is finalized, the only valid call on the mz_zip_archive
1482// struct is mz_zip_writer_end().
1483// An archive must be manually finalized by calling this function for it to be
1484// valid.
1485mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
1486mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
1487 size_t *pSize);
1488
1489// Ends archive writing, freeing all allocations, and closing the output file if
1490// mz_zip_writer_init_file() was used.
1491// Note for the archive to be valid, it must have been finalized before ending.
1492mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
1493
1494// Misc. high-level helper functions:
1495
1496// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically)
1497// appends a memory blob to a ZIP archive.
1498// level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1499// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1500// just set to MZ_DEFAULT_COMPRESSION.
1501mz_bool mz_zip_add_mem_to_archive_file_in_place(
1502 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
1503 size_t buf_size, const void *pComment, mz_uint16 comment_size,
1504 mz_uint level_and_flags);
1505
1506// Reads a single file from an archive into a heap block.
1507// Returns NULL on failure.
1508void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
1509 const char *pArchive_name,
1510 size_t *pSize, mz_uint zip_flags);
1511
1512#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
1513
1514#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
1515
1516// ------------------- Low-level Decompression API Definitions
1517
1518// Decompression flags used by tinfl_decompress().
1519// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and
1520// ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the
1521// input is a raw deflate stream.
1522// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available
1523// beyond the end of the supplied input buffer. If clear, the input buffer
1524// contains all remaining input.
1525// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large
1526// enough to hold the entire decompressed stream. If clear, the output buffer is
1527// at least the size of the dictionary (typically 32KB).
1528// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the
1529// decompressed bytes.
1530enum {
1531 TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
1532 TINFL_FLAG_HAS_MORE_INPUT = 2,
1533 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
1534 TINFL_FLAG_COMPUTE_ADLER32 = 8
1535};
1536
1537// High level decompression functions:
1538// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block
1539// allocated via malloc().
1540// On entry:
1541// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data
1542// to decompress.
1543// On return:
1544// Function returns a pointer to the decompressed data, or NULL on failure.
1545// *pOut_len will be set to the decompressed data's size, which could be larger
1546// than src_buf_len on uncompressible data.
1547// The caller must call mz_free() on the returned block when it's no longer
1548// needed.
1549void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
1550 size_t *pOut_len, int flags);
1551
1552// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block
1553// in memory.
1554// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes
1555// written on success.
1556#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
1557size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
1558 const void *pSrc_buf, size_t src_buf_len,
1559 int flags);
1560
1561// tinfl_decompress_mem_to_callback() decompresses a block in memory to an
1562// internal 32KB buffer, and a user provided callback function will be called to
1563// flush the buffer.
1564// Returns 1 on success or 0 on failure.
1565typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);
1566int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
1567 tinfl_put_buf_func_ptr pPut_buf_func,
1568 void *pPut_buf_user, int flags);
1569
1570struct tinfl_decompressor_tag;
1571typedef struct tinfl_decompressor_tag tinfl_decompressor;
1572
1573// Max size of LZ dictionary.
1574#define TINFL_LZ_DICT_SIZE 32768
1575
1576// Return status.
1577typedef enum {
1578 TINFL_STATUS_BAD_PARAM = -3,
1579 TINFL_STATUS_ADLER32_MISMATCH = -2,
1580 TINFL_STATUS_FAILED = -1,
1581 TINFL_STATUS_DONE = 0,
1582 TINFL_STATUS_NEEDS_MORE_INPUT = 1,
1583 TINFL_STATUS_HAS_MORE_OUTPUT = 2
1584} tinfl_status;
1585
1586// Initializes the decompressor to its initial state.
1587#define tinfl_init(r) \
1588 do { \
1589 (r)->m_state = 0; \
1590 } \
1591 MZ_MACRO_END
1592#define tinfl_get_adler32(r) (r)->m_check_adler32
1593
1594// Main low-level decompressor coroutine function. This is the only function
1595// actually needed for decompression. All the other functions are just
1596// high-level helpers for improved usability.
1597// This is a universal API, i.e. it can be used as a building block to build any
1598// desired higher level decompression API. In the limit case, it can be called
1599// once per every byte input or output.
1600tinfl_status tinfl_decompress(tinfl_decompressor *r,
1601 const mz_uint8 *pIn_buf_next,
1602 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
1603 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
1604 const mz_uint32 decomp_flags);
1605
1606// Internal/private bits follow.
1607enum {
1608 TINFL_MAX_HUFF_TABLES = 3,
1609 TINFL_MAX_HUFF_SYMBOLS_0 = 288,
1610 TINFL_MAX_HUFF_SYMBOLS_1 = 32,
1611 TINFL_MAX_HUFF_SYMBOLS_2 = 19,
1612 TINFL_FAST_LOOKUP_BITS = 10,
1613 TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
1614};
1615
1616typedef struct {
1617 mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
1618 mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE],
1619 m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
1620} tinfl_huff_table;
1621
1622#if MINIZ_HAS_64BIT_REGISTERS
1623#define TINFL_USE_64BIT_BITBUF 1
1624#endif
1625
1626#if TINFL_USE_64BIT_BITBUF
1627typedef mz_uint64 tinfl_bit_buf_t;
1628#define TINFL_BITBUF_SIZE (64)
1629#else
1630typedef mz_uint32 tinfl_bit_buf_t;
1631#define TINFL_BITBUF_SIZE (32)
1632#endif
1633
1634struct tinfl_decompressor_tag {
1635 mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type,
1636 m_check_adler32, m_dist, m_counter, m_num_extra,
1637 m_table_sizes[TINFL_MAX_HUFF_TABLES];
1638 tinfl_bit_buf_t m_bit_buf;
1639 size_t m_dist_from_out_buf_start;
1640 tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
1641 mz_uint8 m_raw_header[4],
1642 m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
1643};
1644
1645// ------------------- Low-level Compression API Definitions
1646
1647// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly
1648// slower, and raw/dynamic blocks will be output more frequently).
1649#define TDEFL_LESS_MEMORY 0
1650
1651// tdefl_init() compression flags logically OR'd together (low 12 bits contain
1652// the max. number of probes per dictionary search):
1653// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes
1654// per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap
1655// compression), 4095=Huffman+LZ (slowest/best compression).
1656enum {
1657 TDEFL_HUFFMAN_ONLY = 0,
1658 TDEFL_DEFAULT_MAX_PROBES = 128,
1659 TDEFL_MAX_PROBES_MASK = 0xFFF
1660};
1661
1662// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before
1663// the deflate data, and the Adler-32 of the source data at the end. Otherwise,
1664// you'll get raw deflate data.
1665// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even
1666// when not writing zlib headers).
1667// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more
1668// efficient lazy parsing.
1669// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's
1670// initialization time to the minimum, but the output may vary from run to run
1671// given the same input (depending on the contents of memory).
1672// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
1673// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
1674// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
1675// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
1676// The low 12 bits are reserved to control the max # of hash probes per
1677// dictionary lookup (see TDEFL_MAX_PROBES_MASK).
1678enum {
1679 TDEFL_WRITE_ZLIB_HEADER = 0x01000,
1680 TDEFL_COMPUTE_ADLER32 = 0x02000,
1681 TDEFL_GREEDY_PARSING_FLAG = 0x04000,
1682 TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
1683 TDEFL_RLE_MATCHES = 0x10000,
1684 TDEFL_FILTER_MATCHES = 0x20000,
1685 TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
1686 TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
1687};
1688
1689// High level compression functions:
1690// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block
1691// allocated via malloc().
1692// On entry:
1693// pSrc_buf, src_buf_len: Pointer and size of source block to compress.
1694// flags: The max match finder probes (default is 128) logically OR'd against
1695// the above flags. Higher probes are slower but improve compression.
1696// On return:
1697// Function returns a pointer to the compressed data, or NULL on failure.
1698// *pOut_len will be set to the compressed data's size, which could be larger
1699// than src_buf_len on uncompressible data.
1700// The caller must free() the returned block when it's no longer needed.
1701void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
1702 size_t *pOut_len, int flags);
1703
1704// tdefl_compress_mem_to_mem() compresses a block in memory to another block in
1705// memory.
1706// Returns 0 on failure.
1707size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
1708 const void *pSrc_buf, size_t src_buf_len,
1709 int flags);
1710
1711// Compresses an image to a compressed PNG file in memory.
1712// On entry:
1713// pImage, w, h, and num_chans describe the image to compress. num_chans may be
1714// 1, 2, 3, or 4.
1715// The image pitch in bytes per scanline will be w*num_chans. The leftmost
1716// pixel on the top scanline is stored first in memory.
1717// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED,
1718// MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL
1719// If flip is true, the image will be flipped on the Y axis (useful for OpenGL
1720// apps).
1721// On return:
1722// Function returns a pointer to the compressed data, or NULL on failure.
1723// *pLen_out will be set to the size of the PNG image file.
1724// The caller must mz_free() the returned heap block (which will typically be
1725// larger than *pLen_out) when it's no longer needed.
1726void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
1727 int h, int num_chans,
1728 size_t *pLen_out,
1729 mz_uint level, mz_bool flip);
1730void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
1731 int num_chans, size_t *pLen_out);
1732
1733// Output stream interface. The compressor uses this interface to write
1734// compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
1735typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len,
1736 void *pUser);
1737
1738// tdefl_compress_mem_to_output() compresses a block to an output stream. The
1739// above helpers use this function internally.
1740mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
1741 tdefl_put_buf_func_ptr pPut_buf_func,
1742 void *pPut_buf_user, int flags);
1743
1744enum {
1745 TDEFL_MAX_HUFF_TABLES = 3,
1746 TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
1747 TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
1748 TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
1749 TDEFL_LZ_DICT_SIZE = 32768,
1750 TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
1751 TDEFL_MIN_MATCH_LEN = 3,
1752 TDEFL_MAX_MATCH_LEN = 258
1753};
1754
1755// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed
1756// output block (using static/fixed Huffman codes).
1757#if TDEFL_LESS_MEMORY
1758enum {
1759 TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,
1760 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
1761 TDEFL_MAX_HUFF_SYMBOLS = 288,
1762 TDEFL_LZ_HASH_BITS = 12,
1763 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
1764 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
1765 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
1766};
1767#else
1768enum {
1769 TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
1770 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
1771 TDEFL_MAX_HUFF_SYMBOLS = 288,
1772 TDEFL_LZ_HASH_BITS = 15,
1773 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
1774 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
1775 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
1776};
1777#endif
1778
1779// The low-level tdefl functions below may be used directly if the above helper
1780// functions aren't flexible enough. The low-level functions don't make any heap
1781// allocations, unlike the above helper functions.
1782typedef enum {
1783 TDEFL_STATUS_BAD_PARAM = -2,
1784 TDEFL_STATUS_PUT_BUF_FAILED = -1,
1785 TDEFL_STATUS_OKAY = 0,
1786 TDEFL_STATUS_DONE = 1
1787} tdefl_status;
1788
1789// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
1790typedef enum {
1791 TDEFL_NO_FLUSH = 0,
1792 TDEFL_SYNC_FLUSH = 2,
1793 TDEFL_FULL_FLUSH = 3,
1794 TDEFL_FINISH = 4
1795} tdefl_flush;
1796
1797// tdefl's compression state structure.
1798typedef struct {
1799 tdefl_put_buf_func_ptr m_pPut_buf_func;
1800 void *m_pPut_buf_user;
1801 mz_uint m_flags, m_max_probes[2];
1802 int m_greedy_parsing;
1803 mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
1804 mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
1805 mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in,
1806 m_bit_buffer;
1807 mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit,
1808 m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index,
1809 m_wants_to_finish;
1810 tdefl_status m_prev_return_status;
1811 const void *m_pIn_buf;
1812 void *m_pOut_buf;
1813 size_t *m_pIn_buf_size, *m_pOut_buf_size;
1814 tdefl_flush m_flush;
1815 const mz_uint8 *m_pSrc;
1816 size_t m_src_buf_left, m_out_buf_ofs;
1817 mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
1818 mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1819 mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1820 mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1821 mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
1822 mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
1823 mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
1824 mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
1825} tdefl_compressor;
1826
1827// Initializes the compressor.
1828// There is no corresponding deinit() function because the tdefl API's do not
1829// dynamically allocate memory.
1830// pBut_buf_func: If NULL, output data will be supplied to the specified
1831// callback. In this case, the user should call the tdefl_compress_buffer() API
1832// for compression.
1833// If pBut_buf_func is NULL the user should always call the tdefl_compress()
1834// API.
1835// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER,
1836// etc.)
1837tdefl_status tdefl_init(tdefl_compressor *d,
1838 tdefl_put_buf_func_ptr pPut_buf_func,
1839 void *pPut_buf_user, int flags);
1840
1841// Compresses a block of data, consuming as much of the specified input buffer
1842// as possible, and writing as much compressed data to the specified output
1843// buffer as possible.
1844tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
1845 size_t *pIn_buf_size, void *pOut_buf,
1846 size_t *pOut_buf_size, tdefl_flush flush);
1847
1848// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a
1849// non-NULL tdefl_put_buf_func_ptr.
1850// tdefl_compress_buffer() always consumes the entire input buffer.
1851tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
1852 size_t in_buf_size, tdefl_flush flush);
1853
1854tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
1855mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
1856
1857// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't
1858// defined, because it uses some of its macros.
1859#ifndef MINIZ_NO_ZLIB_APIS
1860// Create tdefl_compress() flags given zlib-style compression parameters.
1861// level may range from [0,10] (where 10 is absolute max compression, but may be
1862// much slower on some files)
1863// window_bits may be -15 (raw deflate) or 15 (zlib)
1864// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY,
1865// MZ_RLE, or MZ_FIXED
1866mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
1867 int strategy);
1868#endif // #ifndef MINIZ_NO_ZLIB_APIS
1869
1870#ifdef __cplusplus
1871}
1872#endif
1873
1874#endif // MINIZ_HEADER_INCLUDED
1875
1876// ------------------- End of Header: Implementation follows. (If you only want
1877// the header, define MINIZ_HEADER_FILE_ONLY.)
1878
1879#ifndef MINIZ_HEADER_FILE_ONLY
1880
1881typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
1882typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
1883typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
1884
1885//#include <assert.h>
1886//#include <string.h>
1887
1888#define MZ_ASSERT(x) assert(x)
1889
1890#ifdef MINIZ_NO_MALLOC
1891#define MZ_MALLOC(x) NULL
1892#define MZ_FREE(x) (void)x, ((void)0)
1893#define MZ_REALLOC(p, x) NULL
1894#else
1895#define MZ_MALLOC(x) malloc(x)
1896#define MZ_FREE(x) free(x)
1897#define MZ_REALLOC(p, x) realloc(p, x)
1898#endif
1899
1900#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b))
1901#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b))
1902#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
1903
1904#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1905#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
1906#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
1907#else
1908#define MZ_READ_LE16(p) \
1909 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
1910 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
1911#define MZ_READ_LE32(p) \
1912 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
1913 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \
1914 ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \
1915 ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
1916#endif
1917
1918#ifdef _MSC_VER
1919#define MZ_FORCEINLINE __forceinline
1920#elif defined(__GNUC__)
1921#define MZ_FORCEINLINE inline __attribute__((__always_inline__))
1922#else
1923#define MZ_FORCEINLINE inline
1924#endif
1925
1926#ifdef __cplusplus
1927extern "C" {
1928#endif
1929
1930// ------------------- zlib-style API's
1931
1932mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) {
1933 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);
1934 size_t block_len = buf_len % 5552;
1935 if (!ptr) return MZ_ADLER32_INIT;
1936 while (buf_len) {
1937 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
1938 s1 += ptr[0], s2 += s1;
1939 s1 += ptr[1], s2 += s1;
1940 s1 += ptr[2], s2 += s1;
1941 s1 += ptr[3], s2 += s1;
1942 s1 += ptr[4], s2 += s1;
1943 s1 += ptr[5], s2 += s1;
1944 s1 += ptr[6], s2 += s1;
1945 s1 += ptr[7], s2 += s1;
1946 }
1947 for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
1948 s1 %= 65521U, s2 %= 65521U;
1949 buf_len -= block_len;
1950 block_len = 5552;
1951 }
1952 return (s2 << 16) + s1;
1953}
1954
1955// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C
1956// implementation that balances processor cache usage against speed":
1957// http://www.geocities.com/malbrain/
1958mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) {
1959 static const mz_uint32 s_crc32[16] = {
1960 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4,
1961 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
1962 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c};
1963 mz_uint32 crcu32 = (mz_uint32)crc;
1964 if (!ptr) return MZ_CRC32_INIT;
1965 crcu32 = ~crcu32;
1966 while (buf_len--) {
1967 mz_uint8 b = *ptr++;
1968 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
1969 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
1970 }
1971 return ~crcu32;
1972}
1973
1974void mz_free(void *p) { MZ_FREE(p); }
1975
1976#ifndef MINIZ_NO_ZLIB_APIS
1977
1978static void *def_alloc_func(void *opaque, size_t items, size_t size) {
1979 (void)opaque, (void)items, (void)size;
1980 return MZ_MALLOC(items * size);
1981}
1982static void def_free_func(void *opaque, void *address) {
1983 (void)opaque, (void)address;
1984 MZ_FREE(address);
1985}
1986// static void *def_realloc_func(void *opaque, void *address, size_t items,
1987// size_t size) {
1988// (void)opaque, (void)address, (void)items, (void)size;
1989// return MZ_REALLOC(address, items * size);
1990//}
1991
1992const char *mz_version(void) { return MZ_VERSION; }
1993
1994int mz_deflateInit(mz_streamp pStream, int level) {
1995 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9,
1996 MZ_DEFAULT_STRATEGY);
1997}
1998
1999int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
2000 int mem_level, int strategy) {
2001 tdefl_compressor *pComp;
2002 mz_uint comp_flags =
2003 TDEFL_COMPUTE_ADLER32 |
2004 tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
2005
2006 if (!pStream) return MZ_STREAM_ERROR;
2007 if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) ||
2008 ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
2009 (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
2010 return MZ_PARAM_ERROR;
2011
2012 pStream->data_type = 0;
2013 pStream->adler = MZ_ADLER32_INIT;
2014 pStream->msg = NULL;
2015 pStream->reserved = 0;
2016 pStream->total_in = 0;
2017 pStream->total_out = 0;
2018 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
2019 if (!pStream->zfree) pStream->zfree = def_free_func;
2020
2021 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1,
2022 sizeof(tdefl_compressor));
2023 if (!pComp) return MZ_MEM_ERROR;
2024
2025 pStream->state = (struct mz_internal_state *)pComp;
2026
2027 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) {
2028 mz_deflateEnd(pStream);
2029 return MZ_PARAM_ERROR;
2030 }
2031
2032 return MZ_OK;
2033}
2034
2035int mz_deflateReset(mz_streamp pStream) {
2036 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) ||
2037 (!pStream->zfree))
2038 return MZ_STREAM_ERROR;
2039 pStream->total_in = pStream->total_out = 0;
2040 tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL,
2041 ((tdefl_compressor *)pStream->state)->m_flags);
2042 return MZ_OK;
2043}
2044
2045int mz_deflate(mz_streamp pStream, int flush) {
2046 size_t in_bytes, out_bytes;
2047 mz_ulong orig_total_in, orig_total_out;
2048 int mz_status = MZ_OK;
2049
2050 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) ||
2051 (!pStream->next_out))
2052 return MZ_STREAM_ERROR;
2053 if (!pStream->avail_out) return MZ_BUF_ERROR;
2054
2055 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
2056
2057 if (((tdefl_compressor *)pStream->state)->m_prev_return_status ==
2058 TDEFL_STATUS_DONE)
2059 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
2060
2061 orig_total_in = pStream->total_in;
2062 orig_total_out = pStream->total_out;
2063 for (;;) {
2064 tdefl_status defl_status;
2065 in_bytes = pStream->avail_in;
2066 out_bytes = pStream->avail_out;
2067
2068 defl_status = tdefl_compress((tdefl_compressor *)pStream->state,
2069 pStream->next_in, &in_bytes, pStream->next_out,
2070 &out_bytes, (tdefl_flush)flush);
2071 pStream->next_in += (mz_uint)in_bytes;
2072 pStream->avail_in -= (mz_uint)in_bytes;
2073 pStream->total_in += (mz_uint)in_bytes;
2074 pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);
2075
2076 pStream->next_out += (mz_uint)out_bytes;
2077 pStream->avail_out -= (mz_uint)out_bytes;
2078 pStream->total_out += (mz_uint)out_bytes;
2079
2080 if (defl_status < 0) {
2081 mz_status = MZ_STREAM_ERROR;
2082 break;
2083 } else if (defl_status == TDEFL_STATUS_DONE) {
2084 mz_status = MZ_STREAM_END;
2085 break;
2086 } else if (!pStream->avail_out)
2087 break;
2088 else if ((!pStream->avail_in) && (flush != MZ_FINISH)) {
2089 if ((flush) || (pStream->total_in != orig_total_in) ||
2090 (pStream->total_out != orig_total_out))
2091 break;
2092 return MZ_BUF_ERROR; // Can't make forward progress without some input.
2093 }
2094 }
2095 return mz_status;
2096}
2097
2098int mz_deflateEnd(mz_streamp pStream) {
2099 if (!pStream) return MZ_STREAM_ERROR;
2100 if (pStream->state) {
2101 pStream->zfree(pStream->opaque, pStream->state);
2102 pStream->state = NULL;
2103 }
2104 return MZ_OK;
2105}
2106
2107mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) {
2108 (void)pStream;
2109 // This is really over conservative. (And lame, but it's actually pretty
2110 // tricky to compute a true upper bound given the way tdefl's blocking works.)
2111 return MZ_MAX(128 + (source_len * 110) / 100,
2112 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
2113}
2114
2115int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
2116 const unsigned char *pSource, mz_ulong source_len, int level) {
2117 int status;
2118 mz_stream stream;
2119 memset(&stream, 0, sizeof(stream));
2120
2121 // In case mz_ulong is 64-bits (argh I hate longs).
2122 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
2123
2124 stream.next_in = pSource;
2125 stream.avail_in = (mz_uint32)source_len;
2126 stream.next_out = pDest;
2127 stream.avail_out = (mz_uint32)*pDest_len;
2128
2129 status = mz_deflateInit(&stream, level);
2130 if (status != MZ_OK) return status;
2131
2132 status = mz_deflate(&stream, MZ_FINISH);
2133 if (status != MZ_STREAM_END) {
2134 mz_deflateEnd(&stream);
2135 return (status == MZ_OK) ? MZ_BUF_ERROR : status;
2136 }
2137
2138 *pDest_len = stream.total_out;
2139 return mz_deflateEnd(&stream);
2140}
2141
2142int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
2143 const unsigned char *pSource, mz_ulong source_len) {
2144 return mz_compress2(pDest, pDest_len, pSource, source_len,
2145 MZ_DEFAULT_COMPRESSION);
2146}
2147
2148mz_ulong mz_compressBound(mz_ulong source_len) {
2149 return mz_deflateBound(NULL, source_len);
2150}
2151
2152typedef struct {
2153 tinfl_decompressor m_decomp;
2154 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;
2155 int m_window_bits;
2156 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
2157 tinfl_status m_last_status;
2158} inflate_state;
2159
2160int mz_inflateInit2(mz_streamp pStream, int window_bits) {
2161 inflate_state *pDecomp;
2162 if (!pStream) return MZ_STREAM_ERROR;
2163 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
2164 (-window_bits != MZ_DEFAULT_WINDOW_BITS))
2165 return MZ_PARAM_ERROR;
2166
2167 pStream->data_type = 0;
2168 pStream->adler = 0;
2169 pStream->msg = NULL;
2170 pStream->total_in = 0;
2171 pStream->total_out = 0;
2172 pStream->reserved = 0;
2173 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
2174 if (!pStream->zfree) pStream->zfree = def_free_func;
2175
2176 pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1,
2177 sizeof(inflate_state));
2178 if (!pDecomp) return MZ_MEM_ERROR;
2179
2180 pStream->state = (struct mz_internal_state *)pDecomp;
2181
2182 tinfl_init(&pDecomp->m_decomp);
2183 pDecomp->m_dict_ofs = 0;
2184 pDecomp->m_dict_avail = 0;
2185 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
2186 pDecomp->m_first_call = 1;
2187 pDecomp->m_has_flushed = 0;
2188 pDecomp->m_window_bits = window_bits;
2189
2190 return MZ_OK;
2191}
2192
2193int mz_inflateInit(mz_streamp pStream) {
2194 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
2195}
2196
2197int mz_inflate(mz_streamp pStream, int flush) {
2198 inflate_state *pState;
2199 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
2200 size_t in_bytes, out_bytes, orig_avail_in;
2201 tinfl_status status;
2202
2203 if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
2204 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
2205 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))
2206 return MZ_STREAM_ERROR;
2207
2208 pState = (inflate_state *)pStream->state;
2209 if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
2210 orig_avail_in = pStream->avail_in;
2211
2212 first_call = pState->m_first_call;
2213 pState->m_first_call = 0;
2214 if (pState->m_last_status < 0) return MZ_DATA_ERROR;
2215
2216 if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
2217 pState->m_has_flushed |= (flush == MZ_FINISH);
2218
2219 if ((flush == MZ_FINISH) && (first_call)) {
2220 // MZ_FINISH on the first call implies that the input and output buffers are
2221 // large enough to hold the entire compressed/decompressed file.
2222 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
2223 in_bytes = pStream->avail_in;
2224 out_bytes = pStream->avail_out;
2225 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes,
2226 pStream->next_out, pStream->next_out, &out_bytes,
2227 decomp_flags);
2228 pState->m_last_status = status;
2229 pStream->next_in += (mz_uint)in_bytes;
2230 pStream->avail_in -= (mz_uint)in_bytes;
2231 pStream->total_in += (mz_uint)in_bytes;
2232 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
2233 pStream->next_out += (mz_uint)out_bytes;
2234 pStream->avail_out -= (mz_uint)out_bytes;
2235 pStream->total_out += (mz_uint)out_bytes;
2236
2237 if (status < 0)
2238 return MZ_DATA_ERROR;
2239 else if (status != TINFL_STATUS_DONE) {
2240 pState->m_last_status = TINFL_STATUS_FAILED;
2241 return MZ_BUF_ERROR;
2242 }
2243 return MZ_STREAM_END;
2244 }
2245 // flush != MZ_FINISH then we must assume there's more input.
2246 if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
2247
2248 if (pState->m_dict_avail) {
2249 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
2250 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
2251 pStream->next_out += n;
2252 pStream->avail_out -= n;
2253 pStream->total_out += n;
2254 pState->m_dict_avail -= n;
2255 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
2256 return ((pState->m_last_status == TINFL_STATUS_DONE) &&
2257 (!pState->m_dict_avail))
2258 ? MZ_STREAM_END
2259 : MZ_OK;
2260 }
2261
2262 for (;;) {
2263 in_bytes = pStream->avail_in;
2264 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
2265
2266 status = tinfl_decompress(
2267 &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict,
2268 pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
2269 pState->m_last_status = status;
2270
2271 pStream->next_in += (mz_uint)in_bytes;
2272 pStream->avail_in -= (mz_uint)in_bytes;
2273 pStream->total_in += (mz_uint)in_bytes;
2274 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
2275
2276 pState->m_dict_avail = (mz_uint)out_bytes;
2277
2278 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
2279 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
2280 pStream->next_out += n;
2281 pStream->avail_out -= n;
2282 pStream->total_out += n;
2283 pState->m_dict_avail -= n;
2284 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
2285
2286 if (status < 0)
2287 return MZ_DATA_ERROR; // Stream is corrupted (there could be some
2288 // uncompressed data left in the output dictionary -
2289 // oh well).
2290 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
2291 return MZ_BUF_ERROR; // Signal caller that we can't make forward progress
2292 // without supplying more input or by setting flush
2293 // to MZ_FINISH.
2294 else if (flush == MZ_FINISH) {
2295 // The output buffer MUST be large to hold the remaining uncompressed data
2296 // when flush==MZ_FINISH.
2297 if (status == TINFL_STATUS_DONE)
2298 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
2299 // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's
2300 // at least 1 more byte on the way. If there's no more room left in the
2301 // output buffer then something is wrong.
2302 else if (!pStream->avail_out)
2303 return MZ_BUF_ERROR;
2304 } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) ||
2305 (!pStream->avail_out) || (pState->m_dict_avail))
2306 break;
2307 }
2308
2309 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail))
2310 ? MZ_STREAM_END
2311 : MZ_OK;
2312}
2313
2314int mz_inflateEnd(mz_streamp pStream) {
2315 if (!pStream) return MZ_STREAM_ERROR;
2316 if (pStream->state) {
2317 pStream->zfree(pStream->opaque, pStream->state);
2318 pStream->state = NULL;
2319 }
2320 return MZ_OK;
2321}
2322
2323int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
2324 const unsigned char *pSource, mz_ulong source_len) {
2325 mz_stream stream;
2326 int status;
2327 memset(&stream, 0, sizeof(stream));
2328
2329 // In case mz_ulong is 64-bits (argh I hate longs).
2330 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
2331
2332 stream.next_in = pSource;
2333 stream.avail_in = (mz_uint32)source_len;
2334 stream.next_out = pDest;
2335 stream.avail_out = (mz_uint32)*pDest_len;
2336
2337 status = mz_inflateInit(&stream);
2338 if (status != MZ_OK) return status;
2339
2340 status = mz_inflate(&stream, MZ_FINISH);
2341 if (status != MZ_STREAM_END) {
2342 mz_inflateEnd(&stream);
2343 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR
2344 : status;
2345 }
2346 *pDest_len = stream.total_out;
2347
2348 return mz_inflateEnd(&stream);
2349}
2350
2351const char *mz_error(int err) {
2352 static struct {
2353 int m_err;
2354 const char *m_pDesc;
2355 } s_error_descs[] = {{MZ_OK, ""},
2356 {MZ_STREAM_END, "stream end"},
2357 {MZ_NEED_DICT, "need dictionary"},
2358 {MZ_ERRNO, "file error"},
2359 {MZ_STREAM_ERROR, "stream error"},
2360 {MZ_DATA_ERROR, "data error"},
2361 {MZ_MEM_ERROR, "out of memory"},
2362 {MZ_BUF_ERROR, "buf error"},
2363 {MZ_VERSION_ERROR, "version error"},
2364 {MZ_PARAM_ERROR, "parameter error"}};
2365 mz_uint i;
2366 for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)
2367 if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc;
2368 return NULL;
2369}
2370
2371#endif // MINIZ_NO_ZLIB_APIS
2372
2373// ------------------- Low-level Decompression (completely independent from all
2374// compression API's)
2375
2376#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
2377#define TINFL_MEMSET(p, c, l) memset(p, c, l)
2378
2379#define TINFL_CR_BEGIN \
2380 switch (r->m_state) { \
2381 case 0:
2382#define TINFL_CR_RETURN(state_index, result) \
2383 do { \
2384 status = result; \
2385 r->m_state = state_index; \
2386 goto common_exit; \
2387 case state_index:; \
2388 } \
2389 MZ_MACRO_END
2390#define TINFL_CR_RETURN_FOREVER(state_index, result) \
2391 do { \
2392 for (;;) { \
2393 TINFL_CR_RETURN(state_index, result); \
2394 } \
2395 } \
2396 MZ_MACRO_END
2397#define TINFL_CR_FINISH }
2398
2399// TODO: If the caller has indicated that there's no more input, and we attempt
2400// to read beyond the input buf, then something is wrong with the input because
2401// the inflator never
2402// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of
2403// the stream with 0's in this scenario.
2404#define TINFL_GET_BYTE(state_index, c) \
2405 do { \
2406 if (pIn_buf_cur >= pIn_buf_end) { \
2407 for (;;) { \
2408 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
2409 TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
2410 if (pIn_buf_cur < pIn_buf_end) { \
2411 c = *pIn_buf_cur++; \
2412 break; \
2413 } \
2414 } else { \
2415 c = 0; \
2416 break; \
2417 } \
2418 } \
2419 } else \
2420 c = *pIn_buf_cur++; \
2421 } \
2422 MZ_MACRO_END
2423
2424#define TINFL_NEED_BITS(state_index, n) \
2425 do { \
2426 mz_uint c; \
2427 TINFL_GET_BYTE(state_index, c); \
2428 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
2429 num_bits += 8; \
2430 } while (num_bits < (mz_uint)(n))
2431#define TINFL_SKIP_BITS(state_index, n) \
2432 do { \
2433 if (num_bits < (mz_uint)(n)) { \
2434 TINFL_NEED_BITS(state_index, n); \
2435 } \
2436 bit_buf >>= (n); \
2437 num_bits -= (n); \
2438 } \
2439 MZ_MACRO_END
2440#define TINFL_GET_BITS(state_index, b, n) \
2441 do { \
2442 if (num_bits < (mz_uint)(n)) { \
2443 TINFL_NEED_BITS(state_index, n); \
2444 } \
2445 b = bit_buf & ((1 << (n)) - 1); \
2446 bit_buf >>= (n); \
2447 num_bits -= (n); \
2448 } \
2449 MZ_MACRO_END
2450
2451// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes
2452// remaining in the input buffer falls below 2.
2453// It reads just enough bytes from the input stream that are needed to decode
2454// the next Huffman code (and absolutely no more). It works by trying to fully
2455// decode a
2456// Huffman code by using whatever bits are currently present in the bit buffer.
2457// If this fails, it reads another byte, and tries again until it succeeds or
2458// until the
2459// bit buffer contains >=15 bits (deflate's max. Huffman code size).
2460#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
2461 do { \
2462 temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
2463 if (temp >= 0) { \
2464 code_len = temp >> 9; \
2465 if ((code_len) && (num_bits >= code_len)) break; \
2466 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
2467 code_len = TINFL_FAST_LOOKUP_BITS; \
2468 do { \
2469 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
2470 } while ((temp < 0) && (num_bits >= (code_len + 1))); \
2471 if (temp >= 0) break; \
2472 } \
2473 TINFL_GET_BYTE(state_index, c); \
2474 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
2475 num_bits += 8; \
2476 } while (num_bits < 15);
2477
2478// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex
2479// than you would initially expect because the zlib API expects the decompressor
2480// to never read
2481// beyond the final byte of the deflate stream. (In other words, when this macro
2482// wants to read another byte from the input, it REALLY needs another byte in
2483// order to fully
2484// decode the next Huffman code.) Handling this properly is particularly
2485// important on raw deflate (non-zlib) streams, which aren't followed by a byte
2486// aligned adler-32.
2487// The slow path is only executed at the very end of the input buffer.
2488#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \
2489 do { \
2490 int temp; \
2491 mz_uint code_len, c; \
2492 if (num_bits < 15) { \
2493 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
2494 TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
2495 } else { \
2496 bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \
2497 (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \
2498 pIn_buf_cur += 2; \
2499 num_bits += 16; \
2500 } \
2501 } \
2502 if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \
2503 0) \
2504 code_len = temp >> 9, temp &= 511; \
2505 else { \
2506 code_len = TINFL_FAST_LOOKUP_BITS; \
2507 do { \
2508 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
2509 } while (temp < 0); \
2510 } \
2511 sym = temp; \
2512 bit_buf >>= code_len; \
2513 num_bits -= code_len; \
2514 } \
2515 MZ_MACRO_END
2516
2517tinfl_status tinfl_decompress(tinfl_decompressor *r,
2518 const mz_uint8 *pIn_buf_next,
2519 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
2520 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
2521 const mz_uint32 decomp_flags) {
2522 static const int s_length_base[31] = {
2523 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
2524 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
2525 static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
2526 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
2527 4, 4, 5, 5, 5, 5, 0, 0, 0};
2528 static const int s_dist_base[32] = {
2529 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33,
2530 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
2531 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0};
2532 static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
2533 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
2534 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
2535 static const mz_uint8 s_length_dezigzag[19] = {
2536 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
2537 static const int s_min_table_sizes[3] = {257, 1, 4};
2538
2539 tinfl_status status = TINFL_STATUS_FAILED;
2540 mz_uint32 num_bits, dist, counter, num_extra;
2541 tinfl_bit_buf_t bit_buf;
2542 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
2543 pIn_buf_next + *pIn_buf_size;
2544 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
2545 pOut_buf_next + *pOut_buf_size;
2546 size_t out_buf_size_mask =
2547 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
2548 ? (size_t)-1
2549 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1,
2550 dist_from_out_buf_start;
2551
2552 // Ensure the output buffer's size is a power of 2, unless the output buffer
2553 // is large enough to hold the entire output file (in which case it doesn't
2554 // matter).
2555 if (((out_buf_size_mask + 1) & out_buf_size_mask) ||
2556 (pOut_buf_next < pOut_buf_start)) {
2557 *pIn_buf_size = *pOut_buf_size = 0;
2558 return TINFL_STATUS_BAD_PARAM;
2559 }
2560
2561 num_bits = r->m_num_bits;
2562 bit_buf = r->m_bit_buf;
2563 dist = r->m_dist;
2564 counter = r->m_counter;
2565 num_extra = r->m_num_extra;
2566 dist_from_out_buf_start = r->m_dist_from_out_buf_start;
2567 TINFL_CR_BEGIN
2568
2569 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;
2570 r->m_z_adler32 = r->m_check_adler32 = 1;
2571 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2572 TINFL_GET_BYTE(1, r->m_zhdr0);
2573 TINFL_GET_BYTE(2, r->m_zhdr1);
2574 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) ||
2575 (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
2576 if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
2577 counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) ||
2578 ((out_buf_size_mask + 1) <
2579 (size_t)(1ULL << (8U + (r->m_zhdr0 >> 4)))));
2580 if (counter) {
2581 TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);
2582 }
2583 }
2584
2585 do {
2586 TINFL_GET_BITS(3, r->m_final, 3);
2587 r->m_type = r->m_final >> 1;
2588 if (r->m_type == 0) {
2589 TINFL_SKIP_BITS(5, num_bits & 7);
2590 for (counter = 0; counter < 4; ++counter) {
2591 if (num_bits)
2592 TINFL_GET_BITS(6, r->m_raw_header[counter], 8);
2593 else
2594 TINFL_GET_BYTE(7, r->m_raw_header[counter]);
2595 }
2596 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) !=
2597 (mz_uint)(0xFFFF ^
2598 (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) {
2599 TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);
2600 }
2601 while ((counter) && (num_bits)) {
2602 TINFL_GET_BITS(51, dist, 8);
2603 while (pOut_buf_cur >= pOut_buf_end) {
2604 TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);
2605 }
2606 *pOut_buf_cur++ = (mz_uint8)dist;
2607 counter--;
2608 }
2609 while (counter) {
2610 size_t n;
2611 while (pOut_buf_cur >= pOut_buf_end) {
2612 TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);
2613 }
2614 while (pIn_buf_cur >= pIn_buf_end) {
2615 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) {
2616 TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
2617 } else {
2618 TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
2619 }
2620 }
2621 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur),
2622 (size_t)(pIn_buf_end - pIn_buf_cur)),
2623 counter);
2624 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);
2625 pIn_buf_cur += n;
2626 pOut_buf_cur += n;
2627 counter -= (mz_uint)n;
2628 }
2629 } else if (r->m_type == 3) {
2630 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
2631 } else {
2632 if (r->m_type == 1) {
2633 mz_uint8 *p = r->m_tables[0].m_code_size;
2634 mz_uint i;
2635 r->m_table_sizes[0] = 288;
2636 r->m_table_sizes[1] = 32;
2637 TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
2638 for (i = 0; i <= 143; ++i) *p++ = 8;
2639 for (; i <= 255; ++i) *p++ = 9;
2640 for (; i <= 279; ++i) *p++ = 7;
2641 for (; i <= 287; ++i) *p++ = 8;
2642 } else {
2643 for (counter = 0; counter < 3; counter++) {
2644 TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]);
2645 r->m_table_sizes[counter] += s_min_table_sizes[counter];
2646 }
2647 MZ_CLEAR_OBJ(r->m_tables[2].m_code_size);
2648 for (counter = 0; counter < r->m_table_sizes[2]; counter++) {
2649 mz_uint s;
2650 TINFL_GET_BITS(14, s, 3);
2651 r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s;
2652 }
2653 r->m_table_sizes[2] = 19;
2654 }
2655 for (; (int)r->m_type >= 0; r->m_type--) {
2656 int tree_next, tree_cur;
2657 tinfl_huff_table *pTable;
2658 mz_uint i, j, used_syms, total, sym_index, next_code[17],
2659 total_syms[16];
2660 pTable = &r->m_tables[r->m_type];
2661 MZ_CLEAR_OBJ(total_syms);
2662 MZ_CLEAR_OBJ(pTable->m_look_up);
2663 MZ_CLEAR_OBJ(pTable->m_tree);
2664 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)
2665 total_syms[pTable->m_code_size[i]]++;
2666 used_syms = 0, total = 0;
2667 next_code[0] = next_code[1] = 0;
2668 for (i = 1; i <= 15; ++i) {
2669 used_syms += total_syms[i];
2670 next_code[i + 1] = (total = ((total + total_syms[i]) << 1));
2671 }
2672 if ((65536 != total) && (used_syms > 1)) {
2673 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
2674 }
2675 for (tree_next = -1, sym_index = 0;
2676 sym_index < r->m_table_sizes[r->m_type]; ++sym_index) {
2677 mz_uint rev_code = 0, l, cur_code,
2678 code_size = pTable->m_code_size[sym_index];
2679 if (!code_size) continue;
2680 cur_code = next_code[code_size]++;
2681 for (l = code_size; l > 0; l--, cur_code >>= 1)
2682 rev_code = (rev_code << 1) | (cur_code & 1);
2683 if (code_size <= TINFL_FAST_LOOKUP_BITS) {
2684 mz_int16 k = (mz_int16)((code_size << 9) | sym_index);
2685 while (rev_code < TINFL_FAST_LOOKUP_SIZE) {
2686 pTable->m_look_up[rev_code] = k;
2687 rev_code += (1 << code_size);
2688 }
2689 continue;
2690 }
2691 if (0 ==
2692 (tree_cur = pTable->m_look_up[rev_code &
2693 (TINFL_FAST_LOOKUP_SIZE - 1)])) {
2694 pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] =
2695 (mz_int16)tree_next;
2696 tree_cur = tree_next;
2697 tree_next -= 2;
2698 }
2699 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
2700 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) {
2701 tree_cur -= ((rev_code >>= 1) & 1);
2702 if (!pTable->m_tree[-tree_cur - 1]) {
2703 pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next;
2704 tree_cur = tree_next;
2705 tree_next -= 2;
2706 } else
2707 tree_cur = pTable->m_tree[-tree_cur - 1];
2708 }
2709 tree_cur -= ((rev_code >>= 1) & 1);
2710 pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
2711 }
2712 if (r->m_type == 2) {
2713 for (counter = 0;
2714 counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) {
2715 mz_uint s;
2716 TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]);
2717 if (dist < 16) {
2718 r->m_len_codes[counter++] = (mz_uint8)dist;
2719 continue;
2720 }
2721 if ((dist == 16) && (!counter)) {
2722 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
2723 }
2724 num_extra = "\02\03\07"[dist - 16];
2725 TINFL_GET_BITS(18, s, num_extra);
2726 s += "\03\03\013"[dist - 16];
2727 TINFL_MEMSET(r->m_len_codes + counter,
2728 (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);
2729 counter += s;
2730 }
2731 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) {
2732 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
2733 }
2734 TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes,
2735 r->m_table_sizes[0]);
2736 TINFL_MEMCPY(r->m_tables[1].m_code_size,
2737 r->m_len_codes + r->m_table_sizes[0],
2738 r->m_table_sizes[1]);
2739 }
2740 }
2741 for (;;) {
2742 mz_uint8 *pSrc;
2743 for (;;) {
2744 if (((pIn_buf_end - pIn_buf_cur) < 4) ||
2745 ((pOut_buf_end - pOut_buf_cur) < 2)) {
2746 TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
2747 if (counter >= 256) break;
2748 while (pOut_buf_cur >= pOut_buf_end) {
2749 TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);
2750 }
2751 *pOut_buf_cur++ = (mz_uint8)counter;
2752 } else {
2753 int sym2;
2754 mz_uint code_len;
2755#if TINFL_USE_64BIT_BITBUF
2756 if (num_bits < 30) {
2757 bit_buf |=
2758 (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);
2759 pIn_buf_cur += 4;
2760 num_bits += 32;
2761 }
2762#else
2763 if (num_bits < 15) {
2764 bit_buf |=
2765 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2766 pIn_buf_cur += 2;
2767 num_bits += 16;
2768 }
2769#endif
2770 if ((sym2 =
2771 r->m_tables[0]
2772 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2773 0)
2774 code_len = sym2 >> 9;
2775 else {
2776 code_len = TINFL_FAST_LOOKUP_BITS;
2777 do {
2778 sym2 = r->m_tables[0]
2779 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
2780 } while (sym2 < 0);
2781 }
2782 counter = sym2;
2783 bit_buf >>= code_len;
2784 num_bits -= code_len;
2785 if (counter & 256) break;
2786
2787#if !TINFL_USE_64BIT_BITBUF
2788 if (num_bits < 15) {
2789 bit_buf |=
2790 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2791 pIn_buf_cur += 2;
2792 num_bits += 16;
2793 }
2794#endif
2795 if ((sym2 =
2796 r->m_tables[0]
2797 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2798 0)
2799 code_len = sym2 >> 9;
2800 else {
2801 code_len = TINFL_FAST_LOOKUP_BITS;
2802 do {
2803 sym2 = r->m_tables[0]
2804 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
2805 } while (sym2 < 0);
2806 }
2807 bit_buf >>= code_len;
2808 num_bits -= code_len;
2809
2810 pOut_buf_cur[0] = (mz_uint8)counter;
2811 if (sym2 & 256) {
2812 pOut_buf_cur++;
2813 counter = sym2;
2814 break;
2815 }
2816 pOut_buf_cur[1] = (mz_uint8)sym2;
2817 pOut_buf_cur += 2;
2818 }
2819 }
2820 if ((counter &= 511) == 256) break;
2821
2822 num_extra = s_length_extra[counter - 257];
2823 counter = s_length_base[counter - 257];
2824 if (num_extra) {
2825 mz_uint extra_bits;
2826 TINFL_GET_BITS(25, extra_bits, num_extra);
2827 counter += extra_bits;
2828 }
2829
2830 TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
2831 num_extra = s_dist_extra[dist];
2832 dist = s_dist_base[dist];
2833 if (num_extra) {
2834 mz_uint extra_bits;
2835 TINFL_GET_BITS(27, extra_bits, num_extra);
2836 dist += extra_bits;
2837 }
2838
2839 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
2840 if ((dist > dist_from_out_buf_start) &&
2841 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) {
2842 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
2843 }
2844
2845 pSrc = pOut_buf_start +
2846 ((dist_from_out_buf_start - dist) & out_buf_size_mask);
2847
2848 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) {
2849 while (counter--) {
2850 while (pOut_buf_cur >= pOut_buf_end) {
2851 TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);
2852 }
2853 *pOut_buf_cur++ =
2854 pOut_buf_start[(dist_from_out_buf_start++ - dist) &
2855 out_buf_size_mask];
2856 }
2857 continue;
2858 }
2859#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
2860 else if ((counter >= 9) && (counter <= dist)) {
2861 const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
2862 do {
2863 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
2864 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
2865 pOut_buf_cur += 8;
2866 } while ((pSrc += 8) < pSrc_end);
2867 if ((counter &= 7) < 3) {
2868 if (counter) {
2869 pOut_buf_cur[0] = pSrc[0];
2870 if (counter > 1) pOut_buf_cur[1] = pSrc[1];
2871 pOut_buf_cur += counter;
2872 }
2873 continue;
2874 }
2875 }
2876#endif
2877 do {
2878 pOut_buf_cur[0] = pSrc[0];
2879 pOut_buf_cur[1] = pSrc[1];
2880 pOut_buf_cur[2] = pSrc[2];
2881 pOut_buf_cur += 3;
2882 pSrc += 3;
2883 } while ((int)(counter -= 3) > 2);
2884 if ((int)counter > 0) {
2885 pOut_buf_cur[0] = pSrc[0];
2886 if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1];
2887 pOut_buf_cur += counter;
2888 }
2889 }
2890 }
2891 } while (!(r->m_final & 1));
2892 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2893 TINFL_SKIP_BITS(32, num_bits & 7);
2894 for (counter = 0; counter < 4; ++counter) {
2895 mz_uint s;
2896 if (num_bits)
2897 TINFL_GET_BITS(41, s, 8);
2898 else
2899 TINFL_GET_BYTE(42, s);
2900 r->m_z_adler32 = (r->m_z_adler32 << 8) | s;
2901 }
2902 }
2903 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
2904 TINFL_CR_FINISH
2905
2906common_exit:
2907 r->m_num_bits = num_bits;
2908 r->m_bit_buf = bit_buf;
2909 r->m_dist = dist;
2910 r->m_counter = counter;
2911 r->m_num_extra = num_extra;
2912 r->m_dist_from_out_buf_start = dist_from_out_buf_start;
2913 *pIn_buf_size = pIn_buf_cur - pIn_buf_next;
2914 *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
2915 if ((decomp_flags &
2916 (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) &&
2917 (status >= 0)) {
2918 const mz_uint8 *ptr = pOut_buf_next;
2919 size_t buf_len = *pOut_buf_size;
2920 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff,
2921 s2 = r->m_check_adler32 >> 16;
2922 size_t block_len = buf_len % 5552;
2923 while (buf_len) {
2924 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
2925 s1 += ptr[0], s2 += s1;
2926 s1 += ptr[1], s2 += s1;
2927 s1 += ptr[2], s2 += s1;
2928 s1 += ptr[3], s2 += s1;
2929 s1 += ptr[4], s2 += s1;
2930 s1 += ptr[5], s2 += s1;
2931 s1 += ptr[6], s2 += s1;
2932 s1 += ptr[7], s2 += s1;
2933 }
2934 for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
2935 s1 %= 65521U, s2 %= 65521U;
2936 buf_len -= block_len;
2937 block_len = 5552;
2938 }
2939 r->m_check_adler32 = (s2 << 16) + s1;
2940 if ((status == TINFL_STATUS_DONE) &&
2941 (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) &&
2942 (r->m_check_adler32 != r->m_z_adler32))
2943 status = TINFL_STATUS_ADLER32_MISMATCH;
2944 }
2945 return status;
2946}
2947
2948// Higher level helper functions.
2949void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
2950 size_t *pOut_len, int flags) {
2951 tinfl_decompressor decomp;
2952 void *pBuf = NULL, *pNew_buf;
2953 size_t src_buf_ofs = 0, out_buf_capacity = 0;
2954 *pOut_len = 0;
2955 tinfl_init(&decomp);
2956 for (;;) {
2957 size_t src_buf_size = src_buf_len - src_buf_ofs,
2958 dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
2959 tinfl_status status = tinfl_decompress(
2960 &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
2961 (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
2962 &dst_buf_size,
2963 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
2964 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
2965 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
2966 MZ_FREE(pBuf);
2967 *pOut_len = 0;
2968 return NULL;
2969 }
2970 src_buf_ofs += src_buf_size;
2971 *pOut_len += dst_buf_size;
2972 if (status == TINFL_STATUS_DONE) break;
2973 new_out_buf_capacity = out_buf_capacity * 2;
2974 if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
2975 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
2976 if (!pNew_buf) {
2977 MZ_FREE(pBuf);
2978 *pOut_len = 0;
2979 return NULL;
2980 }
2981 pBuf = pNew_buf;
2982 out_buf_capacity = new_out_buf_capacity;
2983 }
2984 return pBuf;
2985}
2986
2987size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
2988 const void *pSrc_buf, size_t src_buf_len,
2989 int flags) {
2990 tinfl_decompressor decomp;
2991 tinfl_status status;
2992 tinfl_init(&decomp);
2993 status =
2994 tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len,
2995 (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len,
2996 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
2997 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
2998 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED
2999 : out_buf_len;
3000}
3001
3002int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
3003 tinfl_put_buf_func_ptr pPut_buf_func,
3004 void *pPut_buf_user, int flags) {
3005 int result = 0;
3006 tinfl_decompressor decomp;
3007 mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);
3008 size_t in_buf_ofs = 0, dict_ofs = 0;
3009 if (!pDict) return TINFL_STATUS_FAILED;
3010 tinfl_init(&decomp);
3011 for (;;) {
3012 size_t in_buf_size = *pIn_buf_size - in_buf_ofs,
3013 dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
3014 tinfl_status status =
3015 tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
3016 &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
3017 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
3018 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
3019 in_buf_ofs += in_buf_size;
3020 if ((dst_buf_size) &&
3021 (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
3022 break;
3023 if (status != TINFL_STATUS_HAS_MORE_OUTPUT) {
3024 result = (status == TINFL_STATUS_DONE);
3025 break;
3026 }
3027 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
3028 }
3029 MZ_FREE(pDict);
3030 *pIn_buf_size = in_buf_ofs;
3031 return result;
3032}
3033
3034// ------------------- Low-level Compression (independent from all decompression
3035// API's)
3036
3037// Purposely making these tables static for faster init and thread safety.
3038static const mz_uint16 s_tdefl_len_sym[256] = {
3039 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268,
3040 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272,
3041 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274,
3042 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276,
3043 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
3044 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
3045 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279,
3046 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280,
3047 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281,
3048 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
3049 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282,
3050 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
3051 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283,
3052 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
3053 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284,
3054 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
3055 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
3056 285};
3057
3058static const mz_uint8 s_tdefl_len_extra[256] = {
3059 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
3060 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3061 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
3062 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3063 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3064 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3065 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3066 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3067 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3068 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3069 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0};
3070
3071static const mz_uint8 s_tdefl_small_dist_sym[512] = {
3072 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
3073 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
3074 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
3075 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
3076 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
3077 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3078 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14,
3079 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
3080 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
3081 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
3082 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
3083 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
3084 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
3085 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3086 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3087 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3088 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3089 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3090 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3091 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
3092 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3093 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3094 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3095 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3096 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3097 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
3098 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17};
3099
3100static const mz_uint8 s_tdefl_small_dist_extra[512] = {
3101 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,
3102 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,
3103 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,
3104 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,
3105 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,
3106 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,
3107 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,
3108 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,
3109 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,
3110 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,
3111 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,
3112 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,
3113 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,
3114 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,
3115 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,
3116 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3117 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3118 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3119 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3120 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3121 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
3122
3123static const mz_uint8 s_tdefl_large_dist_sym[128] = {
3124 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24,
3125 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
3126 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27,
3127 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
3128 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
3129 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
3130 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29};
3131
3132static const mz_uint8 s_tdefl_large_dist_extra[128] = {
3133 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
3134 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
3135 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
3136 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3137 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3138 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
3139 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
3140
3141// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
3142// values.
3143typedef struct {
3144 mz_uint16 m_key, m_sym_index;
3145} tdefl_sym_freq;
3146static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
3147 tdefl_sym_freq *pSyms0,
3148 tdefl_sym_freq *pSyms1) {
3149 mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];
3150 tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;
3151 MZ_CLEAR_OBJ(hist);
3152 for (i = 0; i < num_syms; i++) {
3153 mz_uint freq = pSyms0[i].m_key;
3154 hist[freq & 0xFF]++;
3155 hist[256 + ((freq >> 8) & 0xFF)]++;
3156 }
3157 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))
3158 total_passes--;
3159 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) {
3160 const mz_uint32 *pHist = &hist[pass << 8];
3161 mz_uint offsets[256], cur_ofs = 0;
3162 for (i = 0; i < 256; i++) {
3163 offsets[i] = cur_ofs;
3164 cur_ofs += pHist[i];
3165 }
3166 for (i = 0; i < num_syms; i++)
3167 pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] =
3168 pCur_syms[i];
3169 {
3170 tdefl_sym_freq *t = pCur_syms;
3171 pCur_syms = pNew_syms;
3172 pNew_syms = t;
3173 }
3174 }
3175 return pCur_syms;
3176}
3177
3178// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat,
3179// alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
3180static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) {
3181 int root, leaf, next, avbl, used, dpth;
3182 if (n == 0)
3183 return;
3184 else if (n == 1) {
3185 A[0].m_key = 1;
3186 return;
3187 }
3188 A[0].m_key += A[1].m_key;
3189 root = 0;
3190 leaf = 2;
3191 for (next = 1; next < n - 1; next++) {
3192 if (leaf >= n || A[root].m_key < A[leaf].m_key) {
3193 A[next].m_key = A[root].m_key;
3194 A[root++].m_key = (mz_uint16)next;
3195 } else
3196 A[next].m_key = A[leaf++].m_key;
3197 if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) {
3198 A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);
3199 A[root++].m_key = (mz_uint16)next;
3200 } else
3201 A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
3202 }
3203 A[n - 2].m_key = 0;
3204 for (next = n - 3; next >= 0; next--)
3205 A[next].m_key = A[A[next].m_key].m_key + 1;
3206 avbl = 1;
3207 used = dpth = 0;
3208 root = n - 2;
3209 next = n - 1;
3210 while (avbl > 0) {
3211 while (root >= 0 && (int)A[root].m_key == dpth) {
3212 used++;
3213 root--;
3214 }
3215 while (avbl > used) {
3216 A[next--].m_key = (mz_uint16)(dpth);
3217 avbl--;
3218 }
3219 avbl = 2 * used;
3220 dpth++;
3221 used = 0;
3222 }
3223}
3224
3225// Limits canonical Huffman code table's max code size.
3226enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
3227static void tdefl_huffman_enforce_max_code_size(int *pNum_codes,
3228 int code_list_len,
3229 int max_code_size) {
3230 int i;
3231 mz_uint32 total = 0;
3232 if (code_list_len <= 1) return;
3233 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)
3234 pNum_codes[max_code_size] += pNum_codes[i];
3235 for (i = max_code_size; i > 0; i--)
3236 total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
3237 while (total != (1UL << max_code_size)) {
3238 pNum_codes[max_code_size]--;
3239 for (i = max_code_size - 1; i > 0; i--)
3240 if (pNum_codes[i]) {
3241 pNum_codes[i]--;
3242 pNum_codes[i + 1] += 2;
3243 break;
3244 }
3245 total--;
3246 }
3247}
3248
3249static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num,
3250 int table_len, int code_size_limit,
3251 int static_table) {
3252 int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];
3253 mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];
3254 MZ_CLEAR_OBJ(num_codes);
3255 if (static_table) {
3256 for (i = 0; i < table_len; i++)
3257 num_codes[d->m_huff_code_sizes[table_num][i]]++;
3258 } else {
3259 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS],
3260 *pSyms;
3261 int num_used_syms = 0;
3262 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
3263 for (i = 0; i < table_len; i++)
3264 if (pSym_count[i]) {
3265 syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];
3266 syms0[num_used_syms++].m_sym_index = (mz_uint16)i;
3267 }
3268
3269 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);
3270 tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
3271
3272 for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++;
3273
3274 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms,
3275 code_size_limit);
3276
3277 MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]);
3278 MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
3279 for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
3280 for (l = num_codes[i]; l > 0; l--)
3281 d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
3282 }
3283
3284 next_code[1] = 0;
3285 for (j = 0, i = 2; i <= code_size_limit; i++)
3286 next_code[i] = j = ((j + num_codes[i - 1]) << 1);
3287
3288 for (i = 0; i < table_len; i++) {
3289 mz_uint rev_code = 0, code, code_size;
3290 if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue;
3291 code = next_code[code_size]++;
3292 for (l = code_size; l > 0; l--, code >>= 1)
3293 rev_code = (rev_code << 1) | (code & 1);
3294 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
3295 }
3296}
3297
3298#define TDEFL_PUT_BITS(b, l) \
3299 do { \
3300 mz_uint bits = b; \
3301 mz_uint len = l; \
3302 MZ_ASSERT(bits <= ((1U << len) - 1U)); \
3303 d->m_bit_buffer |= (bits << d->m_bits_in); \
3304 d->m_bits_in += len; \
3305 while (d->m_bits_in >= 8) { \
3306 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
3307 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
3308 d->m_bit_buffer >>= 8; \
3309 d->m_bits_in -= 8; \
3310 } \
3311 } \
3312 MZ_MACRO_END
3313
3314#define TDEFL_RLE_PREV_CODE_SIZE() \
3315 { \
3316 if (rle_repeat_count) { \
3317 if (rle_repeat_count < 3) { \
3318 d->m_huff_count[2][prev_code_size] = (mz_uint16)( \
3319 d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
3320 while (rle_repeat_count--) \
3321 packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
3322 } else { \
3323 d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \
3324 packed_code_sizes[num_packed_code_sizes++] = 16; \
3325 packed_code_sizes[num_packed_code_sizes++] = \
3326 (mz_uint8)(rle_repeat_count - 3); \
3327 } \
3328 rle_repeat_count = 0; \
3329 } \
3330 }
3331
3332#define TDEFL_RLE_ZERO_CODE_SIZE() \
3333 { \
3334 if (rle_z_count) { \
3335 if (rle_z_count < 3) { \
3336 d->m_huff_count[2][0] = \
3337 (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \
3338 while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \
3339 } else if (rle_z_count <= 10) { \
3340 d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \
3341 packed_code_sizes[num_packed_code_sizes++] = 17; \
3342 packed_code_sizes[num_packed_code_sizes++] = \
3343 (mz_uint8)(rle_z_count - 3); \
3344 } else { \
3345 d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \
3346 packed_code_sizes[num_packed_code_sizes++] = 18; \
3347 packed_code_sizes[num_packed_code_sizes++] = \
3348 (mz_uint8)(rle_z_count - 11); \
3349 } \
3350 rle_z_count = 0; \
3351 } \
3352 }
3353
3354static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {
3355 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
3356
3357static void tdefl_start_dynamic_block(tdefl_compressor *d) {
3358 int num_lit_codes, num_dist_codes, num_bit_lengths;
3359 mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count,
3360 rle_repeat_count, packed_code_sizes_index;
3361 mz_uint8
3362 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
3363 packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
3364 prev_code_size = 0xFF;
3365
3366 d->m_huff_count[0][256] = 1;
3367
3368 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
3369 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
3370
3371 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)
3372 if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break;
3373 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)
3374 if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break;
3375
3376 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
3377 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0],
3378 num_dist_codes);
3379 total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
3380 num_packed_code_sizes = 0;
3381 rle_z_count = 0;
3382 rle_repeat_count = 0;
3383
3384 memset(&d->m_huff_count[2][0], 0,
3385 sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
3386 for (i = 0; i < total_code_sizes_to_pack; i++) {
3387 mz_uint8 code_size = code_sizes_to_pack[i];
3388 if (!code_size) {
3389 TDEFL_RLE_PREV_CODE_SIZE();
3390 if (++rle_z_count == 138) {
3391 TDEFL_RLE_ZERO_CODE_SIZE();
3392 }
3393 } else {
3394 TDEFL_RLE_ZERO_CODE_SIZE();
3395 if (code_size != prev_code_size) {
3396 TDEFL_RLE_PREV_CODE_SIZE();
3397 d->m_huff_count[2][code_size] =
3398 (mz_uint16)(d->m_huff_count[2][code_size] + 1);
3399 packed_code_sizes[num_packed_code_sizes++] = code_size;
3400 } else if (++rle_repeat_count == 6) {
3401 TDEFL_RLE_PREV_CODE_SIZE();
3402 }
3403 }
3404 prev_code_size = code_size;
3405 }
3406 if (rle_repeat_count) {
3407 TDEFL_RLE_PREV_CODE_SIZE();
3408 } else {
3409 TDEFL_RLE_ZERO_CODE_SIZE();
3410 }
3411
3412 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
3413
3414 TDEFL_PUT_BITS(2, 2);
3415
3416 TDEFL_PUT_BITS(num_lit_codes - 257, 5);
3417 TDEFL_PUT_BITS(num_dist_codes - 1, 5);
3418
3419 for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)
3420 if (d->m_huff_code_sizes
3421 [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])
3422 break;
3423 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));
3424 TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
3425 for (i = 0; (int)i < num_bit_lengths; i++)
3426 TDEFL_PUT_BITS(
3427 d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
3428
3429 for (packed_code_sizes_index = 0;
3430 packed_code_sizes_index < num_packed_code_sizes;) {
3431 mz_uint code = packed_code_sizes[packed_code_sizes_index++];
3432 MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
3433 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
3434 if (code >= 16)
3435 TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++],
3436 "\02\03\07"[code - 16]);
3437 }
3438}
3439
3440static void tdefl_start_static_block(tdefl_compressor *d) {
3441 mz_uint i;
3442 mz_uint8 *p = &d->m_huff_code_sizes[0][0];
3443
3444 for (i = 0; i <= 143; ++i) *p++ = 8;
3445 for (; i <= 255; ++i) *p++ = 9;
3446 for (; i <= 279; ++i) *p++ = 7;
3447 for (; i <= 287; ++i) *p++ = 8;
3448
3449 memset(d->m_huff_code_sizes[1], 5, 32);
3450
3451 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
3452 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
3453
3454 TDEFL_PUT_BITS(1, 2);
3455}
3456
3457static const mz_uint mz_bitmasks[17] = {
3458 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
3459 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
3460
3461#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \
3462 MINIZ_HAS_64BIT_REGISTERS
3463static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
3464 mz_uint flags;
3465 mz_uint8 *pLZ_codes;
3466 mz_uint8 *pOutput_buf = d->m_pOutput_buf;
3467 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
3468 mz_uint64 bit_buffer = d->m_bit_buffer;
3469 mz_uint bits_in = d->m_bits_in;
3470
3471#define TDEFL_PUT_BITS_FAST(b, l) \
3472 { \
3473 bit_buffer |= (((mz_uint64)(b)) << bits_in); \
3474 bits_in += (l); \
3475 }
3476
3477 flags = 1;
3478 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end;
3479 flags >>= 1) {
3480 if (flags == 1) flags = *pLZ_codes++ | 0x100;
3481
3482 if (flags & 1) {
3483 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
3484 mz_uint match_len = pLZ_codes[0],
3485 match_dist = *(const mz_uint16 *)(pLZ_codes + 1);
3486 pLZ_codes += 3;
3487
3488 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3489 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
3490 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3491 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
3492 s_tdefl_len_extra[match_len]);
3493
3494 // This sequence coaxes MSVC into using cmov's vs. jmp's.
3495 s0 = s_tdefl_small_dist_sym[match_dist & 511];
3496 n0 = s_tdefl_small_dist_extra[match_dist & 511];
3497 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
3498 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
3499 sym = (match_dist < 512) ? s0 : s1;
3500 num_extra_bits = (match_dist < 512) ? n0 : n1;
3501
3502 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
3503 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym],
3504 d->m_huff_code_sizes[1][sym]);
3505 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits],
3506 num_extra_bits);
3507 } else {
3508 mz_uint lit = *pLZ_codes++;
3509 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3510 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3511 d->m_huff_code_sizes[0][lit]);
3512
3513 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3514 flags >>= 1;
3515 lit = *pLZ_codes++;
3516 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3517 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3518 d->m_huff_code_sizes[0][lit]);
3519
3520 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3521 flags >>= 1;
3522 lit = *pLZ_codes++;
3523 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3524 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3525 d->m_huff_code_sizes[0][lit]);
3526 }
3527 }
3528 }
3529
3530 if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE;
3531
3532 *(mz_uint64 *)pOutput_buf = bit_buffer;
3533 pOutput_buf += (bits_in >> 3);
3534 bit_buffer >>= (bits_in & ~7);
3535 bits_in &= 7;
3536 }
3537
3538#undef TDEFL_PUT_BITS_FAST
3539
3540 d->m_pOutput_buf = pOutput_buf;
3541 d->m_bits_in = 0;
3542 d->m_bit_buffer = 0;
3543
3544 while (bits_in) {
3545 mz_uint32 n = MZ_MIN(bits_in, 16);
3546 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
3547 bit_buffer >>= n;
3548 bits_in -= n;
3549 }
3550
3551 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3552
3553 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3554}
3555#else
3556static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
3557 mz_uint flags;
3558 mz_uint8 *pLZ_codes;
3559
3560 flags = 1;
3561 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf;
3562 flags >>= 1) {
3563 if (flags == 1) flags = *pLZ_codes++ | 0x100;
3564 if (flags & 1) {
3565 mz_uint sym, num_extra_bits;
3566 mz_uint match_len = pLZ_codes[0],
3567 match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
3568 pLZ_codes += 3;
3569
3570 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3571 TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
3572 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3573 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
3574 s_tdefl_len_extra[match_len]);
3575
3576 if (match_dist < 512) {
3577 sym = s_tdefl_small_dist_sym[match_dist];
3578 num_extra_bits = s_tdefl_small_dist_extra[match_dist];
3579 } else {
3580 sym = s_tdefl_large_dist_sym[match_dist >> 8];
3581 num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
3582 }
3583 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
3584 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
3585 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
3586 } else {
3587 mz_uint lit = *pLZ_codes++;
3588 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3589 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
3590 }
3591 }
3592
3593 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3594
3595 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3596}
3597#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN &&
3598 // MINIZ_HAS_64BIT_REGISTERS
3599
3600static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) {
3601 if (static_block)
3602 tdefl_start_static_block(d);
3603 else
3604 tdefl_start_dynamic_block(d);
3605 return tdefl_compress_lz_codes(d);
3606}
3607
3608static int tdefl_flush_block(tdefl_compressor *d, int flush) {
3609 mz_uint saved_bit_buf, saved_bits_in;
3610 mz_uint8 *pSaved_output_buf;
3611 mz_bool comp_block_succeeded = MZ_FALSE;
3612 int n, use_raw_block =
3613 ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
3614 (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
3615 mz_uint8 *pOutput_buf_start =
3616 ((d->m_pPut_buf_func == NULL) &&
3617 ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE))
3618 ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs)
3619 : d->m_output_buf;
3620
3621 d->m_pOutput_buf = pOutput_buf_start;
3622 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
3623
3624 MZ_ASSERT(!d->m_output_flush_remaining);
3625 d->m_output_flush_ofs = 0;
3626 d->m_output_flush_remaining = 0;
3627
3628 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
3629 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
3630
3631 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) {
3632 TDEFL_PUT_BITS(0x78, 8);
3633 TDEFL_PUT_BITS(0x01, 8);
3634 }
3635
3636 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
3637
3638 pSaved_output_buf = d->m_pOutput_buf;
3639 saved_bit_buf = d->m_bit_buffer;
3640 saved_bits_in = d->m_bits_in;
3641
3642 if (!use_raw_block)
3643 comp_block_succeeded =
3644 tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
3645 (d->m_total_lz_bytes < 48));
3646
3647 // If the block gets expanded, forget the current contents of the output
3648 // buffer and send a raw block instead.
3649 if (((use_raw_block) ||
3650 ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >=
3651 d->m_total_lz_bytes))) &&
3652 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) {
3653 mz_uint i;
3654 d->m_pOutput_buf = pSaved_output_buf;
3655 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3656 TDEFL_PUT_BITS(0, 2);
3657 if (d->m_bits_in) {
3658 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3659 }
3660 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) {
3661 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
3662 }
3663 for (i = 0; i < d->m_total_lz_bytes; ++i) {
3664 TDEFL_PUT_BITS(
3665 d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK],
3666 8);
3667 }
3668 }
3669 // Check for the extremely unlikely (if not impossible) case of the compressed
3670 // block not fitting into the output buffer when using dynamic codes.
3671 else if (!comp_block_succeeded) {
3672 d->m_pOutput_buf = pSaved_output_buf;
3673 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3674 tdefl_compress_block(d, MZ_TRUE);
3675 }
3676
3677 if (flush) {
3678 if (flush == TDEFL_FINISH) {
3679 if (d->m_bits_in) {
3680 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3681 }
3682 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) {
3683 mz_uint i, a = d->m_adler32;
3684 for (i = 0; i < 4; i++) {
3685 TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);
3686 a <<= 8;
3687 }
3688 }
3689 } else {
3690 mz_uint i, z = 0;
3691 TDEFL_PUT_BITS(0, 3);
3692 if (d->m_bits_in) {
3693 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3694 }
3695 for (i = 2; i; --i, z ^= 0xFFFF) {
3696 TDEFL_PUT_BITS(z & 0xFFFF, 16);
3697 }
3698 }
3699 }
3700
3701 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
3702
3703 memset(&d->m_huff_count[0][0], 0,
3704 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
3705 memset(&d->m_huff_count[1][0], 0,
3706 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
3707
3708 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
3709 d->m_pLZ_flags = d->m_lz_code_buf;
3710 d->m_num_flags_left = 8;
3711 d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;
3712 d->m_total_lz_bytes = 0;
3713 d->m_block_index++;
3714
3715 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) {
3716 if (d->m_pPut_buf_func) {
3717 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
3718 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
3719 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
3720 } else if (pOutput_buf_start == d->m_output_buf) {
3721 int bytes_to_copy = (int)MZ_MIN(
3722 (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
3723 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf,
3724 bytes_to_copy);
3725 d->m_out_buf_ofs += bytes_to_copy;
3726 if ((n -= bytes_to_copy) != 0) {
3727 d->m_output_flush_ofs = bytes_to_copy;
3728 d->m_output_flush_remaining = n;
3729 }
3730 } else {
3731 d->m_out_buf_ofs += n;
3732 }
3733 }
3734
3735 return d->m_output_flush_remaining;
3736}
3737
3738#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
3739#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)
3740static MZ_FORCEINLINE void tdefl_find_match(
3741 tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3742 mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) {
3743 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3744 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3745 probe_len;
3746 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3747 const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;
3748 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]),
3749 s01 = TDEFL_READ_UNALIGNED_WORD(s);
3750 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3751 if (max_match_len <= match_len) return;
3752 for (;;) {
3753 for (;;) {
3754 if (--num_probes_left == 0) return;
3755#define TDEFL_PROBE \
3756 next_probe_pos = d->m_next[probe_pos]; \
3757 if ((!next_probe_pos) || \
3758 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3759 return; \
3760 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3761 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \
3762 break;
3763 TDEFL_PROBE;
3764 TDEFL_PROBE;
3765 TDEFL_PROBE;
3766 }
3767 if (!dist) break;
3768 q = (const mz_uint16 *)(d->m_dict + probe_pos);
3769 if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue;
3770 p = s;
3771 probe_len = 32;
3772 do {
3773 } while (
3774 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3775 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3776 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3777 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
3778 (--probe_len > 0));
3779 if (!probe_len) {
3780 *pMatch_dist = dist;
3781 *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN);
3782 break;
3783 } else if ((probe_len = ((mz_uint)(p - s) * 2) +
3784 (mz_uint)(*(const mz_uint8 *)p ==
3785 *(const mz_uint8 *)q)) > match_len) {
3786 *pMatch_dist = dist;
3787 if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) ==
3788 max_match_len)
3789 break;
3790 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
3791 }
3792 }
3793}
3794#else
3795static MZ_FORCEINLINE void tdefl_find_match(
3796 tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3797 mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) {
3798 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3799 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3800 probe_len;
3801 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3802 const mz_uint8 *s = d->m_dict + pos, *p, *q;
3803 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
3804 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3805 if (max_match_len <= match_len) return;
3806 for (;;) {
3807 for (;;) {
3808 if (--num_probes_left == 0) return;
3809#define TDEFL_PROBE \
3810 next_probe_pos = d->m_next[probe_pos]; \
3811 if ((!next_probe_pos) || \
3812 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3813 return; \
3814 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3815 if ((d->m_dict[probe_pos + match_len] == c0) && \
3816 (d->m_dict[probe_pos + match_len - 1] == c1)) \
3817 break;
3818 TDEFL_PROBE;
3819 TDEFL_PROBE;
3820 TDEFL_PROBE;
3821 }
3822 if (!dist) break;
3823 p = s;
3824 q = d->m_dict + probe_pos;
3825 for (probe_len = 0; probe_len < max_match_len; probe_len++)
3826 if (*p++ != *q++) break;
3827 if (probe_len > match_len) {
3828 *pMatch_dist = dist;
3829 if ((*pMatch_len = match_len = probe_len) == max_match_len) return;
3830 c0 = d->m_dict[pos + match_len];
3831 c1 = d->m_dict[pos + match_len - 1];
3832 }
3833 }
3834}
3835#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
3836
3837#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
3838static mz_bool tdefl_compress_fast(tdefl_compressor *d) {
3839 // Faster, minimally featured LZRW1-style match+parse loop with better
3840 // register utilization. Intended for applications where raw throughput is
3841 // valued more highly than ratio.
3842 mz_uint lookahead_pos = d->m_lookahead_pos,
3843 lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size,
3844 total_lz_bytes = d->m_total_lz_bytes,
3845 num_flags_left = d->m_num_flags_left;
3846 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
3847 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
3848
3849 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) {
3850 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
3851 mz_uint dst_pos =
3852 (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
3853 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
3854 d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
3855 d->m_src_buf_left -= num_bytes_to_process;
3856 lookahead_size += num_bytes_to_process;
3857
3858 while (num_bytes_to_process) {
3859 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
3860 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
3861 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
3862 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc,
3863 MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
3864 d->m_pSrc += n;
3865 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
3866 num_bytes_to_process -= n;
3867 }
3868
3869 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
3870 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))
3871 break;
3872
3873 while (lookahead_size >= 4) {
3874 mz_uint cur_match_dist, cur_match_len = 1;
3875 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
3876 mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
3877 mz_uint hash =
3878 (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) &
3879 TDEFL_LEVEL1_HASH_SIZE_MASK;
3880 mz_uint probe_pos = d->m_hash[hash];
3881 d->m_hash[hash] = (mz_uint16)lookahead_pos;
3882
3883 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <=
3884 dict_size) &&
3885 ((*(const mz_uint32 *)(d->m_dict +
3886 (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) &
3887 0xFFFFFF) == first_trigram)) {
3888 const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
3889 const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
3890 mz_uint32 probe_len = 32;
3891 do {
3892 } while ((TDEFL_READ_UNALIGNED_WORD(++p) ==
3893 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3894 (TDEFL_READ_UNALIGNED_WORD(++p) ==
3895 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3896 (TDEFL_READ_UNALIGNED_WORD(++p) ==
3897 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3898 (TDEFL_READ_UNALIGNED_WORD(++p) ==
3899 TDEFL_READ_UNALIGNED_WORD(++q)) &&
3900 (--probe_len > 0));
3901 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) +
3902 (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
3903 if (!probe_len)
3904 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
3905
3906 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) ||
3907 ((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
3908 (cur_match_dist >= 8U * 1024U))) {
3909 cur_match_len = 1;
3910 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3911 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3912 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3913 } else {
3914 mz_uint32 s0, s1;
3915 cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
3916
3917 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) &&
3918 (cur_match_dist >= 1) &&
3919 (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
3920
3921 cur_match_dist--;
3922
3923 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
3924 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
3925 pLZ_code_buf += 3;
3926 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
3927
3928 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
3929 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
3930 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
3931
3932 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len -
3933 TDEFL_MIN_MATCH_LEN]]++;
3934 }
3935 } else {
3936 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3937 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3938 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3939 }
3940
3941 if (--num_flags_left == 0) {
3942 num_flags_left = 8;
3943 pLZ_flags = pLZ_code_buf++;
3944 }
3945
3946 total_lz_bytes += cur_match_len;
3947 lookahead_pos += cur_match_len;
3948 dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
3949 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
3950 MZ_ASSERT(lookahead_size >= cur_match_len);
3951 lookahead_size -= cur_match_len;
3952
3953 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
3954 int n;
3955 d->m_lookahead_pos = lookahead_pos;
3956 d->m_lookahead_size = lookahead_size;
3957 d->m_dict_size = dict_size;
3958 d->m_total_lz_bytes = total_lz_bytes;
3959 d->m_pLZ_code_buf = pLZ_code_buf;
3960 d->m_pLZ_flags = pLZ_flags;
3961 d->m_num_flags_left = num_flags_left;
3962 if ((n = tdefl_flush_block(d, 0)) != 0)
3963 return (n < 0) ? MZ_FALSE : MZ_TRUE;
3964 total_lz_bytes = d->m_total_lz_bytes;
3965 pLZ_code_buf = d->m_pLZ_code_buf;
3966 pLZ_flags = d->m_pLZ_flags;
3967 num_flags_left = d->m_num_flags_left;
3968 }
3969 }
3970
3971 while (lookahead_size) {
3972 mz_uint8 lit = d->m_dict[cur_pos];
3973
3974 total_lz_bytes++;
3975 *pLZ_code_buf++ = lit;
3976 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3977 if (--num_flags_left == 0) {
3978 num_flags_left = 8;
3979 pLZ_flags = pLZ_code_buf++;
3980 }
3981
3982 d->m_huff_count[0][lit]++;
3983
3984 lookahead_pos++;
3985 dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
3986 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
3987 lookahead_size--;
3988
3989 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
3990 int n;
3991 d->m_lookahead_pos = lookahead_pos;
3992 d->m_lookahead_size = lookahead_size;
3993 d->m_dict_size = dict_size;
3994 d->m_total_lz_bytes = total_lz_bytes;
3995 d->m_pLZ_code_buf = pLZ_code_buf;
3996 d->m_pLZ_flags = pLZ_flags;
3997 d->m_num_flags_left = num_flags_left;
3998 if ((n = tdefl_flush_block(d, 0)) != 0)
3999 return (n < 0) ? MZ_FALSE : MZ_TRUE;
4000 total_lz_bytes = d->m_total_lz_bytes;
4001 pLZ_code_buf = d->m_pLZ_code_buf;
4002 pLZ_flags = d->m_pLZ_flags;
4003 num_flags_left = d->m_num_flags_left;
4004 }
4005 }
4006 }
4007
4008 d->m_lookahead_pos = lookahead_pos;
4009 d->m_lookahead_size = lookahead_size;
4010 d->m_dict_size = dict_size;
4011 d->m_total_lz_bytes = total_lz_bytes;
4012 d->m_pLZ_code_buf = pLZ_code_buf;
4013 d->m_pLZ_flags = pLZ_flags;
4014 d->m_num_flags_left = num_flags_left;
4015 return MZ_TRUE;
4016}
4017#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
4018
4019static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d,
4020 mz_uint8 lit) {
4021 d->m_total_lz_bytes++;
4022 *d->m_pLZ_code_buf++ = lit;
4023 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);
4024 if (--d->m_num_flags_left == 0) {
4025 d->m_num_flags_left = 8;
4026 d->m_pLZ_flags = d->m_pLZ_code_buf++;
4027 }
4028 d->m_huff_count[0][lit]++;
4029}
4030
4031static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d,
4032 mz_uint match_len,
4033 mz_uint match_dist) {
4034 mz_uint32 s0, s1;
4035
4036 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) &&
4037 (match_dist <= TDEFL_LZ_DICT_SIZE));
4038
4039 d->m_total_lz_bytes += match_len;
4040
4041 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
4042
4043 match_dist -= 1;
4044 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
4045 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);
4046 d->m_pLZ_code_buf += 3;
4047
4048 *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);
4049 if (--d->m_num_flags_left == 0) {
4050 d->m_num_flags_left = 8;
4051 d->m_pLZ_flags = d->m_pLZ_code_buf++;
4052 }
4053
4054 s0 = s_tdefl_small_dist_sym[match_dist & 511];
4055 s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
4056 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
4057
4058 if (match_len >= TDEFL_MIN_MATCH_LEN)
4059 d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
4060}
4061
4062static mz_bool tdefl_compress_normal(tdefl_compressor *d) {
4063 const mz_uint8 *pSrc = d->m_pSrc;
4064 size_t src_buf_left = d->m_src_buf_left;
4065 tdefl_flush flush = d->m_flush;
4066
4067 while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) {
4068 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
4069 // Update dictionary and hash chains. Keeps the lookahead size equal to
4070 // TDEFL_MAX_MATCH_LEN.
4071 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) {
4072 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
4073 TDEFL_LZ_DICT_SIZE_MASK,
4074 ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
4075 mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
4076 << TDEFL_LZ_HASH_SHIFT) ^
4077 d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
4078 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
4079 src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
4080 const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
4081 src_buf_left -= num_bytes_to_process;
4082 d->m_lookahead_size += num_bytes_to_process;
4083 while (pSrc != pSrc_end) {
4084 mz_uint8 c = *pSrc++;
4085 d->m_dict[dst_pos] = c;
4086 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
4087 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
4088 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
4089 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
4090 d->m_hash[hash] = (mz_uint16)(ins_pos);
4091 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
4092 ins_pos++;
4093 }
4094 } else {
4095 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) {
4096 mz_uint8 c = *pSrc++;
4097 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
4098 TDEFL_LZ_DICT_SIZE_MASK;
4099 src_buf_left--;
4100 d->m_dict[dst_pos] = c;
4101 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
4102 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
4103 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) {
4104 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
4105 mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
4106 << (TDEFL_LZ_HASH_SHIFT * 2)) ^
4107 (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]
4108 << TDEFL_LZ_HASH_SHIFT) ^
4109 c) &
4110 (TDEFL_LZ_HASH_SIZE - 1);
4111 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
4112 d->m_hash[hash] = (mz_uint16)(ins_pos);
4113 }
4114 }
4115 }
4116 d->m_dict_size =
4117 MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
4118 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break;
4119
4120 // Simple lazy/greedy parsing state machine.
4121 len_to_move = 1;
4122 cur_match_dist = 0;
4123 cur_match_len =
4124 d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);
4125 cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
4126 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) {
4127 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) {
4128 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
4129 cur_match_len = 0;
4130 while (cur_match_len < d->m_lookahead_size) {
4131 if (d->m_dict[cur_pos + cur_match_len] != c) break;
4132 cur_match_len++;
4133 }
4134 if (cur_match_len < TDEFL_MIN_MATCH_LEN)
4135 cur_match_len = 0;
4136 else
4137 cur_match_dist = 1;
4138 }
4139 } else {
4140 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size,
4141 d->m_lookahead_size, &cur_match_dist, &cur_match_len);
4142 }
4143 if (((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
4144 (cur_match_dist >= 8U * 1024U)) ||
4145 (cur_pos == cur_match_dist) ||
4146 ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) {
4147 cur_match_dist = cur_match_len = 0;
4148 }
4149 if (d->m_saved_match_len) {
4150 if (cur_match_len > d->m_saved_match_len) {
4151 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
4152 if (cur_match_len >= 128) {
4153 tdefl_record_match(d, cur_match_len, cur_match_dist);
4154 d->m_saved_match_len = 0;
4155 len_to_move = cur_match_len;
4156 } else {
4157 d->m_saved_lit = d->m_dict[cur_pos];
4158 d->m_saved_match_dist = cur_match_dist;
4159 d->m_saved_match_len = cur_match_len;
4160 }
4161 } else {
4162 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
4163 len_to_move = d->m_saved_match_len - 1;
4164 d->m_saved_match_len = 0;
4165 }
4166 } else if (!cur_match_dist)
4167 tdefl_record_literal(d,
4168 d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
4169 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) ||
4170 (cur_match_len >= 128)) {
4171 tdefl_record_match(d, cur_match_len, cur_match_dist);
4172 len_to_move = cur_match_len;
4173 } else {
4174 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];
4175 d->m_saved_match_dist = cur_match_dist;
4176 d->m_saved_match_len = cur_match_len;
4177 }
4178 // Move the lookahead forward by len_to_move bytes.
4179 d->m_lookahead_pos += len_to_move;
4180 MZ_ASSERT(d->m_lookahead_size >= len_to_move);
4181 d->m_lookahead_size -= len_to_move;
4182 d->m_dict_size =
4183 MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);
4184 // Check if it's time to flush the current LZ codes to the internal output
4185 // buffer.
4186 if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
4187 ((d->m_total_lz_bytes > 31 * 1024) &&
4188 (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >=
4189 d->m_total_lz_bytes) ||
4190 (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) {
4191 int n;
4192 d->m_pSrc = pSrc;
4193 d->m_src_buf_left = src_buf_left;
4194 if ((n = tdefl_flush_block(d, 0)) != 0)
4195 return (n < 0) ? MZ_FALSE : MZ_TRUE;
4196 }
4197 }
4198
4199 d->m_pSrc = pSrc;
4200 d->m_src_buf_left = src_buf_left;
4201 return MZ_TRUE;
4202}
4203
4204static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) {
4205 if (d->m_pIn_buf_size) {
4206 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
4207 }
4208
4209 if (d->m_pOut_buf_size) {
4210 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs,
4211 d->m_output_flush_remaining);
4212 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs,
4213 d->m_output_buf + d->m_output_flush_ofs, n);
4214 d->m_output_flush_ofs += (mz_uint)n;
4215 d->m_output_flush_remaining -= (mz_uint)n;
4216 d->m_out_buf_ofs += n;
4217
4218 *d->m_pOut_buf_size = d->m_out_buf_ofs;
4219 }
4220
4221 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE
4222 : TDEFL_STATUS_OKAY;
4223}
4224
4225tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
4226 size_t *pIn_buf_size, void *pOut_buf,
4227 size_t *pOut_buf_size, tdefl_flush flush) {
4228 if (!d) {
4229 if (pIn_buf_size) *pIn_buf_size = 0;
4230 if (pOut_buf_size) *pOut_buf_size = 0;
4231 return TDEFL_STATUS_BAD_PARAM;
4232 }
4233
4234 d->m_pIn_buf = pIn_buf;
4235 d->m_pIn_buf_size = pIn_buf_size;
4236 d->m_pOut_buf = pOut_buf;
4237 d->m_pOut_buf_size = pOut_buf_size;
4238 d->m_pSrc = (const mz_uint8 *)(pIn_buf);
4239 d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
4240 d->m_out_buf_ofs = 0;
4241 d->m_flush = flush;
4242
4243 if (((d->m_pPut_buf_func != NULL) ==
4244 ((pOut_buf != NULL) || (pOut_buf_size != NULL))) ||
4245 (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
4246 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) ||
4247 (pIn_buf_size && *pIn_buf_size && !pIn_buf) ||
4248 (pOut_buf_size && *pOut_buf_size && !pOut_buf)) {
4249 if (pIn_buf_size) *pIn_buf_size = 0;
4250 if (pOut_buf_size) *pOut_buf_size = 0;
4251 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
4252 }
4253 d->m_wants_to_finish |= (flush == TDEFL_FINISH);
4254
4255 if ((d->m_output_flush_remaining) || (d->m_finished))
4256 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
4257
4258#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
4259 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
4260 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
4261 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS |
4262 TDEFL_RLE_MATCHES)) == 0)) {
4263 if (!tdefl_compress_fast(d)) return d->m_prev_return_status;
4264 } else
4265#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
4266 {
4267 if (!tdefl_compress_normal(d)) return d->m_prev_return_status;
4268 }
4269
4270 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) &&
4271 (pIn_buf))
4272 d->m_adler32 =
4273 (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf,
4274 d->m_pSrc - (const mz_uint8 *)pIn_buf);
4275
4276 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) &&
4277 (!d->m_output_flush_remaining)) {
4278 if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status;
4279 d->m_finished = (flush == TDEFL_FINISH);
4280 if (flush == TDEFL_FULL_FLUSH) {
4281 MZ_CLEAR_OBJ(d->m_hash);
4282 MZ_CLEAR_OBJ(d->m_next);
4283 d->m_dict_size = 0;
4284 }
4285 }
4286
4287 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
4288}
4289
4290tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
4291 size_t in_buf_size, tdefl_flush flush) {
4292 MZ_ASSERT(d->m_pPut_buf_func);
4293 return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
4294}
4295
4296tdefl_status tdefl_init(tdefl_compressor *d,
4297 tdefl_put_buf_func_ptr pPut_buf_func,
4298 void *pPut_buf_user, int flags) {
4299 d->m_pPut_buf_func = pPut_buf_func;
4300 d->m_pPut_buf_user = pPut_buf_user;
4301 d->m_flags = (mz_uint)(flags);
4302 d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;
4303 d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
4304 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
4305 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash);
4306 d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size =
4307 d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
4308 d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished =
4309 d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
4310 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
4311 d->m_pLZ_flags = d->m_lz_code_buf;
4312 d->m_num_flags_left = 8;
4313 d->m_pOutput_buf = d->m_output_buf;
4314 d->m_pOutput_buf_end = d->m_output_buf;
4315 d->m_prev_return_status = TDEFL_STATUS_OKAY;
4316 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;
4317 d->m_adler32 = 1;
4318 d->m_pIn_buf = NULL;
4319 d->m_pOut_buf = NULL;
4320 d->m_pIn_buf_size = NULL;
4321 d->m_pOut_buf_size = NULL;
4322 d->m_flush = TDEFL_NO_FLUSH;
4323 d->m_pSrc = NULL;
4324 d->m_src_buf_left = 0;
4325 d->m_out_buf_ofs = 0;
4326 memset(&d->m_huff_count[0][0], 0,
4327 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
4328 memset(&d->m_huff_count[1][0], 0,
4329 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
4330 return TDEFL_STATUS_OKAY;
4331}
4332
4333tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) {
4334 return d->m_prev_return_status;
4335}
4336
4337mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; }
4338
4339mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
4340 tdefl_put_buf_func_ptr pPut_buf_func,
4341 void *pPut_buf_user, int flags) {
4342 tdefl_compressor *pComp;
4343 mz_bool succeeded;
4344 if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE;
4345 pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
4346 if (!pComp) return MZ_FALSE;
4347 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) ==
4348 TDEFL_STATUS_OKAY);
4349 succeeded =
4350 succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) ==
4351 TDEFL_STATUS_DONE);
4352 MZ_FREE(pComp);
4353 return succeeded;
4354}
4355
4356typedef struct {
4357 size_t m_size, m_capacity;
4358 mz_uint8 *m_pBuf;
4359 mz_bool m_expandable;
4360} tdefl_output_buffer;
4361
4362static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len,
4363 void *pUser) {
4364 tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
4365 size_t new_size = p->m_size + len;
4366 if (new_size > p->m_capacity) {
4367 size_t new_capacity = p->m_capacity;
4368 mz_uint8 *pNew_buf;
4369 if (!p->m_expandable) return MZ_FALSE;
4370 do {
4371 new_capacity = MZ_MAX(128U, new_capacity << 1U);
4372 } while (new_size > new_capacity);
4373 pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);
4374 if (!pNew_buf) return MZ_FALSE;
4375 p->m_pBuf = pNew_buf;
4376 p->m_capacity = new_capacity;
4377 }
4378 memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);
4379 p->m_size = new_size;
4380 return MZ_TRUE;
4381}
4382
4383void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
4384 size_t *pOut_len, int flags) {
4385 tdefl_output_buffer out_buf;
4386 MZ_CLEAR_OBJ(out_buf);
4387 if (!pOut_len)
4388 return MZ_FALSE;
4389 else
4390 *pOut_len = 0;
4391 out_buf.m_expandable = MZ_TRUE;
4392 if (!tdefl_compress_mem_to_output(
4393 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
4394 return NULL;
4395 *pOut_len = out_buf.m_size;
4396 return out_buf.m_pBuf;
4397}
4398
4399size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
4400 const void *pSrc_buf, size_t src_buf_len,
4401 int flags) {
4402 tdefl_output_buffer out_buf;
4403 MZ_CLEAR_OBJ(out_buf);
4404 if (!pOut_buf) return 0;
4405 out_buf.m_pBuf = (mz_uint8 *)pOut_buf;
4406 out_buf.m_capacity = out_buf_len;
4407 if (!tdefl_compress_mem_to_output(
4408 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
4409 return 0;
4410 return out_buf.m_size;
4411}
4412
4413#ifndef MINIZ_NO_ZLIB_APIS
4414static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32,
4415 128, 256, 512, 768, 1500};
4416
4417// level may actually range from [0,10] (10 is a "hidden" max level, where we
4418// want a bit more compression and it's fine if throughput to fall off a cliff
4419// on some files).
4420mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
4421 int strategy) {
4422 mz_uint comp_flags =
4423 s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] |
4424 ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
4425 if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
4426
4427 if (!level)
4428 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
4429 else if (strategy == MZ_FILTERED)
4430 comp_flags |= TDEFL_FILTER_MATCHES;
4431 else if (strategy == MZ_HUFFMAN_ONLY)
4432 comp_flags &= ~TDEFL_MAX_PROBES_MASK;
4433 else if (strategy == MZ_FIXED)
4434 comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
4435 else if (strategy == MZ_RLE)
4436 comp_flags |= TDEFL_RLE_MATCHES;
4437
4438 return comp_flags;
4439}
4440#endif // MINIZ_NO_ZLIB_APIS
4441
4442#ifdef _MSC_VER
4443#pragma warning(push)
4444#pragma warning(disable : 4204) // nonstandard extension used : non-constant
4445 // aggregate initializer (also supported by GNU
4446 // C and C99, so no big deal)
4447#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
4448 // 'int', possible loss of data
4449#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
4450 // 'int', possible loss of data
4451#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
4452 // deprecated. Instead, use the ISO C and C++
4453 // conformant name: _strdup.
4454#endif
4455
4456// Simple PNG writer function by Alex Evans, 2011. Released into the public
4457// domain: https://gist.github.com/908299, more context at
4458// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
4459// This is actually a modification of Alex's original code so PNG files
4460// generated by this function pass pngcheck.
4461void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
4462 int h, int num_chans,
4463 size_t *pLen_out,
4464 mz_uint level, mz_bool flip) {
4465 // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was
4466 // defined.
4467 static const mz_uint s_tdefl_png_num_probes[11] = {
4468 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500};
4469 tdefl_compressor *pComp =
4470 (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
4471 tdefl_output_buffer out_buf;
4472 int i, bpl = w * num_chans, y, z;
4473 mz_uint32 c;
4474 *pLen_out = 0;
4475 if (!pComp) return NULL;
4476 MZ_CLEAR_OBJ(out_buf);
4477 out_buf.m_expandable = MZ_TRUE;
4478 out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);
4479 if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) {
4480 MZ_FREE(pComp);
4481 return NULL;
4482 }
4483 // write dummy header
4484 for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
4485 // compress image data
4486 tdefl_init(
4487 pComp, tdefl_output_buffer_putter, &out_buf,
4488 s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
4489 for (y = 0; y < h; ++y) {
4490 tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);
4491 tdefl_compress_buffer(pComp,
4492 (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl,
4493 bpl, TDEFL_NO_FLUSH);
4494 }
4495 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) !=
4496 TDEFL_STATUS_DONE) {
4497 MZ_FREE(pComp);
4498 MZ_FREE(out_buf.m_pBuf);
4499 return NULL;
4500 }
4501 // write real header
4502 *pLen_out = out_buf.m_size - 41;
4503 {
4504 static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
4505 mz_uint8 pnghdr[41] = {0x89,
4506 0x50,
4507 0x4e,
4508 0x47,
4509 0x0d,
4510 0x0a,
4511 0x1a,
4512 0x0a,
4513 0x00,
4514 0x00,
4515 0x00,
4516 0x0d,
4517 0x49,
4518 0x48,
4519 0x44,
4520 0x52,
4521 0,
4522 0,
4523 (mz_uint8)(w >> 8),
4524 (mz_uint8)w,
4525 0,
4526 0,
4527 (mz_uint8)(h >> 8),
4528 (mz_uint8)h,
4529 8,
4530 chans[num_chans],
4531 0,
4532 0,
4533 0,
4534 0,
4535 0,
4536 0,
4537 0,
4538 (mz_uint8)(*pLen_out >> 24),
4539 (mz_uint8)(*pLen_out >> 16),
4540 (mz_uint8)(*pLen_out >> 8),
4541 (mz_uint8)*pLen_out,
4542 0x49,
4543 0x44,
4544 0x41,
4545 0x54};
4546 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);
4547 for (i = 0; i < 4; ++i, c <<= 8)
4548 ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);
4549 memcpy(out_buf.m_pBuf, pnghdr, 41);
4550 }
4551 // write footer (IDAT CRC-32, followed by IEND chunk)
4552 if (!tdefl_output_buffer_putter(
4553 "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) {
4554 *pLen_out = 0;
4555 MZ_FREE(pComp);
4556 MZ_FREE(out_buf.m_pBuf);
4557 return NULL;
4558 }
4559 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4,
4560 *pLen_out + 4);
4561 for (i = 0; i < 4; ++i, c <<= 8)
4562 (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);
4563 // compute final size of file, grab compressed data buffer and return
4564 *pLen_out += 57;
4565 MZ_FREE(pComp);
4566 return out_buf.m_pBuf;
4567}
4568void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
4569 int num_chans, size_t *pLen_out) {
4570 // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we
4571 // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's
4572 // where #defined out)
4573 return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans,
4574 pLen_out, 6, MZ_FALSE);
4575}
4576
4577// ------------------- .ZIP archive reading
4578
4579#ifndef MINIZ_NO_ARCHIVE_APIS
4580#error "No arvhive APIs"
4581
4582#ifdef MINIZ_NO_STDIO
4583#define MZ_FILE void *
4584#else
4585#include <stdio.h>
4586#include <sys/stat.h>
4587
4588#if defined(_MSC_VER) || defined(__MINGW64__)
4589static FILE *mz_fopen(const char *pFilename, const char *pMode) {
4590 FILE *pFile = NULL;
4591 fopen_s(&pFile, pFilename, pMode);
4592 return pFile;
4593}
4594static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) {
4595 FILE *pFile = NULL;
4596 if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL;
4597 return pFile;
4598}
4599#ifndef MINIZ_NO_TIME
4600#include <sys/utime.h>
4601#endif
4602#define MZ_FILE FILE
4603#define MZ_FOPEN mz_fopen
4604#define MZ_FCLOSE fclose
4605#define MZ_FREAD fread
4606#define MZ_FWRITE fwrite
4607#define MZ_FTELL64 _ftelli64
4608#define MZ_FSEEK64 _fseeki64
4609#define MZ_FILE_STAT_STRUCT _stat
4610#define MZ_FILE_STAT _stat
4611#define MZ_FFLUSH fflush
4612#define MZ_FREOPEN mz_freopen
4613#define MZ_DELETE_FILE remove
4614#elif defined(__MINGW32__)
4615#ifndef MINIZ_NO_TIME
4616#include <sys/utime.h>
4617#endif
4618#define MZ_FILE FILE
4619#define MZ_FOPEN(f, m) fopen(f, m)
4620#define MZ_FCLOSE fclose
4621#define MZ_FREAD fread
4622#define MZ_FWRITE fwrite
4623#define MZ_FTELL64 ftello64
4624#define MZ_FSEEK64 fseeko64
4625#define MZ_FILE_STAT_STRUCT _stat
4626#define MZ_FILE_STAT _stat
4627#define MZ_FFLUSH fflush
4628#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4629#define MZ_DELETE_FILE remove
4630#elif defined(__TINYC__)
4631#ifndef MINIZ_NO_TIME
4632#include <sys/utime.h>
4633#endif
4634#define MZ_FILE FILE
4635#define MZ_FOPEN(f, m) fopen(f, m)
4636#define MZ_FCLOSE fclose
4637#define MZ_FREAD fread
4638#define MZ_FWRITE fwrite
4639#define MZ_FTELL64 ftell
4640#define MZ_FSEEK64 fseek
4641#define MZ_FILE_STAT_STRUCT stat
4642#define MZ_FILE_STAT stat
4643#define MZ_FFLUSH fflush
4644#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4645#define MZ_DELETE_FILE remove
4646#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) && _LARGEFILE64_SOURCE
4647#ifndef MINIZ_NO_TIME
4648#include <utime.h>
4649#endif
4650#define MZ_FILE FILE
4651#define MZ_FOPEN(f, m) fopen64(f, m)
4652#define MZ_FCLOSE fclose
4653#define MZ_FREAD fread
4654#define MZ_FWRITE fwrite
4655#define MZ_FTELL64 ftello64
4656#define MZ_FSEEK64 fseeko64
4657#define MZ_FILE_STAT_STRUCT stat64
4658#define MZ_FILE_STAT stat64
4659#define MZ_FFLUSH fflush
4660#define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
4661#define MZ_DELETE_FILE remove
4662#else
4663#ifndef MINIZ_NO_TIME
4664#include <utime.h>
4665#endif
4666#define MZ_FILE FILE
4667#define MZ_FOPEN(f, m) fopen(f, m)
4668#define MZ_FCLOSE fclose
4669#define MZ_FREAD fread
4670#define MZ_FWRITE fwrite
4671#define MZ_FTELL64 ftello
4672#define MZ_FSEEK64 fseeko
4673#define MZ_FILE_STAT_STRUCT stat
4674#define MZ_FILE_STAT stat
4675#define MZ_FFLUSH fflush
4676#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4677#define MZ_DELETE_FILE remove
4678#endif // #ifdef _MSC_VER
4679#endif // #ifdef MINIZ_NO_STDIO
4680
4681#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
4682
4683// Various ZIP archive enums. To completely avoid cross platform compiler
4684// alignment and platform endian issues, miniz.c doesn't use structs for any of
4685// this stuff.
4686enum {
4687 // ZIP archive identifiers and record sizes
4688 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,
4689 MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,
4690 MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
4691 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
4692 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
4693 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
4694 // Central directory header record offsets
4695 MZ_ZIP_CDH_SIG_OFS = 0,
4696 MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
4697 MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,
4698 MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
4699 MZ_ZIP_CDH_METHOD_OFS = 10,
4700 MZ_ZIP_CDH_FILE_TIME_OFS = 12,
4701 MZ_ZIP_CDH_FILE_DATE_OFS = 14,
4702 MZ_ZIP_CDH_CRC32_OFS = 16,
4703 MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,
4704 MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,
4705 MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,
4706 MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
4707 MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,
4708 MZ_ZIP_CDH_DISK_START_OFS = 34,
4709 MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,
4710 MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,
4711 MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
4712 // Local directory header offsets
4713 MZ_ZIP_LDH_SIG_OFS = 0,
4714 MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,
4715 MZ_ZIP_LDH_BIT_FLAG_OFS = 6,
4716 MZ_ZIP_LDH_METHOD_OFS = 8,
4717 MZ_ZIP_LDH_FILE_TIME_OFS = 10,
4718 MZ_ZIP_LDH_FILE_DATE_OFS = 12,
4719 MZ_ZIP_LDH_CRC32_OFS = 14,
4720 MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,
4721 MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
4722 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,
4723 MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
4724 // End of central directory offsets
4725 MZ_ZIP_ECDH_SIG_OFS = 0,
4726 MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,
4727 MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,
4728 MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
4729 MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,
4730 MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
4731 MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
4732 MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
4733};
4734
4735typedef struct {
4736 void *m_p;
4737 size_t m_size, m_capacity;
4738 mz_uint m_element_size;
4739} mz_zip_array;
4740
4741struct mz_zip_internal_state_tag {
4742 mz_zip_array m_central_dir;
4743 mz_zip_array m_central_dir_offsets;
4744 mz_zip_array m_sorted_central_dir_offsets;
4745 MZ_FILE *m_pFile;
4746 void *m_pMem;
4747 size_t m_mem_size;
4748 size_t m_mem_capacity;
4749};
4750
4751#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \
4752 (array_ptr)->m_element_size = element_size
4753#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \
4754 ((element_type *)((array_ptr)->m_p))[index]
4755
4756static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip,
4757 mz_zip_array *pArray) {
4758 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
4759 memset(pArray, 0, sizeof(mz_zip_array));
4760}
4761
4762static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip,
4763 mz_zip_array *pArray,
4764 size_t min_new_capacity,
4765 mz_uint growing) {
4766 void *pNew_p;
4767 size_t new_capacity = min_new_capacity;
4768 MZ_ASSERT(pArray->m_element_size);
4769 if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE;
4770 if (growing) {
4771 new_capacity = MZ_MAX(1, pArray->m_capacity);
4772 while (new_capacity < min_new_capacity) new_capacity *= 2;
4773 }
4774 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p,
4775 pArray->m_element_size, new_capacity)))
4776 return MZ_FALSE;
4777 pArray->m_p = pNew_p;
4778 pArray->m_capacity = new_capacity;
4779 return MZ_TRUE;
4780}
4781
4782static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip,
4783 mz_zip_array *pArray,
4784 size_t new_capacity,
4785 mz_uint growing) {
4786 if (new_capacity > pArray->m_capacity) {
4787 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
4788 return MZ_FALSE;
4789 }
4790 return MZ_TRUE;
4791}
4792
4793static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip,
4794 mz_zip_array *pArray,
4795 size_t new_size,
4796 mz_uint growing) {
4797 if (new_size > pArray->m_capacity) {
4798 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
4799 return MZ_FALSE;
4800 }
4801 pArray->m_size = new_size;
4802 return MZ_TRUE;
4803}
4804
4805static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip,
4806 mz_zip_array *pArray,
4807 size_t n) {
4808 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
4809}
4810
4811static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip,
4812 mz_zip_array *pArray,
4813 const void *pElements,
4814 size_t n) {
4815 size_t orig_size = pArray->m_size;
4816 if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))
4817 return MZ_FALSE;
4818 memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size,
4819 pElements, n * pArray->m_element_size);
4820 return MZ_TRUE;
4821}
4822
4823#ifndef MINIZ_NO_TIME
4824static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) {
4825 struct tm tm;
4826 memset(&tm, 0, sizeof(tm));
4827 tm.tm_isdst = -1;
4828 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;
4829 tm.tm_mon = ((dos_date >> 5) & 15) - 1;
4830 tm.tm_mday = dos_date & 31;
4831 tm.tm_hour = (dos_time >> 11) & 31;
4832 tm.tm_min = (dos_time >> 5) & 63;
4833 tm.tm_sec = (dos_time << 1) & 62;
4834 return mktime(&tm);
4835}
4836
4837static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time,
4838 mz_uint16 *pDOS_date) {
4839#ifdef _MSC_VER
4840 struct tm tm_struct;
4841 struct tm *tm = &tm_struct;
4842 errno_t err = localtime_s(tm, &time);
4843 if (err) {
4844 *pDOS_date = 0;
4845 *pDOS_time = 0;
4846 return;
4847 }
4848#else
4849 struct tm *tm = localtime(&time);
4850#endif
4851 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) +
4852 ((tm->tm_sec) >> 1));
4853 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) +
4854 ((tm->tm_mon + 1) << 5) + tm->tm_mday);
4855}
4856#endif
4857
4858#ifndef MINIZ_NO_STDIO
4859static mz_bool mz_zip_get_file_modified_time(const char *pFilename,
4860 mz_uint16 *pDOS_time,
4861 mz_uint16 *pDOS_date) {
4862#ifdef MINIZ_NO_TIME
4863 (void)pFilename;
4864 *pDOS_date = *pDOS_time = 0;
4865#else
4866 struct MZ_FILE_STAT_STRUCT file_stat;
4867 // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000
4868 // bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh.
4869 if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE;
4870 mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date);
4871#endif // #ifdef MINIZ_NO_TIME
4872 return MZ_TRUE;
4873}
4874
4875#ifndef MINIZ_NO_TIME
4876static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
4877 time_t modified_time) {
4878 struct utimbuf t;
4879 t.actime = access_time;
4880 t.modtime = modified_time;
4881 return !utime(pFilename, &t);
4882}
4883#endif // #ifndef MINIZ_NO_TIME
4884#endif // #ifndef MINIZ_NO_STDIO
4885
4886static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
4887 mz_uint32 flags) {
4888 (void)flags;
4889 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
4890 return MZ_FALSE;
4891
4892 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
4893 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
4894 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
4895
4896 pZip->m_zip_mode = MZ_ZIP_MODE_READING;
4897 pZip->m_archive_size = 0;
4898 pZip->m_central_directory_file_ofs = 0;
4899 pZip->m_total_files = 0;
4900
4901 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
4902 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
4903 return MZ_FALSE;
4904 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
4905 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
4906 sizeof(mz_uint8));
4907 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
4908 sizeof(mz_uint32));
4909 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
4910 sizeof(mz_uint32));
4911 return MZ_TRUE;
4912}
4913
4914static MZ_FORCEINLINE mz_bool
4915mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array,
4916 const mz_zip_array *pCentral_dir_offsets,
4917 mz_uint l_index, mz_uint r_index) {
4918 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
4919 pCentral_dir_array, mz_uint8,
4920 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
4921 l_index)),
4922 *pE;
4923 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(
4924 pCentral_dir_array, mz_uint8,
4925 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
4926 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS),
4927 r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4928 mz_uint8 l = 0, r = 0;
4929 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4930 pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4931 pE = pL + MZ_MIN(l_len, r_len);
4932 while (pL < pE) {
4933 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break;
4934 pL++;
4935 pR++;
4936 }
4937 return (pL == pE) ? (l_len < r_len) : (l < r);
4938}
4939
4940#define MZ_SWAP_UINT32(a, b) \
4941 do { \
4942 mz_uint32 t = a; \
4943 a = b; \
4944 b = t; \
4945 } \
4946 MZ_MACRO_END
4947
4948// Heap sort of lowercased filenames, used to help accelerate plain central
4949// directory searches by mz_zip_reader_locate_file(). (Could also use qsort(),
4950// but it could allocate memory.)
4951static void mz_zip_reader_sort_central_dir_offsets_by_filename(
4952 mz_zip_archive *pZip) {
4953 mz_zip_internal_state *pState = pZip->m_pState;
4954 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
4955 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
4956 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
4957 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
4958 const int size = pZip->m_total_files;
4959 int start = (size - 2) >> 1, end;
4960 while (start >= 0) {
4961 int child, root = start;
4962 for (;;) {
4963 if ((child = (root << 1) + 1) >= size) break;
4964 child +=
4965 (((child + 1) < size) &&
4966 (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4967 pIndices[child], pIndices[child + 1])));
4968 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4969 pIndices[root], pIndices[child]))
4970 break;
4971 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
4972 root = child;
4973 }
4974 start--;
4975 }
4976
4977 end = size - 1;
4978 while (end > 0) {
4979 int child, root = 0;
4980 MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
4981 for (;;) {
4982 if ((child = (root << 1) + 1) >= end) break;
4983 child +=
4984 (((child + 1) < end) &&
4985 mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4986 pIndices[child], pIndices[child + 1]));
4987 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4988 pIndices[root], pIndices[child]))
4989 break;
4990 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
4991 root = child;
4992 }
4993 end--;
4994 }
4995}
4996
4997static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
4998 mz_uint32 flags) {
4999 mz_uint cdir_size, num_this_disk, cdir_disk_index;
5000 mz_uint64 cdir_ofs;
5001 mz_int64 cur_file_ofs;
5002 const mz_uint8 *p;
5003 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
5004 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
5005 mz_bool sort_central_dir =
5006 ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
5007 // Basic sanity checks - reject files which are too small, and check the first
5008 // 4 bytes of the file to make sure a local header is there.
5009 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5010 return MZ_FALSE;
5011 // Find the end of central directory record by scanning the file from the end
5012 // towards the beginning.
5013 cur_file_ofs =
5014 MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
5015 for (;;) {
5016 int i,
5017 n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
5018 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
5019 return MZ_FALSE;
5020 for (i = n - 4; i >= 0; --i)
5021 if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break;
5022 if (i >= 0) {
5023 cur_file_ofs += i;
5024 break;
5025 }
5026 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
5027 (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
5028 return MZ_FALSE;
5029 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
5030 }
5031 // Read and verify the end of central directory record.
5032 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
5033 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
5034 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5035 return MZ_FALSE;
5036 if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
5037 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
5038 ((pZip->m_total_files =
5039 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
5040 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
5041 return MZ_FALSE;
5042
5043 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
5044 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
5045 if (((num_this_disk | cdir_disk_index) != 0) &&
5046 ((num_this_disk != 1) || (cdir_disk_index != 1)))
5047 return MZ_FALSE;
5048
5049 if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
5050 pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
5051 return MZ_FALSE;
5052
5053 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
5054 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE;
5055
5056 pZip->m_central_directory_file_ofs = cdir_ofs;
5057
5058 if (pZip->m_total_files) {
5059 mz_uint i, n;
5060
5061 // Read the entire central directory into a heap block, and allocate another
5062 // heap block to hold the unsorted central dir file record offsets, and
5063 // another to hold the sorted indices.
5064 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
5065 MZ_FALSE)) ||
5066 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
5067 pZip->m_total_files, MZ_FALSE)))
5068 return MZ_FALSE;
5069
5070 if (sort_central_dir) {
5071 if (!mz_zip_array_resize(pZip,
5072 &pZip->m_pState->m_sorted_central_dir_offsets,
5073 pZip->m_total_files, MZ_FALSE))
5074 return MZ_FALSE;
5075 }
5076
5077 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
5078 pZip->m_pState->m_central_dir.m_p,
5079 cdir_size) != cdir_size)
5080 return MZ_FALSE;
5081
5082 // Now create an index into the central directory file records, do some
5083 // basic sanity checking on each record, and check for zip64 entries (which
5084 // are not yet supported).
5085 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
5086 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
5087 mz_uint total_header_size, comp_size, decomp_size, disk_index;
5088 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
5089 (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
5090 return MZ_FALSE;
5091 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5092 i) =
5093 (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
5094 if (sort_central_dir)
5095 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
5096 mz_uint32, i) = i;
5097 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5098 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5099 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
5100 (decomp_size != comp_size)) ||
5101 (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
5102 (comp_size == 0xFFFFFFFF))
5103 return MZ_FALSE;
5104 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
5105 if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE;
5106 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
5107 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
5108 return MZ_FALSE;
5109 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5110 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
5111 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
5112 MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
5113 n)
5114 return MZ_FALSE;
5115 n -= total_header_size;
5116 p += total_header_size;
5117 }
5118 }
5119
5120 if (sort_central_dir)
5121 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
5122
5123 return MZ_TRUE;
5124}
5125
5126mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
5127 mz_uint32 flags) {
5128 if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE;
5129 if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE;
5130 pZip->m_archive_size = size;
5131 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5132 mz_zip_reader_end(pZip);
5133 return MZ_FALSE;
5134 }
5135 return MZ_TRUE;
5136}
5137
5138static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs,
5139 void *pBuf, size_t n) {
5140 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5141 size_t s = (file_ofs >= pZip->m_archive_size)
5142 ? 0
5143 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
5144 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
5145 return s;
5146}
5147
5148mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
5149 size_t size, mz_uint32 flags) {
5150 if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE;
5151 pZip->m_archive_size = size;
5152 pZip->m_pRead = mz_zip_mem_read_func;
5153 pZip->m_pIO_opaque = pZip;
5154#ifdef __cplusplus
5155 pZip->m_pState->m_pMem = const_cast<void *>(pMem);
5156#else
5157 pZip->m_pState->m_pMem = (void *)pMem;
5158#endif
5159 pZip->m_pState->m_mem_size = size;
5160 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5161 mz_zip_reader_end(pZip);
5162 return MZ_FALSE;
5163 }
5164 return MZ_TRUE;
5165}
5166
5167#ifndef MINIZ_NO_STDIO
5168static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs,
5169 void *pBuf, size_t n) {
5170 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5171 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
5172 if (((mz_int64)file_ofs < 0) ||
5173 (((cur_ofs != (mz_int64)file_ofs)) &&
5174 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
5175 return 0;
5176 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
5177}
5178
5179mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
5180 mz_uint32 flags) {
5181 mz_uint64 file_size;
5182 MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb");
5183 if (!pFile) return MZ_FALSE;
5184 if (MZ_FSEEK64(pFile, 0, SEEK_END)) {
5185 MZ_FCLOSE(pFile);
5186 return MZ_FALSE;
5187 }
5188 file_size = MZ_FTELL64(pFile);
5189 if (!mz_zip_reader_init_internal(pZip, flags)) {
5190 MZ_FCLOSE(pFile);
5191 return MZ_FALSE;
5192 }
5193 pZip->m_pRead = mz_zip_file_read_func;
5194 pZip->m_pIO_opaque = pZip;
5195 pZip->m_pState->m_pFile = pFile;
5196 pZip->m_archive_size = file_size;
5197 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5198 mz_zip_reader_end(pZip);
5199 return MZ_FALSE;
5200 }
5201 return MZ_TRUE;
5202}
5203#endif // #ifndef MINIZ_NO_STDIO
5204
5205mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) {
5206 return pZip ? pZip->m_total_files : 0;
5207}
5208
5209static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(
5210 mz_zip_archive *pZip, mz_uint file_index) {
5211 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) ||
5212 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5213 return NULL;
5214 return &MZ_ZIP_ARRAY_ELEMENT(
5215 &pZip->m_pState->m_central_dir, mz_uint8,
5216 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5217 file_index));
5218}
5219
5220mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
5221 mz_uint file_index) {
5222 mz_uint m_bit_flag;
5223 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5224 if (!p) return MZ_FALSE;
5225 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
5226 return (m_bit_flag & 1);
5227}
5228
5229mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
5230 mz_uint file_index) {
5231 mz_uint filename_len, external_attr;
5232 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5233 if (!p) return MZ_FALSE;
5234
5235 // First see if the filename ends with a '/' character.
5236 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5237 if (filename_len) {
5238 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
5239 return MZ_TRUE;
5240 }
5241
5242 // Bugfix: This code was also checking if the internal attribute was non-zero,
5243 // which wasn't correct.
5244 // Most/all zip writers (hopefully) set DOS file/directory attributes in the
5245 // low 16-bits, so check for the DOS directory flag and ignore the source OS
5246 // ID in the created by field.
5247 // FIXME: Remove this check? Is it necessary - we already check the filename.
5248 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5249 if ((external_attr & 0x10) != 0) return MZ_TRUE;
5250
5251 return MZ_FALSE;
5252}
5253
5254mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
5255 mz_zip_archive_file_stat *pStat) {
5256 mz_uint n;
5257 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5258 if ((!p) || (!pStat)) return MZ_FALSE;
5259
5260 // Unpack the central directory record.
5261 pStat->m_file_index = file_index;
5262 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(
5263 &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
5264 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
5265 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
5266 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
5267 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
5268#ifndef MINIZ_NO_TIME
5269 pStat->m_time =
5270 mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS),
5271 MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
5272#endif
5273 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
5274 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5275 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5276 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
5277 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5278 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
5279
5280 // Copy as much of the filename and comment as possible.
5281 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5282 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
5283 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
5284 pStat->m_filename[n] = '\0';
5285
5286 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
5287 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
5288 pStat->m_comment_size = n;
5289 memcpy(pStat->m_comment,
5290 p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5291 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
5292 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
5293 n);
5294 pStat->m_comment[n] = '\0';
5295
5296 return MZ_TRUE;
5297}
5298
5299mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
5300 char *pFilename, mz_uint filename_buf_size) {
5301 mz_uint n;
5302 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5303 if (!p) {
5304 if (filename_buf_size) pFilename[0] = '\0';
5305 return 0;
5306 }
5307 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5308 if (filename_buf_size) {
5309 n = MZ_MIN(n, filename_buf_size - 1);
5310 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
5311 pFilename[n] = '\0';
5312 }
5313 return n + 1;
5314}
5315
5316static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA,
5317 const char *pB,
5318 mz_uint len,
5319 mz_uint flags) {
5320 mz_uint i;
5321 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len);
5322 for (i = 0; i < len; ++i)
5323 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE;
5324 return MZ_TRUE;
5325}
5326
5327static MZ_FORCEINLINE int mz_zip_reader_filename_compare(
5328 const mz_zip_array *pCentral_dir_array,
5329 const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR,
5330 mz_uint r_len) {
5331 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
5332 pCentral_dir_array, mz_uint8,
5333 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
5334 l_index)),
5335 *pE;
5336 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5337 mz_uint8 l = 0, r = 0;
5338 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5339 pE = pL + MZ_MIN(l_len, r_len);
5340 while (pL < pE) {
5341 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break;
5342 pL++;
5343 pR++;
5344 }
5345 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
5346}
5347
5348static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip,
5349 const char *pFilename) {
5350 mz_zip_internal_state *pState = pZip->m_pState;
5351 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
5352 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
5353 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
5354 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
5355 const int size = pZip->m_total_files;
5356 const mz_uint filename_len = (mz_uint)strlen(pFilename);
5357 int l = 0, h = size - 1;
5358 while (l <= h) {
5359 int m = (l + h) >> 1, file_index = pIndices[m],
5360 comp =
5361 mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets,
5362 file_index, pFilename, filename_len);
5363 if (!comp)
5364 return file_index;
5365 else if (comp < 0)
5366 l = m + 1;
5367 else
5368 h = m - 1;
5369 }
5370 return -1;
5371}
5372
5373int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
5374 const char *pComment, mz_uint flags) {
5375 mz_uint file_index;
5376 size_t name_len, comment_len;
5377 if ((!pZip) || (!pZip->m_pState) || (!pName) ||
5378 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5379 return -1;
5380 if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) &&
5381 (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
5382 return mz_zip_reader_locate_file_binary_search(pZip, pName);
5383 name_len = strlen(pName);
5384 if (name_len > 0xFFFF) return -1;
5385 comment_len = pComment ? strlen(pComment) : 0;
5386 if (comment_len > 0xFFFF) return -1;
5387 for (file_index = 0; file_index < pZip->m_total_files; file_index++) {
5388 const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(
5389 &pZip->m_pState->m_central_dir, mz_uint8,
5390 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5391 file_index));
5392 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5393 const char *pFilename =
5394 (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5395 if (filename_len < name_len) continue;
5396 if (comment_len) {
5397 mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS),
5398 file_comment_len =
5399 MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
5400 const char *pFile_comment = pFilename + filename_len + file_extra_len;
5401 if ((file_comment_len != comment_len) ||
5402 (!mz_zip_reader_string_equal(pComment, pFile_comment,
5403 file_comment_len, flags)))
5404 continue;
5405 }
5406 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) {
5407 int ofs = filename_len - 1;
5408 do {
5409 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') ||
5410 (pFilename[ofs] == ':'))
5411 break;
5412 } while (--ofs >= 0);
5413 ofs++;
5414 pFilename += ofs;
5415 filename_len -= ofs;
5416 }
5417 if ((filename_len == name_len) &&
5418 (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
5419 return file_index;
5420 }
5421 return -1;
5422}
5423
5424mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
5425 mz_uint file_index, void *pBuf,
5426 size_t buf_size, mz_uint flags,
5427 void *pUser_read_buf,
5428 size_t user_read_buf_size) {
5429 int status = TINFL_STATUS_DONE;
5430 mz_uint64 needed_size, cur_file_ofs, comp_remaining,
5431 out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
5432 mz_zip_archive_file_stat file_stat;
5433 void *pRead_buf;
5434 mz_uint32
5435 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5436 sizeof(mz_uint32)];
5437 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5438 tinfl_decompressor inflator;
5439
5440 if ((buf_size) && (!pBuf)) return MZ_FALSE;
5441
5442 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
5443
5444 // Empty file, or a directory (but not always a directory - I've seen odd zips
5445 // with directories that have compressed data which inflates to 0 bytes)
5446 if (!file_stat.m_comp_size) return MZ_TRUE;
5447
5448 // Entry is a subdirectory (I've seen old zips with dir entries which have
5449 // compressed deflate data which inflates to 0 bytes, but these entries claim
5450 // to uncompress to 512 bytes in the headers).
5451 // I'm torn how to handle this case - should it fail instead?
5452 if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE;
5453
5454 // Encryption and patch files are not supported.
5455 if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE;
5456
5457 // This function only supports stored and deflate.
5458 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
5459 (file_stat.m_method != MZ_DEFLATED))
5460 return MZ_FALSE;
5461
5462 // Ensure supplied output buffer is large enough.
5463 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size
5464 : file_stat.m_uncomp_size;
5465 if (buf_size < needed_size) return MZ_FALSE;
5466
5467 // Read and parse the local directory entry.
5468 cur_file_ofs = file_stat.m_local_header_ofs;
5469 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
5470 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5471 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5472 return MZ_FALSE;
5473 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5474 return MZ_FALSE;
5475
5476 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5477 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5478 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5479 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
5480 return MZ_FALSE;
5481
5482 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
5483 // The file is stored or the caller has requested the compressed data.
5484 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
5485 (size_t)needed_size) != needed_size)
5486 return MZ_FALSE;
5487 return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) ||
5488 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
5489 (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32);
5490 }
5491
5492 // Decompress the file either directly from memory or from a file input
5493 // buffer.
5494 tinfl_init(&inflator);
5495
5496 if (pZip->m_pState->m_pMem) {
5497 // Read directly from the archive in memory.
5498 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
5499 read_buf_size = read_buf_avail = file_stat.m_comp_size;
5500 comp_remaining = 0;
5501 } else if (pUser_read_buf) {
5502 // Use a user provided read buffer.
5503 if (!user_read_buf_size) return MZ_FALSE;
5504 pRead_buf = (mz_uint8 *)pUser_read_buf;
5505 read_buf_size = user_read_buf_size;
5506 read_buf_avail = 0;
5507 comp_remaining = file_stat.m_comp_size;
5508 } else {
5509 // Temporarily allocate a read buffer.
5510 read_buf_size =
5511 MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
5512#ifdef _MSC_VER
5513 if (((0, sizeof(size_t) == sizeof(mz_uint32))) &&
5514 (read_buf_size > 0x7FFFFFFF))
5515#else
5516 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
5517#endif
5518 return MZ_FALSE;
5519 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5520 (size_t)read_buf_size)))
5521 return MZ_FALSE;
5522 read_buf_avail = 0;
5523 comp_remaining = file_stat.m_comp_size;
5524 }
5525
5526 do {
5527 size_t in_buf_size,
5528 out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
5529 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
5530 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5531 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5532 (size_t)read_buf_avail) != read_buf_avail) {
5533 status = TINFL_STATUS_FAILED;
5534 break;
5535 }
5536 cur_file_ofs += read_buf_avail;
5537 comp_remaining -= read_buf_avail;
5538 read_buf_ofs = 0;
5539 }
5540 in_buf_size = (size_t)read_buf_avail;
5541 status = tinfl_decompress(
5542 &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
5543 (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size,
5544 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF |
5545 (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
5546 read_buf_avail -= in_buf_size;
5547 read_buf_ofs += in_buf_size;
5548 out_buf_ofs += out_buf_size;
5549 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
5550
5551 if (status == TINFL_STATUS_DONE) {
5552 // Make sure the entire file was decompressed, and check its CRC.
5553 if ((out_buf_ofs != file_stat.m_uncomp_size) ||
5554 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
5555 (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32))
5556 status = TINFL_STATUS_FAILED;
5557 }
5558
5559 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
5560 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
5561
5562 return status == TINFL_STATUS_DONE;
5563}
5564
5565mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
5566 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
5567 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) {
5568 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5569 if (file_index < 0) return MZ_FALSE;
5570 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
5571 flags, pUser_read_buf,
5572 user_read_buf_size);
5573}
5574
5575mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
5576 void *pBuf, size_t buf_size,
5577 mz_uint flags) {
5578 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
5579 flags, NULL, 0);
5580}
5581
5582mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
5583 const char *pFilename, void *pBuf,
5584 size_t buf_size, mz_uint flags) {
5585 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf,
5586 buf_size, flags, NULL, 0);
5587}
5588
5589void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
5590 size_t *pSize, mz_uint flags) {
5591 mz_uint64 comp_size, uncomp_size, alloc_size;
5592 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5593 void *pBuf;
5594
5595 if (pSize) *pSize = 0;
5596 if (!p) return NULL;
5597
5598 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5599 uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5600
5601 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
5602#ifdef _MSC_VER
5603 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
5604#else
5605 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
5606#endif
5607 return NULL;
5608 if (NULL ==
5609 (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
5610 return NULL;
5611
5612 if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size,
5613 flags)) {
5614 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
5615 return NULL;
5616 }
5617
5618 if (pSize) *pSize = (size_t)alloc_size;
5619 return pBuf;
5620}
5621
5622void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
5623 const char *pFilename, size_t *pSize,
5624 mz_uint flags) {
5625 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5626 if (file_index < 0) {
5627 if (pSize) *pSize = 0;
5628 return MZ_FALSE;
5629 }
5630 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
5631}
5632
5633mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
5634 mz_uint file_index,
5635 mz_file_write_func pCallback,
5636 void *pOpaque, mz_uint flags) {
5637 int status = TINFL_STATUS_DONE;
5638 mz_uint file_crc32 = MZ_CRC32_INIT;
5639 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining,
5640 out_buf_ofs = 0, cur_file_ofs;
5641 mz_zip_archive_file_stat file_stat;
5642 void *pRead_buf = NULL;
5643 void *pWrite_buf = NULL;
5644 mz_uint32
5645 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5646 sizeof(mz_uint32)];
5647 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5648
5649 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
5650
5651 // Empty file, or a directory (but not always a directory - I've seen odd zips
5652 // with directories that have compressed data which inflates to 0 bytes)
5653 if (!file_stat.m_comp_size) return MZ_TRUE;
5654
5655 // Entry is a subdirectory (I've seen old zips with dir entries which have
5656 // compressed deflate data which inflates to 0 bytes, but these entries claim
5657 // to uncompress to 512 bytes in the headers).
5658 // I'm torn how to handle this case - should it fail instead?
5659 if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE;
5660
5661 // Encryption and patch files are not supported.
5662 if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE;
5663
5664 // This function only supports stored and deflate.
5665 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
5666 (file_stat.m_method != MZ_DEFLATED))
5667 return MZ_FALSE;
5668
5669 // Read and parse the local directory entry.
5670 cur_file_ofs = file_stat.m_local_header_ofs;
5671 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
5672 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5673 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5674 return MZ_FALSE;
5675 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5676 return MZ_FALSE;
5677
5678 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5679 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5680 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5681 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
5682 return MZ_FALSE;
5683
5684 // Decompress the file either directly from memory or from a file input
5685 // buffer.
5686 if (pZip->m_pState->m_pMem) {
5687 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
5688 read_buf_size = read_buf_avail = file_stat.m_comp_size;
5689 comp_remaining = 0;
5690 } else {
5691 read_buf_size =
5692 MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
5693 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5694 (size_t)read_buf_size)))
5695 return MZ_FALSE;
5696 read_buf_avail = 0;
5697 comp_remaining = file_stat.m_comp_size;
5698 }
5699
5700 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
5701 // The file is stored or the caller has requested the compressed data.
5702 if (pZip->m_pState->m_pMem) {
5703#ifdef _MSC_VER
5704 if (((0, sizeof(size_t) == sizeof(mz_uint32))) &&
5705 (file_stat.m_comp_size > 0xFFFFFFFF))
5706#else
5707 if (((sizeof(size_t) == sizeof(mz_uint32))) &&
5708 (file_stat.m_comp_size > 0xFFFFFFFF))
5709#endif
5710 return MZ_FALSE;
5711 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5712 (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
5713 status = TINFL_STATUS_FAILED;
5714 else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
5715 file_crc32 =
5716 (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf,
5717 (size_t)file_stat.m_comp_size);
5718 cur_file_ofs += file_stat.m_comp_size;
5719 out_buf_ofs += file_stat.m_comp_size;
5720 comp_remaining = 0;
5721 } else {
5722 while (comp_remaining) {
5723 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5724 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5725 (size_t)read_buf_avail) != read_buf_avail) {
5726 status = TINFL_STATUS_FAILED;
5727 break;
5728 }
5729
5730 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
5731 file_crc32 = (mz_uint32)mz_crc32(
5732 file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
5733
5734 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5735 (size_t)read_buf_avail) != read_buf_avail) {
5736 status = TINFL_STATUS_FAILED;
5737 break;
5738 }
5739 cur_file_ofs += read_buf_avail;
5740 out_buf_ofs += read_buf_avail;
5741 comp_remaining -= read_buf_avail;
5742 }
5743 }
5744 } else {
5745 tinfl_decompressor inflator;
5746 tinfl_init(&inflator);
5747
5748 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5749 TINFL_LZ_DICT_SIZE)))
5750 status = TINFL_STATUS_FAILED;
5751 else {
5752 do {
5753 mz_uint8 *pWrite_buf_cur =
5754 (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5755 size_t in_buf_size,
5756 out_buf_size =
5757 TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5758 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
5759 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5760 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5761 (size_t)read_buf_avail) != read_buf_avail) {
5762 status = TINFL_STATUS_FAILED;
5763 break;
5764 }
5765 cur_file_ofs += read_buf_avail;
5766 comp_remaining -= read_buf_avail;
5767 read_buf_ofs = 0;
5768 }
5769
5770 in_buf_size = (size_t)read_buf_avail;
5771 status = tinfl_decompress(
5772 &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
5773 (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size,
5774 comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
5775 read_buf_avail -= in_buf_size;
5776 read_buf_ofs += in_buf_size;
5777
5778 if (out_buf_size) {
5779 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) !=
5780 out_buf_size) {
5781 status = TINFL_STATUS_FAILED;
5782 break;
5783 }
5784 file_crc32 =
5785 (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
5786 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) {
5787 status = TINFL_STATUS_FAILED;
5788 break;
5789 }
5790 }
5791 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) ||
5792 (status == TINFL_STATUS_HAS_MORE_OUTPUT));
5793 }
5794 }
5795
5796 if ((status == TINFL_STATUS_DONE) &&
5797 (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) {
5798 // Make sure the entire file was decompressed, and check its CRC.
5799 if ((out_buf_ofs != file_stat.m_uncomp_size) ||
5800 (file_crc32 != file_stat.m_crc32))
5801 status = TINFL_STATUS_FAILED;
5802 }
5803
5804 if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
5805 if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
5806
5807 return status == TINFL_STATUS_DONE;
5808}
5809
5810mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
5811 const char *pFilename,
5812 mz_file_write_func pCallback,
5813 void *pOpaque, mz_uint flags) {
5814 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5815 if (file_index < 0) return MZ_FALSE;
5816 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque,
5817 flags);
5818}
5819
5820#ifndef MINIZ_NO_STDIO
5821static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs,
5822 const void *pBuf, size_t n) {
5823 (void)ofs;
5824 return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);
5825}
5826
5827mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
5828 const char *pDst_filename,
5829 mz_uint flags) {
5830 mz_bool status;
5831 mz_zip_archive_file_stat file_stat;
5832 MZ_FILE *pFile;
5833 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE;
5834 pFile = MZ_FOPEN(pDst_filename, "wb");
5835 if (!pFile) return MZ_FALSE;
5836 status = mz_zip_reader_extract_to_callback(
5837 pZip, file_index, mz_zip_file_write_callback, pFile, flags);
5838 if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE;
5839#ifndef MINIZ_NO_TIME
5840 if (status)
5841 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
5842#endif
5843 return status;
5844}
5845#endif // #ifndef MINIZ_NO_STDIO
5846
5847mz_bool mz_zip_reader_end(mz_zip_archive *pZip) {
5848 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
5849 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5850 return MZ_FALSE;
5851
5852 if (pZip->m_pState) {
5853 mz_zip_internal_state *pState = pZip->m_pState;
5854 pZip->m_pState = NULL;
5855 mz_zip_array_clear(pZip, &pState->m_central_dir);
5856 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
5857 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
5858
5859#ifndef MINIZ_NO_STDIO
5860 if (pState->m_pFile) {
5861 MZ_FCLOSE(pState->m_pFile);
5862 pState->m_pFile = NULL;
5863 }
5864#endif // #ifndef MINIZ_NO_STDIO
5865
5866 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5867 }
5868 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
5869
5870 return MZ_TRUE;
5871}
5872
5873#ifndef MINIZ_NO_STDIO
5874mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
5875 const char *pArchive_filename,
5876 const char *pDst_filename,
5877 mz_uint flags) {
5878 int file_index =
5879 mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags);
5880 if (file_index < 0) return MZ_FALSE;
5881 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
5882}
5883#endif
5884
5885// ------------------- .ZIP archive writing
5886
5887#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
5888
5889static void mz_write_le16(mz_uint8 *p, mz_uint16 v) {
5890 p[0] = (mz_uint8)v;
5891 p[1] = (mz_uint8)(v >> 8);
5892}
5893static void mz_write_le32(mz_uint8 *p, mz_uint32 v) {
5894 p[0] = (mz_uint8)v;
5895 p[1] = (mz_uint8)(v >> 8);
5896 p[2] = (mz_uint8)(v >> 16);
5897 p[3] = (mz_uint8)(v >> 24);
5898}
5899#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
5900#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
5901
5902mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) {
5903 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) ||
5904 (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
5905 return MZ_FALSE;
5906
5907 if (pZip->m_file_offset_alignment) {
5908 // Ensure user specified file offset alignment is a power of 2.
5909 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
5910 return MZ_FALSE;
5911 }
5912
5913 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
5914 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
5915 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
5916
5917 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
5918 pZip->m_archive_size = existing_size;
5919 pZip->m_central_directory_file_ofs = 0;
5920 pZip->m_total_files = 0;
5921
5922 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
5923 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
5924 return MZ_FALSE;
5925 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
5926 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
5927 sizeof(mz_uint8));
5928 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
5929 sizeof(mz_uint32));
5930 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
5931 sizeof(mz_uint32));
5932 return MZ_TRUE;
5933}
5934
5935static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs,
5936 const void *pBuf, size_t n) {
5937 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5938 mz_zip_internal_state *pState = pZip->m_pState;
5939 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
5940#ifdef _MSC_VER
5941 if ((!n) ||
5942 ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
5943#else
5944 if ((!n) ||
5945 ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
5946#endif
5947 return 0;
5948 if (new_size > pState->m_mem_capacity) {
5949 void *pNew_block;
5950 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);
5951 while (new_capacity < new_size) new_capacity *= 2;
5952 if (NULL == (pNew_block = pZip->m_pRealloc(
5953 pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
5954 return 0;
5955 pState->m_pMem = pNew_block;
5956 pState->m_mem_capacity = new_capacity;
5957 }
5958 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
5959 pState->m_mem_size = (size_t)new_size;
5960 return n;
5961}
5962
5963mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
5964 size_t size_to_reserve_at_beginning,
5965 size_t initial_allocation_size) {
5966 pZip->m_pWrite = mz_zip_heap_write_func;
5967 pZip->m_pIO_opaque = pZip;
5968 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE;
5969 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size,
5970 size_to_reserve_at_beginning))) {
5971 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(
5972 pZip->m_pAlloc_opaque, 1, initial_allocation_size))) {
5973 mz_zip_writer_end(pZip);
5974 return MZ_FALSE;
5975 }
5976 pZip->m_pState->m_mem_capacity = initial_allocation_size;
5977 }
5978 return MZ_TRUE;
5979}
5980
5981#ifndef MINIZ_NO_STDIO
5982static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs,
5983 const void *pBuf, size_t n) {
5984 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5985 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
5986 if (((mz_int64)file_ofs < 0) ||
5987 (((cur_ofs != (mz_int64)file_ofs)) &&
5988 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
5989 return 0;
5990 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
5991}
5992
5993mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
5994 mz_uint64 size_to_reserve_at_beginning) {
5995 MZ_FILE *pFile;
5996 pZip->m_pWrite = mz_zip_file_write_func;
5997 pZip->m_pIO_opaque = pZip;
5998 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE;
5999 if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) {
6000 mz_zip_writer_end(pZip);
6001 return MZ_FALSE;
6002 }
6003 pZip->m_pState->m_pFile = pFile;
6004 if (size_to_reserve_at_beginning) {
6005 mz_uint64 cur_ofs = 0;
6006 char buf[4096];
6007 MZ_CLEAR_OBJ(buf);
6008 do {
6009 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
6010 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) {
6011 mz_zip_writer_end(pZip);
6012 return MZ_FALSE;
6013 }
6014 cur_ofs += n;
6015 size_to_reserve_at_beginning -= n;
6016 } while (size_to_reserve_at_beginning);
6017 }
6018 return MZ_TRUE;
6019}
6020#endif // #ifndef MINIZ_NO_STDIO
6021
6022mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
6023 const char *pFilename) {
6024 mz_zip_internal_state *pState;
6025 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
6026 return MZ_FALSE;
6027 // No sense in trying to write to an archive that's already at the support max
6028 // size
6029 if ((pZip->m_total_files == 0xFFFF) ||
6030 ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6031 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
6032 return MZ_FALSE;
6033
6034 pState = pZip->m_pState;
6035
6036 if (pState->m_pFile) {
6037#ifdef MINIZ_NO_STDIO
6038 pFilename;
6039 return MZ_FALSE;
6040#else
6041 // Archive is being read from stdio - try to reopen as writable.
6042 if (pZip->m_pIO_opaque != pZip) return MZ_FALSE;
6043 if (!pFilename) return MZ_FALSE;
6044 pZip->m_pWrite = mz_zip_file_write_func;
6045 if (NULL ==
6046 (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) {
6047 // The mz_zip_archive is now in a bogus state because pState->m_pFile is
6048 // NULL, so just close it.
6049 mz_zip_reader_end(pZip);
6050 return MZ_FALSE;
6051 }
6052#endif // #ifdef MINIZ_NO_STDIO
6053 } else if (pState->m_pMem) {
6054 // Archive lives in a memory block. Assume it's from the heap that we can
6055 // resize using the realloc callback.
6056 if (pZip->m_pIO_opaque != pZip) return MZ_FALSE;
6057 pState->m_mem_capacity = pState->m_mem_size;
6058 pZip->m_pWrite = mz_zip_heap_write_func;
6059 }
6060 // Archive is being read via a user provided read function - make sure the
6061 // user has specified a write function too.
6062 else if (!pZip->m_pWrite)
6063 return MZ_FALSE;
6064
6065 // Start writing new files at the archive's current central directory
6066 // location.
6067 pZip->m_archive_size = pZip->m_central_directory_file_ofs;
6068 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
6069 pZip->m_central_directory_file_ofs = 0;
6070
6071 return MZ_TRUE;
6072}
6073
6074mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
6075 const void *pBuf, size_t buf_size,
6076 mz_uint level_and_flags) {
6077 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0,
6078 level_and_flags, 0, 0);
6079}
6080
6081typedef struct {
6082 mz_zip_archive *m_pZip;
6083 mz_uint64 m_cur_archive_file_ofs;
6084 mz_uint64 m_comp_size;
6085} mz_zip_writer_add_state;
6086
6087static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len,
6088 void *pUser) {
6089 mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
6090 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque,
6091 pState->m_cur_archive_file_ofs, pBuf,
6092 len) != len)
6093 return MZ_FALSE;
6094 pState->m_cur_archive_file_ofs += len;
6095 pState->m_comp_size += len;
6096 return MZ_TRUE;
6097}
6098
6099static mz_bool mz_zip_writer_create_local_dir_header(
6100 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
6101 mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
6102 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
6103 mz_uint16 dos_time, mz_uint16 dos_date) {
6104 (void)pZip;
6105 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
6106 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
6107 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
6108 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
6109 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
6110 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
6111 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
6112 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
6113 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size);
6114 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
6115 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
6116 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
6117 return MZ_TRUE;
6118}
6119
6120static mz_bool mz_zip_writer_create_central_dir_header(
6121 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
6122 mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size,
6123 mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method,
6124 mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
6125 mz_uint64 local_header_ofs, mz_uint32 ext_attributes) {
6126 (void)pZip;
6127 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
6128 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
6129 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
6130 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
6131 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
6132 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
6133 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
6134 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
6135 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size);
6136 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
6137 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
6138 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
6139 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
6140 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
6141 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs);
6142 return MZ_TRUE;
6143}
6144
6145static mz_bool mz_zip_writer_add_to_central_dir(
6146 mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,
6147 const void *pExtra, mz_uint16 extra_size, const void *pComment,
6148 mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
6149 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
6150 mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs,
6151 mz_uint32 ext_attributes) {
6152 mz_zip_internal_state *pState = pZip->m_pState;
6153 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
6154 size_t orig_central_dir_size = pState->m_central_dir.m_size;
6155 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6156
6157 // No zip64 support yet
6158 if ((local_header_ofs > 0xFFFFFFFF) ||
6159 (((mz_uint64)pState->m_central_dir.m_size +
6160 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size +
6161 comment_size) > 0xFFFFFFFF))
6162 return MZ_FALSE;
6163
6164 if (!mz_zip_writer_create_central_dir_header(
6165 pZip, central_dir_header, filename_size, extra_size, comment_size,
6166 uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time,
6167 dos_date, local_header_ofs, ext_attributes))
6168 return MZ_FALSE;
6169
6170 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header,
6171 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
6172 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename,
6173 filename_size)) ||
6174 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra,
6175 extra_size)) ||
6176 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment,
6177 comment_size)) ||
6178 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets,
6179 &central_dir_ofs, 1))) {
6180 // Try to push the central directory array back into its original state.
6181 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6182 MZ_FALSE);
6183 return MZ_FALSE;
6184 }
6185
6186 return MZ_TRUE;
6187}
6188
6189static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) {
6190 // Basic ZIP archive filename validity checks: Valid filenames cannot start
6191 // with a forward slash, cannot contain a drive letter, and cannot use
6192 // DOS-style backward slashes.
6193 if (*pArchive_name == '/') return MZ_FALSE;
6194 while (*pArchive_name) {
6195 if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE;
6196 pArchive_name++;
6197 }
6198 return MZ_TRUE;
6199}
6200
6201static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(
6202 mz_zip_archive *pZip) {
6203 mz_uint32 n;
6204 if (!pZip->m_file_offset_alignment) return 0;
6205 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
6206 return (pZip->m_file_offset_alignment - n) &
6207 (pZip->m_file_offset_alignment - 1);
6208}
6209
6210static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip,
6211 mz_uint64 cur_file_ofs, mz_uint32 n) {
6212 char buf[4096];
6213 memset(buf, 0, MZ_MIN(sizeof(buf), n));
6214 while (n) {
6215 mz_uint32 s = MZ_MIN(sizeof(buf), n);
6216 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
6217 return MZ_FALSE;
6218 cur_file_ofs += s;
6219 n -= s;
6220 }
6221 return MZ_TRUE;
6222}
6223
6224mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
6225 const char *pArchive_name, const void *pBuf,
6226 size_t buf_size, const void *pComment,
6227 mz_uint16 comment_size,
6228 mz_uint level_and_flags, mz_uint64 uncomp_size,
6229 mz_uint32 uncomp_crc32) {
6230 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
6231 mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
6232 mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
6233 cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
6234 size_t archive_name_size;
6235 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6236 tdefl_compressor *pComp = NULL;
6237 mz_bool store_data_uncompressed;
6238 mz_zip_internal_state *pState;
6239
6240 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
6241 level = level_and_flags & 0xF;
6242 store_data_uncompressed =
6243 ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
6244
6245 if ((!pZip) || (!pZip->m_pState) ||
6246 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) ||
6247 (!pArchive_name) || ((comment_size) && (!pComment)) ||
6248 (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION))
6249 return MZ_FALSE;
6250
6251 pState = pZip->m_pState;
6252
6253 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
6254 return MZ_FALSE;
6255 // No zip64 support yet
6256 if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE;
6257 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
6258
6259#ifndef MINIZ_NO_TIME
6260 {
6261 time_t cur_time;
6262 time(&cur_time);
6263 mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date);
6264 }
6265#endif // #ifndef MINIZ_NO_TIME
6266
6267 archive_name_size = strlen(pArchive_name);
6268 if (archive_name_size > 0xFFFF) return MZ_FALSE;
6269
6270 num_alignment_padding_bytes =
6271 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6272
6273 // no zip64 support yet
6274 if ((pZip->m_total_files == 0xFFFF) ||
6275 ((pZip->m_archive_size + num_alignment_padding_bytes +
6276 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6277 comment_size + archive_name_size) > 0xFFFFFFFF))
6278 return MZ_FALSE;
6279
6280 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) {
6281 // Set DOS Subdirectory attribute bit.
6282 ext_attributes |= 0x10;
6283 // Subdirectories cannot contain data.
6284 if ((buf_size) || (uncomp_size)) return MZ_FALSE;
6285 }
6286
6287 // Try to do any allocations before writing to the archive, so if an
6288 // allocation fails the file remains unmodified. (A good idea if we're doing
6289 // an in-place modification.)
6290 if ((!mz_zip_array_ensure_room(
6291 pZip, &pState->m_central_dir,
6292 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) ||
6293 (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
6294 return MZ_FALSE;
6295
6296 if ((!store_data_uncompressed) && (buf_size)) {
6297 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(
6298 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
6299 return MZ_FALSE;
6300 }
6301
6302 if (!mz_zip_writer_write_zeros(
6303 pZip, cur_archive_file_ofs,
6304 num_alignment_padding_bytes + sizeof(local_dir_header))) {
6305 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6306 return MZ_FALSE;
6307 }
6308 local_dir_header_ofs += num_alignment_padding_bytes;
6309 if (pZip->m_file_offset_alignment) {
6310 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6311 0);
6312 }
6313 cur_archive_file_ofs +=
6314 num_alignment_padding_bytes + sizeof(local_dir_header);
6315
6316 MZ_CLEAR_OBJ(local_dir_header);
6317 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6318 archive_name_size) != archive_name_size) {
6319 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6320 return MZ_FALSE;
6321 }
6322 cur_archive_file_ofs += archive_name_size;
6323
6324 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
6325 uncomp_crc32 =
6326 (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
6327 uncomp_size = buf_size;
6328 if (uncomp_size <= 3) {
6329 level = 0;
6330 store_data_uncompressed = MZ_TRUE;
6331 }
6332 }
6333
6334 if (store_data_uncompressed) {
6335 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf,
6336 buf_size) != buf_size) {
6337 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6338 return MZ_FALSE;
6339 }
6340
6341 cur_archive_file_ofs += buf_size;
6342 comp_size = buf_size;
6343
6344 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED;
6345 } else if (buf_size) {
6346 mz_zip_writer_add_state state;
6347
6348 state.m_pZip = pZip;
6349 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6350 state.m_comp_size = 0;
6351
6352 if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
6353 tdefl_create_comp_flags_from_zip_params(
6354 level, -15, MZ_DEFAULT_STRATEGY)) !=
6355 TDEFL_STATUS_OKAY) ||
6356 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) !=
6357 TDEFL_STATUS_DONE)) {
6358 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6359 return MZ_FALSE;
6360 }
6361
6362 comp_size = state.m_comp_size;
6363 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6364
6365 method = MZ_DEFLATED;
6366 }
6367
6368 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6369 pComp = NULL;
6370
6371 // no zip64 support yet
6372 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
6373 return MZ_FALSE;
6374
6375 if (!mz_zip_writer_create_local_dir_header(
6376 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
6377 comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
6378 return MZ_FALSE;
6379
6380 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
6381 sizeof(local_dir_header)) != sizeof(local_dir_header))
6382 return MZ_FALSE;
6383
6384 if (!mz_zip_writer_add_to_central_dir(
6385 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
6386 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
6387 dos_time, dos_date, local_dir_header_ofs, ext_attributes))
6388 return MZ_FALSE;
6389
6390 pZip->m_total_files++;
6391 pZip->m_archive_size = cur_archive_file_ofs;
6392
6393 return MZ_TRUE;
6394}
6395
6396#ifndef MINIZ_NO_STDIO
6397mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
6398 const char *pSrc_filename, const void *pComment,
6399 mz_uint16 comment_size,
6400 mz_uint level_and_flags) {
6401 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
6402 mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
6403 mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
6404 cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0,
6405 comp_size = 0;
6406 size_t archive_name_size;
6407 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6408 MZ_FILE *pSrc_file = NULL;
6409
6410 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
6411 level = level_and_flags & 0xF;
6412
6413 if ((!pZip) || (!pZip->m_pState) ||
6414 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) ||
6415 ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
6416 return MZ_FALSE;
6417 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE;
6418 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
6419
6420 archive_name_size = strlen(pArchive_name);
6421 if (archive_name_size > 0xFFFF) return MZ_FALSE;
6422
6423 num_alignment_padding_bytes =
6424 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6425
6426 // no zip64 support yet
6427 if ((pZip->m_total_files == 0xFFFF) ||
6428 ((pZip->m_archive_size + num_alignment_padding_bytes +
6429 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6430 comment_size + archive_name_size) > 0xFFFFFFFF))
6431 return MZ_FALSE;
6432
6433 if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date))
6434 return MZ_FALSE;
6435
6436 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
6437 if (!pSrc_file) return MZ_FALSE;
6438 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
6439 uncomp_size = MZ_FTELL64(pSrc_file);
6440 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
6441
6442 if (uncomp_size > 0xFFFFFFFF) {
6443 // No zip64 support yet
6444 MZ_FCLOSE(pSrc_file);
6445 return MZ_FALSE;
6446 }
6447 if (uncomp_size <= 3) level = 0;
6448
6449 if (!mz_zip_writer_write_zeros(
6450 pZip, cur_archive_file_ofs,
6451 num_alignment_padding_bytes + sizeof(local_dir_header))) {
6452 MZ_FCLOSE(pSrc_file);
6453 return MZ_FALSE;
6454 }
6455 local_dir_header_ofs += num_alignment_padding_bytes;
6456 if (pZip->m_file_offset_alignment) {
6457 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6458 0);
6459 }
6460 cur_archive_file_ofs +=
6461 num_alignment_padding_bytes + sizeof(local_dir_header);
6462
6463 MZ_CLEAR_OBJ(local_dir_header);
6464 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6465 archive_name_size) != archive_name_size) {
6466 MZ_FCLOSE(pSrc_file);
6467 return MZ_FALSE;
6468 }
6469 cur_archive_file_ofs += archive_name_size;
6470
6471 if (uncomp_size) {
6472 mz_uint64 uncomp_remaining = uncomp_size;
6473 void *pRead_buf =
6474 pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
6475 if (!pRead_buf) {
6476 MZ_FCLOSE(pSrc_file);
6477 return MZ_FALSE;
6478 }
6479
6480 if (!level) {
6481 while (uncomp_remaining) {
6482 mz_uint n =
6483 (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
6484 if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) ||
6485 (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf,
6486 n) != n)) {
6487 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6488 MZ_FCLOSE(pSrc_file);
6489 return MZ_FALSE;
6490 }
6491 uncomp_crc32 =
6492 (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
6493 uncomp_remaining -= n;
6494 cur_archive_file_ofs += n;
6495 }
6496 comp_size = uncomp_size;
6497 } else {
6498 mz_bool result = MZ_FALSE;
6499 mz_zip_writer_add_state state;
6500 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(
6501 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
6502 if (!pComp) {
6503 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6504 MZ_FCLOSE(pSrc_file);
6505 return MZ_FALSE;
6506 }
6507
6508 state.m_pZip = pZip;
6509 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6510 state.m_comp_size = 0;
6511
6512 if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
6513 tdefl_create_comp_flags_from_zip_params(
6514 level, -15, MZ_DEFAULT_STRATEGY)) !=
6515 TDEFL_STATUS_OKAY) {
6516 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6517 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6518 MZ_FCLOSE(pSrc_file);
6519 return MZ_FALSE;
6520 }
6521
6522 for (;;) {
6523 size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining,
6524 (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE);
6525 tdefl_status status;
6526
6527 if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
6528 break;
6529
6530 uncomp_crc32 = (mz_uint32)mz_crc32(
6531 uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
6532 uncomp_remaining -= in_buf_size;
6533
6534 status = tdefl_compress_buffer(
6535 pComp, pRead_buf, in_buf_size,
6536 uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH);
6537 if (status == TDEFL_STATUS_DONE) {
6538 result = MZ_TRUE;
6539 break;
6540 } else if (status != TDEFL_STATUS_OKAY)
6541 break;
6542 }
6543
6544 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6545
6546 if (!result) {
6547 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6548 MZ_FCLOSE(pSrc_file);
6549 return MZ_FALSE;
6550 }
6551
6552 comp_size = state.m_comp_size;
6553 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6554
6555 method = MZ_DEFLATED;
6556 }
6557
6558 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6559 }
6560
6561 MZ_FCLOSE(pSrc_file);
6562 pSrc_file = NULL;
6563
6564 // no zip64 support yet
6565 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
6566 return MZ_FALSE;
6567
6568 if (!mz_zip_writer_create_local_dir_header(
6569 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
6570 comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
6571 return MZ_FALSE;
6572
6573 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
6574 sizeof(local_dir_header)) != sizeof(local_dir_header))
6575 return MZ_FALSE;
6576
6577 if (!mz_zip_writer_add_to_central_dir(
6578 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
6579 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
6580 dos_time, dos_date, local_dir_header_ofs, ext_attributes))
6581 return MZ_FALSE;
6582
6583 pZip->m_total_files++;
6584 pZip->m_archive_size = cur_archive_file_ofs;
6585
6586 return MZ_TRUE;
6587}
6588#endif // #ifndef MINIZ_NO_STDIO
6589
6590mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
6591 mz_zip_archive *pSource_zip,
6592 mz_uint file_index) {
6593 mz_uint n, bit_flags, num_alignment_padding_bytes;
6594 mz_uint64 comp_bytes_remaining, local_dir_header_ofs;
6595 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
6596 mz_uint32
6597 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
6598 sizeof(mz_uint32)];
6599 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
6600 mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6601 size_t orig_central_dir_size;
6602 mz_zip_internal_state *pState;
6603 void *pBuf;
6604 const mz_uint8 *pSrc_central_header;
6605
6606 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
6607 return MZ_FALSE;
6608 if (NULL ==
6609 (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index)))
6610 return MZ_FALSE;
6611 pState = pZip->m_pState;
6612
6613 num_alignment_padding_bytes =
6614 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6615
6616 // no zip64 support yet
6617 if ((pZip->m_total_files == 0xFFFF) ||
6618 ((pZip->m_archive_size + num_alignment_padding_bytes +
6619 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) >
6620 0xFFFFFFFF))
6621 return MZ_FALSE;
6622
6623 cur_src_file_ofs =
6624 MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
6625 cur_dst_file_ofs = pZip->m_archive_size;
6626
6627 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
6628 pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6629 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6630 return MZ_FALSE;
6631 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
6632 return MZ_FALSE;
6633 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
6634
6635 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs,
6636 num_alignment_padding_bytes))
6637 return MZ_FALSE;
6638 cur_dst_file_ofs += num_alignment_padding_bytes;
6639 local_dir_header_ofs = cur_dst_file_ofs;
6640 if (pZip->m_file_offset_alignment) {
6641 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6642 0);
6643 }
6644
6645 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header,
6646 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6647 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6648 return MZ_FALSE;
6649 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
6650
6651 n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
6652 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
6653 comp_bytes_remaining =
6654 n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
6655
6656 if (NULL == (pBuf = pZip->m_pAlloc(
6657 pZip->m_pAlloc_opaque, 1,
6658 (size_t)MZ_MAX(sizeof(mz_uint32) * 4,
6659 MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE,
6660 comp_bytes_remaining)))))
6661 return MZ_FALSE;
6662
6663 while (comp_bytes_remaining) {
6664 n = (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining);
6665 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
6666 n) != n) {
6667 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6668 return MZ_FALSE;
6669 }
6670 cur_src_file_ofs += n;
6671
6672 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
6673 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6674 return MZ_FALSE;
6675 }
6676 cur_dst_file_ofs += n;
6677
6678 comp_bytes_remaining -= n;
6679 }
6680
6681 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
6682 if (bit_flags & 8) {
6683 // Copy data descriptor
6684 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
6685 sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) {
6686 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6687 return MZ_FALSE;
6688 }
6689
6690 n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3);
6691 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
6692 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6693 return MZ_FALSE;
6694 }
6695
6696 cur_src_file_ofs += n;
6697 cur_dst_file_ofs += n;
6698 }
6699 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6700
6701 // no zip64 support yet
6702 if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE;
6703
6704 orig_central_dir_size = pState->m_central_dir.m_size;
6705
6706 memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
6707 MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
6708 local_dir_header_ofs);
6709 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header,
6710 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
6711 return MZ_FALSE;
6712
6713 n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
6714 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
6715 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
6716 if (!mz_zip_array_push_back(
6717 pZip, &pState->m_central_dir,
6718 pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) {
6719 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6720 MZ_FALSE);
6721 return MZ_FALSE;
6722 }
6723
6724 if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE;
6725 n = (mz_uint32)orig_central_dir_size;
6726 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) {
6727 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6728 MZ_FALSE);
6729 return MZ_FALSE;
6730 }
6731
6732 pZip->m_total_files++;
6733 pZip->m_archive_size = cur_dst_file_ofs;
6734
6735 return MZ_TRUE;
6736}
6737
6738mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) {
6739 mz_zip_internal_state *pState;
6740 mz_uint64 central_dir_ofs, central_dir_size;
6741 mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE];
6742
6743 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
6744 return MZ_FALSE;
6745
6746 pState = pZip->m_pState;
6747
6748 // no zip64 support yet
6749 if ((pZip->m_total_files > 0xFFFF) ||
6750 ((pZip->m_archive_size + pState->m_central_dir.m_size +
6751 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
6752 return MZ_FALSE;
6753
6754 central_dir_ofs = 0;
6755 central_dir_size = 0;
6756 if (pZip->m_total_files) {
6757 // Write central directory
6758 central_dir_ofs = pZip->m_archive_size;
6759 central_dir_size = pState->m_central_dir.m_size;
6760 pZip->m_central_directory_file_ofs = central_dir_ofs;
6761 if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs,
6762 pState->m_central_dir.m_p,
6763 (size_t)central_dir_size) != central_dir_size)
6764 return MZ_FALSE;
6765 pZip->m_archive_size += central_dir_size;
6766 }
6767
6768 // Write end of central directory record
6769 MZ_CLEAR_OBJ(hdr);
6770 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS,
6771 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
6772 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS,
6773 pZip->m_total_files);
6774 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
6775 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size);
6776 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs);
6777
6778 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
6779 sizeof(hdr)) != sizeof(hdr))
6780 return MZ_FALSE;
6781#ifndef MINIZ_NO_STDIO
6782 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE;
6783#endif // #ifndef MINIZ_NO_STDIO
6784
6785 pZip->m_archive_size += sizeof(hdr);
6786
6787 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
6788 return MZ_TRUE;
6789}
6790
6791mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
6792 size_t *pSize) {
6793 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE;
6794 if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE;
6795 if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE;
6796
6797 *pBuf = pZip->m_pState->m_pMem;
6798 *pSize = pZip->m_pState->m_mem_size;
6799 pZip->m_pState->m_pMem = NULL;
6800 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
6801 return MZ_TRUE;
6802}
6803
6804mz_bool mz_zip_writer_end(mz_zip_archive *pZip) {
6805 mz_zip_internal_state *pState;
6806 mz_bool status = MZ_TRUE;
6807 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
6808 ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) &&
6809 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))
6810 return MZ_FALSE;
6811
6812 pState = pZip->m_pState;
6813 pZip->m_pState = NULL;
6814 mz_zip_array_clear(pZip, &pState->m_central_dir);
6815 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
6816 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
6817
6818#ifndef MINIZ_NO_STDIO
6819 if (pState->m_pFile) {
6820 MZ_FCLOSE(pState->m_pFile);
6821 pState->m_pFile = NULL;
6822 }
6823#endif // #ifndef MINIZ_NO_STDIO
6824
6825 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
6826 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
6827 pState->m_pMem = NULL;
6828 }
6829
6830 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
6831 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
6832 return status;
6833}
6834
6835#ifndef MINIZ_NO_STDIO
6836mz_bool mz_zip_add_mem_to_archive_file_in_place(
6837 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
6838 size_t buf_size, const void *pComment, mz_uint16 comment_size,
6839 mz_uint level_and_flags) {
6840 mz_bool status, created_new_archive = MZ_FALSE;
6841 mz_zip_archive zip_archive;
6842 struct MZ_FILE_STAT_STRUCT file_stat;
6843 MZ_CLEAR_OBJ(zip_archive);
6844 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL;
6845 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) ||
6846 ((comment_size) && (!pComment)) ||
6847 ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
6848 return MZ_FALSE;
6849 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE;
6850 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) {
6851 // Create a new archive.
6852 if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0))
6853 return MZ_FALSE;
6854 created_new_archive = MZ_TRUE;
6855 } else {
6856 // Append to an existing archive.
6857 if (!mz_zip_reader_init_file(
6858 &zip_archive, pZip_filename,
6859 level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
6860 return MZ_FALSE;
6861 if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) {
6862 mz_zip_reader_end(&zip_archive);
6863 return MZ_FALSE;
6864 }
6865 }
6866 status =
6867 mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size,
6868 pComment, comment_size, level_and_flags, 0, 0);
6869 // Always finalize, even if adding failed for some reason, so we have a valid
6870 // central directory. (This may not always succeed, but we can try.)
6871 if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE;
6872 if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE;
6873 if ((!status) && (created_new_archive)) {
6874 // It's a new archive and something went wrong, so just delete it.
6875 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
6876 (void)ignoredStatus;
6877 }
6878 return status;
6879}
6880
6881void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
6882 const char *pArchive_name,
6883 size_t *pSize, mz_uint flags) {
6884 int file_index;
6885 mz_zip_archive zip_archive;
6886 void *p = NULL;
6887
6888 if (pSize) *pSize = 0;
6889
6890 if ((!pZip_filename) || (!pArchive_name)) return NULL;
6891
6892 MZ_CLEAR_OBJ(zip_archive);
6893 if (!mz_zip_reader_init_file(
6894 &zip_archive, pZip_filename,
6895 flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
6896 return NULL;
6897
6898 if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL,
6899 flags)) >= 0)
6900 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
6901
6902 mz_zip_reader_end(&zip_archive);
6903 return p;
6904}
6905
6906#endif // #ifndef MINIZ_NO_STDIO
6907
6908#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
6909
6910#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
6911
6912#ifdef __cplusplus
6913}
6914#endif
6915
6916#endif // MINIZ_HEADER_FILE_ONLY
6917
6918/*
6919 This is free and unencumbered software released into the public domain.
6920
6921 Anyone is free to copy, modify, publish, use, compile, sell, or
6922 distribute this software, either in source code form or as a compiled
6923 binary, for any purpose, commercial or non-commercial, and by any
6924 means.
6925
6926 In jurisdictions that recognize copyright laws, the author or authors
6927 of this software dedicate any and all copyright interest in the
6928 software to the public domain. We make this dedication for the benefit
6929 of the public at large and to the detriment of our heirs and
6930 successors. We intend this dedication to be an overt act of
6931 relinquishment in perpetuity of all present and future rights to this
6932 software under copyright law.
6933
6934 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
6935 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
6936 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
6937 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
6938 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
6939 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
6940 OTHER DEALINGS IN THE SOFTWARE.
6941
6942 For more information, please refer to <http://unlicense.org/>
6943*/
6944
6945// ---------------------- end of miniz ----------------------------------------
6946
6947#ifdef __clang__
6948#pragma clang diagnostic pop
6949#endif
6950
6951#ifdef _MSC_VER
6952#pragma warning(pop)
6953#endif
6954} // namespace miniz
6955#else
6956
6957// Reuse MINIZ_LITTE_ENDIAN macro
6958
6959#if defined(__sparcv9)
6960// Big endian
6961#else
6962#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
6963// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
6964#define MINIZ_LITTLE_ENDIAN 1
6965#endif
6966#endif
6967
6968#endif // TINYEXR_USE_MINIZ
6969
6970// static bool IsBigEndian(void) {
6971// union {
6972// unsigned int i;
6973// char c[4];
6974// } bint = {0x01020304};
6975//
6976// return bint.c[0] == 1;
6977//}
6978
6979static void SetErrorMessage(const std::string &msg, const char **err) {
6980 if (err) {
6981#ifdef _WIN32
6982 (*err) = _strdup(msg.c_str());
6983#else
6984 (*err) = strdup(msg.c_str());
6985#endif
6986 }
6987}
6988
6989static const int kEXRVersionSize = 8;
6990
6991static void cpy2(unsigned short *dst_val, const unsigned short *src_val) {
6992 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
6993 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
6994
6995 dst[0] = src[0];
6996 dst[1] = src[1];
6997}
6998
6999static void swap2(unsigned short *val) {
7000#ifdef MINIZ_LITTLE_ENDIAN
7001 (void)val;
7002#else
7003 unsigned short tmp = *val;
7004 unsigned char *dst = reinterpret_cast<unsigned char *>(val);
7005 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
7006
7007 dst[0] = src[1];
7008 dst[1] = src[0];
7009#endif
7010}
7011
7012#ifdef __clang__
7013#pragma clang diagnostic push
7014#pragma clang diagnostic ignored "-Wunused-function"
7015#endif
7016static void cpy4(int *dst_val, const int *src_val) {
7017 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7018 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7019
7020 dst[0] = src[0];
7021 dst[1] = src[1];
7022 dst[2] = src[2];
7023 dst[3] = src[3];
7024}
7025
7026static void cpy4(unsigned int *dst_val, const unsigned int *src_val) {
7027 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7028 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7029
7030 dst[0] = src[0];
7031 dst[1] = src[1];
7032 dst[2] = src[2];
7033 dst[3] = src[3];
7034}
7035
7036static void cpy4(float *dst_val, const float *src_val) {
7037 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7038 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7039
7040 dst[0] = src[0];
7041 dst[1] = src[1];
7042 dst[2] = src[2];
7043 dst[3] = src[3];
7044}
7045#ifdef __clang__
7046#pragma clang diagnostic pop
7047#endif
7048
7049static void swap4(unsigned int *val) {
7050#ifdef MINIZ_LITTLE_ENDIAN
7051 (void)val;
7052#else
7053 unsigned int tmp = *val;
7054 unsigned char *dst = reinterpret_cast<unsigned char *>(val);
7055 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
7056
7057 dst[0] = src[3];
7058 dst[1] = src[2];
7059 dst[2] = src[1];
7060 dst[3] = src[0];
7061#endif
7062}
7063
7064#if 0
7065static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) {
7066 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
7067 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
7068
7069 dst[0] = src[0];
7070 dst[1] = src[1];
7071 dst[2] = src[2];
7072 dst[3] = src[3];
7073 dst[4] = src[4];
7074 dst[5] = src[5];
7075 dst[6] = src[6];
7076 dst[7] = src[7];
7077}
7078#endif
7079
7080static void swap8(tinyexr::tinyexr_uint64 *val) {
7081#ifdef MINIZ_LITTLE_ENDIAN
7082 (void)val;
7083#else
7084 tinyexr::tinyexr_uint64 tmp = (*val);
7085 unsigned char *dst = reinterpret_cast<unsigned char *>(val);
7086 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
7087
7088 dst[0] = src[7];
7089 dst[1] = src[6];
7090 dst[2] = src[5];
7091 dst[3] = src[4];
7092 dst[4] = src[3];
7093 dst[5] = src[2];
7094 dst[6] = src[1];
7095 dst[7] = src[0];
7096#endif
7097}
7098
7099// https://gist.github.com/rygorous/2156668
7100// Reuse MINIZ_LITTLE_ENDIAN flag from miniz.
7101union FP32 {
7102 unsigned int u;
7103 float f;
7104 struct {
7105#if MINIZ_LITTLE_ENDIAN
7106 unsigned int Mantissa : 23;
7107 unsigned int Exponent : 8;
7108 unsigned int Sign : 1;
7109#else
7110 unsigned int Sign : 1;
7111 unsigned int Exponent : 8;
7112 unsigned int Mantissa : 23;
7113#endif
7114 } s;
7115};
7116
7117#ifdef __clang__
7118#pragma clang diagnostic push
7119#pragma clang diagnostic ignored "-Wpadded"
7120#endif
7121
7122union FP16 {
7123 unsigned short u;
7124 struct {
7125#if MINIZ_LITTLE_ENDIAN
7126 unsigned int Mantissa : 10;
7127 unsigned int Exponent : 5;
7128 unsigned int Sign : 1;
7129#else
7130 unsigned int Sign : 1;
7131 unsigned int Exponent : 5;
7132 unsigned int Mantissa : 10;
7133#endif
7134 } s;
7135};
7136
7137#ifdef __clang__
7138#pragma clang diagnostic pop
7139#endif
7140
7141static FP32 half_to_float(FP16 h) {
7142 static const FP32 magic = {113 << 23};
7143 static const unsigned int shifted_exp = 0x7c00
7144 << 13; // exponent mask after shift
7145 FP32 o;
7146
7147 o.u = (h.u & 0x7fffU) << 13U; // exponent/mantissa bits
7148 unsigned int exp_ = shifted_exp & o.u; // just the exponent
7149 o.u += (127 - 15) << 23; // exponent adjust
7150
7151 // handle exponent special cases
7152 if (exp_ == shifted_exp) // Inf/NaN?
7153 o.u += (128 - 16) << 23; // extra exp adjust
7154 else if (exp_ == 0) // Zero/Denormal?
7155 {
7156 o.u += 1 << 23; // extra exp adjust
7157 o.f -= magic.f; // renormalize
7158 }
7159
7160 o.u |= (h.u & 0x8000U) << 16U; // sign bit
7161 return o;
7162}
7163
7164static FP16 float_to_half_full(FP32 f) {
7165 FP16 o = {0};
7166
7167 // Based on ISPC reference code (with minor modifications)
7168 if (f.s.Exponent == 0) // Signed zero/denormal (which will underflow)
7169 o.s.Exponent = 0;
7170 else if (f.s.Exponent == 255) // Inf or NaN (all exponent bits set)
7171 {
7172 o.s.Exponent = 31;
7173 o.s.Mantissa = f.s.Mantissa ? 0x200 : 0; // NaN->qNaN and Inf->Inf
7174 } else // Normalized number
7175 {
7176 // Exponent unbias the single, then bias the halfp
7177 int newexp = f.s.Exponent - 127 + 15;
7178 if (newexp >= 31) // Overflow, return signed infinity
7179 o.s.Exponent = 31;
7180 else if (newexp <= 0) // Underflow
7181 {
7182 if ((14 - newexp) <= 24) // Mantissa might be non-zero
7183 {
7184 unsigned int mant = f.s.Mantissa | 0x800000; // Hidden 1 bit
7185 o.s.Mantissa = mant >> (14 - newexp);
7186 if ((mant >> (13 - newexp)) & 1) // Check for rounding
7187 o.u++; // Round, might overflow into exp bit, but this is OK
7188 }
7189 } else {
7190 o.s.Exponent = static_cast<unsigned int>(newexp);
7191 o.s.Mantissa = f.s.Mantissa >> 13;
7192 if (f.s.Mantissa & 0x1000) // Check for rounding
7193 o.u++; // Round, might overflow to inf, this is OK
7194 }
7195 }
7196
7197 o.s.Sign = f.s.Sign;
7198 return o;
7199}
7200
7201// NOTE: From OpenEXR code
7202// #define IMF_INCREASING_Y 0
7203// #define IMF_DECREASING_Y 1
7204// #define IMF_RAMDOM_Y 2
7205//
7206// #define IMF_NO_COMPRESSION 0
7207// #define IMF_RLE_COMPRESSION 1
7208// #define IMF_ZIPS_COMPRESSION 2
7209// #define IMF_ZIP_COMPRESSION 3
7210// #define IMF_PIZ_COMPRESSION 4
7211// #define IMF_PXR24_COMPRESSION 5
7212// #define IMF_B44_COMPRESSION 6
7213// #define IMF_B44A_COMPRESSION 7
7214
7215#ifdef __clang__
7216#pragma clang diagnostic push
7217
7218#if __has_warning("-Wzero-as-null-pointer-constant")
7219#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
7220#endif
7221
7222#endif
7223
7224static const char *ReadString(std::string *s, const char *ptr, size_t len) {
7225 // Read untile NULL(\0).
7226 const char *p = ptr;
7227 const char *q = ptr;
7228 while ((size_t(q - ptr) < len) && (*q) != 0) {
7229 q++;
7230 }
7231
7232 if (size_t(q - ptr) >= len) {
7233 (*s) = std::string();
7234 return NULL;
7235 }
7236
7237 (*s) = std::string(p, q);
7238
7239 return q + 1; // skip '\0'
7240}
7241
7242static bool ReadAttribute(std::string *name, std::string *type,
7243 std::vector<unsigned char> *data, size_t *marker_size,
7244 const char *marker, size_t size) {
7245 size_t name_len = strnlen(marker, size);
7246 if (name_len == size) {
7247 // String does not have a terminating character.
7248 return false;
7249 }
7250 *name = std::string(marker, name_len);
7251
7252 marker += name_len + 1;
7253 size -= name_len + 1;
7254
7255 size_t type_len = strnlen(marker, size);
7256 if (type_len == size) {
7257 return false;
7258 }
7259 *type = std::string(marker, type_len);
7260
7261 marker += type_len + 1;
7262 size -= type_len + 1;
7263
7264 if (size < sizeof(uint32_t)) {
7265 return false;
7266 }
7267
7268 uint32_t data_len;
7269 memcpy(&data_len, marker, sizeof(uint32_t));
7270 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
7271
7272 if (data_len == 0) {
7273 if ((*type).compare("string") == 0) {
7274 // Accept empty string attribute.
7275
7276 marker += sizeof(uint32_t);
7277 size -= sizeof(uint32_t);
7278
7279 *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t);
7280
7281 data->resize(1);
7282 (*data)[0] = '\0';
7283
7284 return true;
7285 } else {
7286 return false;
7287 }
7288 }
7289
7290 marker += sizeof(uint32_t);
7291 size -= sizeof(uint32_t);
7292
7293 if (size < data_len) {
7294 return false;
7295 }
7296
7297 data->resize(static_cast<size_t>(data_len));
7298 memcpy(&data->at(0), marker, static_cast<size_t>(data_len));
7299
7300 *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t) + data_len;
7301 return true;
7302}
7303
7304static void WriteAttributeToMemory(std::vector<unsigned char> *out,
7305 const char *name, const char *type,
7306 const unsigned char *data, int len) {
7307 out->insert(out->end(), name, name + strlen(name) + 1);
7308 out->insert(out->end(), type, type + strlen(type) + 1);
7309
7310 int outLen = len;
7311 tinyexr::swap4(reinterpret_cast<unsigned int *>(&outLen));
7312 out->insert(out->end(), reinterpret_cast<unsigned char *>(&outLen),
7313 reinterpret_cast<unsigned char *>(&outLen) + sizeof(int));
7314 out->insert(out->end(), data, data + len);
7315}
7316
7317typedef struct {
7318 std::string name; // less than 255 bytes long
7319 int pixel_type;
7320 int x_sampling;
7321 int y_sampling;
7322 unsigned char p_linear;
7323 unsigned char pad[3];
7324} ChannelInfo;
7325
7326typedef struct {
7327 std::vector<tinyexr::ChannelInfo> channels;
7328 std::vector<EXRAttribute> attributes;
7329
7330 int data_window[4];
7331 int line_order;
7332 int display_window[4];
7333 float screen_window_center[2];
7334 float screen_window_width;
7335 float pixel_aspect_ratio;
7336
7337 int chunk_count;
7338
7339 // Tiled format
7340 int tile_size_x;
7341 int tile_size_y;
7342 int tile_level_mode;
7343 int tile_rounding_mode;
7344
7345 unsigned int header_len;
7346
7347 int compression_type;
7348
7349 void clear() {
7350 channels.clear();
7351 attributes.clear();
7352
7353 data_window[0] = 0;
7354 data_window[1] = 0;
7355 data_window[2] = 0;
7356 data_window[3] = 0;
7357 line_order = 0;
7358 display_window[0] = 0;
7359 display_window[1] = 0;
7360 display_window[2] = 0;
7361 display_window[3] = 0;
7362 screen_window_center[0] = 0.0f;
7363 screen_window_center[1] = 0.0f;
7364 screen_window_width = 0.0f;
7365 pixel_aspect_ratio = 0.0f;
7366
7367 chunk_count = 0;
7368
7369 // Tiled format
7370 tile_size_x = 0;
7371 tile_size_y = 0;
7372 tile_level_mode = 0;
7373 tile_rounding_mode = 0;
7374
7375 header_len = 0;
7376 compression_type = 0;
7377 }
7378} HeaderInfo;
7379
7380static bool ReadChannelInfo(std::vector<ChannelInfo> &channels,
7381 const std::vector<unsigned char> &data) {
7382 const char *p = reinterpret_cast<const char *>(&data.at(0));
7383
7384 for (;;) {
7385 if ((*p) == 0) {
7386 break;
7387 }
7388 ChannelInfo info;
7389
7390 tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) -
7391 (p - reinterpret_cast<const char *>(data.data()));
7392 if (data_len < 0) {
7393 return false;
7394 }
7395
7396 p = ReadString(&info.name, p, size_t(data_len));
7397 if ((p == NULL) && (info.name.empty())) {
7398 // Buffer overrun. Issue #51.
7399 return false;
7400 }
7401
7402 const unsigned char *data_end =
7403 reinterpret_cast<const unsigned char *>(p) + 16;
7404 if (data_end >= (data.data() + data.size())) {
7405 return false;
7406 }
7407
7408 memcpy(&info.pixel_type, p, sizeof(int));
7409 p += 4;
7410 info.p_linear = static_cast<unsigned char>(p[0]); // uchar
7411 p += 1 + 3; // reserved: uchar[3]
7412 memcpy(&info.x_sampling, p, sizeof(int)); // int
7413 p += 4;
7414 memcpy(&info.y_sampling, p, sizeof(int)); // int
7415 p += 4;
7416
7417 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.pixel_type));
7418 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.x_sampling));
7419 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.y_sampling));
7420
7421 channels.push_back(info);
7422 }
7423
7424 return true;
7425}
7426
7427static void WriteChannelInfo(std::vector<unsigned char> &data,
7428 const std::vector<ChannelInfo> &channels) {
7429 size_t sz = 0;
7430
7431 // Calculate total size.
7432 for (size_t c = 0; c < channels.size(); c++) {
7433 sz += strlen(channels[c].name.c_str()) + 1; // +1 for \0
7434 sz += 16; // 4 * int
7435 }
7436 data.resize(sz + 1);
7437
7438 unsigned char *p = &data.at(0);
7439
7440 for (size_t c = 0; c < channels.size(); c++) {
7441 memcpy(p, channels[c].name.c_str(), strlen(channels[c].name.c_str()));
7442 p += strlen(channels[c].name.c_str());
7443 (*p) = '\0';
7444 p++;
7445
7446 int pixel_type = channels[c].pixel_type;
7447 int x_sampling = channels[c].x_sampling;
7448 int y_sampling = channels[c].y_sampling;
7449 tinyexr::swap4(reinterpret_cast<unsigned int *>(&pixel_type));
7450 tinyexr::swap4(reinterpret_cast<unsigned int *>(&x_sampling));
7451 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y_sampling));
7452
7453 memcpy(p, &pixel_type, sizeof(int));
7454 p += sizeof(int);
7455
7456 (*p) = channels[c].p_linear;
7457 p += 4;
7458
7459 memcpy(p, &x_sampling, sizeof(int));
7460 p += sizeof(int);
7461
7462 memcpy(p, &y_sampling, sizeof(int));
7463 p += sizeof(int);
7464 }
7465
7466 (*p) = '\0';
7467}
7468
7469static void CompressZip(unsigned char *dst,
7470 tinyexr::tinyexr_uint64 &compressedSize,
7471 const unsigned char *src, unsigned long src_size) {
7472 std::vector<unsigned char> tmpBuf(src_size);
7473
7474 //
7475 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7476 // ImfZipCompressor.cpp
7477 //
7478
7479 //
7480 // Reorder the pixel data.
7481 //
7482
7483 const char *srcPtr = reinterpret_cast<const char *>(src);
7484
7485 {
7486 char *t1 = reinterpret_cast<char *>(&tmpBuf.at(0));
7487 char *t2 = reinterpret_cast<char *>(&tmpBuf.at(0)) + (src_size + 1) / 2;
7488 const char *stop = srcPtr + src_size;
7489
7490 for (;;) {
7491 if (srcPtr < stop)
7492 *(t1++) = *(srcPtr++);
7493 else
7494 break;
7495
7496 if (srcPtr < stop)
7497 *(t2++) = *(srcPtr++);
7498 else
7499 break;
7500 }
7501 }
7502
7503 //
7504 // Predictor.
7505 //
7506
7507 {
7508 unsigned char *t = &tmpBuf.at(0) + 1;
7509 unsigned char *stop = &tmpBuf.at(0) + src_size;
7510 int p = t[-1];
7511
7512 while (t < stop) {
7513 int d = int(t[0]) - p + (128 + 256);
7514 p = t[0];
7515 t[0] = static_cast<unsigned char>(d);
7516 ++t;
7517 }
7518 }
7519
7520#if TINYEXR_USE_MINIZ
7521 //
7522 // Compress the data using miniz
7523 //
7524
7525 miniz::mz_ulong outSize = miniz::mz_compressBound(src_size);
7526 int ret = miniz::mz_compress(
7527 dst, &outSize, static_cast<const unsigned char *>(&tmpBuf.at(0)),
7528 src_size);
7529 assert(ret == miniz::MZ_OK);
7530 (void)ret;
7531
7532 compressedSize = outSize;
7533#else
7534 uLong outSize = compressBound(static_cast<uLong>(src_size));
7535 int ret = compress(dst, &outSize, static_cast<const Bytef *>(&tmpBuf.at(0)),
7536 src_size);
7537 assert(ret == Z_OK);
7538
7539 compressedSize = outSize;
7540#endif
7541
7542 // Use uncompressed data when compressed data is larger than uncompressed.
7543 // (Issue 40)
7544 if (compressedSize >= src_size) {
7545 compressedSize = src_size;
7546 memcpy(dst, src, src_size);
7547 }
7548}
7549
7550static bool DecompressZip(unsigned char *dst,
7551 unsigned long *uncompressed_size /* inout */,
7552 const unsigned char *src, unsigned long src_size) {
7553 if ((*uncompressed_size) == src_size) {
7554 // Data is not compressed(Issue 40).
7555 memcpy(dst, src, src_size);
7556 return true;
7557 }
7558 std::vector<unsigned char> tmpBuf(*uncompressed_size);
7559
7560#if TINYEXR_USE_MINIZ
7561 int ret =
7562 miniz::mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
7563 if (miniz::MZ_OK != ret) {
7564 return false;
7565 }
7566#else
7567 int ret = uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
7568 if (Z_OK != ret) {
7569 return false;
7570 }
7571#endif
7572
7573 //
7574 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7575 // ImfZipCompressor.cpp
7576 //
7577
7578 // Predictor.
7579 {
7580 unsigned char *t = &tmpBuf.at(0) + 1;
7581 unsigned char *stop = &tmpBuf.at(0) + (*uncompressed_size);
7582
7583 while (t < stop) {
7584 int d = int(t[-1]) + int(t[0]) - 128;
7585 t[0] = static_cast<unsigned char>(d);
7586 ++t;
7587 }
7588 }
7589
7590 // Reorder the pixel data.
7591 {
7592 const char *t1 = reinterpret_cast<const char *>(&tmpBuf.at(0));
7593 const char *t2 = reinterpret_cast<const char *>(&tmpBuf.at(0)) +
7594 (*uncompressed_size + 1) / 2;
7595 char *s = reinterpret_cast<char *>(dst);
7596 char *stop = s + (*uncompressed_size);
7597
7598 for (;;) {
7599 if (s < stop)
7600 *(s++) = *(t1++);
7601 else
7602 break;
7603
7604 if (s < stop)
7605 *(s++) = *(t2++);
7606 else
7607 break;
7608 }
7609 }
7610
7611 return true;
7612}
7613
7614// RLE code from OpenEXR --------------------------------------
7615
7616#ifdef __clang__
7617#pragma clang diagnostic push
7618#pragma clang diagnostic ignored "-Wsign-conversion"
7619#endif
7620
7621#ifdef _MSC_VER
7622#pragma warning(push)
7623#pragma warning(disable : 4204) // nonstandard extension used : non-constant
7624 // aggregate initializer (also supported by GNU
7625 // C and C99, so no big deal)
7626#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
7627 // 'int', possible loss of data
7628#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
7629 // 'int', possible loss of data
7630#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
7631 // deprecated. Instead, use the ISO C and C++
7632 // conformant name: _strdup.
7633#endif
7634
7635const int MIN_RUN_LENGTH = 3;
7636const int MAX_RUN_LENGTH = 127;
7637
7638//
7639// Compress an array of bytes, using run-length encoding,
7640// and return the length of the compressed data.
7641//
7642
7643static int rleCompress(int inLength, const char in[], signed char out[]) {
7644 const char *inEnd = in + inLength;
7645 const char *runStart = in;
7646 const char *runEnd = in + 1;
7647 signed char *outWrite = out;
7648
7649 while (runStart < inEnd) {
7650 while (runEnd < inEnd && *runStart == *runEnd &&
7651 runEnd - runStart - 1 < MAX_RUN_LENGTH) {
7652 ++runEnd;
7653 }
7654
7655 if (runEnd - runStart >= MIN_RUN_LENGTH) {
7656 //
7657 // Compressable run
7658 //
7659
7660 *outWrite++ = static_cast<char>(runEnd - runStart) - 1;
7661 *outWrite++ = *(reinterpret_cast<const signed char *>(runStart));
7662 runStart = runEnd;
7663 } else {
7664 //
7665 // Uncompressable run
7666 //
7667
7668 while (runEnd < inEnd &&
7669 ((runEnd + 1 >= inEnd || *runEnd != *(runEnd + 1)) ||
7670 (runEnd + 2 >= inEnd || *(runEnd + 1) != *(runEnd + 2))) &&
7671 runEnd - runStart < MAX_RUN_LENGTH) {
7672 ++runEnd;
7673 }
7674
7675 *outWrite++ = static_cast<char>(runStart - runEnd);
7676
7677 while (runStart < runEnd) {
7678 *outWrite++ = *(reinterpret_cast<const signed char *>(runStart++));
7679 }
7680 }
7681
7682 ++runEnd;
7683 }
7684
7685 return static_cast<int>(outWrite - out);
7686}
7687
7688//
7689// Uncompress an array of bytes compressed with rleCompress().
7690// Returns the length of the oncompressed data, or 0 if the
7691// length of the uncompressed data would be more than maxLength.
7692//
7693
7694static int rleUncompress(int inLength, int maxLength, const signed char in[],
7695 char out[]) {
7696 char *outStart = out;
7697
7698 while (inLength > 0) {
7699 if (*in < 0) {
7700 int count = -(static_cast<int>(*in++));
7701 inLength -= count + 1;
7702
7703 // Fixes #116: Add bounds check to in buffer.
7704 if ((0 > (maxLength -= count)) || (inLength < 0)) return 0;
7705
7706 memcpy(out, in, count);
7707 out += count;
7708 in += count;
7709 } else {
7710 int count = *in++;
7711 inLength -= 2;
7712
7713 if (0 > (maxLength -= count + 1)) return 0;
7714
7715 memset(out, *reinterpret_cast<const char *>(in), count + 1);
7716 out += count + 1;
7717
7718 in++;
7719 }
7720 }
7721
7722 return static_cast<int>(out - outStart);
7723}
7724
7725#ifdef __clang__
7726#pragma clang diagnostic pop
7727#endif
7728
7729// End of RLE code from OpenEXR -----------------------------------
7730
7731static void CompressRle(unsigned char *dst,
7732 tinyexr::tinyexr_uint64 &compressedSize,
7733 const unsigned char *src, unsigned long src_size) {
7734 std::vector<unsigned char> tmpBuf(src_size);
7735
7736 //
7737 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7738 // ImfRleCompressor.cpp
7739 //
7740
7741 //
7742 // Reorder the pixel data.
7743 //
7744
7745 const char *srcPtr = reinterpret_cast<const char *>(src);
7746
7747 {
7748 char *t1 = reinterpret_cast<char *>(&tmpBuf.at(0));
7749 char *t2 = reinterpret_cast<char *>(&tmpBuf.at(0)) + (src_size + 1) / 2;
7750 const char *stop = srcPtr + src_size;
7751
7752 for (;;) {
7753 if (srcPtr < stop)
7754 *(t1++) = *(srcPtr++);
7755 else
7756 break;
7757
7758 if (srcPtr < stop)
7759 *(t2++) = *(srcPtr++);
7760 else
7761 break;
7762 }
7763 }
7764
7765 //
7766 // Predictor.
7767 //
7768
7769 {
7770 unsigned char *t = &tmpBuf.at(0) + 1;
7771 unsigned char *stop = &tmpBuf.at(0) + src_size;
7772 int p = t[-1];
7773
7774 while (t < stop) {
7775 int d = int(t[0]) - p + (128 + 256);
7776 p = t[0];
7777 t[0] = static_cast<unsigned char>(d);
7778 ++t;
7779 }
7780 }
7781
7782 // outSize will be (srcSiz * 3) / 2 at max.
7783 int outSize = rleCompress(static_cast<int>(src_size),
7784 reinterpret_cast<const char *>(&tmpBuf.at(0)),
7785 reinterpret_cast<signed char *>(dst));
7786 assert(outSize > 0);
7787
7788 compressedSize = static_cast<tinyexr::tinyexr_uint64>(outSize);
7789
7790 // Use uncompressed data when compressed data is larger than uncompressed.
7791 // (Issue 40)
7792 if (compressedSize >= src_size) {
7793 compressedSize = src_size;
7794 memcpy(dst, src, src_size);
7795 }
7796}
7797
7798static bool DecompressRle(unsigned char *dst,
7799 const unsigned long uncompressed_size,
7800 const unsigned char *src, unsigned long src_size) {
7801 if (uncompressed_size == src_size) {
7802 // Data is not compressed(Issue 40).
7803 memcpy(dst, src, src_size);
7804 return true;
7805 }
7806
7807 // Workaround for issue #112.
7808 // TODO(syoyo): Add more robust out-of-bounds check in `rleUncompress`.
7809 if (src_size <= 2) {
7810 return false;
7811 }
7812
7813 std::vector<unsigned char> tmpBuf(uncompressed_size);
7814
7815 int ret = rleUncompress(static_cast<int>(src_size),
7816 static_cast<int>(uncompressed_size),
7817 reinterpret_cast<const signed char *>(src),
7818 reinterpret_cast<char *>(&tmpBuf.at(0)));
7819 if (ret != static_cast<int>(uncompressed_size)) {
7820 return false;
7821 }
7822
7823 //
7824 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
7825 // ImfRleCompressor.cpp
7826 //
7827
7828 // Predictor.
7829 {
7830 unsigned char *t = &tmpBuf.at(0) + 1;
7831 unsigned char *stop = &tmpBuf.at(0) + uncompressed_size;
7832
7833 while (t < stop) {
7834 int d = int(t[-1]) + int(t[0]) - 128;
7835 t[0] = static_cast<unsigned char>(d);
7836 ++t;
7837 }
7838 }
7839
7840 // Reorder the pixel data.
7841 {
7842 const char *t1 = reinterpret_cast<const char *>(&tmpBuf.at(0));
7843 const char *t2 = reinterpret_cast<const char *>(&tmpBuf.at(0)) +
7844 (uncompressed_size + 1) / 2;
7845 char *s = reinterpret_cast<char *>(dst);
7846 char *stop = s + uncompressed_size;
7847
7848 for (;;) {
7849 if (s < stop)
7850 *(s++) = *(t1++);
7851 else
7852 break;
7853
7854 if (s < stop)
7855 *(s++) = *(t2++);
7856 else
7857 break;
7858 }
7859 }
7860
7861 return true;
7862}
7863
7864#if TINYEXR_USE_PIZ
7865
7866#ifdef __clang__
7867#pragma clang diagnostic push
7868#pragma clang diagnostic ignored "-Wc++11-long-long"
7869#pragma clang diagnostic ignored "-Wold-style-cast"
7870#pragma clang diagnostic ignored "-Wpadded"
7871#pragma clang diagnostic ignored "-Wsign-conversion"
7872#pragma clang diagnostic ignored "-Wc++11-extensions"
7873#pragma clang diagnostic ignored "-Wconversion"
7874#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
7875
7876#if __has_warning("-Wcast-qual")
7877#pragma clang diagnostic ignored "-Wcast-qual"
7878#endif
7879
7880#endif
7881
7882//
7883// PIZ compress/uncompress, based on OpenEXR's ImfPizCompressor.cpp
7884//
7885// -----------------------------------------------------------------
7886// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
7887// Digital Ltd. LLC)
7888// (3 clause BSD license)
7889//
7890
7891struct PIZChannelData {
7892 unsigned short *start;
7893 unsigned short *end;
7894 int nx;
7895 int ny;
7896 int ys;
7897 int size;
7898};
7899
7900//-----------------------------------------------------------------------------
7901//
7902// 16-bit Haar Wavelet encoding and decoding
7903//
7904// The source code in this file is derived from the encoding
7905// and decoding routines written by Christian Rouet for his
7906// PIZ image file format.
7907//
7908//-----------------------------------------------------------------------------
7909
7910//
7911// Wavelet basis functions without modulo arithmetic; they produce
7912// the best compression ratios when the wavelet-transformed data are
7913// Huffman-encoded, but the wavelet transform works only for 14-bit
7914// data (untransformed data values must be less than (1 << 14)).
7915//
7916
7917inline void wenc14(unsigned short a, unsigned short b, unsigned short &l,
7918 unsigned short &h) {
7919 short as = static_cast<short>(a);
7920 short bs = static_cast<short>(b);
7921
7922 short ms = (as + bs) >> 1;
7923 short ds = as - bs;
7924
7925 l = static_cast<unsigned short>(ms);
7926 h = static_cast<unsigned short>(ds);
7927}
7928
7929inline void wdec14(unsigned short l, unsigned short h, unsigned short &a,
7930 unsigned short &b) {
7931 short ls = static_cast<short>(l);
7932 short hs = static_cast<short>(h);
7933
7934 int hi = hs;
7935 int ai = ls + (hi & 1) + (hi >> 1);
7936
7937 short as = static_cast<short>(ai);
7938 short bs = static_cast<short>(ai - hi);
7939
7940 a = static_cast<unsigned short>(as);
7941 b = static_cast<unsigned short>(bs);
7942}
7943
7944//
7945// Wavelet basis functions with modulo arithmetic; they work with full
7946// 16-bit data, but Huffman-encoding the wavelet-transformed data doesn't
7947// compress the data quite as well.
7948//
7949
7950const int NBITS = 16;
7951const int A_OFFSET = 1 << (NBITS - 1);
7952const int M_OFFSET = 1 << (NBITS - 1);
7953const int MOD_MASK = (1 << NBITS) - 1;
7954
7955inline void wenc16(unsigned short a, unsigned short b, unsigned short &l,
7956 unsigned short &h) {
7957 int ao = (a + A_OFFSET) & MOD_MASK;
7958 int m = ((ao + b) >> 1);
7959 int d = ao - b;
7960
7961 if (d < 0) m = (m + M_OFFSET) & MOD_MASK;
7962
7963 d &= MOD_MASK;
7964
7965 l = static_cast<unsigned short>(m);
7966 h = static_cast<unsigned short>(d);
7967}
7968
7969inline void wdec16(unsigned short l, unsigned short h, unsigned short &a,
7970 unsigned short &b) {
7971 int m = l;
7972 int d = h;
7973 int bb = (m - (d >> 1)) & MOD_MASK;
7974 int aa = (d + bb - A_OFFSET) & MOD_MASK;
7975 b = static_cast<unsigned short>(bb);
7976 a = static_cast<unsigned short>(aa);
7977}
7978
7979//
7980// 2D Wavelet encoding:
7981//
7982
7983static void wav2Encode(
7984 unsigned short *in, // io: values are transformed in place
7985 int nx, // i : x size
7986 int ox, // i : x offset
7987 int ny, // i : y size
7988 int oy, // i : y offset
7989 unsigned short mx) // i : maximum in[x][y] value
7990{
7991 bool w14 = (mx < (1 << 14));
7992 int n = (nx > ny) ? ny : nx;
7993 int p = 1; // == 1 << level
7994 int p2 = 2; // == 1 << (level+1)
7995
7996 //
7997 // Hierachical loop on smaller dimension n
7998 //
7999
8000 while (p2 <= n) {
8001 unsigned short *py = in;
8002 unsigned short *ey = in + oy * (ny - p2);
8003 int oy1 = oy * p;
8004 int oy2 = oy * p2;
8005 int ox1 = ox * p;
8006 int ox2 = ox * p2;
8007 unsigned short i00, i01, i10, i11;
8008
8009 //
8010 // Y loop
8011 //
8012
8013 for (; py <= ey; py += oy2) {
8014 unsigned short *px = py;
8015 unsigned short *ex = py + ox * (nx - p2);
8016
8017 //
8018 // X loop
8019 //
8020
8021 for (; px <= ex; px += ox2) {
8022 unsigned short *p01 = px + ox1;
8023 unsigned short *p10 = px + oy1;
8024 unsigned short *p11 = p10 + ox1;
8025
8026 //
8027 // 2D wavelet encoding
8028 //
8029
8030 if (w14) {
8031 wenc14(*px, *p01, i00, i01);
8032 wenc14(*p10, *p11, i10, i11);
8033 wenc14(i00, i10, *px, *p10);
8034 wenc14(i01, i11, *p01, *p11);
8035 } else {
8036 wenc16(*px, *p01, i00, i01);
8037 wenc16(*p10, *p11, i10, i11);
8038 wenc16(i00, i10, *px, *p10);
8039 wenc16(i01, i11, *p01, *p11);
8040 }
8041 }
8042
8043 //
8044 // Encode (1D) odd column (still in Y loop)
8045 //
8046
8047 if (nx & p) {
8048 unsigned short *p10 = px + oy1;
8049
8050 if (w14)
8051 wenc14(*px, *p10, i00, *p10);
8052 else
8053 wenc16(*px, *p10, i00, *p10);
8054
8055 *px = i00;
8056 }
8057 }
8058
8059 //
8060 // Encode (1D) odd line (must loop in X)
8061 //
8062
8063 if (ny & p) {
8064 unsigned short *px = py;
8065 unsigned short *ex = py + ox * (nx - p2);
8066
8067 for (; px <= ex; px += ox2) {
8068 unsigned short *p01 = px + ox1;
8069
8070 if (w14)
8071 wenc14(*px, *p01, i00, *p01);
8072 else
8073 wenc16(*px, *p01, i00, *p01);
8074
8075 *px = i00;
8076 }
8077 }
8078
8079 //
8080 // Next level
8081 //
8082
8083 p = p2;
8084 p2 <<= 1;
8085 }
8086}
8087
8088//
8089// 2D Wavelet decoding:
8090//
8091
8092static void wav2Decode(
8093 unsigned short *in, // io: values are transformed in place
8094 int nx, // i : x size
8095 int ox, // i : x offset
8096 int ny, // i : y size
8097 int oy, // i : y offset
8098 unsigned short mx) // i : maximum in[x][y] value
8099{
8100 bool w14 = (mx < (1 << 14));
8101 int n = (nx > ny) ? ny : nx;
8102 int p = 1;
8103 int p2;
8104
8105 //
8106 // Search max level
8107 //
8108
8109 while (p <= n) p <<= 1;
8110
8111 p >>= 1;
8112 p2 = p;
8113 p >>= 1;
8114
8115 //
8116 // Hierarchical loop on smaller dimension n
8117 //
8118
8119 while (p >= 1) {
8120 unsigned short *py = in;
8121 unsigned short *ey = in + oy * (ny - p2);
8122 int oy1 = oy * p;
8123 int oy2 = oy * p2;
8124 int ox1 = ox * p;
8125 int ox2 = ox * p2;
8126 unsigned short i00, i01, i10, i11;
8127
8128 //
8129 // Y loop
8130 //
8131
8132 for (; py <= ey; py += oy2) {
8133 unsigned short *px = py;
8134 unsigned short *ex = py + ox * (nx - p2);
8135
8136 //
8137 // X loop
8138 //
8139
8140 for (; px <= ex; px += ox2) {
8141 unsigned short *p01 = px + ox1;
8142 unsigned short *p10 = px + oy1;
8143 unsigned short *p11 = p10 + ox1;
8144
8145 //
8146 // 2D wavelet decoding
8147 //
8148
8149 if (w14) {
8150 wdec14(*px, *p10, i00, i10);
8151 wdec14(*p01, *p11, i01, i11);
8152 wdec14(i00, i01, *px, *p01);
8153 wdec14(i10, i11, *p10, *p11);
8154 } else {
8155 wdec16(*px, *p10, i00, i10);
8156 wdec16(*p01, *p11, i01, i11);
8157 wdec16(i00, i01, *px, *p01);
8158 wdec16(i10, i11, *p10, *p11);
8159 }
8160 }
8161
8162 //
8163 // Decode (1D) odd column (still in Y loop)
8164 //
8165
8166 if (nx & p) {
8167 unsigned short *p10 = px + oy1;
8168
8169 if (w14)
8170 wdec14(*px, *p10, i00, *p10);
8171 else
8172 wdec16(*px, *p10, i00, *p10);
8173
8174 *px = i00;
8175 }
8176 }
8177
8178 //
8179 // Decode (1D) odd line (must loop in X)
8180 //
8181
8182 if (ny & p) {
8183 unsigned short *px = py;
8184 unsigned short *ex = py + ox * (nx - p2);
8185
8186 for (; px <= ex; px += ox2) {
8187 unsigned short *p01 = px + ox1;
8188
8189 if (w14)
8190 wdec14(*px, *p01, i00, *p01);
8191 else
8192 wdec16(*px, *p01, i00, *p01);
8193
8194 *px = i00;
8195 }
8196 }
8197
8198 //
8199 // Next level
8200 //
8201
8202 p2 = p;
8203 p >>= 1;
8204 }
8205}
8206
8207//-----------------------------------------------------------------------------
8208//
8209// 16-bit Huffman compression and decompression.
8210//
8211// The source code in this file is derived from the 8-bit
8212// Huffman compression and decompression routines written
8213// by Christian Rouet for his PIZ image file format.
8214//
8215//-----------------------------------------------------------------------------
8216
8217// Adds some modification for tinyexr.
8218
8219const int HUF_ENCBITS = 16; // literal (value) bit length
8220const int HUF_DECBITS = 14; // decoding bit size (>= 8)
8221
8222const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1; // encoding table size
8223const int HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size
8224const int HUF_DECMASK = HUF_DECSIZE - 1;
8225
8226struct HufDec { // short code long code
8227 //-------------------------------
8228 int len : 8; // code length 0
8229 int lit : 24; // lit p size
8230 int *p; // 0 lits
8231};
8232
8233inline long long hufLength(long long code) { return code & 63; }
8234
8235inline long long hufCode(long long code) { return code >> 6; }
8236
8237inline void outputBits(int nBits, long long bits, long long &c, int &lc,
8238 char *&out) {
8239 c <<= nBits;
8240 lc += nBits;
8241
8242 c |= bits;
8243
8244 while (lc >= 8) *out++ = static_cast<char>((c >> (lc -= 8)));
8245}
8246
8247inline long long getBits(int nBits, long long &c, int &lc, const char *&in) {
8248 while (lc < nBits) {
8249 c = (c << 8) | *(reinterpret_cast<const unsigned char *>(in++));
8250 lc += 8;
8251 }
8252
8253 lc -= nBits;
8254 return (c >> lc) & ((1 << nBits) - 1);
8255}
8256
8257//
8258// ENCODING TABLE BUILDING & (UN)PACKING
8259//
8260
8261//
8262// Build a "canonical" Huffman code table:
8263// - for each (uncompressed) symbol, hcode contains the length
8264// of the corresponding code (in the compressed data)
8265// - canonical codes are computed and stored in hcode
8266// - the rules for constructing canonical codes are as follows:
8267// * shorter codes (if filled with zeroes to the right)
8268// have a numerically higher value than longer codes
8269// * for codes with the same length, numerical values
8270// increase with numerical symbol values
8271// - because the canonical code table can be constructed from
8272// symbol lengths alone, the code table can be transmitted
8273// without sending the actual code values
8274// - see http://www.compressconsult.com/huffman/
8275//
8276
8277static void hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE]) {
8278 long long n[59];
8279
8280 //
8281 // For each i from 0 through 58, count the
8282 // number of different codes of length i, and
8283 // store the count in n[i].
8284 //
8285
8286 for (int i = 0; i <= 58; ++i) n[i] = 0;
8287
8288 for (int i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1;
8289
8290 //
8291 // For each i from 58 through 1, compute the
8292 // numerically lowest code with length i, and
8293 // store that code in n[i].
8294 //
8295
8296 long long c = 0;
8297
8298 for (int i = 58; i > 0; --i) {
8299 long long nc = ((c + n[i]) >> 1);
8300 n[i] = c;
8301 c = nc;
8302 }
8303
8304 //
8305 // hcode[i] contains the length, l, of the
8306 // code for symbol i. Assign the next available
8307 // code of length l to the symbol and store both
8308 // l and the code in hcode[i].
8309 //
8310
8311 for (int i = 0; i < HUF_ENCSIZE; ++i) {
8312 int l = static_cast<int>(hcode[i]);
8313
8314 if (l > 0) hcode[i] = l | (n[l]++ << 6);
8315 }
8316}
8317
8318//
8319// Compute Huffman codes (based on frq input) and store them in frq:
8320// - code structure is : [63:lsb - 6:msb] | [5-0: bit length];
8321// - max code length is 58 bits;
8322// - codes outside the range [im-iM] have a null length (unused values);
8323// - original frequencies are destroyed;
8324// - encoding tables are used by hufEncode() and hufBuildDecTable();
8325//
8326
8327struct FHeapCompare {
8328 bool operator()(long long *a, long long *b) { return *a > *b; }
8329};
8330
8331static void hufBuildEncTable(
8332 long long *frq, // io: input frequencies [HUF_ENCSIZE], output table
8333 int *im, // o: min frq index
8334 int *iM) // o: max frq index
8335{
8336 //
8337 // This function assumes that when it is called, array frq
8338 // indicates the frequency of all possible symbols in the data
8339 // that are to be Huffman-encoded. (frq[i] contains the number
8340 // of occurrences of symbol i in the data.)
8341 //
8342 // The loop below does three things:
8343 //
8344 // 1) Finds the minimum and maximum indices that point
8345 // to non-zero entries in frq:
8346 //
8347 // frq[im] != 0, and frq[i] == 0 for all i < im
8348 // frq[iM] != 0, and frq[i] == 0 for all i > iM
8349 //
8350 // 2) Fills array fHeap with pointers to all non-zero
8351 // entries in frq.
8352 //
8353 // 3) Initializes array hlink such that hlink[i] == i
8354 // for all array entries.
8355 //
8356
8357 std::vector<int> hlink(HUF_ENCSIZE);
8358 std::vector<long long *> fHeap(HUF_ENCSIZE);
8359
8360 *im = 0;
8361
8362 while (!frq[*im]) (*im)++;
8363
8364 int nf = 0;
8365
8366 for (int i = *im; i < HUF_ENCSIZE; i++) {
8367 hlink[i] = i;
8368
8369 if (frq[i]) {
8370 fHeap[nf] = &frq[i];
8371 nf++;
8372 *iM = i;
8373 }
8374 }
8375
8376 //
8377 // Add a pseudo-symbol, with a frequency count of 1, to frq;
8378 // adjust the fHeap and hlink array accordingly. Function
8379 // hufEncode() uses the pseudo-symbol for run-length encoding.
8380 //
8381
8382 (*iM)++;
8383 frq[*iM] = 1;
8384 fHeap[nf] = &frq[*iM];
8385 nf++;
8386
8387 //
8388 // Build an array, scode, such that scode[i] contains the number
8389 // of bits assigned to symbol i. Conceptually this is done by
8390 // constructing a tree whose leaves are the symbols with non-zero
8391 // frequency:
8392 //
8393 // Make a heap that contains all symbols with a non-zero frequency,
8394 // with the least frequent symbol on top.
8395 //
8396 // Repeat until only one symbol is left on the heap:
8397 //
8398 // Take the two least frequent symbols off the top of the heap.
8399 // Create a new node that has first two nodes as children, and
8400 // whose frequency is the sum of the frequencies of the first
8401 // two nodes. Put the new node back into the heap.
8402 //
8403 // The last node left on the heap is the root of the tree. For each
8404 // leaf node, the distance between the root and the leaf is the length
8405 // of the code for the corresponding symbol.
8406 //
8407 // The loop below doesn't actually build the tree; instead we compute
8408 // the distances of the leaves from the root on the fly. When a new
8409 // node is added to the heap, then that node's descendants are linked
8410 // into a single linear list that starts at the new node, and the code
8411 // lengths of the descendants (that is, their distance from the root
8412 // of the tree) are incremented by one.
8413 //
8414
8415 std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8416
8417 std::vector<long long> scode(HUF_ENCSIZE);
8418 memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE);
8419
8420 while (nf > 1) {
8421 //
8422 // Find the indices, mm and m, of the two smallest non-zero frq
8423 // values in fHeap, add the smallest frq to the second-smallest
8424 // frq, and remove the smallest frq value from fHeap.
8425 //
8426
8427 int mm = fHeap[0] - frq;
8428 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8429 --nf;
8430
8431 int m = fHeap[0] - frq;
8432 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8433
8434 frq[m] += frq[mm];
8435 std::push_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
8436
8437 //
8438 // The entries in scode are linked into lists with the
8439 // entries in hlink serving as "next" pointers and with
8440 // the end of a list marked by hlink[j] == j.
8441 //
8442 // Traverse the lists that start at scode[m] and scode[mm].
8443 // For each element visited, increment the length of the
8444 // corresponding code by one bit. (If we visit scode[j]
8445 // during the traversal, then the code for symbol j becomes
8446 // one bit longer.)
8447 //
8448 // Merge the lists that start at scode[m] and scode[mm]
8449 // into a single list that starts at scode[m].
8450 //
8451
8452 //
8453 // Add a bit to all codes in the first list.
8454 //
8455
8456 for (int j = m;; j = hlink[j]) {
8457 scode[j]++;
8458
8459 assert(scode[j] <= 58);
8460
8461 if (hlink[j] == j) {
8462 //
8463 // Merge the two lists.
8464 //
8465
8466 hlink[j] = mm;
8467 break;
8468 }
8469 }
8470
8471 //
8472 // Add a bit to all codes in the second list
8473 //
8474
8475 for (int j = mm;; j = hlink[j]) {
8476 scode[j]++;
8477
8478 assert(scode[j] <= 58);
8479
8480 if (hlink[j] == j) break;
8481 }
8482 }
8483
8484 //
8485 // Build a canonical Huffman code table, replacing the code
8486 // lengths in scode with (code, code length) pairs. Copy the
8487 // code table from scode into frq.
8488 //
8489
8490 hufCanonicalCodeTable(scode.data());
8491 memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE);
8492}
8493
8494//
8495// Pack an encoding table:
8496// - only code lengths, not actual codes, are stored
8497// - runs of zeroes are compressed as follows:
8498//
8499// unpacked packed
8500// --------------------------------
8501// 1 zero 0 (6 bits)
8502// 2 zeroes 59
8503// 3 zeroes 60
8504// 4 zeroes 61
8505// 5 zeroes 62
8506// n zeroes (6 or more) 63 n-6 (6 + 8 bits)
8507//
8508
8509const int SHORT_ZEROCODE_RUN = 59;
8510const int LONG_ZEROCODE_RUN = 63;
8511const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
8512const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN;
8513
8514static void hufPackEncTable(
8515 const long long *hcode, // i : encoding table [HUF_ENCSIZE]
8516 int im, // i : min hcode index
8517 int iM, // i : max hcode index
8518 char **pcode) // o: ptr to packed table (updated)
8519{
8520 char *p = *pcode;
8521 long long c = 0;
8522 int lc = 0;
8523
8524 for (; im <= iM; im++) {
8525 int l = hufLength(hcode[im]);
8526
8527 if (l == 0) {
8528 int zerun = 1;
8529
8530 while ((im < iM) && (zerun < LONGEST_LONG_RUN)) {
8531 if (hufLength(hcode[im + 1]) > 0) break;
8532 im++;
8533 zerun++;
8534 }
8535
8536 if (zerun >= 2) {
8537 if (zerun >= SHORTEST_LONG_RUN) {
8538 outputBits(6, LONG_ZEROCODE_RUN, c, lc, p);
8539 outputBits(8, zerun - SHORTEST_LONG_RUN, c, lc, p);
8540 } else {
8541 outputBits(6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p);
8542 }
8543 continue;
8544 }
8545 }
8546
8547 outputBits(6, l, c, lc, p);
8548 }
8549
8550 if (lc > 0) *p++ = (unsigned char)(c << (8 - lc));
8551
8552 *pcode = p;
8553}
8554
8555//
8556// Unpack an encoding table packed by hufPackEncTable():
8557//
8558
8559static bool hufUnpackEncTable(
8560 const char **pcode, // io: ptr to packed table (updated)
8561 int ni, // i : input size (in bytes)
8562 int im, // i : min hcode index
8563 int iM, // i : max hcode index
8564 long long *hcode) // o: encoding table [HUF_ENCSIZE]
8565{
8566 memset(hcode, 0, sizeof(long long) * HUF_ENCSIZE);
8567
8568 const char *p = *pcode;
8569 long long c = 0;
8570 int lc = 0;
8571
8572 for (; im <= iM; im++) {
8573 if (p - *pcode > ni) {
8574 return false;
8575 }
8576
8577 long long l = hcode[im] = getBits(6, c, lc, p); // code length
8578
8579 if (l == (long long)LONG_ZEROCODE_RUN) {
8580 if (p - *pcode > ni) {
8581 return false;
8582 }
8583
8584 int zerun = getBits(8, c, lc, p) + SHORTEST_LONG_RUN;
8585
8586 if (im + zerun > iM + 1) {
8587 return false;
8588 }
8589
8590 while (zerun--) hcode[im++] = 0;
8591
8592 im--;
8593 } else if (l >= (long long)SHORT_ZEROCODE_RUN) {
8594 int zerun = l - SHORT_ZEROCODE_RUN + 2;
8595
8596 if (im + zerun > iM + 1) {
8597 return false;
8598 }
8599
8600 while (zerun--) hcode[im++] = 0;
8601
8602 im--;
8603 }
8604 }
8605
8606 *pcode = const_cast<char *>(p);
8607
8608 hufCanonicalCodeTable(hcode);
8609
8610 return true;
8611}
8612
8613//
8614// DECODING TABLE BUILDING
8615//
8616
8617//
8618// Clear a newly allocated decoding table so that it contains only zeroes.
8619//
8620
8621static void hufClearDecTable(HufDec *hdecod) // io: (allocated by caller)
8622// decoding table [HUF_DECSIZE]
8623{
8624 for (int i = 0; i < HUF_DECSIZE; i++) {
8625 hdecod[i].len = 0;
8626 hdecod[i].lit = 0;
8627 hdecod[i].p = NULL;
8628 }
8629 // memset(hdecod, 0, sizeof(HufDec) * HUF_DECSIZE);
8630}
8631
8632//
8633// Build a decoding hash table based on the encoding table hcode:
8634// - short codes (<= HUF_DECBITS) are resolved with a single table access;
8635// - long code entry allocations are not optimized, because long codes are
8636// unfrequent;
8637// - decoding tables are used by hufDecode();
8638//
8639
8640static bool hufBuildDecTable(const long long *hcode, // i : encoding table
8641 int im, // i : min index in hcode
8642 int iM, // i : max index in hcode
8643 HufDec *hdecod) // o: (allocated by caller)
8644// decoding table [HUF_DECSIZE]
8645{
8646 //
8647 // Init hashtable & loop on all codes.
8648 // Assumes that hufClearDecTable(hdecod) has already been called.
8649 //
8650
8651 for (; im <= iM; im++) {
8652 long long c = hufCode(hcode[im]);
8653 int l = hufLength(hcode[im]);
8654
8655 if (c >> l) {
8656 //
8657 // Error: c is supposed to be an l-bit code,
8658 // but c contains a value that is greater
8659 // than the largest l-bit number.
8660 //
8661
8662 // invalidTableEntry();
8663 return false;
8664 }
8665
8666 if (l > HUF_DECBITS) {
8667 //
8668 // Long code: add a secondary entry
8669 //
8670
8671 HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
8672
8673 if (pl->len) {
8674 //
8675 // Error: a short code has already
8676 // been stored in table entry *pl.
8677 //
8678
8679 // invalidTableEntry();
8680 return false;
8681 }
8682
8683 pl->lit++;
8684
8685 if (pl->p) {
8686 int *p = pl->p;
8687 pl->p = new int[pl->lit];
8688
8689 for (int i = 0; i < pl->lit - 1; ++i) pl->p[i] = p[i];
8690
8691 delete[] p;
8692 } else {
8693 pl->p = new int[1];
8694 }
8695
8696 pl->p[pl->lit - 1] = im;
8697 } else if (l) {
8698 //
8699 // Short code: init all primary entries
8700 //
8701
8702 HufDec *pl = hdecod + (c << (HUF_DECBITS - l));
8703
8704 for (long long i = 1ULL << (HUF_DECBITS - l); i > 0; i--, pl++) {
8705 if (pl->len || pl->p) {
8706 //
8707 // Error: a short code or a long code has
8708 // already been stored in table entry *pl.
8709 //
8710
8711 // invalidTableEntry();
8712 return false;
8713 }
8714
8715 pl->len = l;
8716 pl->lit = im;
8717 }
8718 }
8719 }
8720
8721 return true;
8722}
8723
8724//
8725// Free the long code entries of a decoding table built by hufBuildDecTable()
8726//
8727
8728static void hufFreeDecTable(HufDec *hdecod) // io: Decoding table
8729{
8730 for (int i = 0; i < HUF_DECSIZE; i++) {
8731 if (hdecod[i].p) {
8732 delete[] hdecod[i].p;
8733 hdecod[i].p = 0;
8734 }
8735 }
8736}
8737
8738//
8739// ENCODING
8740//
8741
8742inline void outputCode(long long code, long long &c, int &lc, char *&out) {
8743 outputBits(hufLength(code), hufCode(code), c, lc, out);
8744}
8745
8746inline void sendCode(long long sCode, int runCount, long long runCode,
8747 long long &c, int &lc, char *&out) {
8748 //
8749 // Output a run of runCount instances of the symbol sCount.
8750 // Output the symbols explicitly, or if that is shorter, output
8751 // the sCode symbol once followed by a runCode symbol and runCount
8752 // expressed as an 8-bit number.
8753 //
8754
8755 if (hufLength(sCode) + hufLength(runCode) + 8 < hufLength(sCode) * runCount) {
8756 outputCode(sCode, c, lc, out);
8757 outputCode(runCode, c, lc, out);
8758 outputBits(8, runCount, c, lc, out);
8759 } else {
8760 while (runCount-- >= 0) outputCode(sCode, c, lc, out);
8761 }
8762}
8763
8764//
8765// Encode (compress) ni values based on the Huffman encoding table hcode:
8766//
8767
8768static int hufEncode // return: output size (in bits)
8769 (const long long *hcode, // i : encoding table
8770 const unsigned short *in, // i : uncompressed input buffer
8771 const int ni, // i : input buffer size (in bytes)
8772 int rlc, // i : rl code
8773 char *out) // o: compressed output buffer
8774{
8775 char *outStart = out;
8776 long long c = 0; // bits not yet written to out
8777 int lc = 0; // number of valid bits in c (LSB)
8778 int s = in[0];
8779 int cs = 0;
8780
8781 //
8782 // Loop on input values
8783 //
8784
8785 for (int i = 1; i < ni; i++) {
8786 //
8787 // Count same values or send code
8788 //
8789
8790 if (s == in[i] && cs < 255) {
8791 cs++;
8792 } else {
8793 sendCode(hcode[s], cs, hcode[rlc], c, lc, out);
8794 cs = 0;
8795 }
8796
8797 s = in[i];
8798 }
8799
8800 //
8801 // Send remaining code
8802 //
8803
8804 sendCode(hcode[s], cs, hcode[rlc], c, lc, out);
8805
8806 if (lc) *out = (c << (8 - lc)) & 0xff;
8807
8808 return (out - outStart) * 8 + lc;
8809}
8810
8811//
8812// DECODING
8813//
8814
8815//
8816// In order to force the compiler to inline them,
8817// getChar() and getCode() are implemented as macros
8818// instead of "inline" functions.
8819//
8820
8821#define getChar(c, lc, in) \
8822 { \
8823 c = (c << 8) | *(unsigned char *)(in++); \
8824 lc += 8; \
8825 }
8826
8827#if 0
8828#define getCode(po, rlc, c, lc, in, out, ob, oe) \
8829 { \
8830 if (po == rlc) { \
8831 if (lc < 8) getChar(c, lc, in); \
8832 \
8833 lc -= 8; \
8834 \
8835 unsigned char cs = (c >> lc); \
8836 \
8837 if (out + cs > oe) return false; \
8838 \
8839 /* TinyEXR issue 78 */ \
8840 unsigned short s = out[-1]; \
8841 \
8842 while (cs-- > 0) *out++ = s; \
8843 } else if (out < oe) { \
8844 *out++ = po; \
8845 } else { \
8846 return false; \
8847 } \
8848 }
8849#else
8850static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in,
8851 const char *in_end, unsigned short *&out,
8852 const unsigned short *ob, const unsigned short *oe) {
8853 (void)ob;
8854 if (po == rlc) {
8855 if (lc < 8) {
8856 /* TinyEXR issue 78 */
8857 if ((in + 1) >= in_end) {
8858 return false;
8859 }
8860
8861 getChar(c, lc, in);
8862 }
8863
8864 lc -= 8;
8865
8866 unsigned char cs = (c >> lc);
8867
8868 if (out + cs > oe) return false;
8869
8870 // Bounds check for safety
8871 // Issue 100.
8872 if ((out - 1) < ob) return false;
8873 unsigned short s = out[-1];
8874
8875 while (cs-- > 0) *out++ = s;
8876 } else if (out < oe) {
8877 *out++ = po;
8878 } else {
8879 return false;
8880 }
8881 return true;
8882}
8883#endif
8884
8885//
8886// Decode (uncompress) ni bits based on encoding & decoding tables:
8887//
8888
8889static bool hufDecode(const long long *hcode, // i : encoding table
8890 const HufDec *hdecod, // i : decoding table
8891 const char *in, // i : compressed input buffer
8892 int ni, // i : input size (in bits)
8893 int rlc, // i : run-length code
8894 int no, // i : expected output size (in bytes)
8895 unsigned short *out) // o: uncompressed output buffer
8896{
8897 long long c = 0;
8898 int lc = 0;
8899 unsigned short *outb = out; // begin
8900 unsigned short *oe = out + no; // end
8901 const char *ie = in + (ni + 7) / 8; // input byte size
8902
8903 //
8904 // Loop on input bytes
8905 //
8906
8907 while (in < ie) {
8908 getChar(c, lc, in);
8909
8910 //
8911 // Access decoding table
8912 //
8913
8914 while (lc >= HUF_DECBITS) {
8915 const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK];
8916
8917 if (pl.len) {
8918 //
8919 // Get short code
8920 //
8921
8922 lc -= pl.len;
8923 // std::cout << "lit = " << pl.lit << std::endl;
8924 // std::cout << "rlc = " << rlc << std::endl;
8925 // std::cout << "c = " << c << std::endl;
8926 // std::cout << "lc = " << lc << std::endl;
8927 // std::cout << "in = " << in << std::endl;
8928 // std::cout << "out = " << out << std::endl;
8929 // std::cout << "oe = " << oe << std::endl;
8930 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
8931 return false;
8932 }
8933 } else {
8934 if (!pl.p) {
8935 return false;
8936 }
8937 // invalidCode(); // wrong code
8938
8939 //
8940 // Search long code
8941 //
8942
8943 int j;
8944
8945 for (j = 0; j < pl.lit; j++) {
8946 int l = hufLength(hcode[pl.p[j]]);
8947
8948 while (lc < l && in < ie) // get more bits
8949 getChar(c, lc, in);
8950
8951 if (lc >= l) {
8952 if (hufCode(hcode[pl.p[j]]) ==
8953 ((c >> (lc - l)) & (((long long)(1) << l) - 1))) {
8954 //
8955 // Found : get long code
8956 //
8957
8958 lc -= l;
8959 if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) {
8960 return false;
8961 }
8962 break;
8963 }
8964 }
8965 }
8966
8967 if (j == pl.lit) {
8968 return false;
8969 // invalidCode(); // Not found
8970 }
8971 }
8972 }
8973 }
8974
8975 //
8976 // Get remaining (short) codes
8977 //
8978
8979 int i = (8 - ni) & 7;
8980 c >>= i;
8981 lc -= i;
8982
8983 while (lc > 0) {
8984 const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
8985
8986 if (pl.len) {
8987 lc -= pl.len;
8988 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
8989 return false;
8990 }
8991 } else {
8992 return false;
8993 // invalidCode(); // wrong (long) code
8994 }
8995 }
8996
8997 if (out - outb != no) {
8998 return false;
8999 }
9000 // notEnoughData ();
9001
9002 return true;
9003}
9004
9005static void countFrequencies(std::vector<long long> &freq,
9006 const unsigned short data[/*n*/], int n) {
9007 for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0;
9008
9009 for (int i = 0; i < n; ++i) ++freq[data[i]];
9010}
9011
9012static void writeUInt(char buf[4], unsigned int i) {
9013 unsigned char *b = (unsigned char *)buf;
9014
9015 b[0] = i;
9016 b[1] = i >> 8;
9017 b[2] = i >> 16;
9018 b[3] = i >> 24;
9019}
9020
9021static unsigned int readUInt(const char buf[4]) {
9022 const unsigned char *b = (const unsigned char *)buf;
9023
9024 return (b[0] & 0x000000ff) | ((b[1] << 8) & 0x0000ff00) |
9025 ((b[2] << 16) & 0x00ff0000) | ((b[3] << 24) & 0xff000000);
9026}
9027
9028//
9029// EXTERNAL INTERFACE
9030//
9031
9032static int hufCompress(const unsigned short raw[], int nRaw,
9033 char compressed[]) {
9034 if (nRaw == 0) return 0;
9035
9036 std::vector<long long> freq(HUF_ENCSIZE);
9037
9038 countFrequencies(freq, raw, nRaw);
9039
9040 int im = 0;
9041 int iM = 0;
9042 hufBuildEncTable(freq.data(), &im, &iM);
9043
9044 char *tableStart = compressed + 20;
9045 char *tableEnd = tableStart;
9046 hufPackEncTable(freq.data(), im, iM, &tableEnd);
9047 int tableLength = tableEnd - tableStart;
9048
9049 char *dataStart = tableEnd;
9050 int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart);
9051 int data_length = (nBits + 7) / 8;
9052
9053 writeUInt(compressed, im);
9054 writeUInt(compressed + 4, iM);
9055 writeUInt(compressed + 8, tableLength);
9056 writeUInt(compressed + 12, nBits);
9057 writeUInt(compressed + 16, 0); // room for future extensions
9058
9059 return dataStart + data_length - compressed;
9060}
9061
9062static bool hufUncompress(const char compressed[], int nCompressed,
9063 std::vector<unsigned short> *raw) {
9064 if (nCompressed == 0) {
9065 if (raw->size() != 0) return false;
9066
9067 return false;
9068 }
9069
9070 int im = readUInt(compressed);
9071 int iM = readUInt(compressed + 4);
9072 // int tableLength = readUInt (compressed + 8);
9073 int nBits = readUInt(compressed + 12);
9074
9075 if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) return false;
9076
9077 const char *ptr = compressed + 20;
9078
9079 //
9080 // Fast decoder needs at least 2x64-bits of compressed data, and
9081 // needs to be run-able on this platform. Otherwise, fall back
9082 // to the original decoder
9083 //
9084
9085 // if (FastHufDecoder::enabled() && nBits > 128)
9086 //{
9087 // FastHufDecoder fhd (ptr, nCompressed - (ptr - compressed), im, iM, iM);
9088 // fhd.decode ((unsigned char*)ptr, nBits, raw, nRaw);
9089 //}
9090 // else
9091 {
9092 std::vector<long long> freq(HUF_ENCSIZE);
9093 std::vector<HufDec> hdec(HUF_DECSIZE);
9094
9095 hufClearDecTable(&hdec.at(0));
9096
9097 hufUnpackEncTable(&ptr, nCompressed - (ptr - compressed), im, iM,
9098 &freq.at(0));
9099
9100 {
9101 if (nBits > 8 * (nCompressed - (ptr - compressed))) {
9102 return false;
9103 }
9104
9105 hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0));
9106 hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(),
9107 raw->data());
9108 }
9109 // catch (...)
9110 //{
9111 // hufFreeDecTable (hdec);
9112 // throw;
9113 //}
9114
9115 hufFreeDecTable(&hdec.at(0));
9116 }
9117
9118 return true;
9119}
9120
9121//
9122// Functions to compress the range of values in the pixel data
9123//
9124
9125const int USHORT_RANGE = (1 << 16);
9126const int BITMAP_SIZE = (USHORT_RANGE >> 3);
9127
9128static void bitmapFromData(const unsigned short data[/*nData*/], int nData,
9129 unsigned char bitmap[BITMAP_SIZE],
9130 unsigned short &minNonZero,
9131 unsigned short &maxNonZero) {
9132 for (int i = 0; i < BITMAP_SIZE; ++i) bitmap[i] = 0;
9133
9134 for (int i = 0; i < nData; ++i) bitmap[data[i] >> 3] |= (1 << (data[i] & 7));
9135
9136 bitmap[0] &= ~1; // zero is not explicitly stored in
9137 // the bitmap; we assume that the
9138 // data always contain zeroes
9139 minNonZero = BITMAP_SIZE - 1;
9140 maxNonZero = 0;
9141
9142 for (int i = 0; i < BITMAP_SIZE; ++i) {
9143 if (bitmap[i]) {
9144 if (minNonZero > i) minNonZero = i;
9145 if (maxNonZero < i) maxNonZero = i;
9146 }
9147 }
9148}
9149
9150static unsigned short forwardLutFromBitmap(
9151 const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) {
9152 int k = 0;
9153
9154 for (int i = 0; i < USHORT_RANGE; ++i) {
9155 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
9156 lut[i] = k++;
9157 else
9158 lut[i] = 0;
9159 }
9160
9161 return k - 1; // maximum value stored in lut[],
9162} // i.e. number of ones in bitmap minus 1
9163
9164static unsigned short reverseLutFromBitmap(
9165 const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) {
9166 int k = 0;
9167
9168 for (int i = 0; i < USHORT_RANGE; ++i) {
9169 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) lut[k++] = i;
9170 }
9171
9172 int n = k - 1;
9173
9174 while (k < USHORT_RANGE) lut[k++] = 0;
9175
9176 return n; // maximum k where lut[k] is non-zero,
9177} // i.e. number of ones in bitmap minus 1
9178
9179static void applyLut(const unsigned short lut[USHORT_RANGE],
9180 unsigned short data[/*nData*/], int nData) {
9181 for (int i = 0; i < nData; ++i) data[i] = lut[data[i]];
9182}
9183
9184#ifdef __clang__
9185#pragma clang diagnostic pop
9186#endif // __clang__
9187
9188#ifdef _MSC_VER
9189#pragma warning(pop)
9190#endif
9191
9192static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
9193 const unsigned char *inPtr, size_t inSize,
9194 const std::vector<ChannelInfo> &channelInfo,
9195 int data_width, int num_lines) {
9196 std::vector<unsigned char> bitmap(BITMAP_SIZE);
9197 unsigned short minNonZero;
9198 unsigned short maxNonZero;
9199
9200#if !MINIZ_LITTLE_ENDIAN
9201 // @todo { PIZ compression on BigEndian architecture. }
9202 assert(0);
9203 return false;
9204#endif
9205
9206 // Assume `inSize` is multiple of 2 or 4.
9207 std::vector<unsigned short> tmpBuffer(inSize / sizeof(unsigned short));
9208
9209 std::vector<PIZChannelData> channelData(channelInfo.size());
9210 unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
9211
9212 for (size_t c = 0; c < channelData.size(); c++) {
9213 PIZChannelData &cd = channelData[c];
9214
9215 cd.start = tmpBufferEnd;
9216 cd.end = cd.start;
9217
9218 cd.nx = data_width;
9219 cd.ny = num_lines;
9220 // cd.ys = c.channel().ySampling;
9221
9222 size_t pixelSize = sizeof(int); // UINT and FLOAT
9223 if (channelInfo[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9224 pixelSize = sizeof(short);
9225 }
9226
9227 cd.size = static_cast<int>(pixelSize / sizeof(short));
9228
9229 tmpBufferEnd += cd.nx * cd.ny * cd.size;
9230 }
9231
9232 const unsigned char *ptr = inPtr;
9233 for (int y = 0; y < num_lines; ++y) {
9234 for (size_t i = 0; i < channelData.size(); ++i) {
9235 PIZChannelData &cd = channelData[i];
9236
9237 // if (modp (y, cd.ys) != 0)
9238 // continue;
9239
9240 size_t n = static_cast<size_t>(cd.nx * cd.size);
9241 memcpy(cd.end, ptr, n * sizeof(unsigned short));
9242 ptr += n * sizeof(unsigned short);
9243 cd.end += n;
9244 }
9245 }
9246
9247 bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()),
9248 bitmap.data(), minNonZero, maxNonZero);
9249
9250 std::vector<unsigned short> lut(USHORT_RANGE);
9251 unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data());
9252 applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()));
9253
9254 //
9255 // Store range compression info in _outBuffer
9256 //
9257
9258 char *buf = reinterpret_cast<char *>(outPtr);
9259
9260 memcpy(buf, &minNonZero, sizeof(unsigned short));
9261 buf += sizeof(unsigned short);
9262 memcpy(buf, &maxNonZero, sizeof(unsigned short));
9263 buf += sizeof(unsigned short);
9264
9265 if (minNonZero <= maxNonZero) {
9266 memcpy(buf, reinterpret_cast<char *>(&bitmap[0] + minNonZero),
9267 maxNonZero - minNonZero + 1);
9268 buf += maxNonZero - minNonZero + 1;
9269 }
9270
9271 //
9272 // Apply wavelet encoding
9273 //
9274
9275 for (size_t i = 0; i < channelData.size(); ++i) {
9276 PIZChannelData &cd = channelData[i];
9277
9278 for (int j = 0; j < cd.size; ++j) {
9279 wav2Encode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size,
9280 maxValue);
9281 }
9282 }
9283
9284 //
9285 // Apply Huffman encoding; append the result to _outBuffer
9286 //
9287
9288 // length header(4byte), then huff data. Initialize length header with zero,
9289 // then later fill it by `length`.
9290 char *lengthPtr = buf;
9291 int zero = 0;
9292 memcpy(buf, &zero, sizeof(int));
9293 buf += sizeof(int);
9294
9295 int length =
9296 hufCompress(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), buf);
9297 memcpy(lengthPtr, &length, sizeof(int));
9298
9299 (*outSize) = static_cast<unsigned int>(
9300 (reinterpret_cast<unsigned char *>(buf) - outPtr) +
9301 static_cast<unsigned int>(length));
9302
9303 // Use uncompressed data when compressed data is larger than uncompressed.
9304 // (Issue 40)
9305 if ((*outSize) >= inSize) {
9306 (*outSize) = static_cast<unsigned int>(inSize);
9307 memcpy(outPtr, inPtr, inSize);
9308 }
9309 return true;
9310}
9311
9312static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
9313 size_t tmpBufSize, size_t inLen, int num_channels,
9314 const EXRChannelInfo *channels, int data_width,
9315 int num_lines) {
9316 if (inLen == tmpBufSize) {
9317 // Data is not compressed(Issue 40).
9318 memcpy(outPtr, inPtr, inLen);
9319 return true;
9320 }
9321
9322 std::vector<unsigned char> bitmap(BITMAP_SIZE);
9323 unsigned short minNonZero;
9324 unsigned short maxNonZero;
9325
9326#if !MINIZ_LITTLE_ENDIAN
9327 // @todo { PIZ compression on BigEndian architecture. }
9328 assert(0);
9329 return false;
9330#endif
9331
9332 memset(bitmap.data(), 0, BITMAP_SIZE);
9333
9334 const unsigned char *ptr = inPtr;
9335 // minNonZero = *(reinterpret_cast<const unsigned short *>(ptr));
9336 tinyexr::cpy2(&minNonZero, reinterpret_cast<const unsigned short *>(ptr));
9337 // maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2));
9338 tinyexr::cpy2(&maxNonZero, reinterpret_cast<const unsigned short *>(ptr + 2));
9339 ptr += 4;
9340
9341 if (maxNonZero >= BITMAP_SIZE) {
9342 return false;
9343 }
9344
9345 if (minNonZero <= maxNonZero) {
9346 memcpy(reinterpret_cast<char *>(&bitmap[0] + minNonZero), ptr,
9347 maxNonZero - minNonZero + 1);
9348 ptr += maxNonZero - minNonZero + 1;
9349 }
9350
9351 std::vector<unsigned short> lut(USHORT_RANGE);
9352 memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE);
9353 unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data());
9354
9355 //
9356 // Huffman decoding
9357 //
9358
9359 int length;
9360
9361 // length = *(reinterpret_cast<const int *>(ptr));
9362 tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr));
9363 ptr += sizeof(int);
9364
9365 if (size_t((ptr - inPtr) + length) > inLen) {
9366 return false;
9367 }
9368
9369 std::vector<unsigned short> tmpBuffer(tmpBufSize);
9370 hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer);
9371
9372 //
9373 // Wavelet decoding
9374 //
9375
9376 std::vector<PIZChannelData> channelData(static_cast<size_t>(num_channels));
9377
9378 unsigned short *tmpBufferEnd = &tmpBuffer.at(0);
9379
9380 for (size_t i = 0; i < static_cast<size_t>(num_channels); ++i) {
9381 const EXRChannelInfo &chan = channels[i];
9382
9383 size_t pixelSize = sizeof(int); // UINT and FLOAT
9384 if (chan.pixel_type == TINYEXR_PIXELTYPE_HALF) {
9385 pixelSize = sizeof(short);
9386 }
9387
9388 channelData[i].start = tmpBufferEnd;
9389 channelData[i].end = channelData[i].start;
9390 channelData[i].nx = data_width;
9391 channelData[i].ny = num_lines;
9392 // channelData[i].ys = 1;
9393 channelData[i].size = static_cast<int>(pixelSize / sizeof(short));
9394
9395 tmpBufferEnd += channelData[i].nx * channelData[i].ny * channelData[i].size;
9396 }
9397
9398 for (size_t i = 0; i < channelData.size(); ++i) {
9399 PIZChannelData &cd = channelData[i];
9400
9401 for (int j = 0; j < cd.size; ++j) {
9402 wav2Decode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size,
9403 maxValue);
9404 }
9405 }
9406
9407 //
9408 // Expand the pixel data to their original range
9409 //
9410
9411 applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBufSize));
9412
9413 for (int y = 0; y < num_lines; y++) {
9414 for (size_t i = 0; i < channelData.size(); ++i) {
9415 PIZChannelData &cd = channelData[i];
9416
9417 // if (modp (y, cd.ys) != 0)
9418 // continue;
9419
9420 size_t n = static_cast<size_t>(cd.nx * cd.size);
9421 memcpy(outPtr, cd.end, static_cast<size_t>(n * sizeof(unsigned short)));
9422 outPtr += n * sizeof(unsigned short);
9423 cd.end += n;
9424 }
9425 }
9426
9427 return true;
9428}
9429#endif // TINYEXR_USE_PIZ
9430
9431#if TINYEXR_USE_ZFP
9432struct ZFPCompressionParam {
9433 double rate;
9434 int precision;
9435 double tolerance;
9436 int type; // TINYEXR_ZFP_COMPRESSIONTYPE_*
9437
9438 ZFPCompressionParam() {
9439 type = TINYEXR_ZFP_COMPRESSIONTYPE_RATE;
9440 rate = 2.0;
9441 precision = 0;
9442 tolerance = 0.0f;
9443 }
9444};
9445
9446bool FindZFPCompressionParam(ZFPCompressionParam *param,
9447 const EXRAttribute *attributes,
9448 int num_attributes) {
9449 bool foundType = false;
9450
9451 for (int i = 0; i < num_attributes; i++) {
9452 if ((strcmp(attributes[i].name, "zfpCompressionType") == 0) &&
9453 (attributes[i].size == 1)) {
9454 param->type = static_cast<int>(attributes[i].value[0]);
9455
9456 foundType = true;
9457 }
9458 }
9459
9460 if (!foundType) {
9461 return false;
9462 }
9463
9464 if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
9465 for (int i = 0; i < num_attributes; i++) {
9466 if ((strcmp(attributes[i].name, "zfpCompressionRate") == 0) &&
9467 (attributes[i].size == 8)) {
9468 param->rate = *(reinterpret_cast<double *>(attributes[i].value));
9469 return true;
9470 }
9471 }
9472 } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
9473 for (int i = 0; i < num_attributes; i++) {
9474 if ((strcmp(attributes[i].name, "zfpCompressionPrecision") == 0) &&
9475 (attributes[i].size == 4)) {
9476 param->rate = *(reinterpret_cast<int *>(attributes[i].value));
9477 return true;
9478 }
9479 }
9480 } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
9481 for (int i = 0; i < num_attributes; i++) {
9482 if ((strcmp(attributes[i].name, "zfpCompressionTolerance") == 0) &&
9483 (attributes[i].size == 8)) {
9484 param->tolerance = *(reinterpret_cast<double *>(attributes[i].value));
9485 return true;
9486 }
9487 }
9488 } else {
9489 assert(0);
9490 }
9491
9492 return false;
9493}
9494
9495// Assume pixel format is FLOAT for all channels.
9496static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
9497 int num_channels, const unsigned char *src,
9498 unsigned long src_size,
9499 const ZFPCompressionParam &param) {
9500 size_t uncompressed_size = dst_width * dst_num_lines * num_channels;
9501
9502 if (uncompressed_size == src_size) {
9503 // Data is not compressed(Issue 40).
9504 memcpy(dst, src, src_size);
9505 }
9506
9507 zfp_stream *zfp = NULL;
9508 zfp_field *field = NULL;
9509
9510 assert((dst_width % 4) == 0);
9511 assert((dst_num_lines % 4) == 0);
9512
9513 if ((dst_width & 3U) || (dst_num_lines & 3U)) {
9514 return false;
9515 }
9516
9517 field =
9518 zfp_field_2d(reinterpret_cast<void *>(const_cast<unsigned char *>(src)),
9519 zfp_type_float, dst_width, dst_num_lines * num_channels);
9520 zfp = zfp_stream_open(NULL);
9521
9522 if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
9523 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimention */ 2,
9524 /* write random access */ 0);
9525 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
9526 zfp_stream_set_precision(zfp, param.precision, zfp_type_float);
9527 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
9528 zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float);
9529 } else {
9530 assert(0);
9531 }
9532
9533 size_t buf_size = zfp_stream_maximum_size(zfp, field);
9534 std::vector<unsigned char> buf(buf_size);
9535 memcpy(&buf.at(0), src, src_size);
9536
9537 bitstream *stream = stream_open(&buf.at(0), buf_size);
9538 zfp_stream_set_bit_stream(zfp, stream);
9539 zfp_stream_rewind(zfp);
9540
9541 size_t image_size = dst_width * dst_num_lines;
9542
9543 for (int c = 0; c < num_channels; c++) {
9544 // decompress 4x4 pixel block.
9545 for (int y = 0; y < dst_num_lines; y += 4) {
9546 for (int x = 0; x < dst_width; x += 4) {
9547 float fblock[16];
9548 zfp_decode_block_float_2(zfp, fblock);
9549 for (int j = 0; j < 4; j++) {
9550 for (int i = 0; i < 4; i++) {
9551 dst[c * image_size + ((y + j) * dst_width + (x + i))] =
9552 fblock[j * 4 + i];
9553 }
9554 }
9555 }
9556 }
9557 }
9558
9559 zfp_field_free(field);
9560 zfp_stream_close(zfp);
9561 stream_close(stream);
9562
9563 return true;
9564}
9565
9566// Assume pixel format is FLOAT for all channels.
9567bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
9568 const float *inPtr, int width, int num_lines, int num_channels,
9569 const ZFPCompressionParam &param) {
9570 zfp_stream *zfp = NULL;
9571 zfp_field *field = NULL;
9572
9573 assert((width % 4) == 0);
9574 assert((num_lines % 4) == 0);
9575
9576 if ((width & 3U) || (num_lines & 3U)) {
9577 return false;
9578 }
9579
9580 // create input array.
9581 field = zfp_field_2d(reinterpret_cast<void *>(const_cast<float *>(inPtr)),
9582 zfp_type_float, width, num_lines * num_channels);
9583
9584 zfp = zfp_stream_open(NULL);
9585
9586 if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) {
9587 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0);
9588 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) {
9589 zfp_stream_set_precision(zfp, param.precision, zfp_type_float);
9590 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
9591 zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float);
9592 } else {
9593 assert(0);
9594 }
9595
9596 size_t buf_size = zfp_stream_maximum_size(zfp, field);
9597
9598 outBuf->resize(buf_size);
9599
9600 bitstream *stream = stream_open(&outBuf->at(0), buf_size);
9601 zfp_stream_set_bit_stream(zfp, stream);
9602 zfp_field_free(field);
9603
9604 size_t image_size = width * num_lines;
9605
9606 for (int c = 0; c < num_channels; c++) {
9607 // compress 4x4 pixel block.
9608 for (int y = 0; y < num_lines; y += 4) {
9609 for (int x = 0; x < width; x += 4) {
9610 float fblock[16];
9611 for (int j = 0; j < 4; j++) {
9612 for (int i = 0; i < 4; i++) {
9613 fblock[j * 4 + i] =
9614 inPtr[c * image_size + ((y + j) * width + (x + i))];
9615 }
9616 }
9617 zfp_encode_block_float_2(zfp, fblock);
9618 }
9619 }
9620 }
9621
9622 zfp_stream_flush(zfp);
9623 (*outSize) = zfp_stream_compressed_size(zfp);
9624
9625 zfp_stream_close(zfp);
9626
9627 return true;
9628}
9629
9630#endif
9631
9632//
9633// -----------------------------------------------------------------
9634//
9635
9636// TODO(syoyo): Refactor function arguments.
9637static bool DecodePixelData(/* out */ unsigned char **out_images,
9638 const int *requested_pixel_types,
9639 const unsigned char *data_ptr, size_t data_len,
9640 int compression_type, int line_order, int width,
9641 int height, int x_stride, int y, int line_no,
9642 int num_lines, size_t pixel_data_size,
9643 size_t num_attributes,
9644 const EXRAttribute *attributes, size_t num_channels,
9645 const EXRChannelInfo *channels,
9646 const std::vector<size_t> &channel_offset_list) {
9647 if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ
9648#if TINYEXR_USE_PIZ
9649 if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) {
9650 // Invalid input #90
9651 return false;
9652 }
9653
9654 // Allocate original data size.
9655 std::vector<unsigned char> outBuf(static_cast<size_t>(
9656 static_cast<size_t>(width * num_lines) * pixel_data_size));
9657 size_t tmpBufLen = outBuf.size();
9658
9659 bool ret = tinyexr::DecompressPiz(
9660 reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen,
9661 data_len, static_cast<int>(num_channels), channels, width, num_lines);
9662
9663 if (!ret) {
9664 return false;
9665 }
9666
9667 // For PIZ_COMPRESSION:
9668 // pixel sample data for channel 0 for scanline 0
9669 // pixel sample data for channel 1 for scanline 0
9670 // pixel sample data for channel ... for scanline 0
9671 // pixel sample data for channel n for scanline 0
9672 // pixel sample data for channel 0 for scanline 1
9673 // pixel sample data for channel 1 for scanline 1
9674 // pixel sample data for channel ... for scanline 1
9675 // pixel sample data for channel n for scanline 1
9676 // ...
9677 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
9678 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9679 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9680 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
9681 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9682 channel_offset_list[c] * static_cast<size_t>(width)));
9683 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9684 FP16 hf;
9685
9686 // hf.u = line_ptr[u];
9687 // use `cpy` to avoid unaligned memory access when compiler's
9688 // optimization is on.
9689 tinyexr::cpy2(&(hf.u), line_ptr + u);
9690
9691 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
9692
9693 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
9694 unsigned short *image =
9695 reinterpret_cast<unsigned short **>(out_images)[c];
9696 if (line_order == 0) {
9697 image += (static_cast<size_t>(line_no) + v) *
9698 static_cast<size_t>(x_stride) +
9699 u;
9700 } else {
9701 image += static_cast<size_t>(
9702 (height - 1 - (line_no + static_cast<int>(v)))) *
9703 static_cast<size_t>(x_stride) +
9704 u;
9705 }
9706 *image = hf.u;
9707 } else { // HALF -> FLOAT
9708 FP32 f32 = half_to_float(hf);
9709 float *image = reinterpret_cast<float **>(out_images)[c];
9710 size_t offset = 0;
9711 if (line_order == 0) {
9712 offset = (static_cast<size_t>(line_no) + v) *
9713 static_cast<size_t>(x_stride) +
9714 u;
9715 } else {
9716 offset = static_cast<size_t>(
9717 (height - 1 - (line_no + static_cast<int>(v)))) *
9718 static_cast<size_t>(x_stride) +
9719 u;
9720 }
9721 image += offset;
9722 *image = f32.f;
9723 }
9724 }
9725 }
9726 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
9727 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
9728
9729 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9730 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
9731 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9732 channel_offset_list[c] * static_cast<size_t>(width)));
9733 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9734 unsigned int val;
9735 // val = line_ptr[u];
9736 tinyexr::cpy4(&val, line_ptr + u);
9737
9738 tinyexr::swap4(&val);
9739
9740 unsigned int *image =
9741 reinterpret_cast<unsigned int **>(out_images)[c];
9742 if (line_order == 0) {
9743 image += (static_cast<size_t>(line_no) + v) *
9744 static_cast<size_t>(x_stride) +
9745 u;
9746 } else {
9747 image += static_cast<size_t>(
9748 (height - 1 - (line_no + static_cast<int>(v)))) *
9749 static_cast<size_t>(x_stride) +
9750 u;
9751 }
9752 *image = val;
9753 }
9754 }
9755 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
9756 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
9757 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9758 const float *line_ptr = reinterpret_cast<float *>(&outBuf.at(
9759 v * pixel_data_size * static_cast<size_t>(x_stride) +
9760 channel_offset_list[c] * static_cast<size_t>(x_stride)));
9761 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9762 float val;
9763 // val = line_ptr[u];
9764 tinyexr::cpy4(&val, line_ptr + u);
9765
9766 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
9767
9768 float *image = reinterpret_cast<float **>(out_images)[c];
9769 if (line_order == 0) {
9770 image += (static_cast<size_t>(line_no) + v) *
9771 static_cast<size_t>(x_stride) +
9772 u;
9773 } else {
9774 image += 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 = val;
9780 }
9781 }
9782 } else {
9783 assert(0);
9784 }
9785 }
9786#else
9787 assert(0 && "PIZ is enabled in this build");
9788 return false;
9789#endif
9790
9791 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS ||
9792 compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
9793 // Allocate original data size.
9794 std::vector<unsigned char> outBuf(static_cast<size_t>(width) *
9795 static_cast<size_t>(num_lines) *
9796 pixel_data_size);
9797
9798 unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
9799 assert(dstLen > 0);
9800 if (!tinyexr::DecompressZip(
9801 reinterpret_cast<unsigned char *>(&outBuf.at(0)), &dstLen, data_ptr,
9802 static_cast<unsigned long>(data_len))) {
9803 return false;
9804 }
9805
9806 // For ZIP_COMPRESSION:
9807 // pixel sample data for channel 0 for scanline 0
9808 // pixel sample data for channel 1 for scanline 0
9809 // pixel sample data for channel ... for scanline 0
9810 // pixel sample data for channel n for scanline 0
9811 // pixel sample data for channel 0 for scanline 1
9812 // pixel sample data for channel 1 for scanline 1
9813 // pixel sample data for channel ... for scanline 1
9814 // pixel sample data for channel n for scanline 1
9815 // ...
9816 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
9817 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9818 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9819 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
9820 &outBuf.at(v * static_cast<size_t>(pixel_data_size) *
9821 static_cast<size_t>(width) +
9822 channel_offset_list[c] * static_cast<size_t>(width)));
9823 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9824 tinyexr::FP16 hf;
9825
9826 // hf.u = line_ptr[u];
9827 tinyexr::cpy2(&(hf.u), line_ptr + u);
9828
9829 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
9830
9831 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
9832 unsigned short *image =
9833 reinterpret_cast<unsigned short **>(out_images)[c];
9834 if (line_order == 0) {
9835 image += (static_cast<size_t>(line_no) + v) *
9836 static_cast<size_t>(x_stride) +
9837 u;
9838 } else {
9839 image += (static_cast<size_t>(height) - 1U -
9840 (static_cast<size_t>(line_no) + v)) *
9841 static_cast<size_t>(x_stride) +
9842 u;
9843 }
9844 *image = hf.u;
9845 } else { // HALF -> FLOAT
9846 tinyexr::FP32 f32 = half_to_float(hf);
9847 float *image = reinterpret_cast<float **>(out_images)[c];
9848 size_t offset = 0;
9849 if (line_order == 0) {
9850 offset = (static_cast<size_t>(line_no) + v) *
9851 static_cast<size_t>(x_stride) +
9852 u;
9853 } else {
9854 offset = (static_cast<size_t>(height) - 1U -
9855 (static_cast<size_t>(line_no) + v)) *
9856 static_cast<size_t>(x_stride) +
9857 u;
9858 }
9859 image += offset;
9860
9861 *image = f32.f;
9862 }
9863 }
9864 }
9865 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
9866 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
9867
9868 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9869 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
9870 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9871 channel_offset_list[c] * static_cast<size_t>(width)));
9872 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9873 unsigned int val;
9874 // val = line_ptr[u];
9875 tinyexr::cpy4(&val, line_ptr + u);
9876
9877 tinyexr::swap4(&val);
9878
9879 unsigned int *image =
9880 reinterpret_cast<unsigned int **>(out_images)[c];
9881 if (line_order == 0) {
9882 image += (static_cast<size_t>(line_no) + v) *
9883 static_cast<size_t>(x_stride) +
9884 u;
9885 } else {
9886 image += (static_cast<size_t>(height) - 1U -
9887 (static_cast<size_t>(line_no) + v)) *
9888 static_cast<size_t>(x_stride) +
9889 u;
9890 }
9891 *image = val;
9892 }
9893 }
9894 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
9895 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
9896 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9897 const float *line_ptr = reinterpret_cast<float *>(
9898 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
9899 channel_offset_list[c] * static_cast<size_t>(width)));
9900 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9901 float val;
9902 // val = line_ptr[u];
9903 tinyexr::cpy4(&val, line_ptr + u);
9904
9905 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
9906
9907 float *image = reinterpret_cast<float **>(out_images)[c];
9908 if (line_order == 0) {
9909 image += (static_cast<size_t>(line_no) + v) *
9910 static_cast<size_t>(x_stride) +
9911 u;
9912 } else {
9913 image += (static_cast<size_t>(height) - 1U -
9914 (static_cast<size_t>(line_no) + v)) *
9915 static_cast<size_t>(x_stride) +
9916 u;
9917 }
9918 *image = val;
9919 }
9920 }
9921 } else {
9922 assert(0);
9923 return false;
9924 }
9925 }
9926 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) {
9927 // Allocate original data size.
9928 std::vector<unsigned char> outBuf(static_cast<size_t>(width) *
9929 static_cast<size_t>(num_lines) *
9930 pixel_data_size);
9931
9932 unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
9933 if (dstLen == 0) {
9934 return false;
9935 }
9936
9937 if (!tinyexr::DecompressRle(reinterpret_cast<unsigned char *>(&outBuf.at(0)),
9938 dstLen, data_ptr,
9939 static_cast<unsigned long>(data_len))) {
9940 return false;
9941 }
9942
9943 // For RLE_COMPRESSION:
9944 // pixel sample data for channel 0 for scanline 0
9945 // pixel sample data for channel 1 for scanline 0
9946 // pixel sample data for channel ... for scanline 0
9947 // pixel sample data for channel n for scanline 0
9948 // pixel sample data for channel 0 for scanline 1
9949 // pixel sample data for channel 1 for scanline 1
9950 // pixel sample data for channel ... for scanline 1
9951 // pixel sample data for channel n for scanline 1
9952 // ...
9953 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
9954 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
9955 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
9956 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
9957 &outBuf.at(v * static_cast<size_t>(pixel_data_size) *
9958 static_cast<size_t>(width) +
9959 channel_offset_list[c] * static_cast<size_t>(width)));
9960 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
9961 tinyexr::FP16 hf;
9962
9963 // hf.u = line_ptr[u];
9964 tinyexr::cpy2(&(hf.u), line_ptr + u);
9965
9966 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
9967
9968 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
9969 unsigned short *image =
9970 reinterpret_cast<unsigned short **>(out_images)[c];
9971 if (line_order == 0) {
9972 image += (static_cast<size_t>(line_no) + v) *
9973 static_cast<size_t>(x_stride) +
9974 u;
9975 } else {
9976 image += (static_cast<size_t>(height) - 1U -
9977 (static_cast<size_t>(line_no) + v)) *
9978 static_cast<size_t>(x_stride) +
9979 u;
9980 }
9981 *image = hf.u;
9982 } else { // HALF -> FLOAT
9983 tinyexr::FP32 f32 = half_to_float(hf);
9984 float *image = reinterpret_cast<float **>(out_images)[c];
9985 if (line_order == 0) {
9986 image += (static_cast<size_t>(line_no) + v) *
9987 static_cast<size_t>(x_stride) +
9988 u;
9989 } else {
9990 image += (static_cast<size_t>(height) - 1U -
9991 (static_cast<size_t>(line_no) + v)) *
9992 static_cast<size_t>(x_stride) +
9993 u;
9994 }
9995 *image = f32.f;
9996 }
9997 }
9998 }
9999 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10000 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
10001
10002 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10003 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
10004 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
10005 channel_offset_list[c] * static_cast<size_t>(width)));
10006 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10007 unsigned int val;
10008 // val = line_ptr[u];
10009 tinyexr::cpy4(&val, line_ptr + u);
10010
10011 tinyexr::swap4(&val);
10012
10013 unsigned int *image =
10014 reinterpret_cast<unsigned int **>(out_images)[c];
10015 if (line_order == 0) {
10016 image += (static_cast<size_t>(line_no) + v) *
10017 static_cast<size_t>(x_stride) +
10018 u;
10019 } else {
10020 image += (static_cast<size_t>(height) - 1U -
10021 (static_cast<size_t>(line_no) + v)) *
10022 static_cast<size_t>(x_stride) +
10023 u;
10024 }
10025 *image = val;
10026 }
10027 }
10028 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10029 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
10030 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10031 const float *line_ptr = reinterpret_cast<float *>(
10032 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
10033 channel_offset_list[c] * static_cast<size_t>(width)));
10034 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10035 float val;
10036 // val = line_ptr[u];
10037 tinyexr::cpy4(&val, line_ptr + u);
10038
10039 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10040
10041 float *image = reinterpret_cast<float **>(out_images)[c];
10042 if (line_order == 0) {
10043 image += (static_cast<size_t>(line_no) + v) *
10044 static_cast<size_t>(x_stride) +
10045 u;
10046 } else {
10047 image += (static_cast<size_t>(height) - 1U -
10048 (static_cast<size_t>(line_no) + v)) *
10049 static_cast<size_t>(x_stride) +
10050 u;
10051 }
10052 *image = val;
10053 }
10054 }
10055 } else {
10056 assert(0);
10057 return false;
10058 }
10059 }
10060 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
10061#if TINYEXR_USE_ZFP
10062 tinyexr::ZFPCompressionParam zfp_compression_param;
10063 if (!FindZFPCompressionParam(&zfp_compression_param, attributes,
10064 num_attributes)) {
10065 assert(0);
10066 return false;
10067 }
10068
10069 // Allocate original data size.
10070 std::vector<unsigned char> outBuf(static_cast<size_t>(width) *
10071 static_cast<size_t>(num_lines) *
10072 pixel_data_size);
10073
10074 unsigned long dstLen = outBuf.size();
10075 assert(dstLen > 0);
10076 tinyexr::DecompressZfp(reinterpret_cast<float *>(&outBuf.at(0)), width,
10077 num_lines, num_channels, data_ptr,
10078 static_cast<unsigned long>(data_len),
10079 zfp_compression_param);
10080
10081 // For ZFP_COMPRESSION:
10082 // pixel sample data for channel 0 for scanline 0
10083 // pixel sample data for channel 1 for scanline 0
10084 // pixel sample data for channel ... for scanline 0
10085 // pixel sample data for channel n for scanline 0
10086 // pixel sample data for channel 0 for scanline 1
10087 // pixel sample data for channel 1 for scanline 1
10088 // pixel sample data for channel ... for scanline 1
10089 // pixel sample data for channel n for scanline 1
10090 // ...
10091 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10092 assert(channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT);
10093 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10094 assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
10095 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10096 const float *line_ptr = reinterpret_cast<float *>(
10097 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
10098 channel_offset_list[c] * static_cast<size_t>(width)));
10099 for (size_t u = 0; u < static_cast<size_t>(width); u++) {
10100 float val;
10101 tinyexr::cpy4(&val, line_ptr + u);
10102
10103 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10104
10105 float *image = reinterpret_cast<float **>(out_images)[c];
10106 if (line_order == 0) {
10107 image += (static_cast<size_t>(line_no) + v) *
10108 static_cast<size_t>(x_stride) +
10109 u;
10110 } else {
10111 image += (static_cast<size_t>(height) - 1U -
10112 (static_cast<size_t>(line_no) + v)) *
10113 static_cast<size_t>(x_stride) +
10114 u;
10115 }
10116 *image = val;
10117 }
10118 }
10119 } else {
10120 assert(0);
10121 return false;
10122 }
10123 }
10124#else
10125 (void)attributes;
10126 (void)num_attributes;
10127 (void)num_channels;
10128 assert(0);
10129 return false;
10130#endif
10131 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
10132 for (size_t c = 0; c < num_channels; c++) {
10133 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
10134 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10135 const unsigned short *line_ptr =
10136 reinterpret_cast<const unsigned short *>(
10137 data_ptr + v * pixel_data_size * size_t(width) +
10138 channel_offset_list[c] * static_cast<size_t>(width));
10139
10140 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
10141 unsigned short *outLine =
10142 reinterpret_cast<unsigned short *>(out_images[c]);
10143 if (line_order == 0) {
10144 outLine += (size_t(y) + v) * size_t(x_stride);
10145 } else {
10146 outLine +=
10147 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10148 }
10149
10150 for (int u = 0; u < width; u++) {
10151 tinyexr::FP16 hf;
10152
10153 // hf.u = line_ptr[u];
10154 tinyexr::cpy2(&(hf.u), line_ptr + u);
10155
10156 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
10157
10158 outLine[u] = hf.u;
10159 }
10160 } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
10161 float *outLine = reinterpret_cast<float *>(out_images[c]);
10162 if (line_order == 0) {
10163 outLine += (size_t(y) + v) * size_t(x_stride);
10164 } else {
10165 outLine +=
10166 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10167 }
10168
10169 if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
10170 (data_ptr + data_len)) {
10171 // Insufficient data size
10172 return false;
10173 }
10174
10175 for (int u = 0; u < width; u++) {
10176 tinyexr::FP16 hf;
10177
10178 // address may not be aliged. use byte-wise copy for safety.#76
10179 // hf.u = line_ptr[u];
10180 tinyexr::cpy2(&(hf.u), line_ptr + u);
10181
10182 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
10183
10184 tinyexr::FP32 f32 = half_to_float(hf);
10185
10186 outLine[u] = f32.f;
10187 }
10188 } else {
10189 assert(0);
10190 return false;
10191 }
10192 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10193 const float *line_ptr = reinterpret_cast<const float *>(
10194 data_ptr + v * pixel_data_size * size_t(width) +
10195 channel_offset_list[c] * static_cast<size_t>(width));
10196
10197 float *outLine = reinterpret_cast<float *>(out_images[c]);
10198 if (line_order == 0) {
10199 outLine += (size_t(y) + v) * size_t(x_stride);
10200 } else {
10201 outLine +=
10202 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10203 }
10204
10205 if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
10206 (data_ptr + data_len)) {
10207 // Insufficient data size
10208 return false;
10209 }
10210
10211 for (int u = 0; u < width; u++) {
10212 float val;
10213 tinyexr::cpy4(&val, line_ptr + u);
10214
10215 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10216
10217 outLine[u] = val;
10218 }
10219 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10220 const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>(
10221 data_ptr + v * pixel_data_size * size_t(width) +
10222 channel_offset_list[c] * static_cast<size_t>(width));
10223
10224 unsigned int *outLine =
10225 reinterpret_cast<unsigned int *>(out_images[c]);
10226 if (line_order == 0) {
10227 outLine += (size_t(y) + v) * size_t(x_stride);
10228 } else {
10229 outLine +=
10230 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
10231 }
10232
10233 for (int u = 0; u < width; u++) {
10234 if (reinterpret_cast<const unsigned char *>(line_ptr + u) >=
10235 (data_ptr + data_len)) {
10236 // Corrupsed data?
10237 return false;
10238 }
10239
10240 unsigned int val;
10241 tinyexr::cpy4(&val, line_ptr + u);
10242
10243 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
10244
10245 outLine[u] = val;
10246 }
10247 }
10248 }
10249 }
10250 }
10251
10252 return true;
10253}
10254
10255static void DecodeTiledPixelData(
10256 unsigned char **out_images, int *width, int *height,
10257 const int *requested_pixel_types, const unsigned char *data_ptr,
10258 size_t data_len, int compression_type, int line_order, int data_width,
10259 int data_height, int tile_offset_x, int tile_offset_y, int tile_size_x,
10260 int tile_size_y, size_t pixel_data_size, size_t num_attributes,
10261 const EXRAttribute *attributes, size_t num_channels,
10262 const EXRChannelInfo *channels,
10263 const std::vector<size_t> &channel_offset_list) {
10264 assert(tile_offset_x * tile_size_x < data_width);
10265 assert(tile_offset_y * tile_size_y < data_height);
10266
10267 // Compute actual image size in a tile.
10268 if ((tile_offset_x + 1) * tile_size_x >= data_width) {
10269 (*width) = data_width - (tile_offset_x * tile_size_x);
10270 } else {
10271 (*width) = tile_size_x;
10272 }
10273
10274 if ((tile_offset_y + 1) * tile_size_y >= data_height) {
10275 (*height) = data_height - (tile_offset_y * tile_size_y);
10276 } else {
10277 (*height) = tile_size_y;
10278 }
10279
10280 // Image size = tile size.
10281 DecodePixelData(out_images, requested_pixel_types, data_ptr, data_len,
10282 compression_type, line_order, (*width), tile_size_y,
10283 /* stride */ tile_size_x, /* y */ 0, /* line_no */ 0,
10284 (*height), pixel_data_size, num_attributes, attributes,
10285 num_channels, channels, channel_offset_list);
10286}
10287
10288static bool ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
10289 int *pixel_data_size, size_t *channel_offset,
10290 int num_channels,
10291 const EXRChannelInfo *channels) {
10292 channel_offset_list->resize(static_cast<size_t>(num_channels));
10293
10294 (*pixel_data_size) = 0;
10295 (*channel_offset) = 0;
10296
10297 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10298 (*channel_offset_list)[c] = (*channel_offset);
10299 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10300 (*pixel_data_size) += sizeof(unsigned short);
10301 (*channel_offset) += sizeof(unsigned short);
10302 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10303 (*pixel_data_size) += sizeof(float);
10304 (*channel_offset) += sizeof(float);
10305 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10306 (*pixel_data_size) += sizeof(unsigned int);
10307 (*channel_offset) += sizeof(unsigned int);
10308 } else {
10309 // ???
10310 return false;
10311 }
10312 }
10313 return true;
10314}
10315
10316static unsigned char **AllocateImage(int num_channels,
10317 const EXRChannelInfo *channels,
10318 const int *requested_pixel_types,
10319 int data_width, int data_height) {
10320 unsigned char **images =
10321 reinterpret_cast<unsigned char **>(static_cast<float **>(
10322 malloc(sizeof(float *) * static_cast<size_t>(num_channels))));
10323
10324 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
10325 size_t data_len =
10326 static_cast<size_t>(data_width) * static_cast<size_t>(data_height);
10327 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
10328 // pixel_data_size += sizeof(unsigned short);
10329 // channel_offset += sizeof(unsigned short);
10330 // Alloc internal image for half type.
10331 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
10332 images[c] =
10333 reinterpret_cast<unsigned char *>(static_cast<unsigned short *>(
10334 malloc(sizeof(unsigned short) * data_len)));
10335 } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
10336 images[c] = reinterpret_cast<unsigned char *>(
10337 static_cast<float *>(malloc(sizeof(float) * data_len)));
10338 } else {
10339 assert(0);
10340 }
10341 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
10342 // pixel_data_size += sizeof(float);
10343 // channel_offset += sizeof(float);
10344 images[c] = reinterpret_cast<unsigned char *>(
10345 static_cast<float *>(malloc(sizeof(float) * data_len)));
10346 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
10347 // pixel_data_size += sizeof(unsigned int);
10348 // channel_offset += sizeof(unsigned int);
10349 images[c] = reinterpret_cast<unsigned char *>(
10350 static_cast<unsigned int *>(malloc(sizeof(unsigned int) * data_len)));
10351 } else {
10352 assert(0);
10353 }
10354 }
10355
10356 return images;
10357}
10358
10359static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
10360 const EXRVersion *version, std::string *err,
10361 const unsigned char *buf, size_t size) {
10362 const char *marker = reinterpret_cast<const char *>(&buf[0]);
10363
10364 if (empty_header) {
10365 (*empty_header) = false;
10366 }
10367
10368 if (version->multipart) {
10369 if (size > 0 && marker[0] == '\0') {
10370 // End of header list.
10371 if (empty_header) {
10372 (*empty_header) = true;
10373 }
10374 return TINYEXR_SUCCESS;
10375 }
10376 }
10377
10378 // According to the spec, the header of every OpenEXR file must contain at
10379 // least the following attributes:
10380 //
10381 // channels chlist
10382 // compression compression
10383 // dataWindow box2i
10384 // displayWindow box2i
10385 // lineOrder lineOrder
10386 // pixelAspectRatio float
10387 // screenWindowCenter v2f
10388 // screenWindowWidth float
10389 bool has_channels = false;
10390 bool has_compression = false;
10391 bool has_data_window = false;
10392 bool has_display_window = false;
10393 bool has_line_order = false;
10394 bool has_pixel_aspect_ratio = false;
10395 bool has_screen_window_center = false;
10396 bool has_screen_window_width = false;
10397
10398 info->data_window[0] = 0;
10399 info->data_window[1] = 0;
10400 info->data_window[2] = 0;
10401 info->data_window[3] = 0;
10402 info->line_order = 0; // @fixme
10403 info->display_window[0] = 0;
10404 info->display_window[1] = 0;
10405 info->display_window[2] = 0;
10406 info->display_window[3] = 0;
10407 info->screen_window_center[0] = 0.0f;
10408 info->screen_window_center[1] = 0.0f;
10409 info->screen_window_width = -1.0f;
10410 info->pixel_aspect_ratio = -1.0f;
10411
10412 info->tile_size_x = -1;
10413 info->tile_size_y = -1;
10414 info->tile_level_mode = -1;
10415 info->tile_rounding_mode = -1;
10416
10417 info->attributes.clear();
10418
10419 // Read attributes
10420 size_t orig_size = size;
10421 for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) {
10422 if (0 == size) {
10423 if (err) {
10424 (*err) += "Insufficient data size for attributes.\n";
10425 }
10426 return TINYEXR_ERROR_INVALID_DATA;
10427 } else if (marker[0] == '\0') {
10428 size--;
10429 break;
10430 }
10431
10432 std::string attr_name;
10433 std::string attr_type;
10434 std::vector<unsigned char> data;
10435 size_t marker_size;
10436 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
10437 marker, size)) {
10438 if (err) {
10439 (*err) += "Failed to read attribute.\n";
10440 }
10441 return TINYEXR_ERROR_INVALID_DATA;
10442 }
10443 marker += marker_size;
10444 size -= marker_size;
10445
10446 if (version->tiled && attr_name.compare("tiles") == 0) {
10447 unsigned int x_size, y_size;
10448 unsigned char tile_mode;
10449 assert(data.size() == 9);
10450 memcpy(&x_size, &data.at(0), sizeof(int));
10451 memcpy(&y_size, &data.at(4), sizeof(int));
10452 tile_mode = data[8];
10453 tinyexr::swap4(&x_size);
10454 tinyexr::swap4(&y_size);
10455
10456 info->tile_size_x = static_cast<int>(x_size);
10457 info->tile_size_y = static_cast<int>(y_size);
10458
10459 // mode = levelMode + roundingMode * 16
10460 info->tile_level_mode = tile_mode & 0x3;
10461 info->tile_rounding_mode = (tile_mode >> 4) & 0x1;
10462
10463 } else if (attr_name.compare("compression") == 0) {
10464 bool ok = false;
10465 if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) {
10466 ok = true;
10467 }
10468
10469 if (data[0] == TINYEXR_COMPRESSIONTYPE_PIZ) {
10470#if TINYEXR_USE_PIZ
10471 ok = true;
10472#else
10473 if (err) {
10474 (*err) = "PIZ compression is not supported.";
10475 }
10476 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
10477#endif
10478 }
10479
10480 if (data[0] == TINYEXR_COMPRESSIONTYPE_ZFP) {
10481#if TINYEXR_USE_ZFP
10482 ok = true;
10483#else
10484 if (err) {
10485 (*err) = "ZFP compression is not supported.";
10486 }
10487 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
10488#endif
10489 }
10490
10491 if (!ok) {
10492 if (err) {
10493 (*err) = "Unknown compression type.";
10494 }
10495 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
10496 }
10497
10498 info->compression_type = static_cast<int>(data[0]);
10499 has_compression = true;
10500
10501 } else if (attr_name.compare("channels") == 0) {
10502 // name: zero-terminated string, from 1 to 255 bytes long
10503 // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2
10504 // pLinear: unsigned char, possible values are 0 and 1
10505 // reserved: three chars, should be zero
10506 // xSampling: int
10507 // ySampling: int
10508
10509 if (!ReadChannelInfo(info->channels, data)) {
10510 if (err) {
10511 (*err) += "Failed to parse channel info.\n";
10512 }
10513 return TINYEXR_ERROR_INVALID_DATA;
10514 }
10515
10516 if (info->channels.size() < 1) {
10517 if (err) {
10518 (*err) += "# of channels is zero.\n";
10519 }
10520 return TINYEXR_ERROR_INVALID_DATA;
10521 }
10522
10523 has_channels = true;
10524
10525 } else if (attr_name.compare("dataWindow") == 0) {
10526 if (data.size() >= 16) {
10527 memcpy(&info->data_window[0], &data.at(0), sizeof(int));
10528 memcpy(&info->data_window[1], &data.at(4), sizeof(int));
10529 memcpy(&info->data_window[2], &data.at(8), sizeof(int));
10530 memcpy(&info->data_window[3], &data.at(12), sizeof(int));
10531 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[0]));
10532 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[1]));
10533 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[2]));
10534 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[3]));
10535 has_data_window = true;
10536 }
10537 } else if (attr_name.compare("displayWindow") == 0) {
10538 if (data.size() >= 16) {
10539 memcpy(&info->display_window[0], &data.at(0), sizeof(int));
10540 memcpy(&info->display_window[1], &data.at(4), sizeof(int));
10541 memcpy(&info->display_window[2], &data.at(8), sizeof(int));
10542 memcpy(&info->display_window[3], &data.at(12), sizeof(int));
10543 tinyexr::swap4(
10544 reinterpret_cast<unsigned int *>(&info->display_window[0]));
10545 tinyexr::swap4(
10546 reinterpret_cast<unsigned int *>(&info->display_window[1]));
10547 tinyexr::swap4(
10548 reinterpret_cast<unsigned int *>(&info->display_window[2]));
10549 tinyexr::swap4(
10550 reinterpret_cast<unsigned int *>(&info->display_window[3]));
10551
10552 has_display_window = true;
10553 }
10554 } else if (attr_name.compare("lineOrder") == 0) {
10555 if (data.size() >= 1) {
10556 info->line_order = static_cast<int>(data[0]);
10557 has_line_order = true;
10558 }
10559 } else if (attr_name.compare("pixelAspectRatio") == 0) {
10560 if (data.size() >= sizeof(float)) {
10561 memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float));
10562 tinyexr::swap4(
10563 reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio));
10564 has_pixel_aspect_ratio = true;
10565 }
10566 } else if (attr_name.compare("screenWindowCenter") == 0) {
10567 if (data.size() >= 8) {
10568 memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float));
10569 memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float));
10570 tinyexr::swap4(
10571 reinterpret_cast<unsigned int *>(&info->screen_window_center[0]));
10572 tinyexr::swap4(
10573 reinterpret_cast<unsigned int *>(&info->screen_window_center[1]));
10574 has_screen_window_center = true;
10575 }
10576 } else if (attr_name.compare("screenWindowWidth") == 0) {
10577 if (data.size() >= sizeof(float)) {
10578 memcpy(&info->screen_window_width, &data.at(0), sizeof(float));
10579 tinyexr::swap4(
10580 reinterpret_cast<unsigned int *>(&info->screen_window_width));
10581
10582 has_screen_window_width = true;
10583 }
10584 } else if (attr_name.compare("chunkCount") == 0) {
10585 if (data.size() >= sizeof(int)) {
10586 memcpy(&info->chunk_count, &data.at(0), sizeof(int));
10587 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count));
10588 }
10589 } else {
10590 // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES)
10591 if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
10592 EXRAttribute attrib;
10593#ifdef _MSC_VER
10594 strncpy_s(attrib.name, attr_name.c_str(), 255);
10595 strncpy_s(attrib.type, attr_type.c_str(), 255);
10596#else
10597 strncpy(attrib.name, attr_name.c_str(), 255);
10598 strncpy(attrib.type, attr_type.c_str(), 255);
10599#endif
10600 attrib.name[255] = '\0';
10601 attrib.type[255] = '\0';
10602 attrib.size = static_cast<int>(data.size());
10603 attrib.value = static_cast<unsigned char *>(malloc(data.size()));
10604 memcpy(reinterpret_cast<char *>(attrib.value), &data.at(0),
10605 data.size());
10606 info->attributes.push_back(attrib);
10607 }
10608 }
10609 }
10610
10611 // Check if required attributes exist
10612 {
10613 std::stringstream ss_err;
10614
10615 if (!has_compression) {
10616 ss_err << "\"compression\" attribute not found in the header."
10617 << std::endl;
10618 }
10619
10620 if (!has_channels) {
10621 ss_err << "\"channels\" attribute not found in the header." << std::endl;
10622 }
10623
10624 if (!has_line_order) {
10625 ss_err << "\"lineOrder\" attribute not found in the header." << std::endl;
10626 }
10627
10628 if (!has_display_window) {
10629 ss_err << "\"displayWindow\" attribute not found in the header."
10630 << std::endl;
10631 }
10632
10633 if (!has_data_window) {
10634 ss_err << "\"dataWindow\" attribute not found in the header or invalid."
10635 << std::endl;
10636 }
10637
10638 if (!has_pixel_aspect_ratio) {
10639 ss_err << "\"pixelAspectRatio\" attribute not found in the header."
10640 << std::endl;
10641 }
10642
10643 if (!has_screen_window_width) {
10644 ss_err << "\"screenWindowWidth\" attribute not found in the header."
10645 << std::endl;
10646 }
10647
10648 if (!has_screen_window_center) {
10649 ss_err << "\"screenWindowCenter\" attribute not found in the header."
10650 << std::endl;
10651 }
10652
10653 if (!(ss_err.str().empty())) {
10654 if (err) {
10655 (*err) += ss_err.str();
10656 }
10657 return TINYEXR_ERROR_INVALID_HEADER;
10658 }
10659 }
10660
10661 info->header_len = static_cast<unsigned int>(orig_size - size);
10662
10663 return TINYEXR_SUCCESS;
10664}
10665
10666// C++ HeaderInfo to C EXRHeader conversion.
10667static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
10668 exr_header->pixel_aspect_ratio = info.pixel_aspect_ratio;
10669 exr_header->screen_window_center[0] = info.screen_window_center[0];
10670 exr_header->screen_window_center[1] = info.screen_window_center[1];
10671 exr_header->screen_window_width = info.screen_window_width;
10672 exr_header->chunk_count = info.chunk_count;
10673 exr_header->display_window[0] = info.display_window[0];
10674 exr_header->display_window[1] = info.display_window[1];
10675 exr_header->display_window[2] = info.display_window[2];
10676 exr_header->display_window[3] = info.display_window[3];
10677 exr_header->data_window[0] = info.data_window[0];
10678 exr_header->data_window[1] = info.data_window[1];
10679 exr_header->data_window[2] = info.data_window[2];
10680 exr_header->data_window[3] = info.data_window[3];
10681 exr_header->line_order = info.line_order;
10682 exr_header->compression_type = info.compression_type;
10683
10684 exr_header->tile_size_x = info.tile_size_x;
10685 exr_header->tile_size_y = info.tile_size_y;
10686 exr_header->tile_level_mode = info.tile_level_mode;
10687 exr_header->tile_rounding_mode = info.tile_rounding_mode;
10688
10689 exr_header->num_channels = static_cast<int>(info.channels.size());
10690
10691 exr_header->channels = static_cast<EXRChannelInfo *>(malloc(
10692 sizeof(EXRChannelInfo) * static_cast<size_t>(exr_header->num_channels)));
10693 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
10694#ifdef _MSC_VER
10695 strncpy_s(exr_header->channels[c].name, info.channels[c].name.c_str(), 255);
10696#else
10697 strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255);
10698#endif
10699 // manually add '\0' for safety.
10700 exr_header->channels[c].name[255] = '\0';
10701
10702 exr_header->channels[c].pixel_type = info.channels[c].pixel_type;
10703 exr_header->channels[c].p_linear = info.channels[c].p_linear;
10704 exr_header->channels[c].x_sampling = info.channels[c].x_sampling;
10705 exr_header->channels[c].y_sampling = info.channels[c].y_sampling;
10706 }
10707
10708 exr_header->pixel_types = static_cast<int *>(
10709 malloc(sizeof(int) * static_cast<size_t>(exr_header->num_channels)));
10710 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
10711 exr_header->pixel_types[c] = info.channels[c].pixel_type;
10712 }
10713
10714 // Initially fill with values of `pixel_types`
10715 exr_header->requested_pixel_types = static_cast<int *>(
10716 malloc(sizeof(int) * static_cast<size_t>(exr_header->num_channels)));
10717 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
10718 exr_header->requested_pixel_types[c] = info.channels[c].pixel_type;
10719 }
10720
10721 exr_header->num_custom_attributes = static_cast<int>(info.attributes.size());
10722
10723 if (exr_header->num_custom_attributes > 0) {
10724 // TODO(syoyo): Report warning when # of attributes exceeds
10725 // `TINYEXR_MAX_CUSTOM_ATTRIBUTES`
10726 if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
10727 exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES;
10728 }
10729
10730 exr_header->custom_attributes = static_cast<EXRAttribute *>(malloc(
10731 sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes)));
10732
10733 for (size_t i = 0; i < info.attributes.size(); i++) {
10734 memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name,
10735 256);
10736 memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type,
10737 256);
10738 exr_header->custom_attributes[i].size = info.attributes[i].size;
10739 // Just copy poiner
10740 exr_header->custom_attributes[i].value = info.attributes[i].value;
10741 }
10742
10743 } else {
10744 exr_header->custom_attributes = NULL;
10745 }
10746
10747 exr_header->header_len = info.header_len;
10748}
10749
10750static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
10751 const std::vector<tinyexr::tinyexr_uint64> &offsets,
10752 const unsigned char *head, const size_t size,
10753 std::string *err) {
10754 int num_channels = exr_header->num_channels;
10755
10756 int num_scanline_blocks = 1;
10757 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
10758 num_scanline_blocks = 16;
10759 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
10760 num_scanline_blocks = 32;
10761 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
10762 num_scanline_blocks = 16;
10763 }
10764
10765 int data_width = exr_header->data_window[2] - exr_header->data_window[0] + 1;
10766 int data_height = exr_header->data_window[3] - exr_header->data_window[1] + 1;
10767
10768 if ((data_width < 0) || (data_height < 0)) {
10769 if (err) {
10770 std::stringstream ss;
10771 ss << "Invalid data width or data height: " << data_width << ", "
10772 << data_height << std::endl;
10773 (*err) += ss.str();
10774 }
10775 return TINYEXR_ERROR_INVALID_DATA;
10776 }
10777
10778 // Do not allow too large data_width and data_height. header invalid?
10779 {
10780 const int threshold = 1024 * 8192; // heuristics
10781 if ((data_width > threshold) || (data_height > threshold)) {
10782 if (err) {
10783 std::stringstream ss;
10784 ss << "data_with or data_height too large. data_width: " << data_width
10785 << ", "
10786 << "data_height = " << data_height << std::endl;
10787 (*err) += ss.str();
10788 }
10789 return TINYEXR_ERROR_INVALID_DATA;
10790 }
10791 }
10792
10793 size_t num_blocks = offsets.size();
10794
10795 std::vector<size_t> channel_offset_list;
10796 int pixel_data_size = 0;
10797 size_t channel_offset = 0;
10798 if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size,
10799 &channel_offset, num_channels,
10800 exr_header->channels)) {
10801 if (err) {
10802 (*err) += "Failed to compute channel layout.\n";
10803 }
10804 return TINYEXR_ERROR_INVALID_DATA;
10805 }
10806
10807 bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety.
10808
10809 if (exr_header->tiled) {
10810 // value check
10811 if (exr_header->tile_size_x < 0) {
10812 if (err) {
10813 std::stringstream ss;
10814 ss << "Invalid tile size x : " << exr_header->tile_size_x << "\n";
10815 (*err) += ss.str();
10816 }
10817 return TINYEXR_ERROR_INVALID_HEADER;
10818 }
10819
10820 if (exr_header->tile_size_y < 0) {
10821 if (err) {
10822 std::stringstream ss;
10823 ss << "Invalid tile size y : " << exr_header->tile_size_y << "\n";
10824 (*err) += ss.str();
10825 }
10826 return TINYEXR_ERROR_INVALID_HEADER;
10827 }
10828
10829 size_t num_tiles = offsets.size(); // = # of blocks
10830
10831 exr_image->tiles = static_cast<EXRTile *>(
10832 calloc(sizeof(EXRTile), static_cast<size_t>(num_tiles)));
10833
10834 for (size_t tile_idx = 0; tile_idx < num_tiles; tile_idx++) {
10835 // Allocate memory for each tile.
10836 exr_image->tiles[tile_idx].images = tinyexr::AllocateImage(
10837 num_channels, exr_header->channels, exr_header->requested_pixel_types,
10838 exr_header->tile_size_x, exr_header->tile_size_y);
10839
10840 // 16 byte: tile coordinates
10841 // 4 byte : data size
10842 // ~ : data(uncompressed or compressed)
10843 if (offsets[tile_idx] + sizeof(int) * 5 > size) {
10844 if (err) {
10845 (*err) += "Insufficient data size.\n";
10846 }
10847 return TINYEXR_ERROR_INVALID_DATA;
10848 }
10849
10850 size_t data_size = size_t(size - (offsets[tile_idx] + sizeof(int) * 5));
10851 const unsigned char *data_ptr =
10852 reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]);
10853
10854 int tile_coordinates[4];
10855 memcpy(tile_coordinates, data_ptr, sizeof(int) * 4);
10856 tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[0]));
10857 tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[1]));
10858 tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[2]));
10859 tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[3]));
10860
10861 // @todo{ LoD }
10862 if (tile_coordinates[2] != 0) {
10863 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
10864 }
10865 if (tile_coordinates[3] != 0) {
10866 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
10867 }
10868
10869 int data_len;
10870 memcpy(&data_len, data_ptr + 16,
10871 sizeof(int)); // 16 = sizeof(tile_coordinates)
10872 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
10873
10874 if (data_len < 4 || size_t(data_len) > data_size) {
10875 if (err) {
10876 (*err) += "Insufficient data length.\n";
10877 }
10878 return TINYEXR_ERROR_INVALID_DATA;
10879 }
10880
10881 // Move to data addr: 20 = 16 + 4;
10882 data_ptr += 20;
10883
10884 tinyexr::DecodeTiledPixelData(
10885 exr_image->tiles[tile_idx].images,
10886 &(exr_image->tiles[tile_idx].width),
10887 &(exr_image->tiles[tile_idx].height),
10888 exr_header->requested_pixel_types, data_ptr,
10889 static_cast<size_t>(data_len), exr_header->compression_type,
10890 exr_header->line_order, data_width, data_height, tile_coordinates[0],
10891 tile_coordinates[1], exr_header->tile_size_x, exr_header->tile_size_y,
10892 static_cast<size_t>(pixel_data_size),
10893 static_cast<size_t>(exr_header->num_custom_attributes),
10894 exr_header->custom_attributes,
10895 static_cast<size_t>(exr_header->num_channels), exr_header->channels,
10896 channel_offset_list);
10897
10898 exr_image->tiles[tile_idx].offset_x = tile_coordinates[0];
10899 exr_image->tiles[tile_idx].offset_y = tile_coordinates[1];
10900 exr_image->tiles[tile_idx].level_x = tile_coordinates[2];
10901 exr_image->tiles[tile_idx].level_y = tile_coordinates[3];
10902
10903 exr_image->num_tiles = static_cast<int>(num_tiles);
10904 }
10905 } else { // scanline format
10906
10907 // Don't allow too large image(256GB * pixel_data_size or more). Workaround
10908 // for #104.
10909 size_t total_data_len =
10910 size_t(data_width) * size_t(data_height) * size_t(num_channels);
10911 if ((total_data_len == 0) || (total_data_len >= 0x4000000000)) {
10912 if (err) {
10913 std::stringstream ss;
10914 ss << "Image data size is zero or too large: width = " << data_width
10915 << ", height = " << data_height << ", channels = " << num_channels
10916 << std::endl;
10917 (*err) += ss.str();
10918 }
10919 return TINYEXR_ERROR_INVALID_DATA;
10920 }
10921
10922 exr_image->images = tinyexr::AllocateImage(
10923 num_channels, exr_header->channels, exr_header->requested_pixel_types,
10924 data_width, data_height);
10925
10926#ifdef _OPENMP
10927#pragma omp parallel for
10928#endif
10929 for (int y = 0; y < static_cast<int>(num_blocks); y++) {
10930 size_t y_idx = static_cast<size_t>(y);
10931
10932 if (offsets[y_idx] + sizeof(int) * 2 > size) {
10933 invalid_data = true;
10934 } else {
10935 // 4 byte: scan line
10936 // 4 byte: data size
10937 // ~ : pixel data(uncompressed or compressed)
10938 size_t data_size = size_t(size - (offsets[y_idx] + sizeof(int) * 2));
10939 const unsigned char *data_ptr =
10940 reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
10941
10942 int line_no;
10943 memcpy(&line_no, data_ptr, sizeof(int));
10944 int data_len;
10945 memcpy(&data_len, data_ptr + 4, sizeof(int));
10946 tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
10947 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
10948
10949 if (size_t(data_len) > data_size) {
10950 invalid_data = true;
10951 } else if (data_len == 0) {
10952 // TODO(syoyo): May be ok to raise the threshold for example `data_len
10953 // < 4`
10954 invalid_data = true;
10955 } else {
10956 // line_no may be negative.
10957 int end_line_no = (std::min)(line_no + num_scanline_blocks,
10958 (exr_header->data_window[3] + 1));
10959
10960 int num_lines = end_line_no - line_no;
10961
10962 if (num_lines <= 0) {
10963 invalid_data = true;
10964 } else {
10965 // Move to data addr: 8 = 4 + 4;
10966 data_ptr += 8;
10967
10968 // Adjust line_no with data_window.bmin.y
10969
10970 // overflow check
10971 tinyexr_int64 lno = static_cast<tinyexr_int64>(line_no) - static_cast<tinyexr_int64>(exr_header->data_window[1]);
10972 if (lno > std::numeric_limits<int>::max()) {
10973 line_no = -1; // invalid
10974 } else if (lno < -std::numeric_limits<int>::max()) {
10975 line_no = -1; // invalid
10976 } else {
10977 line_no -= exr_header->data_window[1];
10978 }
10979
10980 if (line_no < 0) {
10981 invalid_data = true;
10982 } else {
10983 if (!tinyexr::DecodePixelData(
10984 exr_image->images, exr_header->requested_pixel_types,
10985 data_ptr, static_cast<size_t>(data_len),
10986 exr_header->compression_type, exr_header->line_order,
10987 data_width, data_height, data_width, y, line_no,
10988 num_lines, static_cast<size_t>(pixel_data_size),
10989 static_cast<size_t>(exr_header->num_custom_attributes),
10990 exr_header->custom_attributes,
10991 static_cast<size_t>(exr_header->num_channels),
10992 exr_header->channels, channel_offset_list)) {
10993 invalid_data = true;
10994 }
10995 }
10996 }
10997 }
10998 }
10999 } // omp parallel
11000 }
11001
11002 if (invalid_data) {
11003 if (err) {
11004 std::stringstream ss;
11005 (*err) += "Invalid data found when decoding pixels.\n";
11006 }
11007 return TINYEXR_ERROR_INVALID_DATA;
11008 }
11009
11010 // Overwrite `pixel_type` with `requested_pixel_type`.
11011 {
11012 for (int c = 0; c < exr_header->num_channels; c++) {
11013 exr_header->pixel_types[c] = exr_header->requested_pixel_types[c];
11014 }
11015 }
11016
11017 {
11018 exr_image->num_channels = num_channels;
11019
11020 exr_image->width = data_width;
11021 exr_image->height = data_height;
11022 }
11023
11024 return TINYEXR_SUCCESS;
11025}
11026
11027static bool ReconstructLineOffsets(
11028 std::vector<tinyexr::tinyexr_uint64> *offsets, size_t n,
11029 const unsigned char *head, const unsigned char *marker, const size_t size) {
11030 assert(head < marker);
11031 assert(offsets->size() == n);
11032
11033 for (size_t i = 0; i < n; i++) {
11034 size_t offset = static_cast<size_t>(marker - head);
11035 // Offset should not exceed whole EXR file/data size.
11036 if ((offset + sizeof(tinyexr::tinyexr_uint64)) >= size) {
11037 return false;
11038 }
11039
11040 int y;
11041 unsigned int data_len;
11042
11043 memcpy(&y, marker, sizeof(int));
11044 memcpy(&data_len, marker + 4, sizeof(unsigned int));
11045
11046 if (data_len >= size) {
11047 return false;
11048 }
11049
11050 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y));
11051 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
11052
11053 (*offsets)[i] = offset;
11054
11055 marker += data_len + 8; // 8 = 4 bytes(y) + 4 bytes(data_len)
11056 }
11057
11058 return true;
11059}
11060
11061static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
11062 const unsigned char *head,
11063 const unsigned char *marker, const size_t size,
11064 const char **err) {
11065 if (exr_image == NULL || exr_header == NULL || head == NULL ||
11066 marker == NULL || (size <= tinyexr::kEXRVersionSize)) {
11067 tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err);
11068 return TINYEXR_ERROR_INVALID_ARGUMENT;
11069 }
11070
11071 int num_scanline_blocks = 1;
11072 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
11073 num_scanline_blocks = 16;
11074 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
11075 num_scanline_blocks = 32;
11076 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
11077 num_scanline_blocks = 16;
11078 }
11079
11080 int data_width = exr_header->data_window[2] - exr_header->data_window[0];
11081 if (data_width >= std::numeric_limits<int>::max()) {
11082 // Issue 63
11083 tinyexr::SetErrorMessage("Invalid data width value", err);
11084 return TINYEXR_ERROR_INVALID_DATA;
11085 }
11086 data_width++;
11087
11088 int data_height = exr_header->data_window[3] - exr_header->data_window[1];
11089 if (data_height >= std::numeric_limits<int>::max()) {
11090 tinyexr::SetErrorMessage("Invalid data height value", err);
11091 return TINYEXR_ERROR_INVALID_DATA;
11092 }
11093 data_height++;
11094
11095 if ((data_width < 0) || (data_height < 0)) {
11096 tinyexr::SetErrorMessage("data width or data height is negative.", err);
11097 return TINYEXR_ERROR_INVALID_DATA;
11098 }
11099
11100 // Do not allow too large data_width and data_height. header invalid?
11101 {
11102 const int threshold = 1024 * 8192; // heuristics
11103 if (data_width > threshold) {
11104 tinyexr::SetErrorMessage("data width too large.", err);
11105 return TINYEXR_ERROR_INVALID_DATA;
11106 }
11107 if (data_height > threshold) {
11108 tinyexr::SetErrorMessage("data height too large.", err);
11109 return TINYEXR_ERROR_INVALID_DATA;
11110 }
11111 }
11112
11113 // Read offset tables.
11114 size_t num_blocks = 0;
11115
11116 if (exr_header->chunk_count > 0) {
11117 // Use `chunkCount` attribute.
11118 num_blocks = static_cast<size_t>(exr_header->chunk_count);
11119 } else if (exr_header->tiled) {
11120 // @todo { LoD }
11121 size_t num_x_tiles = static_cast<size_t>(data_width) /
11122 static_cast<size_t>(exr_header->tile_size_x);
11123 if (num_x_tiles * static_cast<size_t>(exr_header->tile_size_x) <
11124 static_cast<size_t>(data_width)) {
11125 num_x_tiles++;
11126 }
11127 size_t num_y_tiles = static_cast<size_t>(data_height) /
11128 static_cast<size_t>(exr_header->tile_size_y);
11129 if (num_y_tiles * static_cast<size_t>(exr_header->tile_size_y) <
11130 static_cast<size_t>(data_height)) {
11131 num_y_tiles++;
11132 }
11133
11134 num_blocks = num_x_tiles * num_y_tiles;
11135 } else {
11136 num_blocks = static_cast<size_t>(data_height) /
11137 static_cast<size_t>(num_scanline_blocks);
11138 if (num_blocks * static_cast<size_t>(num_scanline_blocks) <
11139 static_cast<size_t>(data_height)) {
11140 num_blocks++;
11141 }
11142 }
11143
11144 std::vector<tinyexr::tinyexr_uint64> offsets(num_blocks);
11145
11146 for (size_t y = 0; y < num_blocks; y++) {
11147 tinyexr::tinyexr_uint64 offset;
11148 // Issue #81
11149 if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) {
11150 tinyexr::SetErrorMessage("Insufficient data size in offset table.", err);
11151 return TINYEXR_ERROR_INVALID_DATA;
11152 }
11153
11154 memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64));
11155 tinyexr::swap8(&offset);
11156 if (offset >= size) {
11157 tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err);
11158 return TINYEXR_ERROR_INVALID_DATA;
11159 }
11160 marker += sizeof(tinyexr::tinyexr_uint64); // = 8
11161 offsets[y] = offset;
11162 }
11163
11164 // If line offsets are invalid, we try to reconstruct it.
11165 // See OpenEXR/IlmImf/ImfScanLineInputFile.cpp::readLineOffsets() for details.
11166 for (size_t y = 0; y < num_blocks; y++) {
11167 if (offsets[y] <= 0) {
11168 // TODO(syoyo) Report as warning?
11169 // if (err) {
11170 // stringstream ss;
11171 // ss << "Incomplete lineOffsets." << std::endl;
11172 // (*err) += ss.str();
11173 //}
11174 bool ret =
11175 ReconstructLineOffsets(&offsets, num_blocks, head, marker, size);
11176 if (ret) {
11177 // OK
11178 break;
11179 } else {
11180 tinyexr::SetErrorMessage(
11181 "Cannot reconstruct lineOffset table in DecodeEXRImage.", err);
11182 return TINYEXR_ERROR_INVALID_DATA;
11183 }
11184 }
11185 }
11186
11187 {
11188 std::string e;
11189 int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e);
11190
11191 if (ret != TINYEXR_SUCCESS) {
11192 if (!e.empty()) {
11193 tinyexr::SetErrorMessage(e, err);
11194 }
11195
11196 // release memory(if exists)
11197 if ((exr_header->num_channels > 0) && exr_image && exr_image->images) {
11198 for (size_t c = 0; c < size_t(exr_header->num_channels); c++) {
11199 if (exr_image->images[c]) {
11200 free(exr_image->images[c]);
11201 exr_image->images[c] = NULL;
11202 }
11203 }
11204 free(exr_image->images);
11205 exr_image->images = NULL;
11206 }
11207 }
11208
11209 return ret;
11210 }
11211}
11212
11213} // namespace tinyexr
11214
11215int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
11216 const char **err) {
11217 if (out_rgba == NULL) {
11218 tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err);
11219 return TINYEXR_ERROR_INVALID_ARGUMENT;
11220 }
11221
11222 EXRVersion exr_version;
11223 EXRImage exr_image;
11224 EXRHeader exr_header;
11225 InitEXRHeader(&exr_header);
11226 InitEXRImage(&exr_image);
11227
11228 {
11229 int ret = ParseEXRVersionFromFile(&exr_version, filename);
11230 if (ret != TINYEXR_SUCCESS) {
11231 tinyexr::SetErrorMessage("Invalid EXR header.", err);
11232 return ret;
11233 }
11234
11235 if (exr_version.multipart || exr_version.non_image) {
11236 tinyexr::SetErrorMessage(
11237 "Loading multipart or DeepImage is not supported in LoadEXR() API",
11238 err);
11239 return TINYEXR_ERROR_INVALID_DATA; // @fixme.
11240 }
11241 }
11242
11243 {
11244 int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err);
11245 if (ret != TINYEXR_SUCCESS) {
11246 FreeEXRHeader(&exr_header);
11247 return ret;
11248 }
11249 }
11250
11251 // Read HALF channel as FLOAT.
11252 for (int i = 0; i < exr_header.num_channels; i++) {
11253 if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
11254 exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
11255 }
11256 }
11257
11258 {
11259 int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err);
11260 if (ret != TINYEXR_SUCCESS) {
11261 FreeEXRHeader(&exr_header);
11262 return ret;
11263 }
11264 }
11265
11266 // RGBA
11267 int idxR = -1;
11268 int idxG = -1;
11269 int idxB = -1;
11270 int idxA = -1;
11271 for (int c = 0; c < exr_header.num_channels; c++) {
11272 if (strcmp(exr_header.channels[c].name, "R") == 0) {
11273 idxR = c;
11274 } else if (strcmp(exr_header.channels[c].name, "G") == 0) {
11275 idxG = c;
11276 } else if (strcmp(exr_header.channels[c].name, "B") == 0) {
11277 idxB = c;
11278 } else if (strcmp(exr_header.channels[c].name, "A") == 0) {
11279 idxA = c;
11280 }
11281 }
11282
11283 if (exr_header.num_channels == 1) {
11284 // Grayscale channel only.
11285
11286 (*out_rgba) = reinterpret_cast<float *>(
11287 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11288 static_cast<size_t>(exr_image.height)));
11289
11290 if (exr_header.tiled) {
11291 for (int it = 0; it < exr_image.num_tiles; it++) {
11292 for (int j = 0; j < exr_header.tile_size_y; j++) {
11293 for (int i = 0; i < exr_header.tile_size_x; i++) {
11294 const int ii =
11295 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11296 const int jj =
11297 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11298 const int idx = ii + jj * exr_image.width;
11299
11300 // out of region check.
11301 if (ii >= exr_image.width) {
11302 continue;
11303 }
11304 if (jj >= exr_image.height) {
11305 continue;
11306 }
11307 const int srcIdx = i + j * exr_header.tile_size_x;
11308 unsigned char **src = exr_image.tiles[it].images;
11309 (*out_rgba)[4 * idx + 0] =
11310 reinterpret_cast<float **>(src)[0][srcIdx];
11311 (*out_rgba)[4 * idx + 1] =
11312 reinterpret_cast<float **>(src)[0][srcIdx];
11313 (*out_rgba)[4 * idx + 2] =
11314 reinterpret_cast<float **>(src)[0][srcIdx];
11315 (*out_rgba)[4 * idx + 3] =
11316 reinterpret_cast<float **>(src)[0][srcIdx];
11317 }
11318 }
11319 }
11320 } else {
11321 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11322 const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
11323 (*out_rgba)[4 * i + 0] = val;
11324 (*out_rgba)[4 * i + 1] = val;
11325 (*out_rgba)[4 * i + 2] = val;
11326 (*out_rgba)[4 * i + 3] = val;
11327 }
11328 }
11329 } else {
11330 // Assume RGB(A)
11331
11332 if (idxR == -1) {
11333 tinyexr::SetErrorMessage("R channel not found", err);
11334
11335 // @todo { free exr_image }
11336 FreeEXRHeader(&exr_header);
11337 return TINYEXR_ERROR_INVALID_DATA;
11338 }
11339
11340 if (idxG == -1) {
11341 tinyexr::SetErrorMessage("G channel not found", err);
11342 // @todo { free exr_image }
11343 FreeEXRHeader(&exr_header);
11344 return TINYEXR_ERROR_INVALID_DATA;
11345 }
11346
11347 if (idxB == -1) {
11348 tinyexr::SetErrorMessage("B channel not found", err);
11349 // @todo { free exr_image }
11350 FreeEXRHeader(&exr_header);
11351 return TINYEXR_ERROR_INVALID_DATA;
11352 }
11353
11354 (*out_rgba) = reinterpret_cast<float *>(
11355 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11356 static_cast<size_t>(exr_image.height)));
11357 if (exr_header.tiled) {
11358 for (int it = 0; it < exr_image.num_tiles; it++) {
11359 for (int j = 0; j < exr_header.tile_size_y; j++) {
11360 for (int i = 0; i < exr_header.tile_size_x; i++) {
11361 const int ii =
11362 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11363 const int jj =
11364 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11365 const int idx = ii + jj * exr_image.width;
11366
11367 // out of region check.
11368 if (ii >= exr_image.width) {
11369 continue;
11370 }
11371 if (jj >= exr_image.height) {
11372 continue;
11373 }
11374 const int srcIdx = i + j * exr_header.tile_size_x;
11375 unsigned char **src = exr_image.tiles[it].images;
11376 (*out_rgba)[4 * idx + 0] =
11377 reinterpret_cast<float **>(src)[idxR][srcIdx];
11378 (*out_rgba)[4 * idx + 1] =
11379 reinterpret_cast<float **>(src)[idxG][srcIdx];
11380 (*out_rgba)[4 * idx + 2] =
11381 reinterpret_cast<float **>(src)[idxB][srcIdx];
11382 if (idxA != -1) {
11383 (*out_rgba)[4 * idx + 3] =
11384 reinterpret_cast<float **>(src)[idxA][srcIdx];
11385 } else {
11386 (*out_rgba)[4 * idx + 3] = 1.0;
11387 }
11388 }
11389 }
11390 }
11391 } else {
11392 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11393 (*out_rgba)[4 * i + 0] =
11394 reinterpret_cast<float **>(exr_image.images)[idxR][i];
11395 (*out_rgba)[4 * i + 1] =
11396 reinterpret_cast<float **>(exr_image.images)[idxG][i];
11397 (*out_rgba)[4 * i + 2] =
11398 reinterpret_cast<float **>(exr_image.images)[idxB][i];
11399 if (idxA != -1) {
11400 (*out_rgba)[4 * i + 3] =
11401 reinterpret_cast<float **>(exr_image.images)[idxA][i];
11402 } else {
11403 (*out_rgba)[4 * i + 3] = 1.0;
11404 }
11405 }
11406 }
11407 }
11408
11409 (*width) = exr_image.width;
11410 (*height) = exr_image.height;
11411
11412 FreeEXRHeader(&exr_header);
11413 FreeEXRImage(&exr_image);
11414
11415 return TINYEXR_SUCCESS;
11416}
11417
11418int IsEXR(const char *filename) {
11419 EXRVersion exr_version;
11420
11421 int ret = ParseEXRVersionFromFile(&exr_version, filename);
11422 if (ret != TINYEXR_SUCCESS) {
11423 return TINYEXR_ERROR_INVALID_HEADER;
11424 }
11425
11426 return TINYEXR_SUCCESS;
11427}
11428
11429int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
11430 const unsigned char *memory, size_t size,
11431 const char **err) {
11432 if (memory == NULL || exr_header == NULL) {
11433 tinyexr::SetErrorMessage(
11434 "Invalid argument. `memory` or `exr_header` argument is null in "
11435 "ParseEXRHeaderFromMemory()",
11436 err);
11437
11438 // Invalid argument
11439 return TINYEXR_ERROR_INVALID_ARGUMENT;
11440 }
11441
11442 if (size < tinyexr::kEXRVersionSize) {
11443 tinyexr::SetErrorMessage("Insufficient header/data size.\n", err);
11444 return TINYEXR_ERROR_INVALID_DATA;
11445 }
11446
11447 const unsigned char *marker = memory + tinyexr::kEXRVersionSize;
11448 size_t marker_size = size - tinyexr::kEXRVersionSize;
11449
11450 tinyexr::HeaderInfo info;
11451 info.clear();
11452
11453 std::string err_str;
11454 int ret = ParseEXRHeader(&info, NULL, version, &err_str, marker, marker_size);
11455
11456 if (ret != TINYEXR_SUCCESS) {
11457 if (err && !err_str.empty()) {
11458 tinyexr::SetErrorMessage(err_str, err);
11459 }
11460 }
11461
11462 ConvertHeader(exr_header, info);
11463
11464 // transfoer `tiled` from version.
11465 exr_header->tiled = version->tiled;
11466
11467 return ret;
11468}
11469
11470int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
11471 const unsigned char *memory, size_t size,
11472 const char **err) {
11473 if (out_rgba == NULL || memory == NULL) {
11474 tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err);
11475 return TINYEXR_ERROR_INVALID_ARGUMENT;
11476 }
11477
11478 EXRVersion exr_version;
11479 EXRImage exr_image;
11480 EXRHeader exr_header;
11481
11482 InitEXRHeader(&exr_header);
11483
11484 int ret = ParseEXRVersionFromMemory(&exr_version, memory, size);
11485 if (ret != TINYEXR_SUCCESS) {
11486 tinyexr::SetErrorMessage("Failed to parse EXR version", err);
11487 return ret;
11488 }
11489
11490 ret = ParseEXRHeaderFromMemory(&exr_header, &exr_version, memory, size, err);
11491 if (ret != TINYEXR_SUCCESS) {
11492 return ret;
11493 }
11494
11495 // Read HALF channel as FLOAT.
11496 for (int i = 0; i < exr_header.num_channels; i++) {
11497 if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
11498 exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
11499 }
11500 }
11501
11502 InitEXRImage(&exr_image);
11503 ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err);
11504 if (ret != TINYEXR_SUCCESS) {
11505 return ret;
11506 }
11507
11508 // RGBA
11509 int idxR = -1;
11510 int idxG = -1;
11511 int idxB = -1;
11512 int idxA = -1;
11513 for (int c = 0; c < exr_header.num_channels; c++) {
11514 if (strcmp(exr_header.channels[c].name, "R") == 0) {
11515 idxR = c;
11516 } else if (strcmp(exr_header.channels[c].name, "G") == 0) {
11517 idxG = c;
11518 } else if (strcmp(exr_header.channels[c].name, "B") == 0) {
11519 idxB = c;
11520 } else if (strcmp(exr_header.channels[c].name, "A") == 0) {
11521 idxA = c;
11522 }
11523 }
11524
11525 // TODO(syoyo): Refactor removing same code as used in LoadEXR().
11526 if (exr_header.num_channels == 1) {
11527 // Grayscale channel only.
11528
11529 (*out_rgba) = reinterpret_cast<float *>(
11530 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11531 static_cast<size_t>(exr_image.height)));
11532
11533 if (exr_header.tiled) {
11534 for (int it = 0; it < exr_image.num_tiles; it++) {
11535 for (int j = 0; j < exr_header.tile_size_y; j++) {
11536 for (int i = 0; i < exr_header.tile_size_x; i++) {
11537 const int ii =
11538 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11539 const int jj =
11540 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11541 const int idx = ii + jj * exr_image.width;
11542
11543 // out of region check.
11544 if (ii >= exr_image.width) {
11545 continue;
11546 }
11547 if (jj >= exr_image.height) {
11548 continue;
11549 }
11550 const int srcIdx = i + j * exr_header.tile_size_x;
11551 unsigned char **src = exr_image.tiles[it].images;
11552 (*out_rgba)[4 * idx + 0] =
11553 reinterpret_cast<float **>(src)[0][srcIdx];
11554 (*out_rgba)[4 * idx + 1] =
11555 reinterpret_cast<float **>(src)[0][srcIdx];
11556 (*out_rgba)[4 * idx + 2] =
11557 reinterpret_cast<float **>(src)[0][srcIdx];
11558 (*out_rgba)[4 * idx + 3] =
11559 reinterpret_cast<float **>(src)[0][srcIdx];
11560 }
11561 }
11562 }
11563 } else {
11564 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11565 const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
11566 (*out_rgba)[4 * i + 0] = val;
11567 (*out_rgba)[4 * i + 1] = val;
11568 (*out_rgba)[4 * i + 2] = val;
11569 (*out_rgba)[4 * i + 3] = val;
11570 }
11571 }
11572
11573 } else {
11574 // TODO(syoyo): Support non RGBA image.
11575
11576 if (idxR == -1) {
11577 tinyexr::SetErrorMessage("R channel not found", err);
11578
11579 // @todo { free exr_image }
11580 return TINYEXR_ERROR_INVALID_DATA;
11581 }
11582
11583 if (idxG == -1) {
11584 tinyexr::SetErrorMessage("G channel not found", err);
11585 // @todo { free exr_image }
11586 return TINYEXR_ERROR_INVALID_DATA;
11587 }
11588
11589 if (idxB == -1) {
11590 tinyexr::SetErrorMessage("B channel not found", err);
11591 // @todo { free exr_image }
11592 return TINYEXR_ERROR_INVALID_DATA;
11593 }
11594
11595 (*out_rgba) = reinterpret_cast<float *>(
11596 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
11597 static_cast<size_t>(exr_image.height)));
11598
11599 if (exr_header.tiled) {
11600 for (int it = 0; it < exr_image.num_tiles; it++) {
11601 for (int j = 0; j < exr_header.tile_size_y; j++)
11602 for (int i = 0; i < exr_header.tile_size_x; i++) {
11603 const int ii =
11604 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
11605 const int jj =
11606 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
11607 const int idx = ii + jj * exr_image.width;
11608
11609 // out of region check.
11610 if (ii >= exr_image.width) {
11611 continue;
11612 }
11613 if (jj >= exr_image.height) {
11614 continue;
11615 }
11616 const int srcIdx = i + j * exr_header.tile_size_x;
11617 unsigned char **src = exr_image.tiles[it].images;
11618 (*out_rgba)[4 * idx + 0] =
11619 reinterpret_cast<float **>(src)[idxR][srcIdx];
11620 (*out_rgba)[4 * idx + 1] =
11621 reinterpret_cast<float **>(src)[idxG][srcIdx];
11622 (*out_rgba)[4 * idx + 2] =
11623 reinterpret_cast<float **>(src)[idxB][srcIdx];
11624 if (idxA != -1) {
11625 (*out_rgba)[4 * idx + 3] =
11626 reinterpret_cast<float **>(src)[idxA][srcIdx];
11627 } else {
11628 (*out_rgba)[4 * idx + 3] = 1.0;
11629 }
11630 }
11631 }
11632 } else {
11633 for (int i = 0; i < exr_image.width * exr_image.height; i++) {
11634 (*out_rgba)[4 * i + 0] =
11635 reinterpret_cast<float **>(exr_image.images)[idxR][i];
11636 (*out_rgba)[4 * i + 1] =
11637 reinterpret_cast<float **>(exr_image.images)[idxG][i];
11638 (*out_rgba)[4 * i + 2] =
11639 reinterpret_cast<float **>(exr_image.images)[idxB][i];
11640 if (idxA != -1) {
11641 (*out_rgba)[4 * i + 3] =
11642 reinterpret_cast<float **>(exr_image.images)[idxA][i];
11643 } else {
11644 (*out_rgba)[4 * i + 3] = 1.0;
11645 }
11646 }
11647 }
11648 }
11649
11650 (*width) = exr_image.width;
11651 (*height) = exr_image.height;
11652
11653 FreeEXRHeader(&exr_header);
11654 FreeEXRImage(&exr_image);
11655
11656 return TINYEXR_SUCCESS;
11657}
11658
11659int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
11660 const char *filename, const char **err) {
11661 if (exr_image == NULL) {
11662 tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err);
11663 return TINYEXR_ERROR_INVALID_ARGUMENT;
11664 }
11665
11666#ifdef _WIN32
11667 FILE *fp = NULL;
11668 fopen_s(&fp, filename, "rb");
11669#else
11670 FILE *fp = fopen(filename, "rb");
11671#endif
11672 if (!fp) {
11673 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
11674 return TINYEXR_ERROR_CANT_OPEN_FILE;
11675 }
11676
11677 size_t filesize;
11678 // Compute size
11679 fseek(fp, 0, SEEK_END);
11680 filesize = static_cast<size_t>(ftell(fp));
11681 fseek(fp, 0, SEEK_SET);
11682
11683 if (filesize < 16) {
11684 tinyexr::SetErrorMessage("File size too short " + std::string(filename),
11685 err);
11686 return TINYEXR_ERROR_INVALID_FILE;
11687 }
11688
11689 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
11690 {
11691 size_t ret;
11692 ret = fread(&buf[0], 1, filesize, fp);
11693 assert(ret == filesize);
11694 fclose(fp);
11695 (void)ret;
11696 }
11697
11698 return LoadEXRImageFromMemory(exr_image, exr_header, &buf.at(0), filesize,
11699 err);
11700}
11701
11702int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header,
11703 const unsigned char *memory, const size_t size,
11704 const char **err) {
11705 if (exr_image == NULL || memory == NULL ||
11706 (size < tinyexr::kEXRVersionSize)) {
11707 tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory",
11708 err);
11709 return TINYEXR_ERROR_INVALID_ARGUMENT;
11710 }
11711
11712 if (exr_header->header_len == 0) {
11713 tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
11714 return TINYEXR_ERROR_INVALID_ARGUMENT;
11715 }
11716
11717 const unsigned char *head = memory;
11718 const unsigned char *marker = reinterpret_cast<const unsigned char *>(
11719 memory + exr_header->header_len +
11720 8); // +8 for magic number + version header.
11721 return tinyexr::DecodeEXRImage(exr_image, exr_header, head, marker, size,
11722 err);
11723}
11724
11725size_t SaveEXRImageToMemory(const EXRImage *exr_image,
11726 const EXRHeader *exr_header,
11727 unsigned char **memory_out, const char **err) {
11728 if (exr_image == NULL || memory_out == NULL ||
11729 exr_header->compression_type < 0) {
11730 tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err);
11731 return 0;
11732 }
11733
11734#if !TINYEXR_USE_PIZ
11735 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
11736 tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
11737 err);
11738 return 0;
11739 }
11740#endif
11741
11742#if !TINYEXR_USE_ZFP
11743 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
11744 tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
11745 err);
11746 return 0;
11747 }
11748#endif
11749
11750#if TINYEXR_USE_ZFP
11751 for (size_t i = 0; i < static_cast<size_t>(exr_header->num_channels); i++) {
11752 if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) {
11753 tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression",
11754 err);
11755 return 0;
11756 }
11757 }
11758#endif
11759
11760 std::vector<unsigned char> memory;
11761
11762 // Header
11763 {
11764 const char header[] = {0x76, 0x2f, 0x31, 0x01};
11765 memory.insert(memory.end(), header, header + 4);
11766 }
11767
11768 // Version, scanline.
11769 {
11770 char marker[] = {2, 0, 0, 0};
11771 /* @todo
11772 if (exr_header->tiled) {
11773 marker[1] |= 0x2;
11774 }
11775 if (exr_header->long_name) {
11776 marker[1] |= 0x4;
11777 }
11778 if (exr_header->non_image) {
11779 marker[1] |= 0x8;
11780 }
11781 if (exr_header->multipart) {
11782 marker[1] |= 0x10;
11783 }
11784 */
11785 memory.insert(memory.end(), marker, marker + 4);
11786 }
11787
11788 int num_scanlines = 1;
11789 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
11790 num_scanlines = 16;
11791 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
11792 num_scanlines = 32;
11793 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
11794 num_scanlines = 16;
11795 }
11796
11797 // Write attributes.
11798 std::vector<tinyexr::ChannelInfo> channels;
11799 {
11800 std::vector<unsigned char> data;
11801
11802 for (int c = 0; c < exr_header->num_channels; c++) {
11803 tinyexr::ChannelInfo info;
11804 info.p_linear = 0;
11805 info.pixel_type = exr_header->requested_pixel_types[c];
11806 info.x_sampling = 1;
11807 info.y_sampling = 1;
11808 info.name = std::string(exr_header->channels[c].name);
11809 channels.push_back(info);
11810 }
11811
11812 tinyexr::WriteChannelInfo(data, channels);
11813
11814 tinyexr::WriteAttributeToMemory(&memory, "channels", "chlist", &data.at(0),
11815 static_cast<int>(data.size()));
11816 }
11817
11818 {
11819 int comp = exr_header->compression_type;
11820 tinyexr::swap4(reinterpret_cast<unsigned int *>(&comp));
11821 tinyexr::WriteAttributeToMemory(
11822 &memory, "compression", "compression",
11823 reinterpret_cast<const unsigned char *>(&comp), 1);
11824 }
11825
11826 {
11827 int data[4] = {0, 0, exr_image->width - 1, exr_image->height - 1};
11828 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[0]));
11829 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[1]));
11830 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[2]));
11831 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[3]));
11832 tinyexr::WriteAttributeToMemory(
11833 &memory, "dataWindow", "box2i",
11834 reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4);
11835 tinyexr::WriteAttributeToMemory(
11836 &memory, "displayWindow", "box2i",
11837 reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4);
11838 }
11839
11840 {
11841 unsigned char line_order = 0; // @fixme { read line_order from EXRHeader }
11842 tinyexr::WriteAttributeToMemory(&memory, "lineOrder", "lineOrder",
11843 &line_order, 1);
11844 }
11845
11846 {
11847 float aspectRatio = 1.0f;
11848 tinyexr::swap4(reinterpret_cast<unsigned int *>(&aspectRatio));
11849 tinyexr::WriteAttributeToMemory(
11850 &memory, "pixelAspectRatio", "float",
11851 reinterpret_cast<const unsigned char *>(&aspectRatio), sizeof(float));
11852 }
11853
11854 {
11855 float center[2] = {0.0f, 0.0f};
11856 tinyexr::swap4(reinterpret_cast<unsigned int *>(&center[0]));
11857 tinyexr::swap4(reinterpret_cast<unsigned int *>(&center[1]));
11858 tinyexr::WriteAttributeToMemory(
11859 &memory, "screenWindowCenter", "v2f",
11860 reinterpret_cast<const unsigned char *>(center), 2 * sizeof(float));
11861 }
11862
11863 {
11864 float w = static_cast<float>(exr_image->width);
11865 tinyexr::swap4(reinterpret_cast<unsigned int *>(&w));
11866 tinyexr::WriteAttributeToMemory(&memory, "screenWindowWidth", "float",
11867 reinterpret_cast<const unsigned char *>(&w),
11868 sizeof(float));
11869 }
11870
11871 // Custom attributes
11872 if (exr_header->num_custom_attributes > 0) {
11873 for (int i = 0; i < exr_header->num_custom_attributes; i++) {
11874 tinyexr::WriteAttributeToMemory(
11875 &memory, exr_header->custom_attributes[i].name,
11876 exr_header->custom_attributes[i].type,
11877 reinterpret_cast<const unsigned char *>(
11878 exr_header->custom_attributes[i].value),
11879 exr_header->custom_attributes[i].size);
11880 }
11881 }
11882
11883 { // end of header
11884 unsigned char e = 0;
11885 memory.push_back(e);
11886 }
11887
11888 int num_blocks = exr_image->height / num_scanlines;
11889 if (num_blocks * num_scanlines < exr_image->height) {
11890 num_blocks++;
11891 }
11892
11893 std::vector<tinyexr::tinyexr_uint64> offsets(static_cast<size_t>(num_blocks));
11894
11895 size_t headerSize = memory.size();
11896 tinyexr::tinyexr_uint64 offset =
11897 headerSize +
11898 static_cast<size_t>(num_blocks) *
11899 sizeof(
11900 tinyexr::tinyexr_int64); // sizeof(header) + sizeof(offsetTable)
11901
11902 std::vector<std::vector<unsigned char> > data_list(
11903 static_cast<size_t>(num_blocks));
11904 std::vector<size_t> channel_offset_list(
11905 static_cast<size_t>(exr_header->num_channels));
11906
11907 int pixel_data_size = 0;
11908 size_t channel_offset = 0;
11909 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
11910 channel_offset_list[c] = channel_offset;
11911 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
11912 pixel_data_size += sizeof(unsigned short);
11913 channel_offset += sizeof(unsigned short);
11914 } else if (exr_header->requested_pixel_types[c] ==
11915 TINYEXR_PIXELTYPE_FLOAT) {
11916 pixel_data_size += sizeof(float);
11917 channel_offset += sizeof(float);
11918 } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
11919 pixel_data_size += sizeof(unsigned int);
11920 channel_offset += sizeof(unsigned int);
11921 } else {
11922 assert(0);
11923 }
11924 }
11925
11926#if TINYEXR_USE_ZFP
11927 tinyexr::ZFPCompressionParam zfp_compression_param;
11928
11929 // Use ZFP compression parameter from custom attributes(if such a parameter
11930 // exists)
11931 {
11932 bool ret = tinyexr::FindZFPCompressionParam(
11933 &zfp_compression_param, exr_header->custom_attributes,
11934 exr_header->num_custom_attributes);
11935
11936 if (!ret) {
11937 // Use predefined compression parameter.
11938 zfp_compression_param.type = 0;
11939 zfp_compression_param.rate = 2;
11940 }
11941 }
11942#endif
11943
11944// Use signed int since some OpenMP compiler doesn't allow unsigned type for
11945// `parallel for`
11946#ifdef _OPENMP
11947#pragma omp parallel for
11948#endif
11949 for (int i = 0; i < num_blocks; i++) {
11950 size_t ii = static_cast<size_t>(i);
11951 int start_y = num_scanlines * i;
11952 int endY = (std::min)(num_scanlines * (i + 1), exr_image->height);
11953 int h = endY - start_y;
11954
11955 std::vector<unsigned char> buf(
11956 static_cast<size_t>(exr_image->width * h * pixel_data_size));
11957
11958 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) {
11959 if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
11960 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
11961 for (int y = 0; y < h; y++) {
11962 // Assume increasing Y
11963 float *line_ptr = reinterpret_cast<float *>(&buf.at(
11964 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
11965 channel_offset_list[c] *
11966 static_cast<size_t>(exr_image->width)));
11967 for (int x = 0; x < exr_image->width; x++) {
11968 tinyexr::FP16 h16;
11969 h16.u = reinterpret_cast<unsigned short **>(
11970 exr_image->images)[c][(y + start_y) * exr_image->width + x];
11971
11972 tinyexr::FP32 f32 = half_to_float(h16);
11973
11974 tinyexr::swap4(reinterpret_cast<unsigned int *>(&f32.f));
11975
11976 // line_ptr[x] = f32.f;
11977 tinyexr::cpy4(line_ptr + x, &(f32.f));
11978 }
11979 }
11980 } else if (exr_header->requested_pixel_types[c] ==
11981 TINYEXR_PIXELTYPE_HALF) {
11982 for (int y = 0; y < h; y++) {
11983 // Assume increasing Y
11984 unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
11985 &buf.at(static_cast<size_t>(pixel_data_size * y *
11986 exr_image->width) +
11987 channel_offset_list[c] *
11988 static_cast<size_t>(exr_image->width)));
11989 for (int x = 0; x < exr_image->width; x++) {
11990 unsigned short val = reinterpret_cast<unsigned short **>(
11991 exr_image->images)[c][(y + start_y) * exr_image->width + x];
11992
11993 tinyexr::swap2(&val);
11994
11995 // line_ptr[x] = val;
11996 tinyexr::cpy2(line_ptr + x, &val);
11997 }
11998 }
11999 } else {
12000 assert(0);
12001 }
12002
12003 } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
12004 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
12005 for (int y = 0; y < h; y++) {
12006 // Assume increasing Y
12007 unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
12008 &buf.at(static_cast<size_t>(pixel_data_size * y *
12009 exr_image->width) +
12010 channel_offset_list[c] *
12011 static_cast<size_t>(exr_image->width)));
12012 for (int x = 0; x < exr_image->width; x++) {
12013 tinyexr::FP32 f32;
12014 f32.f = reinterpret_cast<float **>(
12015 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12016
12017 tinyexr::FP16 h16;
12018 h16 = float_to_half_full(f32);
12019
12020 tinyexr::swap2(reinterpret_cast<unsigned short *>(&h16.u));
12021
12022 // line_ptr[x] = h16.u;
12023 tinyexr::cpy2(line_ptr + x, &(h16.u));
12024 }
12025 }
12026 } else if (exr_header->requested_pixel_types[c] ==
12027 TINYEXR_PIXELTYPE_FLOAT) {
12028 for (int y = 0; y < h; y++) {
12029 // Assume increasing Y
12030 float *line_ptr = reinterpret_cast<float *>(&buf.at(
12031 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
12032 channel_offset_list[c] *
12033 static_cast<size_t>(exr_image->width)));
12034 for (int x = 0; x < exr_image->width; x++) {
12035 float val = reinterpret_cast<float **>(
12036 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12037
12038 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
12039
12040 // line_ptr[x] = val;
12041 tinyexr::cpy4(line_ptr + x, &val);
12042 }
12043 }
12044 } else {
12045 assert(0);
12046 }
12047 } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
12048 for (int y = 0; y < h; y++) {
12049 // Assume increasing Y
12050 unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
12051 static_cast<size_t>(pixel_data_size * y * exr_image->width) +
12052 channel_offset_list[c] * static_cast<size_t>(exr_image->width)));
12053 for (int x = 0; x < exr_image->width; x++) {
12054 unsigned int val = reinterpret_cast<unsigned int **>(
12055 exr_image->images)[c][(y + start_y) * exr_image->width + x];
12056
12057 tinyexr::swap4(&val);
12058
12059 // line_ptr[x] = val;
12060 tinyexr::cpy4(line_ptr + x, &val);
12061 }
12062 }
12063 }
12064 }
12065
12066 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
12067 // 4 byte: scan line
12068 // 4 byte: data size
12069 // ~ : pixel data(uncompressed)
12070 std::vector<unsigned char> header(8);
12071 unsigned int data_len = static_cast<unsigned int>(buf.size());
12072 memcpy(&header.at(0), &start_y, sizeof(int));
12073 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12074
12075 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12076 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12077
12078 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12079 data_list[ii].insert(data_list[ii].end(), buf.begin(),
12080 buf.begin() + data_len);
12081
12082 } else if ((exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
12083 (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) {
12084#if TINYEXR_USE_MINIZ
12085 std::vector<unsigned char> block(tinyexr::miniz::mz_compressBound(
12086 static_cast<unsigned long>(buf.size())));
12087#else
12088 std::vector<unsigned char> block(
12089 compressBound(static_cast<uLong>(buf.size())));
12090#endif
12091 tinyexr::tinyexr_uint64 outSize = block.size();
12092
12093 tinyexr::CompressZip(&block.at(0), outSize,
12094 reinterpret_cast<const unsigned char *>(&buf.at(0)),
12095 static_cast<unsigned long>(buf.size()));
12096
12097 // 4 byte: scan line
12098 // 4 byte: data size
12099 // ~ : pixel data(compressed)
12100 std::vector<unsigned char> header(8);
12101 unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
12102 memcpy(&header.at(0), &start_y, sizeof(int));
12103 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12104
12105 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12106 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12107
12108 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12109 data_list[ii].insert(data_list[ii].end(), block.begin(),
12110 block.begin() + data_len);
12111
12112 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_RLE) {
12113 // (buf.size() * 3) / 2 would be enough.
12114 std::vector<unsigned char> block((buf.size() * 3) / 2);
12115
12116 tinyexr::tinyexr_uint64 outSize = block.size();
12117
12118 tinyexr::CompressRle(&block.at(0), outSize,
12119 reinterpret_cast<const unsigned char *>(&buf.at(0)),
12120 static_cast<unsigned long>(buf.size()));
12121
12122 // 4 byte: scan line
12123 // 4 byte: data size
12124 // ~ : pixel data(compressed)
12125 std::vector<unsigned char> header(8);
12126 unsigned int data_len = static_cast<unsigned int>(outSize); // truncate
12127 memcpy(&header.at(0), &start_y, sizeof(int));
12128 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12129
12130 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12131 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12132
12133 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12134 data_list[ii].insert(data_list[ii].end(), block.begin(),
12135 block.begin() + data_len);
12136
12137 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
12138#if TINYEXR_USE_PIZ
12139 unsigned int bufLen =
12140 8192 + static_cast<unsigned int>(
12141 2 * static_cast<unsigned int>(
12142 buf.size())); // @fixme { compute good bound. }
12143 std::vector<unsigned char> block(bufLen);
12144 unsigned int outSize = static_cast<unsigned int>(block.size());
12145
12146 CompressPiz(&block.at(0), &outSize,
12147 reinterpret_cast<const unsigned char *>(&buf.at(0)),
12148 buf.size(), channels, exr_image->width, h);
12149
12150 // 4 byte: scan line
12151 // 4 byte: data size
12152 // ~ : pixel data(compressed)
12153 std::vector<unsigned char> header(8);
12154 unsigned int data_len = outSize;
12155 memcpy(&header.at(0), &start_y, sizeof(int));
12156 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12157
12158 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12159 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12160
12161 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12162 data_list[ii].insert(data_list[ii].end(), block.begin(),
12163 block.begin() + data_len);
12164
12165#else
12166 assert(0);
12167#endif
12168 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
12169#if TINYEXR_USE_ZFP
12170 std::vector<unsigned char> block;
12171 unsigned int outSize;
12172
12173 tinyexr::CompressZfp(
12174 &block, &outSize, reinterpret_cast<const float *>(&buf.at(0)),
12175 exr_image->width, h, exr_header->num_channels, zfp_compression_param);
12176
12177 // 4 byte: scan line
12178 // 4 byte: data size
12179 // ~ : pixel data(compressed)
12180 std::vector<unsigned char> header(8);
12181 unsigned int data_len = outSize;
12182 memcpy(&header.at(0), &start_y, sizeof(int));
12183 memcpy(&header.at(4), &data_len, sizeof(unsigned int));
12184
12185 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0)));
12186 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4)));
12187
12188 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end());
12189 data_list[ii].insert(data_list[ii].end(), block.begin(),
12190 block.begin() + data_len);
12191
12192#else
12193 assert(0);
12194#endif
12195 } else {
12196 assert(0);
12197 }
12198 } // omp parallel
12199
12200 for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
12201 offsets[i] = offset;
12202 tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offsets[i]));
12203 offset += data_list[i].size();
12204 }
12205
12206 size_t totalSize = static_cast<size_t>(offset);
12207 {
12208 memory.insert(
12209 memory.end(), reinterpret_cast<unsigned char *>(&offsets.at(0)),
12210 reinterpret_cast<unsigned char *>(&offsets.at(0)) +
12211 sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(num_blocks));
12212 }
12213
12214 if (memory.size() == 0) {
12215 tinyexr::SetErrorMessage("Output memory size is zero", err);
12216 return 0;
12217 }
12218
12219 (*memory_out) = static_cast<unsigned char *>(malloc(totalSize));
12220 memcpy((*memory_out), &memory.at(0), memory.size());
12221 unsigned char *memory_ptr = *memory_out + memory.size();
12222
12223 for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
12224 memcpy(memory_ptr, &data_list[i].at(0), data_list[i].size());
12225 memory_ptr += data_list[i].size();
12226 }
12227
12228 return totalSize; // OK
12229}
12230
12231int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
12232 const char *filename, const char **err) {
12233 if (exr_image == NULL || filename == NULL ||
12234 exr_header->compression_type < 0) {
12235 tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err);
12236 return TINYEXR_ERROR_INVALID_ARGUMENT;
12237 }
12238
12239#if !TINYEXR_USE_PIZ
12240 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
12241 tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
12242 err);
12243 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
12244 }
12245#endif
12246
12247#if !TINYEXR_USE_ZFP
12248 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
12249 tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
12250 err);
12251 return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
12252 }
12253#endif
12254
12255#ifdef _WIN32
12256 FILE *fp = NULL;
12257 fopen_s(&fp, filename, "wb");
12258#else
12259 FILE *fp = fopen(filename, "wb");
12260#endif
12261 if (!fp) {
12262 tinyexr::SetErrorMessage("Cannot write a file", err);
12263 return TINYEXR_ERROR_CANT_WRITE_FILE;
12264 }
12265
12266 unsigned char *mem = NULL;
12267 size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err);
12268 if (mem_size == 0) {
12269 return TINYEXR_ERROR_SERIALZATION_FAILED;
12270 }
12271
12272 size_t written_size = 0;
12273 if ((mem_size > 0) && mem) {
12274 written_size = fwrite(mem, 1, mem_size, fp);
12275 }
12276 free(mem);
12277
12278 fclose(fp);
12279
12280 if (written_size != mem_size) {
12281 tinyexr::SetErrorMessage("Cannot write a file", err);
12282 return TINYEXR_ERROR_CANT_WRITE_FILE;
12283 }
12284
12285 return TINYEXR_SUCCESS;
12286}
12287
12288int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
12289 if (deep_image == NULL) {
12290 tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err);
12291 return TINYEXR_ERROR_INVALID_ARGUMENT;
12292 }
12293
12294#ifdef _MSC_VER
12295 FILE *fp = NULL;
12296 errno_t errcode = fopen_s(&fp, filename, "rb");
12297 if ((0 != errcode) || (!fp)) {
12298 tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
12299 err);
12300 return TINYEXR_ERROR_CANT_OPEN_FILE;
12301 }
12302#else
12303 FILE *fp = fopen(filename, "rb");
12304 if (!fp) {
12305 tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
12306 err);
12307 return TINYEXR_ERROR_CANT_OPEN_FILE;
12308 }
12309#endif
12310
12311 size_t filesize;
12312 // Compute size
12313 fseek(fp, 0, SEEK_END);
12314 filesize = static_cast<size_t>(ftell(fp));
12315 fseek(fp, 0, SEEK_SET);
12316
12317 if (filesize == 0) {
12318 fclose(fp);
12319 tinyexr::SetErrorMessage("File size is zero : " + std::string(filename),
12320 err);
12321 return TINYEXR_ERROR_INVALID_FILE;
12322 }
12323
12324 std::vector<char> buf(filesize); // @todo { use mmap }
12325 {
12326 size_t ret;
12327 ret = fread(&buf[0], 1, filesize, fp);
12328 assert(ret == filesize);
12329 (void)ret;
12330 }
12331 fclose(fp);
12332
12333 const char *head = &buf[0];
12334 const char *marker = &buf[0];
12335
12336 // Header check.
12337 {
12338 const char header[] = {0x76, 0x2f, 0x31, 0x01};
12339
12340 if (memcmp(marker, header, 4) != 0) {
12341 tinyexr::SetErrorMessage("Invalid magic number", err);
12342 return TINYEXR_ERROR_INVALID_MAGIC_NUMBER;
12343 }
12344 marker += 4;
12345 }
12346
12347 // Version, scanline.
12348 {
12349 // ver 2.0, scanline, deep bit on(0x800)
12350 // must be [2, 0, 0, 0]
12351 if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) {
12352 tinyexr::SetErrorMessage("Unsupported version or scanline", err);
12353 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
12354 }
12355
12356 marker += 4;
12357 }
12358
12359 int dx = -1;
12360 int dy = -1;
12361 int dw = -1;
12362 int dh = -1;
12363 int num_scanline_blocks = 1; // 16 for ZIP compression.
12364 int compression_type = -1;
12365 int num_channels = -1;
12366 std::vector<tinyexr::ChannelInfo> channels;
12367
12368 // Read attributes
12369 size_t size = filesize - tinyexr::kEXRVersionSize;
12370 for (;;) {
12371 if (0 == size) {
12372 return TINYEXR_ERROR_INVALID_DATA;
12373 } else if (marker[0] == '\0') {
12374 marker++;
12375 size--;
12376 break;
12377 }
12378
12379 std::string attr_name;
12380 std::string attr_type;
12381 std::vector<unsigned char> data;
12382 size_t marker_size;
12383 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
12384 marker, size)) {
12385 std::stringstream ss;
12386 ss << "Failed to parse attribute\n";
12387 tinyexr::SetErrorMessage(ss.str(), err);
12388 return TINYEXR_ERROR_INVALID_DATA;
12389 }
12390 marker += marker_size;
12391 size -= marker_size;
12392
12393 if (attr_name.compare("compression") == 0) {
12394 compression_type = data[0];
12395 if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) {
12396 std::stringstream ss;
12397 ss << "Unsupported compression type : " << compression_type;
12398 tinyexr::SetErrorMessage(ss.str(), err);
12399 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
12400 }
12401
12402 if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) {
12403 num_scanline_blocks = 16;
12404 }
12405
12406 } else if (attr_name.compare("channels") == 0) {
12407 // name: zero-terminated string, from 1 to 255 bytes long
12408 // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2
12409 // pLinear: unsigned char, possible values are 0 and 1
12410 // reserved: three chars, should be zero
12411 // xSampling: int
12412 // ySampling: int
12413
12414 if (!tinyexr::ReadChannelInfo(channels, data)) {
12415 tinyexr::SetErrorMessage("Failed to parse channel info", err);
12416 return TINYEXR_ERROR_INVALID_DATA;
12417 }
12418
12419 num_channels = static_cast<int>(channels.size());
12420
12421 if (num_channels < 1) {
12422 tinyexr::SetErrorMessage("Invalid channels format", err);
12423 return TINYEXR_ERROR_INVALID_DATA;
12424 }
12425
12426 } else if (attr_name.compare("dataWindow") == 0) {
12427 memcpy(&dx, &data.at(0), sizeof(int));
12428 memcpy(&dy, &data.at(4), sizeof(int));
12429 memcpy(&dw, &data.at(8), sizeof(int));
12430 memcpy(&dh, &data.at(12), sizeof(int));
12431 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dx));
12432 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dy));
12433 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dw));
12434 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dh));
12435
12436 } else if (attr_name.compare("displayWindow") == 0) {
12437 int x;
12438 int y;
12439 int w;
12440 int h;
12441 memcpy(&x, &data.at(0), sizeof(int));
12442 memcpy(&y, &data.at(4), sizeof(int));
12443 memcpy(&w, &data.at(8), sizeof(int));
12444 memcpy(&h, &data.at(12), sizeof(int));
12445 tinyexr::swap4(reinterpret_cast<unsigned int *>(&x));
12446 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y));
12447 tinyexr::swap4(reinterpret_cast<unsigned int *>(&w));
12448 tinyexr::swap4(reinterpret_cast<unsigned int *>(&h));
12449 }
12450 }
12451
12452 assert(dx >= 0);
12453 assert(dy >= 0);
12454 assert(dw >= 0);
12455 assert(dh >= 0);
12456 assert(num_channels >= 1);
12457
12458 int data_width = dw - dx + 1;
12459 int data_height = dh - dy + 1;
12460
12461 std::vector<float> image(
12462 static_cast<size_t>(data_width * data_height * 4)); // 4 = RGBA
12463
12464 // Read offset tables.
12465 int num_blocks = data_height / num_scanline_blocks;
12466 if (num_blocks * num_scanline_blocks < data_height) {
12467 num_blocks++;
12468 }
12469
12470 std::vector<tinyexr::tinyexr_int64> offsets(static_cast<size_t>(num_blocks));
12471
12472 for (size_t y = 0; y < static_cast<size_t>(num_blocks); y++) {
12473 tinyexr::tinyexr_int64 offset;
12474 memcpy(&offset, marker, sizeof(tinyexr::tinyexr_int64));
12475 tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offset));
12476 marker += sizeof(tinyexr::tinyexr_int64); // = 8
12477 offsets[y] = offset;
12478 }
12479
12480#if TINYEXR_USE_PIZ
12481 if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) ||
12482 (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) ||
12483 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
12484 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) ||
12485 (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ)) {
12486#else
12487 if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) ||
12488 (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) ||
12489 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) ||
12490 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) {
12491#endif
12492 // OK
12493 } else {
12494 tinyexr::SetErrorMessage("Unsupported compression format", err);
12495 return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
12496 }
12497
12498 deep_image->image = static_cast<float ***>(
12499 malloc(sizeof(float **) * static_cast<size_t>(num_channels)));
12500 for (int c = 0; c < num_channels; c++) {
12501 deep_image->image[c] = static_cast<float **>(
12502 malloc(sizeof(float *) * static_cast<size_t>(data_height)));
12503 for (int y = 0; y < data_height; y++) {
12504 }
12505 }
12506
12507 deep_image->offset_table = static_cast<int **>(
12508 malloc(sizeof(int *) * static_cast<size_t>(data_height)));
12509 for (int y = 0; y < data_height; y++) {
12510 deep_image->offset_table[y] = static_cast<int *>(
12511 malloc(sizeof(int) * static_cast<size_t>(data_width)));
12512 }
12513
12514 for (size_t y = 0; y < static_cast<size_t>(num_blocks); y++) {
12515 const unsigned char *data_ptr =
12516 reinterpret_cast<const unsigned char *>(head + offsets[y]);
12517
12518 // int: y coordinate
12519 // int64: packed size of pixel offset table
12520 // int64: packed size of sample data
12521 // int64: unpacked size of sample data
12522 // compressed pixel offset table
12523 // compressed sample data
12524 int line_no;
12525 tinyexr::tinyexr_int64 packedOffsetTableSize;
12526 tinyexr::tinyexr_int64 packedSampleDataSize;
12527 tinyexr::tinyexr_int64 unpackedSampleDataSize;
12528 memcpy(&line_no, data_ptr, sizeof(int));
12529 memcpy(&packedOffsetTableSize, data_ptr + 4,
12530 sizeof(tinyexr::tinyexr_int64));
12531 memcpy(&packedSampleDataSize, data_ptr + 12,
12532 sizeof(tinyexr::tinyexr_int64));
12533 memcpy(&unpackedSampleDataSize, data_ptr + 20,
12534 sizeof(tinyexr::tinyexr_int64));
12535
12536 tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
12537 tinyexr::swap8(
12538 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&packedOffsetTableSize));
12539 tinyexr::swap8(
12540 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&packedSampleDataSize));
12541 tinyexr::swap8(
12542 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&unpackedSampleDataSize));
12543
12544 std::vector<int> pixelOffsetTable(static_cast<size_t>(data_width));
12545
12546 // decode pixel offset table.
12547 {
12548 unsigned long dstLen =
12549 static_cast<unsigned long>(pixelOffsetTable.size() * sizeof(int));
12550 if (!tinyexr::DecompressZip(
12551 reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)),
12552 &dstLen, data_ptr + 28,
12553 static_cast<unsigned long>(packedOffsetTableSize))) {
12554 return false;
12555 }
12556
12557 assert(dstLen == pixelOffsetTable.size() * sizeof(int));
12558 for (size_t i = 0; i < static_cast<size_t>(data_width); i++) {
12559 deep_image->offset_table[y][i] = pixelOffsetTable[i];
12560 }
12561 }
12562
12563 std::vector<unsigned char> sample_data(
12564 static_cast<size_t>(unpackedSampleDataSize));
12565
12566 // decode sample data.
12567 {
12568 unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize);
12569 if (dstLen) {
12570 if (!tinyexr::DecompressZip(
12571 reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen,
12572 data_ptr + 28 + packedOffsetTableSize,
12573 static_cast<unsigned long>(packedSampleDataSize))) {
12574 return false;
12575 }
12576 assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize));
12577 }
12578 }
12579
12580 // decode sample
12581 int sampleSize = -1;
12582 std::vector<int> channel_offset_list(static_cast<size_t>(num_channels));
12583 {
12584 int channel_offset = 0;
12585 for (size_t i = 0; i < static_cast<size_t>(num_channels); i++) {
12586 channel_offset_list[i] = channel_offset;
12587 if (channels[i].pixel_type == TINYEXR_PIXELTYPE_UINT) { // UINT
12588 channel_offset += 4;
12589 } else if (channels[i].pixel_type == TINYEXR_PIXELTYPE_HALF) { // half
12590 channel_offset += 2;
12591 } else if (channels[i].pixel_type ==
12592 TINYEXR_PIXELTYPE_FLOAT) { // float
12593 channel_offset += 4;
12594 } else {
12595 assert(0);
12596 }
12597 }
12598 sampleSize = channel_offset;
12599 }
12600 assert(sampleSize >= 2);
12601
12602 assert(static_cast<size_t>(
12603 pixelOffsetTable[static_cast<size_t>(data_width - 1)] *
12604 sampleSize) == sample_data.size());
12605 int samples_per_line = static_cast<int>(sample_data.size()) / sampleSize;
12606
12607 //
12608 // Alloc memory
12609 //
12610
12611 //
12612 // pixel data is stored as image[channels][pixel_samples]
12613 //
12614 {
12615 tinyexr::tinyexr_uint64 data_offset = 0;
12616 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
12617 deep_image->image[c][y] = static_cast<float *>(
12618 malloc(sizeof(float) * static_cast<size_t>(samples_per_line)));
12619
12620 if (channels[c].pixel_type == 0) { // UINT
12621 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
12622 unsigned int ui;
12623 unsigned int *src_ptr = reinterpret_cast<unsigned int *>(
12624 &sample_data.at(size_t(data_offset) + x * sizeof(int)));
12625 tinyexr::cpy4(&ui, src_ptr);
12626 deep_image->image[c][y][x] = static_cast<float>(ui); // @fixme
12627 }
12628 data_offset +=
12629 sizeof(unsigned int) * static_cast<size_t>(samples_per_line);
12630 } else if (channels[c].pixel_type == 1) { // half
12631 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
12632 tinyexr::FP16 f16;
12633 const unsigned short *src_ptr = reinterpret_cast<unsigned short *>(
12634 &sample_data.at(size_t(data_offset) + x * sizeof(short)));
12635 tinyexr::cpy2(&(f16.u), src_ptr);
12636 tinyexr::FP32 f32 = half_to_float(f16);
12637 deep_image->image[c][y][x] = f32.f;
12638 }
12639 data_offset += sizeof(short) * static_cast<size_t>(samples_per_line);
12640 } else { // float
12641 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
12642 float f;
12643 const float *src_ptr = reinterpret_cast<float *>(
12644 &sample_data.at(size_t(data_offset) + x * sizeof(float)));
12645 tinyexr::cpy4(&f, src_ptr);
12646 deep_image->image[c][y][x] = f;
12647 }
12648 data_offset += sizeof(float) * static_cast<size_t>(samples_per_line);
12649 }
12650 }
12651 }
12652 } // y
12653
12654 deep_image->width = data_width;
12655 deep_image->height = data_height;
12656
12657 deep_image->channel_names = static_cast<const char **>(
12658 malloc(sizeof(const char *) * static_cast<size_t>(num_channels)));
12659 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
12660#ifdef _WIN32
12661 deep_image->channel_names[c] = _strdup(channels[c].name.c_str());
12662#else
12663 deep_image->channel_names[c] = strdup(channels[c].name.c_str());
12664#endif
12665 }
12666 deep_image->num_channels = num_channels;
12667
12668 return TINYEXR_SUCCESS;
12669}
12670
12671void InitEXRImage(EXRImage *exr_image) {
12672 if (exr_image == NULL) {
12673 return;
12674 }
12675
12676 exr_image->width = 0;
12677 exr_image->height = 0;
12678 exr_image->num_channels = 0;
12679
12680 exr_image->images = NULL;
12681 exr_image->tiles = NULL;
12682
12683 exr_image->num_tiles = 0;
12684}
12685
12686void FreeEXRErrorMessage(const char *msg) {
12687 if (msg) {
12688 free(reinterpret_cast<void *>(const_cast<char *>(msg)));
12689 }
12690 return;
12691}
12692
12693void InitEXRHeader(EXRHeader *exr_header) {
12694 if (exr_header == NULL) {
12695 return;
12696 }
12697
12698 memset(exr_header, 0, sizeof(EXRHeader));
12699}
12700
12701int FreeEXRHeader(EXRHeader *exr_header) {
12702 if (exr_header == NULL) {
12703 return TINYEXR_ERROR_INVALID_ARGUMENT;
12704 }
12705
12706 if (exr_header->channels) {
12707 free(exr_header->channels);
12708 }
12709
12710 if (exr_header->pixel_types) {
12711 free(exr_header->pixel_types);
12712 }
12713
12714 if (exr_header->requested_pixel_types) {
12715 free(exr_header->requested_pixel_types);
12716 }
12717
12718 for (int i = 0; i < exr_header->num_custom_attributes; i++) {
12719 if (exr_header->custom_attributes[i].value) {
12720 free(exr_header->custom_attributes[i].value);
12721 }
12722 }
12723
12724 if (exr_header->custom_attributes) {
12725 free(exr_header->custom_attributes);
12726 }
12727
12728 return TINYEXR_SUCCESS;
12729}
12730
12731int FreeEXRImage(EXRImage *exr_image) {
12732 if (exr_image == NULL) {
12733 return TINYEXR_ERROR_INVALID_ARGUMENT;
12734 }
12735
12736 for (int i = 0; i < exr_image->num_channels; i++) {
12737 if (exr_image->images && exr_image->images[i]) {
12738 free(exr_image->images[i]);
12739 }
12740 }
12741
12742 if (exr_image->images) {
12743 free(exr_image->images);
12744 }
12745
12746 if (exr_image->tiles) {
12747 for (int tid = 0; tid < exr_image->num_tiles; tid++) {
12748 for (int i = 0; i < exr_image->num_channels; i++) {
12749 if (exr_image->tiles[tid].images && exr_image->tiles[tid].images[i]) {
12750 free(exr_image->tiles[tid].images[i]);
12751 }
12752 }
12753 if (exr_image->tiles[tid].images) {
12754 free(exr_image->tiles[tid].images);
12755 }
12756 }
12757 free(exr_image->tiles);
12758 }
12759
12760 return TINYEXR_SUCCESS;
12761}
12762
12763int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
12764 const char *filename, const char **err) {
12765 if (exr_header == NULL || exr_version == NULL || filename == NULL) {
12766 tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile",
12767 err);
12768 return TINYEXR_ERROR_INVALID_ARGUMENT;
12769 }
12770
12771#ifdef _WIN32
12772 FILE *fp = NULL;
12773 fopen_s(&fp, filename, "rb");
12774#else
12775 FILE *fp = fopen(filename, "rb");
12776#endif
12777 if (!fp) {
12778 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
12779 return TINYEXR_ERROR_CANT_OPEN_FILE;
12780 }
12781
12782 size_t filesize;
12783 // Compute size
12784 fseek(fp, 0, SEEK_END);
12785 filesize = static_cast<size_t>(ftell(fp));
12786 fseek(fp, 0, SEEK_SET);
12787
12788 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
12789 {
12790 size_t ret;
12791 ret = fread(&buf[0], 1, filesize, fp);
12792 assert(ret == filesize);
12793 fclose(fp);
12794
12795 if (ret != filesize) {
12796 tinyexr::SetErrorMessage("fread() error on " + std::string(filename),
12797 err);
12798 return TINYEXR_ERROR_INVALID_FILE;
12799 }
12800 }
12801
12802 return ParseEXRHeaderFromMemory(exr_header, exr_version, &buf.at(0), filesize,
12803 err);
12804}
12805
12806int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
12807 int *num_headers,
12808 const EXRVersion *exr_version,
12809 const unsigned char *memory, size_t size,
12810 const char **err) {
12811 if (memory == NULL || exr_headers == NULL || num_headers == NULL ||
12812 exr_version == NULL) {
12813 // Invalid argument
12814 tinyexr::SetErrorMessage(
12815 "Invalid argument for ParseEXRMultipartHeaderFromMemory", err);
12816 return TINYEXR_ERROR_INVALID_ARGUMENT;
12817 }
12818
12819 if (size < tinyexr::kEXRVersionSize) {
12820 tinyexr::SetErrorMessage("Data size too short", err);
12821 return TINYEXR_ERROR_INVALID_DATA;
12822 }
12823
12824 const unsigned char *marker = memory + tinyexr::kEXRVersionSize;
12825 size_t marker_size = size - tinyexr::kEXRVersionSize;
12826
12827 std::vector<tinyexr::HeaderInfo> infos;
12828
12829 for (;;) {
12830 tinyexr::HeaderInfo info;
12831 info.clear();
12832
12833 std::string err_str;
12834 bool empty_header = false;
12835 int ret = ParseEXRHeader(&info, &empty_header, exr_version, &err_str,
12836 marker, marker_size);
12837
12838 if (ret != TINYEXR_SUCCESS) {
12839 tinyexr::SetErrorMessage(err_str, err);
12840 return ret;
12841 }
12842
12843 if (empty_header) {
12844 marker += 1; // skip '\0'
12845 break;
12846 }
12847
12848 // `chunkCount` must exist in the header.
12849 if (info.chunk_count == 0) {
12850 tinyexr::SetErrorMessage(
12851 "`chunkCount' attribute is not found in the header.", err);
12852 return TINYEXR_ERROR_INVALID_DATA;
12853 }
12854
12855 infos.push_back(info);
12856
12857 // move to next header.
12858 marker += info.header_len;
12859 size -= info.header_len;
12860 }
12861
12862 // allocate memory for EXRHeader and create array of EXRHeader pointers.
12863 (*exr_headers) =
12864 static_cast<EXRHeader **>(malloc(sizeof(EXRHeader *) * infos.size()));
12865 for (size_t i = 0; i < infos.size(); i++) {
12866 EXRHeader *exr_header = static_cast<EXRHeader *>(malloc(sizeof(EXRHeader)));
12867
12868 ConvertHeader(exr_header, infos[i]);
12869
12870 // transfoer `tiled` from version.
12871 exr_header->tiled = exr_version->tiled;
12872
12873 (*exr_headers)[i] = exr_header;
12874 }
12875
12876 (*num_headers) = static_cast<int>(infos.size());
12877
12878 return TINYEXR_SUCCESS;
12879}
12880
12881int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
12882 const EXRVersion *exr_version,
12883 const char *filename, const char **err) {
12884 if (exr_headers == NULL || num_headers == NULL || exr_version == NULL ||
12885 filename == NULL) {
12886 tinyexr::SetErrorMessage(
12887 "Invalid argument for ParseEXRMultipartHeaderFromFile()", err);
12888 return TINYEXR_ERROR_INVALID_ARGUMENT;
12889 }
12890
12891#ifdef _WIN32
12892 FILE *fp = NULL;
12893 fopen_s(&fp, filename, "rb");
12894#else
12895 FILE *fp = fopen(filename, "rb");
12896#endif
12897 if (!fp) {
12898 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
12899 return TINYEXR_ERROR_CANT_OPEN_FILE;
12900 }
12901
12902 size_t filesize;
12903 // Compute size
12904 fseek(fp, 0, SEEK_END);
12905 filesize = static_cast<size_t>(ftell(fp));
12906 fseek(fp, 0, SEEK_SET);
12907
12908 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
12909 {
12910 size_t ret;
12911 ret = fread(&buf[0], 1, filesize, fp);
12912 assert(ret == filesize);
12913 fclose(fp);
12914
12915 if (ret != filesize) {
12916 tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err);
12917 return TINYEXR_ERROR_INVALID_FILE;
12918 }
12919 }
12920
12921 return ParseEXRMultipartHeaderFromMemory(
12922 exr_headers, num_headers, exr_version, &buf.at(0), filesize, err);
12923}
12924
12925int ParseEXRVersionFromMemory(EXRVersion *version, const unsigned char *memory,
12926 size_t size) {
12927 if (version == NULL || memory == NULL) {
12928 return TINYEXR_ERROR_INVALID_ARGUMENT;
12929 }
12930
12931 if (size < tinyexr::kEXRVersionSize) {
12932 return TINYEXR_ERROR_INVALID_DATA;
12933 }
12934
12935 const unsigned char *marker = memory;
12936
12937 // Header check.
12938 {
12939 const char header[] = {0x76, 0x2f, 0x31, 0x01};
12940
12941 if (memcmp(marker, header, 4) != 0) {
12942 return TINYEXR_ERROR_INVALID_MAGIC_NUMBER;
12943 }
12944 marker += 4;
12945 }
12946
12947 version->tiled = false;
12948 version->long_name = false;
12949 version->non_image = false;
12950 version->multipart = false;
12951
12952 // Parse version header.
12953 {
12954 // must be 2
12955 if (marker[0] != 2) {
12956 return TINYEXR_ERROR_INVALID_EXR_VERSION;
12957 }
12958
12959 if (version == NULL) {
12960 return TINYEXR_SUCCESS; // May OK
12961 }
12962
12963 version->version = 2;
12964
12965 if (marker[1] & 0x2) { // 9th bit
12966 version->tiled = true;
12967 }
12968 if (marker[1] & 0x4) { // 10th bit
12969 version->long_name = true;
12970 }
12971 if (marker[1] & 0x8) { // 11th bit
12972 version->non_image = true; // (deep image)
12973 }
12974 if (marker[1] & 0x10) { // 12th bit
12975 version->multipart = true;
12976 }
12977 }
12978
12979 return TINYEXR_SUCCESS;
12980}
12981
12982int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) {
12983 if (filename == NULL) {
12984 return TINYEXR_ERROR_INVALID_ARGUMENT;
12985 }
12986
12987#ifdef _WIN32
12988 FILE *fp = NULL;
12989 fopen_s(&fp, filename, "rb");
12990#else
12991 FILE *fp = fopen(filename, "rb");
12992#endif
12993 if (!fp) {
12994 return TINYEXR_ERROR_CANT_OPEN_FILE;
12995 }
12996
12997 size_t file_size;
12998 // Compute size
12999 fseek(fp, 0, SEEK_END);
13000 file_size = static_cast<size_t>(ftell(fp));
13001 fseek(fp, 0, SEEK_SET);
13002
13003 if (file_size < tinyexr::kEXRVersionSize) {
13004 return TINYEXR_ERROR_INVALID_FILE;
13005 }
13006
13007 unsigned char buf[tinyexr::kEXRVersionSize];
13008 size_t ret = fread(&buf[0], 1, tinyexr::kEXRVersionSize, fp);
13009 fclose(fp);
13010
13011 if (ret != tinyexr::kEXRVersionSize) {
13012 return TINYEXR_ERROR_INVALID_FILE;
13013 }
13014
13015 return ParseEXRVersionFromMemory(version, buf, tinyexr::kEXRVersionSize);
13016}
13017
13018int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
13019 const EXRHeader **exr_headers,
13020 unsigned int num_parts,
13021 const unsigned char *memory,
13022 const size_t size, const char **err) {
13023 if (exr_images == NULL || exr_headers == NULL || num_parts == 0 ||
13024 memory == NULL || (size <= tinyexr::kEXRVersionSize)) {
13025 tinyexr::SetErrorMessage(
13026 "Invalid argument for LoadEXRMultipartImageFromMemory()", err);
13027 return TINYEXR_ERROR_INVALID_ARGUMENT;
13028 }
13029
13030 // compute total header size.
13031 size_t total_header_size = 0;
13032 for (unsigned int i = 0; i < num_parts; i++) {
13033 if (exr_headers[i]->header_len == 0) {
13034 tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
13035 return TINYEXR_ERROR_INVALID_ARGUMENT;
13036 }
13037
13038 total_header_size += exr_headers[i]->header_len;
13039 }
13040
13041 const char *marker = reinterpret_cast<const char *>(
13042 memory + total_header_size + 4 +
13043 4); // +8 for magic number and version header.
13044
13045 marker += 1; // Skip empty header.
13046
13047 // NOTE 1:
13048 // In multipart image, There is 'part number' before chunk data.
13049 // 4 byte : part number
13050 // 4+ : chunk
13051 //
13052 // NOTE 2:
13053 // EXR spec says 'part number' is 'unsigned long' but actually this is
13054 // 'unsigned int(4 bytes)' in OpenEXR implementation...
13055 // http://www.openexr.com/openexrfilelayout.pdf
13056
13057 // Load chunk offset table.
13058 std::vector<std::vector<tinyexr::tinyexr_uint64> > chunk_offset_table_list;
13059 for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
13060 std::vector<tinyexr::tinyexr_uint64> offset_table(
13061 static_cast<size_t>(exr_headers[i]->chunk_count));
13062
13063 for (size_t c = 0; c < offset_table.size(); c++) {
13064 tinyexr::tinyexr_uint64 offset;
13065 memcpy(&offset, marker, 8);
13066 tinyexr::swap8(&offset);
13067
13068 if (offset >= size) {
13069 tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.",
13070 err);
13071 return TINYEXR_ERROR_INVALID_DATA;
13072 }
13073
13074 offset_table[c] = offset + 4; // +4 to skip 'part number'
13075 marker += 8;
13076 }
13077
13078 chunk_offset_table_list.push_back(offset_table);
13079 }
13080
13081 // Decode image.
13082 for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) {
13083 std::vector<tinyexr::tinyexr_uint64> &offset_table =
13084 chunk_offset_table_list[i];
13085
13086 // First check 'part number' is identitical to 'i'
13087 for (size_t c = 0; c < offset_table.size(); c++) {
13088 const unsigned char *part_number_addr =
13089 memory + offset_table[c] - 4; // -4 to move to 'part number' field.
13090 unsigned int part_no;
13091 memcpy(&part_no, part_number_addr, sizeof(unsigned int)); // 4
13092 tinyexr::swap4(&part_no);
13093
13094 if (part_no != i) {
13095 tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.",
13096 err);
13097 return TINYEXR_ERROR_INVALID_DATA;
13098 }
13099 }
13100
13101 std::string e;
13102 int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
13103 memory, size, &e);
13104 if (ret != TINYEXR_SUCCESS) {
13105 if (!e.empty()) {
13106 tinyexr::SetErrorMessage(e, err);
13107 }
13108 return ret;
13109 }
13110 }
13111
13112 return TINYEXR_SUCCESS;
13113}
13114
13115int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
13116 const EXRHeader **exr_headers,
13117 unsigned int num_parts, const char *filename,
13118 const char **err) {
13119 if (exr_images == NULL || exr_headers == NULL || num_parts == 0) {
13120 tinyexr::SetErrorMessage(
13121 "Invalid argument for LoadEXRMultipartImageFromFile", err);
13122 return TINYEXR_ERROR_INVALID_ARGUMENT;
13123 }
13124
13125#ifdef _WIN32
13126 FILE *fp = NULL;
13127 fopen_s(&fp, filename, "rb");
13128#else
13129 FILE *fp = fopen(filename, "rb");
13130#endif
13131 if (!fp) {
13132 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
13133 return TINYEXR_ERROR_CANT_OPEN_FILE;
13134 }
13135
13136 size_t filesize;
13137 // Compute size
13138 fseek(fp, 0, SEEK_END);
13139 filesize = static_cast<size_t>(ftell(fp));
13140 fseek(fp, 0, SEEK_SET);
13141
13142 std::vector<unsigned char> buf(filesize); // @todo { use mmap }
13143 {
13144 size_t ret;
13145 ret = fread(&buf[0], 1, filesize, fp);
13146 assert(ret == filesize);
13147 fclose(fp);
13148 (void)ret;
13149 }
13150
13151 return LoadEXRMultipartImageFromMemory(exr_images, exr_headers, num_parts,
13152 &buf.at(0), filesize, err);
13153}
13154
13155int SaveEXR(const float *data, int width, int height, int components,
13156 const int save_as_fp16, const char *outfilename, const char **err) {
13157 if ((components == 1) || components == 3 || components == 4) {
13158 // OK
13159 } else {
13160 std::stringstream ss;
13161 ss << "Unsupported component value : " << components << std::endl;
13162
13163 tinyexr::SetErrorMessage(ss.str(), err);
13164 return TINYEXR_ERROR_INVALID_ARGUMENT;
13165 }
13166
13167 EXRHeader header;
13168 InitEXRHeader(&header);
13169
13170 if ((width < 16) && (height < 16)) {
13171 // No compression for small image.
13172 header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE;
13173 } else {
13174 header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP;
13175 }
13176
13177 EXRImage image;
13178 InitEXRImage(&image);
13179
13180 image.num_channels = components;
13181
13182 std::vector<float> images[4];
13183
13184 if (components == 1) {
13185 images[0].resize(static_cast<size_t>(width * height));
13186 memcpy(images[0].data(), data, sizeof(float) * size_t(width * height));
13187 } else {
13188 images[0].resize(static_cast<size_t>(width * height));
13189 images[1].resize(static_cast<size_t>(width * height));
13190 images[2].resize(static_cast<size_t>(width * height));
13191 images[3].resize(static_cast<size_t>(width * height));
13192
13193 // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers
13194 for (size_t i = 0; i < static_cast<size_t>(width * height); i++) {
13195 images[0][i] = data[static_cast<size_t>(components) * i + 0];
13196 images[1][i] = data[static_cast<size_t>(components) * i + 1];
13197 images[2][i] = data[static_cast<size_t>(components) * i + 2];
13198 if (components == 4) {
13199 images[3][i] = data[static_cast<size_t>(components) * i + 3];
13200 }
13201 }
13202 }
13203
13204 float *image_ptr[4] = {0, 0, 0, 0};
13205 if (components == 4) {
13206 image_ptr[0] = &(images[3].at(0)); // A
13207 image_ptr[1] = &(images[2].at(0)); // B
13208 image_ptr[2] = &(images[1].at(0)); // G
13209 image_ptr[3] = &(images[0].at(0)); // R
13210 } else if (components == 3) {
13211 image_ptr[0] = &(images[2].at(0)); // B
13212 image_ptr[1] = &(images[1].at(0)); // G
13213 image_ptr[2] = &(images[0].at(0)); // R
13214 } else if (components == 1) {
13215 image_ptr[0] = &(images[0].at(0)); // A
13216 }
13217
13218 image.images = reinterpret_cast<unsigned char **>(image_ptr);
13219 image.width = width;
13220 image.height = height;
13221
13222 header.num_channels = components;
13223 header.channels = static_cast<EXRChannelInfo *>(malloc(
13224 sizeof(EXRChannelInfo) * static_cast<size_t>(header.num_channels)));
13225 // Must be (A)BGR order, since most of EXR viewers expect this channel order.
13226 if (components == 4) {
13227#ifdef _MSC_VER
13228 strncpy_s(header.channels[0].name, "A", 255);
13229 strncpy_s(header.channels[1].name, "B", 255);
13230 strncpy_s(header.channels[2].name, "G", 255);
13231 strncpy_s(header.channels[3].name, "R", 255);
13232#else
13233 strncpy(header.channels[0].name, "A", 255);
13234 strncpy(header.channels[1].name, "B", 255);
13235 strncpy(header.channels[2].name, "G", 255);
13236 strncpy(header.channels[3].name, "R", 255);
13237#endif
13238 header.channels[0].name[strlen("A")] = '\0';
13239 header.channels[1].name[strlen("B")] = '\0';
13240 header.channels[2].name[strlen("G")] = '\0';
13241 header.channels[3].name[strlen("R")] = '\0';
13242 } else if (components == 3) {
13243#ifdef _MSC_VER
13244 strncpy_s(header.channels[0].name, "B", 255);
13245 strncpy_s(header.channels[1].name, "G", 255);
13246 strncpy_s(header.channels[2].name, "R", 255);
13247#else
13248 strncpy(header.channels[0].name, "B", 255);
13249 strncpy(header.channels[1].name, "G", 255);
13250 strncpy(header.channels[2].name, "R", 255);
13251#endif
13252 header.channels[0].name[strlen("B")] = '\0';
13253 header.channels[1].name[strlen("G")] = '\0';
13254 header.channels[2].name[strlen("R")] = '\0';
13255 } else {
13256#ifdef _MSC_VER
13257 strncpy_s(header.channels[0].name, "A", 255);
13258#else
13259 strncpy(header.channels[0].name, "A", 255);
13260#endif
13261 header.channels[0].name[strlen("A")] = '\0';
13262 }
13263
13264 header.pixel_types = static_cast<int *>(
13265 malloc(sizeof(int) * static_cast<size_t>(header.num_channels)));
13266 header.requested_pixel_types = static_cast<int *>(
13267 malloc(sizeof(int) * static_cast<size_t>(header.num_channels)));
13268 for (int i = 0; i < header.num_channels; i++) {
13269 header.pixel_types[i] =
13270 TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image
13271
13272 if (save_as_fp16 > 0) {
13273 header.requested_pixel_types[i] =
13274 TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format
13275 } else {
13276 header.requested_pixel_types[i] =
13277 TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e.
13278 // no precision reduction)
13279 }
13280 }
13281
13282 int ret = SaveEXRImageToFile(&image, &header, outfilename, err);
13283 if (ret != TINYEXR_SUCCESS) {
13284 return ret;
13285 }
13286
13287 free(header.channels);
13288 free(header.pixel_types);
13289 free(header.requested_pixel_types);
13290
13291 return ret;
13292}
13293
13294#ifdef __clang__
13295// zero-as-null-ppinter-constant
13296#pragma clang diagnostic pop
13297#endif
13298
13299#endif // TINYEXR_IMPLEMENTATION_DEIFNED
13300#endif // TINYEXR_IMPLEMENTATION
13301