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#ifndef TINYEXR_USE_THREAD 109#define TINYEXR_USE_THREAD (0) // No threaded loading. 110// http://computation.llnl.gov/projects/floating-point-compression 111#endif 112 113#ifndef TINYEXR_USE_OPENMP 114#ifdef _OPENMP 115#define TINYEXR_USE_OPENMP (1) 116#else 117#define TINYEXR_USE_OPENMP (0) 118#endif 119#endif 120 121#define TINYEXR_SUCCESS (0) 122#define TINYEXR_ERROR_INVALID_MAGIC_NUMBER (-1) 123#define TINYEXR_ERROR_INVALID_EXR_VERSION (-2) 124#define TINYEXR_ERROR_INVALID_ARGUMENT (-3) 125#define TINYEXR_ERROR_INVALID_DATA (-4) 126#define TINYEXR_ERROR_INVALID_FILE (-5) 127#define TINYEXR_ERROR_INVALID_PARAMETER (-6) 128#define TINYEXR_ERROR_CANT_OPEN_FILE (-7) 129#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-8) 130#define TINYEXR_ERROR_INVALID_HEADER (-9) 131#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-10) 132#define TINYEXR_ERROR_CANT_WRITE_FILE (-11) 133#define TINYEXR_ERROR_SERIALZATION_FAILED (-12) 134#define TINYEXR_ERROR_LAYER_NOT_FOUND (-13) 135 136// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf } 137 138// pixel type: possible values are: UINT = 0 HALF = 1 FLOAT = 2 139#define TINYEXR_PIXELTYPE_UINT (0) 140#define TINYEXR_PIXELTYPE_HALF (1) 141#define TINYEXR_PIXELTYPE_FLOAT (2) 142 143#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024) 144#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128) 145 146#define TINYEXR_COMPRESSIONTYPE_NONE (0) 147#define TINYEXR_COMPRESSIONTYPE_RLE (1) 148#define TINYEXR_COMPRESSIONTYPE_ZIPS (2) 149#define TINYEXR_COMPRESSIONTYPE_ZIP (3) 150#define TINYEXR_COMPRESSIONTYPE_PIZ (4) 151#define TINYEXR_COMPRESSIONTYPE_ZFP (128) // TinyEXR extension 152 153#define TINYEXR_ZFP_COMPRESSIONTYPE_RATE (0) 154#define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION (1) 155#define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY (2) 156 157#define TINYEXR_TILE_ONE_LEVEL (0) 158#define TINYEXR_TILE_MIPMAP_LEVELS (1) 159#define TINYEXR_TILE_RIPMAP_LEVELS (2) 160 161#define TINYEXR_TILE_ROUND_DOWN (0) 162#define TINYEXR_TILE_ROUND_UP (1) 163 164typedef struct _EXRVersion { 165 int version; // this must be 2 166 int tiled; // tile format image 167 int long_name; // long name attribute 168 int non_image; // deep image(EXR 2.0) 169 int multipart; // multi-part(EXR 2.0) 170} EXRVersion; 171 172typedef struct _EXRAttribute { 173 char name[256]; // name and type are up to 255 chars long. 174 char type[256]; 175 unsigned char *value; // uint8_t* 176 int size; 177 int pad0; 178} EXRAttribute; 179 180typedef struct _EXRChannelInfo { 181 char name[256]; // less than 255 bytes long 182 int pixel_type; 183 int x_sampling; 184 int y_sampling; 185 unsigned char p_linear; 186 unsigned char pad[3]; 187} EXRChannelInfo; 188 189typedef struct _EXRTile { 190 int offset_x; 191 int offset_y; 192 int level_x; 193 int level_y; 194 195 int width; // actual width in a tile. 196 int height; // actual height int a tile. 197 198 unsigned char **images; // image[channels][pixels] 199} EXRTile; 200 201typedef struct _EXRHeader { 202 float pixel_aspect_ratio; 203 int line_order; 204 int data_window[4]; 205 int display_window[4]; 206 float screen_window_center[2]; 207 float screen_window_width; 208 209 int chunk_count; 210 211 // Properties for tiled format(`tiledesc`). 212 int tiled; 213 int tile_size_x; 214 int tile_size_y; 215 int tile_level_mode; 216 int tile_rounding_mode; 217 218 int long_name; 219 int non_image; 220 int multipart; 221 unsigned int header_len; 222 223 // Custom attributes(exludes required attributes(e.g. `channels`, 224 // `compression`, etc) 225 int num_custom_attributes; 226 EXRAttribute *custom_attributes; // array of EXRAttribute. size = 227 // `num_custom_attributes`. 228 229 EXRChannelInfo *channels; // [num_channels] 230 231 int *pixel_types; // Loaded pixel type(TINYEXR_PIXELTYPE_*) of `images` for 232 // each channel. This is overwritten with `requested_pixel_types` when 233 // loading. 234 int num_channels; 235 236 int compression_type; // compression type(TINYEXR_COMPRESSIONTYPE_*) 237 int *requested_pixel_types; // Filled initially by 238 // ParseEXRHeaderFrom(Meomory|File), then users 239 // can edit it(only valid for HALF pixel type 240 // channel) 241 242} EXRHeader; 243 244typedef struct _EXRMultiPartHeader { 245 int num_headers; 246 EXRHeader *headers; 247 248} EXRMultiPartHeader; 249 250typedef struct _EXRImage { 251 EXRTile *tiles; // Tiled pixel data. The application must reconstruct image 252 // from tiles manually. NULL if scanline format. 253 unsigned char **images; // image[channels][pixels]. NULL if tiled format. 254 255 int width; 256 int height; 257 int num_channels; 258 259 // Properties for tile format. 260 int num_tiles; 261 262} EXRImage; 263 264typedef struct _EXRMultiPartImage { 265 int num_images; 266 EXRImage *images; 267 268} EXRMultiPartImage; 269 270typedef struct _DeepImage { 271 const char **channel_names; 272 float ***image; // image[channels][scanlines][samples] 273 int **offset_table; // offset_table[scanline][offsets] 274 int num_channels; 275 int width; 276 int height; 277 int pad0; 278} DeepImage; 279 280// @deprecated { For backward compatibility. Not recommended to use. } 281// Loads single-frame OpenEXR image. Assume EXR image contains A(single channel 282// alpha) or RGB(A) channels. 283// Application must free image data as returned by `out_rgba` 284// Result image format is: float x RGBA x width x hight 285// Returns negative value and may set error string in `err` when there's an 286// error 287extern int LoadEXR(float **out_rgba, int *width, int *height, 288 const char *filename, const char **err); 289 290// Loads single-frame OpenEXR image by specifing layer name. Assume EXR image contains A(single channel 291// alpha) or RGB(A) channels. 292// Application must free image data as returned by `out_rgba` 293// Result image format is: float x RGBA x width x hight 294// Returns negative value and may set error string in `err` when there's an 295// error 296// When the specified layer name is not found in the EXR file, the function will return `TINYEXR_ERROR_LAYER_NOT_FOUND`. 297extern int LoadEXRWithLayer(float **out_rgba, int *width, int *height, 298 const char *filename, const char *layer_name, const char **err); 299 300// 301// Get layer infos from EXR file. 302// 303// @param[out] layer_names List of layer names. Application must free memory after using this. 304// @param[out] num_layers The number of layers 305// @param[out] err Error string(wll be filled when the function returns error code). Free it using FreeEXRErrorMessage after using this value. 306// 307// @return TINYEXR_SUCCEES upon success. 308// 309extern int EXRLayers(const char *filename, const char **layer_names[], int *num_layers, const char **err); 310 311// @deprecated { to be removed. } 312// Simple wrapper API for ParseEXRHeaderFromFile. 313// checking given file is a EXR file(by just look up header) 314// @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for 315// others 316extern int IsEXR(const char *filename); 317 318// @deprecated { to be removed. } 319// Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels. 320// components must be 1(Grayscale), 3(RGB) or 4(RGBA). 321// Input image format is: `float x width x height`, or `float x RGB(A) x width x 322// hight` 323// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero 324// value. 325// Save image as fp32(FLOAT) format when `save_as_fp16` is 0. 326// Use ZIP compression by default. 327// Returns negative value and may set error string in `err` when there's an 328// error 329extern int SaveEXR(const float *data, const int width, const int height, 330 const int components, const int save_as_fp16, 331 const char *filename, const char **err); 332 333// Initialize EXRHeader struct 334extern void InitEXRHeader(EXRHeader *exr_header); 335 336// Initialize EXRImage struct 337extern void InitEXRImage(EXRImage *exr_image); 338 339// Free's internal data of EXRHeader struct 340extern int FreeEXRHeader(EXRHeader *exr_header); 341 342// Free's internal data of EXRImage struct 343extern int FreeEXRImage(EXRImage *exr_image); 344 345// Free's error message 346extern void FreeEXRErrorMessage(const char *msg); 347 348// Parse EXR version header of a file. 349extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename); 350 351// Parse EXR version header from memory-mapped EXR data. 352extern int ParseEXRVersionFromMemory(EXRVersion *version, 353 const unsigned char *memory, size_t size); 354 355// Parse single-part OpenEXR header from a file and initialize `EXRHeader`. 356// When there was an error message, Application must free `err` with 357// FreeEXRErrorMessage() 358extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version, 359 const char *filename, const char **err); 360 361// Parse single-part OpenEXR header from a memory and initialize `EXRHeader`. 362// When there was an error message, Application must free `err` with 363// FreeEXRErrorMessage() 364extern int ParseEXRHeaderFromMemory(EXRHeader *header, 365 const EXRVersion *version, 366 const unsigned char *memory, size_t size, 367 const char **err); 368 369// Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*` 370// array. 371// When there was an error message, Application must free `err` with 372// FreeEXRErrorMessage() 373extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers, 374 int *num_headers, 375 const EXRVersion *version, 376 const char *filename, 377 const char **err); 378 379// Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*` 380// array 381// When there was an error message, Application must free `err` with 382// FreeEXRErrorMessage() 383extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers, 384 int *num_headers, 385 const EXRVersion *version, 386 const unsigned char *memory, 387 size_t size, const char **err); 388 389// Loads single-part OpenEXR image from a file. 390// Application must setup `ParseEXRHeaderFromFile` before calling this function. 391// Application can free EXRImage using `FreeEXRImage` 392// Returns negative value and may set error string in `err` when there's an 393// error 394// When there was an error message, Application must free `err` with 395// FreeEXRErrorMessage() 396extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header, 397 const char *filename, const char **err); 398 399// Loads single-part OpenEXR image from a memory. 400// Application must setup `EXRHeader` with 401// `ParseEXRHeaderFromMemory` before calling this function. 402// Application can free EXRImage using `FreeEXRImage` 403// Returns negative value and may set error string in `err` when there's an 404// error 405// When there was an error message, Application must free `err` with 406// FreeEXRErrorMessage() 407extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header, 408 const unsigned char *memory, 409 const size_t size, const char **err); 410 411// Loads multi-part OpenEXR image from a file. 412// Application must setup `ParseEXRMultipartHeaderFromFile` before calling this 413// function. 414// Application can free EXRImage using `FreeEXRImage` 415// Returns negative value and may set error string in `err` when there's an 416// error 417// When there was an error message, Application must free `err` with 418// FreeEXRErrorMessage() 419extern int LoadEXRMultipartImageFromFile(EXRImage *images, 420 const EXRHeader **headers, 421 unsigned int num_parts, 422 const char *filename, 423 const char **err); 424 425// Loads multi-part OpenEXR image from a memory. 426// Application must setup `EXRHeader*` array with 427// `ParseEXRMultipartHeaderFromMemory` before calling this function. 428// Application can free EXRImage using `FreeEXRImage` 429// Returns negative value and may set error string in `err` when there's an 430// error 431// When there was an error message, Application must free `err` with 432// FreeEXRErrorMessage() 433extern int LoadEXRMultipartImageFromMemory(EXRImage *images, 434 const EXRHeader **headers, 435 unsigned int num_parts, 436 const unsigned char *memory, 437 const size_t size, const char **err); 438 439// Saves multi-channel, single-frame OpenEXR image to a file. 440// Returns negative value and may set error string in `err` when there's an 441// error 442// When there was an error message, Application must free `err` with 443// FreeEXRErrorMessage() 444extern int SaveEXRImageToFile(const EXRImage *image, 445 const EXRHeader *exr_header, const char *filename, 446 const char **err); 447 448// Saves multi-channel, single-frame OpenEXR image to a memory. 449// Image is compressed using EXRImage.compression value. 450// Return the number of bytes if success. 451// Return zero and will set error string in `err` when there's an 452// error. 453// When there was an error message, Application must free `err` with 454// FreeEXRErrorMessage() 455extern size_t SaveEXRImageToMemory(const EXRImage *image, 456 const EXRHeader *exr_header, 457 unsigned char **memory, const char **err); 458 459// Loads single-frame OpenEXR deep image. 460// Application must free memory of variables in DeepImage(image, offset_table) 461// Returns negative value and may set error string in `err` when there's an 462// error 463// When there was an error message, Application must free `err` with 464// FreeEXRErrorMessage() 465extern int LoadDeepEXR(DeepImage *out_image, const char *filename, 466 const char **err); 467 468// NOT YET IMPLEMENTED: 469// Saves single-frame OpenEXR deep image. 470// Returns negative value and may set error string in `err` when there's an 471// error 472// extern int SaveDeepEXR(const DeepImage *in_image, const char *filename, 473// const char **err); 474 475// NOT YET IMPLEMENTED: 476// Loads multi-part OpenEXR deep image. 477// Application must free memory of variables in DeepImage(image, offset_table) 478// extern int LoadMultiPartDeepEXR(DeepImage **out_image, int num_parts, const 479// char *filename, 480// const char **err); 481 482// For emscripten. 483// Loads single-frame OpenEXR image from memory. Assume EXR image contains 484// RGB(A) channels. 485// Returns negative value and may set error string in `err` when there's an 486// error 487// When there was an error message, Application must free `err` with 488// FreeEXRErrorMessage() 489extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height, 490 const unsigned char *memory, size_t size, 491 const char **err); 492 493#ifdef __cplusplus 494} 495#endif 496 497#endif // TINYEXR_H_ 498 499#ifdef TINYEXR_IMPLEMENTATION 500#ifndef TINYEXR_IMPLEMENTATION_DEIFNED 501#define TINYEXR_IMPLEMENTATION_DEIFNED 502 503#include <algorithm> 504#include <cstdio> 505#include <cstdlib> 506#include <cstring> 507#include <sstream> 508 509// #include <iostream> // debug 510 511#include <limits> 512#include <string> 513#include <vector> 514 515#if __cplusplus > 199711L 516// C++11 517#include <cstdint> 518 519#if TINYEXR_USE_THREAD 520#include <atomic> 521#include <thread> 522#endif 523 524#endif // __cplusplus > 199711L 525 526#if TINYEXR_USE_OPENMP 527#include <omp.h> 528#endif 529 530#if TINYEXR_USE_MINIZ 531#else 532// Issue #46. Please include your own zlib-compatible API header before 533// including `tinyexr.h` 534//#include "zlib.h" 535#endif 536 537#if TINYEXR_USE_ZFP 538#include "zfp.h" 539#endif 540 541namespace tinyexr { 542 543#if __cplusplus > 199711L 544// C++11 545typedef uint64_t tinyexr_uint64; 546typedef int64_t tinyexr_int64; 547#else 548// Although `long long` is not a standard type pre C++11, assume it is defined 549// as a compiler's extension. 550#ifdef __clang__ 551#pragma clang diagnostic push 552#pragma clang diagnostic ignored "-Wc++11-long-long" 553#endif 554typedef unsigned long long tinyexr_uint64; 555typedef long long tinyexr_int64; 556#ifdef __clang__ 557#pragma clang diagnostic pop 558#endif 559#endif 560 561#if TINYEXR_USE_MINIZ 562 563namespace miniz { 564 565#ifdef __clang__ 566#pragma clang diagnostic push 567#pragma clang diagnostic ignored "-Wc++11-long-long" 568#pragma clang diagnostic ignored "-Wold-style-cast" 569#pragma clang diagnostic ignored "-Wpadded" 570#pragma clang diagnostic ignored "-Wsign-conversion" 571#pragma clang diagnostic ignored "-Wc++11-extensions" 572#pragma clang diagnostic ignored "-Wconversion" 573#pragma clang diagnostic ignored "-Wunused-function" 574#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" 575#pragma clang diagnostic ignored "-Wundef" 576 577#if __has_warning("-Wcomma") 578#pragma clang diagnostic ignored "-Wcomma" 579#endif 580 581#if __has_warning("-Wmacro-redefined") 582#pragma clang diagnostic ignored "-Wmacro-redefined" 583#endif 584 585#if __has_warning("-Wcast-qual") 586#pragma clang diagnostic ignored "-Wcast-qual" 587#endif 588 589#if __has_warning("-Wzero-as-null-pointer-constant") 590#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" 591#endif 592 593#if __has_warning("-Wtautological-constant-compare") 594#pragma clang diagnostic ignored "-Wtautological-constant-compare" 595#endif 596 597#if __has_warning("-Wextra-semi-stmt") 598#pragma clang diagnostic ignored "-Wextra-semi-stmt" 599#endif 600 601#endif 602 603/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP 604 reading/writing/appending, PNG writing 605 See "unlicense" statement at the end of this file. 606 Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013 607 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: 608 http://www.ietf.org/rfc/rfc1951.txt 609 610 Most API's defined in miniz.c are optional. For example, to disable the 611 archive related functions just define 612 MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO 613 (see the list below for more macros). 614 615 * Change History 616 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major 617 release with Zip64 support (almost there!): 618 - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug 619 (thanks kahmyong.moon@hp.com) which could cause locate files to not find 620 files. This bug 621 would only have occured in earlier versions if you explicitly used this 622 flag, OR if you used mz_zip_extract_archive_file_to_heap() or 623 mz_zip_add_mem_to_archive_file_in_place() 624 (which used this flag). If you can't switch to v1.15 but want to fix 625 this bug, just remove the uses of this flag from both helper funcs (and of 626 course don't use the flag). 627 - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when 628 pUser_read_buf is not NULL and compressed size is > uncompressed size 629 - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract 630 compressed data from directory entries, to account for weird zipfiles which 631 contain zero-size compressed data on dir entries. 632 Hopefully this fix won't cause any issues on weird zip archives, 633 because it assumes the low 16-bits of zip external attributes are DOS 634 attributes (which I believe they always are in practice). 635 - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the 636 internal attributes, just the filename and external attributes 637 - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed 638 - Added cmake support for Linux builds which builds all the examples, 639 tested with clang v3.3 and gcc v4.6. 640 - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti 641 - Merged MZ_FORCEINLINE fix from hdeanclark 642 - Fix <time.h> include before config #ifdef, thanks emil.brink 643 - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping 644 (super useful for OpenGL apps), and explicit control over the compression 645 level (so you can 646 set it to 1 for real-time compression). 647 - Merged in some compiler fixes from paulharris's github repro. 648 - Retested this build under Windows (VS 2010, including static analysis), 649 tcc 0.9.26, gcc v4.6 and clang v3.3. 650 - Added example6.c, which dumps an image of the mandelbrot set to a PNG 651 file. 652 - Modified example2 to help test the 653 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. 654 - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix 655 possible src file fclose() leak if alignment bytes+local header file write 656 faiiled 657 - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): 658 Was pushing the wrong central dir header offset, appears harmless in this 659 release, but it became a problem in the zip64 branch 660 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, 661 #include <time.h> (thanks fermtect). 662 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix 663 mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. 664 - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and 665 re-ran a randomized regression test on ~500k files. 666 - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. 667 - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze 668 (static analysis) option and fixed all warnings (except for the silly 669 "Use of the comma-operator in a tested expression.." analysis warning, 670 which I purposely use to work around a MSVC compiler warning). 671 - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and 672 tested Linux executables. The codeblocks workspace is compatible with 673 Linux+Win32/x64. 674 - Added miniz_tester solution/project, which is a useful little app 675 derived from LZHAM's tester app that I use as part of the regression test. 676 - Ran miniz.c and tinfl.c through another series of regression testing on 677 ~500,000 files and archives. 678 - Modified example5.c so it purposely disables a bunch of high-level 679 functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the 680 MINIZ_NO_STDIO bug report.) 681 - Fix ftell() usage in examples so they exit with an error on files which 682 are too large (a limitation of the examples, not miniz itself). 683 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple 684 minor level_and_flags issues in the archive API's. 685 level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce 686 Dawson <bruced@valvesoftware.com> for the feedback/bug report. 687 5/28/11 v1.11 - Added statement from unlicense.org 688 5/27/11 v1.10 - Substantial compressor optimizations: 689 - Level 1 is now ~4x faster than before. The L1 compressor's throughput 690 now varies between 70-110MB/sec. on a 691 - Core i7 (actual throughput varies depending on the type of data, and x64 692 vs. x86). 693 - Improved baseline L2-L9 compression perf. Also, greatly improved 694 compression perf. issues on some file types. 695 - Refactored the compression code for better readability and 696 maintainability. 697 - Added level 10 compression level (L10 has slightly better ratio than 698 level 9, but could have a potentially large 699 drop in throughput on some files). 700 5/15/11 v1.09 - Initial stable release. 701 702 * Low-level Deflate/Inflate implementation notes: 703 704 Compression: Use the "tdefl" API's. The compressor supports raw, static, 705 and dynamic blocks, lazy or 706 greedy parsing, match length filtering, RLE-only, and Huffman-only streams. 707 It performs and compresses 708 approximately as well as zlib. 709 710 Decompression: Use the "tinfl" API's. The entire decompressor is 711 implemented as a single function 712 coroutine: see tinfl_decompress(). It supports decompression into a 32KB 713 (or larger power of 2) wrapping buffer, or into a memory 714 block large enough to hold the entire file. 715 716 The low-level tdefl/tinfl API's do not make any use of dynamic memory 717 allocation. 718 719 * zlib-style API notes: 720 721 miniz.c implements a fairly large subset of zlib. There's enough 722 functionality present for it to be a drop-in 723 zlib replacement in many apps: 724 The z_stream struct, optional memory allocation callbacks 725 deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound 726 inflateInit/inflateInit2/inflate/inflateEnd 727 compress, compress2, compressBound, uncompress 728 CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly 729 routines. 730 Supports raw deflate streams or standard zlib streams with adler-32 731 checking. 732 733 Limitations: 734 The callback API's are not implemented yet. No support for gzip headers or 735 zlib static dictionaries. 736 I've tried to closely emulate zlib's various flavors of stream flushing 737 and return status codes, but 738 there are no guarantees that miniz.c pulls this off perfectly. 739 740 * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, 741 originally written by 742 Alex Evans. Supports 1-4 bytes/pixel images. 743 744 * ZIP archive API notes: 745 746 The ZIP archive API's where designed with simplicity and efficiency in 747 mind, with just enough abstraction to 748 get the job done with minimal fuss. There are simple API's to retrieve file 749 information, read files from 750 existing archives, create new archives, append new files to existing 751 archives, or clone archive data from 752 one archive to another. It supports archives located in memory or the heap, 753 on disk (using stdio.h), 754 or you can specify custom file read/write callbacks. 755 756 - Archive reading: Just call this function to read a single file from a 757 disk archive: 758 759 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const 760 char *pArchive_name, 761 size_t *pSize, mz_uint zip_flags); 762 763 For more complex cases, use the "mz_zip_reader" functions. Upon opening an 764 archive, the entire central 765 directory is located and read as-is into memory, and subsequent file access 766 only occurs when reading individual files. 767 768 - Archives file scanning: The simple way is to use this function to scan a 769 loaded archive for a specific file: 770 771 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, 772 const char *pComment, mz_uint flags); 773 774 The locate operation can optionally check file comments too, which (as one 775 example) can be used to identify 776 multiple versions of the same file in an archive. This function uses a 777 simple linear search through the central 778 directory, so it's not very fast. 779 780 Alternately, you can iterate through all the files in an archive (using 781 mz_zip_reader_get_num_files()) and 782 retrieve detailed info on each file by calling mz_zip_reader_file_stat(). 783 784 - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer 785 immediately writes compressed file data 786 to disk and builds an exact image of the central directory in memory. The 787 central directory image is written 788 all at once at the end of the archive file when the archive is finalized. 789 790 The archive writer can optionally align each file's local header and file 791 data to any power of 2 alignment, 792 which can be useful when the archive will be read from optical media. Also, 793 the writer supports placing 794 arbitrary data blobs at the very beginning of ZIP archives. Archives 795 written using either feature are still 796 readable by any ZIP tool. 797 798 - Archive appending: The simple way to add a single file to an archive is 799 to call this function: 800 801 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, 802 const char *pArchive_name, 803 const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 804 comment_size, mz_uint level_and_flags); 805 806 The archive will be created if it doesn't already exist, otherwise it'll be 807 appended to. 808 Note the appending is done in-place and is not an atomic operation, so if 809 something goes wrong 810 during the operation it's possible the archive could be left without a 811 central directory (although the local 812 file headers and file data will be fine, so the archive will be 813 recoverable). 814 815 For more complex archive modification scenarios: 816 1. The safest way is to use a mz_zip_reader to read the existing archive, 817 cloning only those bits you want to 818 preserve into a new archive using using the 819 mz_zip_writer_add_from_zip_reader() function (which compiles the 820 compressed file data as-is). When you're done, delete the old archive and 821 rename the newly written archive, and 822 you're done. This is safe but requires a bunch of temporary disk space or 823 heap memory. 824 825 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using 826 mz_zip_writer_init_from_reader(), 827 append new files as needed, then finalize the archive which will write an 828 updated central directory to the 829 original archive. (This is basically what 830 mz_zip_add_mem_to_archive_file_in_place() does.) There's a 831 possibility that the archive's central directory could be lost with this 832 method if anything goes wrong, though. 833 834 - ZIP archive support limitations: 835 No zip64 or spanning support. Extraction functions can only handle 836 unencrypted, stored or deflated files. 837 Requires streams capable of seeking. 838 839 * This is a header file library, like stb_image.c. To get only a header file, 840 either cut and paste the 841 below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then 842 include miniz.c from it. 843 844 * Important: For best perf. be sure to customize the below macros for your 845 target platform: 846 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 847 #define MINIZ_LITTLE_ENDIAN 1 848 #define MINIZ_HAS_64BIT_REGISTERS 1 849 850 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before 851 including miniz.c to ensure miniz 852 uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be 853 able to process large files 854 (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). 855*/ 856 857#ifndef MINIZ_HEADER_INCLUDED 858#define MINIZ_HEADER_INCLUDED 859 860//#include <stdlib.h> 861 862// Defines to completely disable specific portions of miniz.c: 863// If all macros here are defined the only functionality remaining will be 864// CRC-32, adler-32, tinfl, and tdefl. 865 866// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on 867// stdio for file I/O. 868//#define MINIZ_NO_STDIO 869 870// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able 871// to get the current time, or 872// get/set file times, and the C run-time funcs that get/set times won't be 873// called. 874// The current downside is the times written to your archives will be from 1979. 875#define MINIZ_NO_TIME 876 877// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. 878#define MINIZ_NO_ARCHIVE_APIS 879 880// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive 881// API's. 882//#define MINIZ_NO_ARCHIVE_WRITING_APIS 883 884// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression 885// API's. 886//#define MINIZ_NO_ZLIB_APIS 887 888// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent 889// conflicts against stock zlib. 890//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES 891 892// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. 893// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom 894// user alloc/free/realloc 895// callbacks to the zlib and archive API's, and a few stand-alone helper API's 896// which don't provide custom user 897// functions (such as tdefl_compress_mem_to_heap() and 898// tinfl_decompress_mem_to_heap()) won't work. 899//#define MINIZ_NO_MALLOC 900 901#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) 902// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc 903// on Linux 904#define MINIZ_NO_TIME 905#endif 906 907#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) 908//#include <time.h> 909#endif 910 911#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \ 912 defined(__i386) || defined(__i486__) || defined(__i486) || \ 913 defined(i386) || defined(__ia64__) || defined(__x86_64__) 914// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. 915#define MINIZ_X86_OR_X64_CPU 1 916#endif 917 918#if defined(__sparcv9) 919// Big endian 920#else 921#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU 922// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. 923#define MINIZ_LITTLE_ENDIAN 1 924#endif 925#endif 926 927#if MINIZ_X86_OR_X64_CPU 928// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient 929// integer loads and stores from unaligned addresses. 930//#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 931#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES \ 932 0 // disable to suppress compiler warnings 933#endif 934 935#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \ 936 defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \ 937 defined(__x86_64__) 938// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are 939// reasonably fast (and don't involve compiler generated calls to helper 940// functions). 941#define MINIZ_HAS_64BIT_REGISTERS 1 942#endif 943 944#ifdef __cplusplus 945extern "C" { 946#endif 947 948// ------------------- zlib-style API Definitions. 949 950// For more compatibility with zlib, miniz.c uses unsigned long for some 951// parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! 952typedef unsigned long mz_ulong; 953 954// mz_free() internally uses the MZ_FREE() macro (which by default calls free() 955// unless you've modified the MZ_MALLOC macro) to release a block allocated from 956// the heap. 957void mz_free(void *p); 958 959#define MZ_ADLER32_INIT (1) 960// mz_adler32() returns the initial adler-32 value to use when called with 961// ptr==NULL. 962mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); 963 964#define MZ_CRC32_INIT (0) 965// mz_crc32() returns the initial CRC-32 value to use when called with 966// ptr==NULL. 967mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); 968 969// Compression strategies. 970enum { 971 MZ_DEFAULT_STRATEGY = 0, 972 MZ_FILTERED = 1, 973 MZ_HUFFMAN_ONLY = 2, 974 MZ_RLE = 3, 975 MZ_FIXED = 4 976}; 977 978// Method 979#define MZ_DEFLATED 8 980 981#ifndef MINIZ_NO_ZLIB_APIS 982 983// Heap allocation callbacks. 984// Note that mz_alloc_func parameter types purpsosely differ from zlib's: 985// items/size is size_t, not unsigned long. 986typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); 987typedef void (*mz_free_func)(void *opaque, void *address); 988typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, 989 size_t size); 990 991#define MZ_VERSION "9.1.15" 992#define MZ_VERNUM 0x91F0 993#define MZ_VER_MAJOR 9 994#define MZ_VER_MINOR 1 995#define MZ_VER_REVISION 15 996#define MZ_VER_SUBREVISION 0 997 998// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The 999// other values are for advanced use (refer to the zlib docs). 1000enum { 1001 MZ_NO_FLUSH = 0, 1002 MZ_PARTIAL_FLUSH = 1, 1003 MZ_SYNC_FLUSH = 2, 1004 MZ_FULL_FLUSH = 3, 1005 MZ_FINISH = 4, 1006 MZ_BLOCK = 5 1007}; 1008 1009// Return status codes. MZ_PARAM_ERROR is non-standard. 1010enum { 1011 MZ_OK = 0, 1012 MZ_STREAM_END = 1, 1013 MZ_NEED_DICT = 2, 1014 MZ_ERRNO = -1, 1015 MZ_STREAM_ERROR = -2, 1016 MZ_DATA_ERROR = -3, 1017 MZ_MEM_ERROR = -4, 1018 MZ_BUF_ERROR = -5, 1019 MZ_VERSION_ERROR = -6, 1020 MZ_PARAM_ERROR = -10000 1021}; 1022 1023// Compression levels: 0-9 are the standard zlib-style levels, 10 is best 1024// possible compression (not zlib compatible, and may be very slow), 1025// MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. 1026enum { 1027 MZ_NO_COMPRESSION = 0, 1028 MZ_BEST_SPEED = 1, 1029 MZ_BEST_COMPRESSION = 9, 1030 MZ_UBER_COMPRESSION = 10, 1031 MZ_DEFAULT_LEVEL = 6, 1032 MZ_DEFAULT_COMPRESSION = -1 1033}; 1034 1035// Window bits 1036#define MZ_DEFAULT_WINDOW_BITS 15 1037 1038struct mz_internal_state; 1039 1040// Compression/decompression stream struct. 1041typedef struct mz_stream_s { 1042 const unsigned char *next_in; // pointer to next byte to read 1043 unsigned int avail_in; // number of bytes available at next_in 1044 mz_ulong total_in; // total number of bytes consumed so far 1045 1046 unsigned char *next_out; // pointer to next byte to write 1047 unsigned int avail_out; // number of bytes that can be written to next_out 1048 mz_ulong total_out; // total number of bytes produced so far 1049 1050 char *msg; // error msg (unused) 1051 struct mz_internal_state *state; // internal state, allocated by zalloc/zfree 1052 1053 mz_alloc_func 1054 zalloc; // optional heap allocation function (defaults to malloc) 1055 mz_free_func zfree; // optional heap free function (defaults to free) 1056 void *opaque; // heap alloc function user pointer 1057 1058 int data_type; // data_type (unused) 1059 mz_ulong adler; // adler32 of the source or uncompressed data 1060 mz_ulong reserved; // not used 1061} mz_stream; 1062 1063typedef mz_stream *mz_streamp; 1064 1065// Returns the version string of miniz.c. 1066const char *mz_version(void); 1067 1068// mz_deflateInit() initializes a compressor with default options: 1069// Parameters: 1070// pStream must point to an initialized mz_stream struct. 1071// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. 1072// level 1 enables a specially optimized compression function that's been 1073// optimized purely for performance, not ratio. 1074// (This special func. is currently only enabled when 1075// MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) 1076// Return values: 1077// MZ_OK on success. 1078// MZ_STREAM_ERROR if the stream is bogus. 1079// MZ_PARAM_ERROR if the input parameters are bogus. 1080// MZ_MEM_ERROR on out of memory. 1081int mz_deflateInit(mz_streamp pStream, int level); 1082 1083// mz_deflateInit2() is like mz_deflate(), except with more control: 1084// Additional parameters: 1085// method must be MZ_DEFLATED 1086// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with 1087// zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no 1088// header or footer) 1089// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) 1090int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, 1091 int mem_level, int strategy); 1092 1093// Quickly resets a compressor without having to reallocate anything. Same as 1094// calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). 1095int mz_deflateReset(mz_streamp pStream); 1096 1097// mz_deflate() compresses the input to output, consuming as much of the input 1098// and producing as much output as possible. 1099// Parameters: 1100// pStream is the stream to read from and write to. You must initialize/update 1101// the next_in, avail_in, next_out, and avail_out members. 1102// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or 1103// MZ_FINISH. 1104// Return values: 1105// MZ_OK on success (when flushing, or if more input is needed but not 1106// available, and/or there's more output to be written but the output buffer 1107// is full). 1108// MZ_STREAM_END if all input has been consumed and all output bytes have been 1109// written. Don't call mz_deflate() on the stream anymore. 1110// MZ_STREAM_ERROR if the stream is bogus. 1111// MZ_PARAM_ERROR if one of the parameters is invalid. 1112// MZ_BUF_ERROR if no forward progress is possible because the input and/or 1113// output buffers are empty. (Fill up the input buffer or free up some output 1114// space and try again.) 1115int mz_deflate(mz_streamp pStream, int flush); 1116 1117// mz_deflateEnd() deinitializes a compressor: 1118// Return values: 1119// MZ_OK on success. 1120// MZ_STREAM_ERROR if the stream is bogus. 1121int mz_deflateEnd(mz_streamp pStream); 1122 1123// mz_deflateBound() returns a (very) conservative upper bound on the amount of 1124// data that could be generated by deflate(), assuming flush is set to only 1125// MZ_NO_FLUSH or MZ_FINISH. 1126mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); 1127 1128// Single-call compression functions mz_compress() and mz_compress2(): 1129// Returns MZ_OK on success, or one of the error codes from mz_deflate() on 1130// failure. 1131int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, 1132 const unsigned char *pSource, mz_ulong source_len); 1133int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, 1134 const unsigned char *pSource, mz_ulong source_len, int level); 1135 1136// mz_compressBound() returns a (very) conservative upper bound on the amount of 1137// data that could be generated by calling mz_compress(). 1138mz_ulong mz_compressBound(mz_ulong source_len); 1139 1140// Initializes a decompressor. 1141int mz_inflateInit(mz_streamp pStream); 1142 1143// mz_inflateInit2() is like mz_inflateInit() with an additional option that 1144// controls the window size and whether or not the stream has been wrapped with 1145// a zlib header/footer: 1146// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or 1147// -MZ_DEFAULT_WINDOW_BITS (raw deflate). 1148int mz_inflateInit2(mz_streamp pStream, int window_bits); 1149 1150// Decompresses the input stream to the output, consuming only as much of the 1151// input as needed, and writing as much to the output as possible. 1152// Parameters: 1153// pStream is the stream to read from and write to. You must initialize/update 1154// the next_in, avail_in, next_out, and avail_out members. 1155// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. 1156// On the first call, if flush is MZ_FINISH it's assumed the input and output 1157// buffers are both sized large enough to decompress the entire stream in a 1158// single call (this is slightly faster). 1159// MZ_FINISH implies that there are no more source bytes available beside 1160// what's already in the input buffer, and that the output buffer is large 1161// enough to hold the rest of the decompressed data. 1162// Return values: 1163// MZ_OK on success. Either more input is needed but not available, and/or 1164// there's more output to be written but the output buffer is full. 1165// MZ_STREAM_END if all needed input has been consumed and all output bytes 1166// have been written. For zlib streams, the adler-32 of the decompressed data 1167// has also been verified. 1168// MZ_STREAM_ERROR if the stream is bogus. 1169// MZ_DATA_ERROR if the deflate stream is invalid. 1170// MZ_PARAM_ERROR if one of the parameters is invalid. 1171// MZ_BUF_ERROR if no forward progress is possible because the input buffer is 1172// empty but the inflater needs more input to continue, or if the output 1173// buffer is not large enough. Call mz_inflate() again 1174// with more input data, or with more room in the output buffer (except when 1175// using single call decompression, described above). 1176int mz_inflate(mz_streamp pStream, int flush); 1177 1178// Deinitializes a decompressor. 1179int mz_inflateEnd(mz_streamp pStream); 1180 1181// Single-call decompression. 1182// Returns MZ_OK on success, or one of the error codes from mz_inflate() on 1183// failure. 1184int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, 1185 const unsigned char *pSource, mz_ulong source_len); 1186 1187// Returns a string description of the specified error code, or NULL if the 1188// error code is invalid. 1189const char *mz_error(int err); 1190 1191// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used 1192// as a drop-in replacement for the subset of zlib that miniz.c supports. 1193// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you 1194// use zlib in the same project. 1195#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES 1196typedef unsigned char Byte; 1197typedef unsigned int uInt; 1198typedef mz_ulong uLong; 1199typedef Byte Bytef; 1200typedef uInt uIntf; 1201typedef char charf; 1202typedef int intf; 1203typedef void *voidpf; 1204typedef uLong uLongf; 1205typedef void *voidp; 1206typedef void *const voidpc; 1207#define Z_NULL 0 1208#define Z_NO_FLUSH MZ_NO_FLUSH 1209#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH 1210#define Z_SYNC_FLUSH MZ_SYNC_FLUSH 1211#define Z_FULL_FLUSH MZ_FULL_FLUSH 1212#define Z_FINISH MZ_FINISH 1213#define Z_BLOCK MZ_BLOCK 1214#define Z_OK MZ_OK 1215#define Z_STREAM_END MZ_STREAM_END 1216#define Z_NEED_DICT MZ_NEED_DICT 1217#define Z_ERRNO MZ_ERRNO 1218#define Z_STREAM_ERROR MZ_STREAM_ERROR 1219#define Z_DATA_ERROR MZ_DATA_ERROR 1220#define Z_MEM_ERROR MZ_MEM_ERROR 1221#define Z_BUF_ERROR MZ_BUF_ERROR 1222#define Z_VERSION_ERROR MZ_VERSION_ERROR 1223#define Z_PARAM_ERROR MZ_PARAM_ERROR 1224#define Z_NO_COMPRESSION MZ_NO_COMPRESSION 1225#define Z_BEST_SPEED MZ_BEST_SPEED 1226#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION 1227#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION 1228#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY 1229#define Z_FILTERED MZ_FILTERED 1230#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY 1231#define Z_RLE MZ_RLE 1232#define Z_FIXED MZ_FIXED 1233#define Z_DEFLATED MZ_DEFLATED 1234#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS 1235#define alloc_func mz_alloc_func 1236#define free_func mz_free_func 1237#define internal_state mz_internal_state 1238#define z_stream mz_stream 1239#define deflateInit mz_deflateInit 1240#define deflateInit2 mz_deflateInit2 1241#define deflateReset mz_deflateReset 1242#define deflate mz_deflate 1243#define deflateEnd mz_deflateEnd 1244#define deflateBound mz_deflateBound 1245#define compress mz_compress 1246#define compress2 mz_compress2 1247#define compressBound mz_compressBound 1248#define inflateInit mz_inflateInit 1249#define inflateInit2 mz_inflateInit2 1250#define inflate mz_inflate 1251#define inflateEnd mz_inflateEnd 1252#define uncompress mz_uncompress 1253#define crc32 mz_crc32 1254#define adler32 mz_adler32 1255#define MAX_WBITS 15 1256#define MAX_MEM_LEVEL 9 1257#define zError mz_error 1258#define ZLIB_VERSION MZ_VERSION 1259#define ZLIB_VERNUM MZ_VERNUM 1260#define ZLIB_VER_MAJOR MZ_VER_MAJOR 1261#define ZLIB_VER_MINOR MZ_VER_MINOR 1262#define ZLIB_VER_REVISION MZ_VER_REVISION 1263#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION 1264#define zlibVersion mz_version 1265#define zlib_version mz_version() 1266#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES 1267 1268#endif // MINIZ_NO_ZLIB_APIS 1269 1270// ------------------- Types and macros 1271 1272typedef unsigned char mz_uint8; 1273typedef signed short mz_int16; 1274typedef unsigned short mz_uint16; 1275typedef unsigned int mz_uint32; 1276typedef unsigned int mz_uint; 1277typedef long long mz_int64; 1278typedef unsigned long long mz_uint64; 1279typedef int mz_bool; 1280 1281#define MZ_FALSE (0) 1282#define MZ_TRUE (1) 1283 1284// An attempt to work around MSVC's spammy "warning C4127: conditional 1285// expression is constant" message. 1286#ifdef _MSC_VER 1287#define MZ_MACRO_END while (0, 0) 1288#else 1289#define MZ_MACRO_END while (0) 1290#endif 1291 1292// ------------------- ZIP archive reading/writing 1293 1294#ifndef MINIZ_NO_ARCHIVE_APIS 1295 1296enum { 1297 MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, 1298 MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, 1299 MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 1300}; 1301 1302typedef struct { 1303 mz_uint32 m_file_index; 1304 mz_uint32 m_central_dir_ofs; 1305 mz_uint16 m_version_made_by; 1306 mz_uint16 m_version_needed; 1307 mz_uint16 m_bit_flag; 1308 mz_uint16 m_method; 1309#ifndef MINIZ_NO_TIME 1310 time_t m_time; 1311#endif 1312 mz_uint32 m_crc32; 1313 mz_uint64 m_comp_size; 1314 mz_uint64 m_uncomp_size; 1315 mz_uint16 m_internal_attr; 1316 mz_uint32 m_external_attr; 1317 mz_uint64 m_local_header_ofs; 1318 mz_uint32 m_comment_size; 1319 char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; 1320 char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; 1321} mz_zip_archive_file_stat; 1322 1323typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, 1324 void *pBuf, size_t n); 1325typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, 1326 const void *pBuf, size_t n); 1327 1328struct mz_zip_internal_state_tag; 1329typedef struct mz_zip_internal_state_tag mz_zip_internal_state; 1330 1331typedef enum { 1332 MZ_ZIP_MODE_INVALID = 0, 1333 MZ_ZIP_MODE_READING = 1, 1334 MZ_ZIP_MODE_WRITING = 2, 1335 MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 1336} mz_zip_mode; 1337 1338typedef struct mz_zip_archive_tag { 1339 mz_uint64 m_archive_size; 1340 mz_uint64 m_central_directory_file_ofs; 1341 mz_uint m_total_files; 1342 mz_zip_mode m_zip_mode; 1343 1344 mz_uint m_file_offset_alignment; 1345 1346 mz_alloc_func m_pAlloc; 1347 mz_free_func m_pFree; 1348 mz_realloc_func m_pRealloc; 1349 void *m_pAlloc_opaque; 1350 1351 mz_file_read_func m_pRead; 1352 mz_file_write_func m_pWrite; 1353 void *m_pIO_opaque; 1354 1355 mz_zip_internal_state *m_pState; 1356 1357} mz_zip_archive; 1358 1359typedef enum { 1360 MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, 1361 MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, 1362 MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, 1363 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 1364} mz_zip_flags; 1365 1366// ZIP archive reading 1367 1368// Inits a ZIP archive reader. 1369// These functions read and validate the archive's central directory. 1370mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, 1371 mz_uint32 flags); 1372mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, 1373 size_t size, mz_uint32 flags); 1374 1375#ifndef MINIZ_NO_STDIO 1376mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, 1377 mz_uint32 flags); 1378#endif 1379 1380// Returns the total number of files in the archive. 1381mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); 1382 1383// Returns detailed information about an archive file entry. 1384mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, 1385 mz_zip_archive_file_stat *pStat); 1386 1387// Determines if an archive file entry is a directory entry. 1388mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, 1389 mz_uint file_index); 1390mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, 1391 mz_uint file_index); 1392 1393// Retrieves the filename of an archive file entry. 1394// Returns the number of bytes written to pFilename, or if filename_buf_size is 1395// 0 this function returns the number of bytes needed to fully store the 1396// filename. 1397mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, 1398 char *pFilename, mz_uint filename_buf_size); 1399 1400// Attempts to locates a file in the archive's central directory. 1401// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH 1402// Returns -1 if the file cannot be found. 1403int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, 1404 const char *pComment, mz_uint flags); 1405 1406// Extracts a archive file to a memory buffer using no memory allocation. 1407mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, 1408 mz_uint file_index, void *pBuf, 1409 size_t buf_size, mz_uint flags, 1410 void *pUser_read_buf, 1411 size_t user_read_buf_size); 1412mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( 1413 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, 1414 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); 1415 1416// Extracts a archive file to a memory buffer. 1417mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, 1418 void *pBuf, size_t buf_size, 1419 mz_uint flags); 1420mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, 1421 const char *pFilename, void *pBuf, 1422 size_t buf_size, mz_uint flags); 1423 1424// Extracts a archive file to a dynamically allocated heap buffer. 1425void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, 1426 size_t *pSize, mz_uint flags); 1427void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, 1428 const char *pFilename, size_t *pSize, 1429 mz_uint flags); 1430 1431// Extracts a archive file using a callback function to output the file's data. 1432mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, 1433 mz_uint file_index, 1434 mz_file_write_func pCallback, 1435 void *pOpaque, mz_uint flags); 1436mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, 1437 const char *pFilename, 1438 mz_file_write_func pCallback, 1439 void *pOpaque, mz_uint flags); 1440 1441#ifndef MINIZ_NO_STDIO 1442// Extracts a archive file to a disk file and sets its last accessed and 1443// modified times. 1444// This function only extracts files, not archive directory records. 1445mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, 1446 const char *pDst_filename, mz_uint flags); 1447mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, 1448 const char *pArchive_filename, 1449 const char *pDst_filename, 1450 mz_uint flags); 1451#endif 1452 1453// Ends archive reading, freeing all allocations, and closing the input archive 1454// file if mz_zip_reader_init_file() was used. 1455mz_bool mz_zip_reader_end(mz_zip_archive *pZip); 1456 1457// ZIP archive writing 1458 1459#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS 1460 1461// Inits a ZIP archive writer. 1462mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); 1463mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, 1464 size_t size_to_reserve_at_beginning, 1465 size_t initial_allocation_size); 1466 1467#ifndef MINIZ_NO_STDIO 1468mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, 1469 mz_uint64 size_to_reserve_at_beginning); 1470#endif 1471 1472// Converts a ZIP archive reader object into a writer object, to allow efficient 1473// in-place file appends to occur on an existing archive. 1474// For archives opened using mz_zip_reader_init_file, pFilename must be the 1475// archive's filename so it can be reopened for writing. If the file can't be 1476// reopened, mz_zip_reader_end() will be called. 1477// For archives opened using mz_zip_reader_init_mem, the memory block must be 1478// growable using the realloc callback (which defaults to realloc unless you've 1479// overridden it). 1480// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's 1481// user provided m_pWrite function cannot be NULL. 1482// Note: In-place archive modification is not recommended unless you know what 1483// you're doing, because if execution stops or something goes wrong before 1484// the archive is finalized the file's central directory will be hosed. 1485mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, 1486 const char *pFilename); 1487 1488// Adds the contents of a memory buffer to an archive. These functions record 1489// the current local time into the archive. 1490// To add a directory entry, call this method with an archive name ending in a 1491// forwardslash with empty buffer. 1492// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, 1493// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or 1494// just set to MZ_DEFAULT_COMPRESSION. 1495mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, 1496 const void *pBuf, size_t buf_size, 1497 mz_uint level_and_flags); 1498mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, 1499 const char *pArchive_name, const void *pBuf, 1500 size_t buf_size, const void *pComment, 1501 mz_uint16 comment_size, 1502 mz_uint level_and_flags, mz_uint64 uncomp_size, 1503 mz_uint32 uncomp_crc32); 1504 1505#ifndef MINIZ_NO_STDIO 1506// Adds the contents of a disk file to an archive. This function also records 1507// the disk file's modified time into the archive. 1508// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, 1509// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or 1510// just set to MZ_DEFAULT_COMPRESSION. 1511mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, 1512 const char *pSrc_filename, const void *pComment, 1513 mz_uint16 comment_size, mz_uint level_and_flags); 1514#endif 1515 1516// Adds a file to an archive by fully cloning the data from another archive. 1517// This function fully clones the source file's compressed data (no 1518// recompression), along with its full filename, extra data, and comment fields. 1519mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, 1520 mz_zip_archive *pSource_zip, 1521 mz_uint file_index); 1522 1523// Finalizes the archive by writing the central directory records followed by 1524// the end of central directory record. 1525// After an archive is finalized, the only valid call on the mz_zip_archive 1526// struct is mz_zip_writer_end(). 1527// An archive must be manually finalized by calling this function for it to be 1528// valid. 1529mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); 1530mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, 1531 size_t *pSize); 1532 1533// Ends archive writing, freeing all allocations, and closing the output file if 1534// mz_zip_writer_init_file() was used. 1535// Note for the archive to be valid, it must have been finalized before ending. 1536mz_bool mz_zip_writer_end(mz_zip_archive *pZip); 1537 1538// Misc. high-level helper functions: 1539 1540// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) 1541// appends a memory blob to a ZIP archive. 1542// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, 1543// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or 1544// just set to MZ_DEFAULT_COMPRESSION. 1545mz_bool mz_zip_add_mem_to_archive_file_in_place( 1546 const char *pZip_filename, const char *pArchive_name, const void *pBuf, 1547 size_t buf_size, const void *pComment, mz_uint16 comment_size, 1548 mz_uint level_and_flags); 1549 1550// Reads a single file from an archive into a heap block. 1551// Returns NULL on failure. 1552void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, 1553 const char *pArchive_name, 1554 size_t *pSize, mz_uint zip_flags); 1555 1556#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS 1557 1558#endif // #ifndef MINIZ_NO_ARCHIVE_APIS 1559 1560// ------------------- Low-level Decompression API Definitions 1561 1562// Decompression flags used by tinfl_decompress(). 1563// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and 1564// ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the 1565// input is a raw deflate stream. 1566// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available 1567// beyond the end of the supplied input buffer. If clear, the input buffer 1568// contains all remaining input. 1569// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large 1570// enough to hold the entire decompressed stream. If clear, the output buffer is 1571// at least the size of the dictionary (typically 32KB). 1572// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the 1573// decompressed bytes. 1574enum { 1575 TINFL_FLAG_PARSE_ZLIB_HEADER = 1, 1576 TINFL_FLAG_HAS_MORE_INPUT = 2, 1577 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, 1578 TINFL_FLAG_COMPUTE_ADLER32 = 8 1579}; 1580 1581// High level decompression functions: 1582// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block 1583// allocated via malloc(). 1584// On entry: 1585// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data 1586// to decompress. 1587// On return: 1588// Function returns a pointer to the decompressed data, or NULL on failure. 1589// *pOut_len will be set to the decompressed data's size, which could be larger 1590// than src_buf_len on uncompressible data. 1591// The caller must call mz_free() on the returned block when it's no longer 1592// needed. 1593void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, 1594 size_t *pOut_len, int flags); 1595 1596// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block 1597// in memory. 1598// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes 1599// written on success. 1600#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) 1601size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, 1602 const void *pSrc_buf, size_t src_buf_len, 1603 int flags); 1604 1605// tinfl_decompress_mem_to_callback() decompresses a block in memory to an 1606// internal 32KB buffer, and a user provided callback function will be called to 1607// flush the buffer. 1608// Returns 1 on success or 0 on failure. 1609typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); 1610int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, 1611 tinfl_put_buf_func_ptr pPut_buf_func, 1612 void *pPut_buf_user, int flags); 1613 1614struct tinfl_decompressor_tag; 1615typedef struct tinfl_decompressor_tag tinfl_decompressor; 1616 1617// Max size of LZ dictionary. 1618#define TINFL_LZ_DICT_SIZE 32768 1619 1620// Return status. 1621typedef enum { 1622 TINFL_STATUS_BAD_PARAM = -3, 1623 TINFL_STATUS_ADLER32_MISMATCH = -2, 1624 TINFL_STATUS_FAILED = -1, 1625 TINFL_STATUS_DONE = 0, 1626 TINFL_STATUS_NEEDS_MORE_INPUT = 1, 1627 TINFL_STATUS_HAS_MORE_OUTPUT = 2 1628} tinfl_status; 1629 1630// Initializes the decompressor to its initial state. 1631#define tinfl_init(r) \ 1632 do { \ 1633 (r)->m_state = 0; \ 1634 } \ 1635 MZ_MACRO_END 1636#define tinfl_get_adler32(r) (r)->m_check_adler32 1637 1638// Main low-level decompressor coroutine function. This is the only function 1639// actually needed for decompression. All the other functions are just 1640// high-level helpers for improved usability. 1641// This is a universal API, i.e. it can be used as a building block to build any 1642// desired higher level decompression API. In the limit case, it can be called 1643// once per every byte input or output. 1644tinfl_status tinfl_decompress(tinfl_decompressor *r, 1645 const mz_uint8 *pIn_buf_next, 1646 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, 1647 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, 1648 const mz_uint32 decomp_flags); 1649 1650// Internal/private bits follow. 1651enum { 1652 TINFL_MAX_HUFF_TABLES = 3, 1653 TINFL_MAX_HUFF_SYMBOLS_0 = 288, 1654 TINFL_MAX_HUFF_SYMBOLS_1 = 32, 1655 TINFL_MAX_HUFF_SYMBOLS_2 = 19, 1656 TINFL_FAST_LOOKUP_BITS = 10, 1657 TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS 1658}; 1659 1660typedef struct { 1661 mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; 1662 mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], 1663 m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; 1664} tinfl_huff_table; 1665 1666#if MINIZ_HAS_64BIT_REGISTERS 1667#define TINFL_USE_64BIT_BITBUF 1 1668#endif 1669 1670#if TINFL_USE_64BIT_BITBUF 1671typedef mz_uint64 tinfl_bit_buf_t; 1672#define TINFL_BITBUF_SIZE (64) 1673#else 1674typedef mz_uint32 tinfl_bit_buf_t; 1675#define TINFL_BITBUF_SIZE (32) 1676#endif 1677 1678struct tinfl_decompressor_tag { 1679 mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, 1680 m_check_adler32, m_dist, m_counter, m_num_extra, 1681 m_table_sizes[TINFL_MAX_HUFF_TABLES]; 1682 tinfl_bit_buf_t m_bit_buf; 1683 size_t m_dist_from_out_buf_start; 1684 tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; 1685 mz_uint8 m_raw_header[4], 1686 m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; 1687}; 1688 1689// ------------------- Low-level Compression API Definitions 1690 1691// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly 1692// slower, and raw/dynamic blocks will be output more frequently). 1693#define TDEFL_LESS_MEMORY 0 1694 1695// tdefl_init() compression flags logically OR'd together (low 12 bits contain 1696// the max. number of probes per dictionary search): 1697// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes 1698// per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap 1699// compression), 4095=Huffman+LZ (slowest/best compression). 1700enum { 1701 TDEFL_HUFFMAN_ONLY = 0, 1702 TDEFL_DEFAULT_MAX_PROBES = 128, 1703 TDEFL_MAX_PROBES_MASK = 0xFFF 1704}; 1705 1706// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before 1707// the deflate data, and the Adler-32 of the source data at the end. Otherwise, 1708// you'll get raw deflate data. 1709// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even 1710// when not writing zlib headers). 1711// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more 1712// efficient lazy parsing. 1713// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's 1714// initialization time to the minimum, but the output may vary from run to run 1715// given the same input (depending on the contents of memory). 1716// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) 1717// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. 1718// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. 1719// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. 1720// The low 12 bits are reserved to control the max # of hash probes per 1721// dictionary lookup (see TDEFL_MAX_PROBES_MASK). 1722enum { 1723 TDEFL_WRITE_ZLIB_HEADER = 0x01000, 1724 TDEFL_COMPUTE_ADLER32 = 0x02000, 1725 TDEFL_GREEDY_PARSING_FLAG = 0x04000, 1726 TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, 1727 TDEFL_RLE_MATCHES = 0x10000, 1728 TDEFL_FILTER_MATCHES = 0x20000, 1729 TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, 1730 TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 1731}; 1732 1733// High level compression functions: 1734// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block 1735// allocated via malloc(). 1736// On entry: 1737// pSrc_buf, src_buf_len: Pointer and size of source block to compress. 1738// flags: The max match finder probes (default is 128) logically OR'd against 1739// the above flags. Higher probes are slower but improve compression. 1740// On return: 1741// Function returns a pointer to the compressed data, or NULL on failure. 1742// *pOut_len will be set to the compressed data's size, which could be larger 1743// than src_buf_len on uncompressible data. 1744// The caller must free() the returned block when it's no longer needed. 1745void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, 1746 size_t *pOut_len, int flags); 1747 1748// tdefl_compress_mem_to_mem() compresses a block in memory to another block in 1749// memory. 1750// Returns 0 on failure. 1751size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, 1752 const void *pSrc_buf, size_t src_buf_len, 1753 int flags); 1754 1755// Compresses an image to a compressed PNG file in memory. 1756// On entry: 1757// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1758// 1, 2, 3, or 4. 1759// The image pitch in bytes per scanline will be w*num_chans. The leftmost 1760// pixel on the top scanline is stored first in memory. 1761// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, 1762// MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL 1763// If flip is true, the image will be flipped on the Y axis (useful for OpenGL 1764// apps). 1765// On return: 1766// Function returns a pointer to the compressed data, or NULL on failure. 1767// *pLen_out will be set to the size of the PNG image file. 1768// The caller must mz_free() the returned heap block (which will typically be 1769// larger than *pLen_out) when it's no longer needed. 1770void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, 1771 int h, int num_chans, 1772 size_t *pLen_out, 1773 mz_uint level, mz_bool flip); 1774void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, 1775 int num_chans, size_t *pLen_out); 1776 1777// Output stream interface. The compressor uses this interface to write 1778// compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. 1779typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, 1780 void *pUser); 1781 1782// tdefl_compress_mem_to_output() compresses a block to an output stream. The 1783// above helpers use this function internally. 1784mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, 1785 tdefl_put_buf_func_ptr pPut_buf_func, 1786 void *pPut_buf_user, int flags); 1787 1788enum { 1789 TDEFL_MAX_HUFF_TABLES = 3, 1790 TDEFL_MAX_HUFF_SYMBOLS_0 = 288, 1791 TDEFL_MAX_HUFF_SYMBOLS_1 = 32, 1792 TDEFL_MAX_HUFF_SYMBOLS_2 = 19, 1793 TDEFL_LZ_DICT_SIZE = 32768, 1794 TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, 1795 TDEFL_MIN_MATCH_LEN = 3, 1796 TDEFL_MAX_MATCH_LEN = 258 1797}; 1798 1799// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed 1800// output block (using static/fixed Huffman codes). 1801#if TDEFL_LESS_MEMORY 1802enum { 1803 TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, 1804 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, 1805 TDEFL_MAX_HUFF_SYMBOLS = 288, 1806 TDEFL_LZ_HASH_BITS = 12, 1807 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, 1808 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, 1809 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS 1810}; 1811#else 1812enum { 1813 TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, 1814 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, 1815 TDEFL_MAX_HUFF_SYMBOLS = 288, 1816 TDEFL_LZ_HASH_BITS = 15, 1817 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, 1818 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, 1819 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS 1820}; 1821#endif 1822 1823// The low-level tdefl functions below may be used directly if the above helper 1824// functions aren't flexible enough. The low-level functions don't make any heap 1825// allocations, unlike the above helper functions. 1826typedef enum { 1827 TDEFL_STATUS_BAD_PARAM = -2, 1828 TDEFL_STATUS_PUT_BUF_FAILED = -1, 1829 TDEFL_STATUS_OKAY = 0, 1830 TDEFL_STATUS_DONE = 1 1831} tdefl_status; 1832 1833// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums 1834typedef enum { 1835 TDEFL_NO_FLUSH = 0, 1836 TDEFL_SYNC_FLUSH = 2, 1837 TDEFL_FULL_FLUSH = 3, 1838 TDEFL_FINISH = 4 1839} tdefl_flush; 1840 1841// tdefl's compression state structure. 1842typedef struct { 1843 tdefl_put_buf_func_ptr m_pPut_buf_func; 1844 void *m_pPut_buf_user; 1845 mz_uint m_flags, m_max_probes[2]; 1846 int m_greedy_parsing; 1847 mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; 1848 mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; 1849 mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, 1850 m_bit_buffer; 1851 mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, 1852 m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, 1853 m_wants_to_finish; 1854 tdefl_status m_prev_return_status; 1855 const void *m_pIn_buf; 1856 void *m_pOut_buf; 1857 size_t *m_pIn_buf_size, *m_pOut_buf_size; 1858 tdefl_flush m_flush; 1859 const mz_uint8 *m_pSrc; 1860 size_t m_src_buf_left, m_out_buf_ofs; 1861 mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; 1862 mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; 1863 mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; 1864 mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; 1865 mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; 1866 mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; 1867 mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; 1868 mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; 1869} tdefl_compressor; 1870 1871// Initializes the compressor. 1872// There is no corresponding deinit() function because the tdefl API's do not 1873// dynamically allocate memory. 1874// pBut_buf_func: If NULL, output data will be supplied to the specified 1875// callback. In this case, the user should call the tdefl_compress_buffer() API 1876// for compression. 1877// If pBut_buf_func is NULL the user should always call the tdefl_compress() 1878// API. 1879// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, 1880// etc.) 1881tdefl_status tdefl_init(tdefl_compressor *d, 1882 tdefl_put_buf_func_ptr pPut_buf_func, 1883 void *pPut_buf_user, int flags); 1884 1885// Compresses a block of data, consuming as much of the specified input buffer 1886// as possible, and writing as much compressed data to the specified output 1887// buffer as possible. 1888tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, 1889 size_t *pIn_buf_size, void *pOut_buf, 1890 size_t *pOut_buf_size, tdefl_flush flush); 1891 1892// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a 1893// non-NULL tdefl_put_buf_func_ptr. 1894// tdefl_compress_buffer() always consumes the entire input buffer. 1895tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, 1896 size_t in_buf_size, tdefl_flush flush); 1897 1898tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); 1899mz_uint32 tdefl_get_adler32(tdefl_compressor *d); 1900 1901// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't 1902// defined, because it uses some of its macros. 1903#ifndef MINIZ_NO_ZLIB_APIS 1904// Create tdefl_compress() flags given zlib-style compression parameters. 1905// level may range from [0,10] (where 10 is absolute max compression, but may be 1906// much slower on some files) 1907// window_bits may be -15 (raw deflate) or 15 (zlib) 1908// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, 1909// MZ_RLE, or MZ_FIXED 1910mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, 1911 int strategy); 1912#endif // #ifndef MINIZ_NO_ZLIB_APIS 1913 1914#ifdef __cplusplus 1915} 1916#endif 1917 1918#endif // MINIZ_HEADER_INCLUDED 1919 1920// ------------------- End of Header: Implementation follows. (If you only want 1921// the header, define MINIZ_HEADER_FILE_ONLY.) 1922 1923#ifndef MINIZ_HEADER_FILE_ONLY 1924 1925typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; 1926typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; 1927typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; 1928 1929#define MZ_ASSERT(x) TEXR_ASSERT(x) 1930 1931#ifdef MINIZ_NO_MALLOC 1932#define MZ_MALLOC(x) NULL 1933#define MZ_FREE(x) (void)x, ((void)0) 1934#define MZ_REALLOC(p, x) NULL 1935#else 1936#define MZ_MALLOC(x) malloc(x) 1937#define MZ_FREE(x) free(x) 1938#define MZ_REALLOC(p, x) realloc(p, x) 1939#endif 1940 1941#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) 1942#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) 1943#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) 1944 1945#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN 1946#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) 1947#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) 1948#else 1949#define MZ_READ_LE16(p) \ 1950 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ 1951 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) 1952#define MZ_READ_LE32(p) \ 1953 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ 1954 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \ 1955 ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \ 1956 ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) 1957#endif 1958 1959#ifdef _MSC_VER 1960#define MZ_FORCEINLINE __forceinline 1961#elif defined(__GNUC__) 1962#define MZ_FORCEINLINE inline __attribute__((__always_inline__)) 1963#else 1964#define MZ_FORCEINLINE inline 1965#endif 1966 1967#ifdef __cplusplus 1968extern "C" { 1969#endif 1970 1971// ------------------- zlib-style API's 1972 1973mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { 1974 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); 1975 size_t block_len = buf_len % 5552; 1976 if (!ptr) return MZ_ADLER32_INIT; 1977 while (buf_len) { 1978 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { 1979 s1 += ptr[0], s2 += s1; 1980 s1 += ptr[1], s2 += s1; 1981 s1 += ptr[2], s2 += s1; 1982 s1 += ptr[3], s2 += s1; 1983 s1 += ptr[4], s2 += s1; 1984 s1 += ptr[5], s2 += s1; 1985 s1 += ptr[6], s2 += s1; 1986 s1 += ptr[7], s2 += s1; 1987 } 1988 for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; 1989 s1 %= 65521U, s2 %= 65521U; 1990 buf_len -= block_len; 1991 block_len = 5552; 1992 } 1993 return (s2 << 16) + s1; 1994} 1995 1996// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C 1997// implementation that balances processor cache usage against speed": 1998// http://www.geocities.com/malbrain/ 1999mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { 2000 static const mz_uint32 s_crc32[16] = { 2001 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 2002 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 2003 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c}; 2004 mz_uint32 crcu32 = (mz_uint32)crc; 2005 if (!ptr) return MZ_CRC32_INIT; 2006 crcu32 = ~crcu32; 2007 while (buf_len--) { 2008 mz_uint8 b = *ptr++; 2009 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; 2010 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; 2011 } 2012 return ~crcu32; 2013} 2014 2015void mz_free(void *p) { MZ_FREE(p); } 2016 2017#ifndef MINIZ_NO_ZLIB_APIS 2018 2019static void *def_alloc_func(void *opaque, size_t items, size_t size) { 2020 (void)opaque, (void)items, (void)size; 2021 return MZ_MALLOC(items * size); 2022} 2023static void def_free_func(void *opaque, void *address) { 2024 (void)opaque, (void)address; 2025 MZ_FREE(address); 2026} 2027// static void *def_realloc_func(void *opaque, void *address, size_t items, 2028// size_t size) { 2029// (void)opaque, (void)address, (void)items, (void)size; 2030// return MZ_REALLOC(address, items * size); 2031//} 2032 2033const char *mz_version(void) { return MZ_VERSION; } 2034 2035int mz_deflateInit(mz_streamp pStream, int level) { 2036 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, 2037 MZ_DEFAULT_STRATEGY); 2038} 2039 2040int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, 2041 int mem_level, int strategy) { 2042 tdefl_compressor *pComp; 2043 mz_uint comp_flags = 2044 TDEFL_COMPUTE_ADLER32 | 2045 tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); 2046 2047 if (!pStream) return MZ_STREAM_ERROR; 2048 if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || 2049 ((window_bits != MZ_DEFAULT_WINDOW_BITS) && 2050 (-window_bits != MZ_DEFAULT_WINDOW_BITS))) 2051 return MZ_PARAM_ERROR; 2052 2053 pStream->data_type = 0; 2054 pStream->adler = MZ_ADLER32_INIT; 2055 pStream->msg = NULL; 2056 pStream->reserved = 0; 2057 pStream->total_in = 0; 2058 pStream->total_out = 0; 2059 if (!pStream->zalloc) pStream->zalloc = def_alloc_func; 2060 if (!pStream->zfree) pStream->zfree = def_free_func; 2061 2062 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, 2063 sizeof(tdefl_compressor)); 2064 if (!pComp) return MZ_MEM_ERROR; 2065 2066 pStream->state = (struct mz_internal_state *)pComp; 2067 2068 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { 2069 mz_deflateEnd(pStream); 2070 return MZ_PARAM_ERROR; 2071 } 2072 2073 return MZ_OK; 2074} 2075 2076int mz_deflateReset(mz_streamp pStream) { 2077 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || 2078 (!pStream->zfree)) 2079 return MZ_STREAM_ERROR; 2080 pStream->total_in = pStream->total_out = 0; 2081 tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, 2082 ((tdefl_compressor *)pStream->state)->m_flags); 2083 return MZ_OK; 2084} 2085 2086int mz_deflate(mz_streamp pStream, int flush) { 2087 size_t in_bytes, out_bytes; 2088 mz_ulong orig_total_in, orig_total_out; 2089 int mz_status = MZ_OK; 2090 2091 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || 2092 (!pStream->next_out)) 2093 return MZ_STREAM_ERROR; 2094 if (!pStream->avail_out) return MZ_BUF_ERROR; 2095 2096 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; 2097 2098 if (((tdefl_compressor *)pStream->state)->m_prev_return_status == 2099 TDEFL_STATUS_DONE) 2100 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; 2101 2102 orig_total_in = pStream->total_in; 2103 orig_total_out = pStream->total_out; 2104 for (;;) { 2105 tdefl_status defl_status; 2106 in_bytes = pStream->avail_in; 2107 out_bytes = pStream->avail_out; 2108 2109 defl_status = tdefl_compress((tdefl_compressor *)pStream->state, 2110 pStream->next_in, &in_bytes, pStream->next_out, 2111 &out_bytes, (tdefl_flush)flush); 2112 pStream->next_in += (mz_uint)in_bytes; 2113 pStream->avail_in -= (mz_uint)in_bytes; 2114 pStream->total_in += (mz_uint)in_bytes; 2115 pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); 2116 2117 pStream->next_out += (mz_uint)out_bytes; 2118 pStream->avail_out -= (mz_uint)out_bytes; 2119 pStream->total_out += (mz_uint)out_bytes; 2120 2121 if (defl_status < 0) { 2122 mz_status = MZ_STREAM_ERROR; 2123 break; 2124 } else if (defl_status == TDEFL_STATUS_DONE) { 2125 mz_status = MZ_STREAM_END; 2126 break; 2127 } else if (!pStream->avail_out) 2128 break; 2129 else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { 2130 if ((flush) || (pStream->total_in != orig_total_in) || 2131 (pStream->total_out != orig_total_out)) 2132 break; 2133 return MZ_BUF_ERROR; // Can't make forward progress without some input. 2134 } 2135 } 2136 return mz_status; 2137} 2138 2139int mz_deflateEnd(mz_streamp pStream) { 2140 if (!pStream) return MZ_STREAM_ERROR; 2141 if (pStream->state) { 2142 pStream->zfree(pStream->opaque, pStream->state); 2143 pStream->state = NULL; 2144 } 2145 return MZ_OK; 2146} 2147 2148mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { 2149 (void)pStream; 2150 // This is really over conservative. (And lame, but it's actually pretty 2151 // tricky to compute a true upper bound given the way tdefl's blocking works.) 2152 return MZ_MAX(128 + (source_len * 110) / 100, 2153 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); 2154} 2155 2156int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, 2157 const unsigned char *pSource, mz_ulong source_len, int level) { 2158 int status; 2159 mz_stream stream; 2160 memset(&stream, 0, sizeof(stream)); 2161 2162 // In case mz_ulong is 64-bits (argh I hate longs). 2163 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; 2164 2165 stream.next_in = pSource; 2166 stream.avail_in = (mz_uint32)source_len; 2167 stream.next_out = pDest; 2168 stream.avail_out = (mz_uint32)*pDest_len; 2169 2170 status = mz_deflateInit(&stream, level); 2171 if (status != MZ_OK) return status; 2172 2173 status = mz_deflate(&stream, MZ_FINISH); 2174 if (status != MZ_STREAM_END) { 2175 mz_deflateEnd(&stream); 2176 return (status == MZ_OK) ? MZ_BUF_ERROR : status; 2177 } 2178 2179 *pDest_len = stream.total_out; 2180 return mz_deflateEnd(&stream); 2181} 2182 2183int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, 2184 const unsigned char *pSource, mz_ulong source_len) { 2185 return mz_compress2(pDest, pDest_len, pSource, source_len, 2186 MZ_DEFAULT_COMPRESSION); 2187} 2188 2189mz_ulong mz_compressBound(mz_ulong source_len) { 2190 return mz_deflateBound(NULL, source_len); 2191} 2192 2193typedef struct { 2194 tinfl_decompressor m_decomp; 2195 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; 2196 int m_window_bits; 2197 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; 2198 tinfl_status m_last_status; 2199} inflate_state; 2200 2201int mz_inflateInit2(mz_streamp pStream, int window_bits) { 2202 inflate_state *pDecomp; 2203 if (!pStream) return MZ_STREAM_ERROR; 2204 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && 2205 (-window_bits != MZ_DEFAULT_WINDOW_BITS)) 2206 return MZ_PARAM_ERROR; 2207 2208 pStream->data_type = 0; 2209 pStream->adler = 0; 2210 pStream->msg = NULL; 2211 pStream->total_in = 0; 2212 pStream->total_out = 0; 2213 pStream->reserved = 0; 2214 if (!pStream->zalloc) pStream->zalloc = def_alloc_func; 2215 if (!pStream->zfree) pStream->zfree = def_free_func; 2216 2217 pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, 2218 sizeof(inflate_state)); 2219 if (!pDecomp) return MZ_MEM_ERROR; 2220 2221 pStream->state = (struct mz_internal_state *)pDecomp; 2222 2223 tinfl_init(&pDecomp->m_decomp); 2224 pDecomp->m_dict_ofs = 0; 2225 pDecomp->m_dict_avail = 0; 2226 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; 2227 pDecomp->m_first_call = 1; 2228 pDecomp->m_has_flushed = 0; 2229 pDecomp->m_window_bits = window_bits; 2230 2231 return MZ_OK; 2232} 2233 2234int mz_inflateInit(mz_streamp pStream) { 2235 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); 2236} 2237 2238int mz_inflate(mz_streamp pStream, int flush) { 2239 inflate_state *pState; 2240 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; 2241 size_t in_bytes, out_bytes, orig_avail_in; 2242 tinfl_status status; 2243 2244 if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; 2245 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; 2246 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) 2247 return MZ_STREAM_ERROR; 2248 2249 pState = (inflate_state *)pStream->state; 2250 if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; 2251 orig_avail_in = pStream->avail_in; 2252 2253 first_call = pState->m_first_call; 2254 pState->m_first_call = 0; 2255 if (pState->m_last_status < 0) return MZ_DATA_ERROR; 2256 2257 if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; 2258 pState->m_has_flushed |= (flush == MZ_FINISH); 2259 2260 if ((flush == MZ_FINISH) && (first_call)) { 2261 // MZ_FINISH on the first call implies that the input and output buffers are 2262 // large enough to hold the entire compressed/decompressed file. 2263 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; 2264 in_bytes = pStream->avail_in; 2265 out_bytes = pStream->avail_out; 2266 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, 2267 pStream->next_out, pStream->next_out, &out_bytes, 2268 decomp_flags); 2269 pState->m_last_status = status; 2270 pStream->next_in += (mz_uint)in_bytes; 2271 pStream->avail_in -= (mz_uint)in_bytes; 2272 pStream->total_in += (mz_uint)in_bytes; 2273 pStream->adler = tinfl_get_adler32(&pState->m_decomp); 2274 pStream->next_out += (mz_uint)out_bytes; 2275 pStream->avail_out -= (mz_uint)out_bytes; 2276 pStream->total_out += (mz_uint)out_bytes; 2277 2278 if (status < 0) 2279 return MZ_DATA_ERROR; 2280 else if (status != TINFL_STATUS_DONE) { 2281 pState->m_last_status = TINFL_STATUS_FAILED; 2282 return MZ_BUF_ERROR; 2283 } 2284 return MZ_STREAM_END; 2285 } 2286 // flush != MZ_FINISH then we must assume there's more input. 2287 if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; 2288 2289 if (pState->m_dict_avail) { 2290 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); 2291 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); 2292 pStream->next_out += n; 2293 pStream->avail_out -= n; 2294 pStream->total_out += n; 2295 pState->m_dict_avail -= n; 2296 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); 2297 return ((pState->m_last_status == TINFL_STATUS_DONE) && 2298 (!pState->m_dict_avail)) 2299 ? MZ_STREAM_END 2300 : MZ_OK; 2301 } 2302 2303 for (;;) { 2304 in_bytes = pStream->avail_in; 2305 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; 2306 2307 status = tinfl_decompress( 2308 &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, 2309 pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); 2310 pState->m_last_status = status; 2311 2312 pStream->next_in += (mz_uint)in_bytes; 2313 pStream->avail_in -= (mz_uint)in_bytes; 2314 pStream->total_in += (mz_uint)in_bytes; 2315 pStream->adler = tinfl_get_adler32(&pState->m_decomp); 2316 2317 pState->m_dict_avail = (mz_uint)out_bytes; 2318 2319 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); 2320 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); 2321 pStream->next_out += n; 2322 pStream->avail_out -= n; 2323 pStream->total_out += n; 2324 pState->m_dict_avail -= n; 2325 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); 2326 2327 if (status < 0) 2328 return MZ_DATA_ERROR; // Stream is corrupted (there could be some 2329 // uncompressed data left in the output dictionary - 2330 // oh well). 2331 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) 2332 return MZ_BUF_ERROR; // Signal caller that we can't make forward progress 2333 // without supplying more input or by setting flush 2334 // to MZ_FINISH. 2335 else if (flush == MZ_FINISH) { 2336 // The output buffer MUST be large to hold the remaining uncompressed data 2337 // when flush==MZ_FINISH. 2338 if (status == TINFL_STATUS_DONE) 2339 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; 2340 // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's 2341 // at least 1 more byte on the way. If there's no more room left in the 2342 // output buffer then something is wrong. 2343 else if (!pStream->avail_out) 2344 return MZ_BUF_ERROR; 2345 } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || 2346 (!pStream->avail_out) || (pState->m_dict_avail)) 2347 break; 2348 } 2349 2350 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) 2351 ? MZ_STREAM_END 2352 : MZ_OK; 2353} 2354 2355int mz_inflateEnd(mz_streamp pStream) { 2356 if (!pStream) return MZ_STREAM_ERROR; 2357 if (pStream->state) { 2358 pStream->zfree(pStream->opaque, pStream->state); 2359 pStream->state = NULL; 2360 } 2361 return MZ_OK; 2362} 2363 2364int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, 2365 const unsigned char *pSource, mz_ulong source_len) { 2366 mz_stream stream; 2367 int status; 2368 memset(&stream, 0, sizeof(stream)); 2369 2370 // In case mz_ulong is 64-bits (argh I hate longs). 2371 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; 2372 2373 stream.next_in = pSource; 2374 stream.avail_in = (mz_uint32)source_len; 2375 stream.next_out = pDest; 2376 stream.avail_out = (mz_uint32)*pDest_len; 2377 2378 status = mz_inflateInit(&stream); 2379 if (status != MZ_OK) return status; 2380 2381 status = mz_inflate(&stream, MZ_FINISH); 2382 if (status != MZ_STREAM_END) { 2383 mz_inflateEnd(&stream); 2384 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR 2385 : status; 2386 } 2387 *pDest_len = stream.total_out; 2388 2389 return mz_inflateEnd(&stream); 2390} 2391 2392const char *mz_error(int err) { 2393 static struct { 2394 int m_err; 2395 const char *m_pDesc; 2396 } s_error_descs[] = {{MZ_OK, ""}, 2397 {MZ_STREAM_END, "stream end"}, 2398 {MZ_NEED_DICT, "need dictionary"}, 2399 {MZ_ERRNO, "file error"}, 2400 {MZ_STREAM_ERROR, "stream error"}, 2401 {MZ_DATA_ERROR, "data error"}, 2402 {MZ_MEM_ERROR, "out of memory"}, 2403 {MZ_BUF_ERROR, "buf error"}, 2404 {MZ_VERSION_ERROR, "version error"}, 2405 {MZ_PARAM_ERROR, "parameter error"}}; 2406 mz_uint i; 2407 for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) 2408 if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; 2409 return NULL; 2410} 2411 2412#endif // MINIZ_NO_ZLIB_APIS 2413 2414// ------------------- Low-level Decompression (completely independent from all 2415// compression API's) 2416 2417#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) 2418#define TINFL_MEMSET(p, c, l) memset(p, c, l) 2419 2420#define TINFL_CR_BEGIN \ 2421 switch (r->m_state) { \ 2422 case 0: 2423#define TINFL_CR_RETURN(state_index, result) \ 2424 do { \ 2425 status = result; \ 2426 r->m_state = state_index; \ 2427 goto common_exit; \ 2428 case state_index:; \ 2429 } \ 2430 MZ_MACRO_END 2431#define TINFL_CR_RETURN_FOREVER(state_index, result) \ 2432 do { \ 2433 for (;;) { \ 2434 TINFL_CR_RETURN(state_index, result); \ 2435 } \ 2436 } \ 2437 MZ_MACRO_END 2438#define TINFL_CR_FINISH } 2439 2440// TODO: If the caller has indicated that there's no more input, and we attempt 2441// to read beyond the input buf, then something is wrong with the input because 2442// the inflator never 2443// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of 2444// the stream with 0's in this scenario. 2445#define TINFL_GET_BYTE(state_index, c) \ 2446 do { \ 2447 if (pIn_buf_cur >= pIn_buf_end) { \ 2448 for (;;) { \ 2449 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ 2450 TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ 2451 if (pIn_buf_cur < pIn_buf_end) { \ 2452 c = *pIn_buf_cur++; \ 2453 break; \ 2454 } \ 2455 } else { \ 2456 c = 0; \ 2457 break; \ 2458 } \ 2459 } \ 2460 } else \ 2461 c = *pIn_buf_cur++; \ 2462 } \ 2463 MZ_MACRO_END 2464 2465#define TINFL_NEED_BITS(state_index, n) \ 2466 do { \ 2467 mz_uint c; \ 2468 TINFL_GET_BYTE(state_index, c); \ 2469 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ 2470 num_bits += 8; \ 2471 } while (num_bits < (mz_uint)(n)) 2472#define TINFL_SKIP_BITS(state_index, n) \ 2473 do { \ 2474 if (num_bits < (mz_uint)(n)) { \ 2475 TINFL_NEED_BITS(state_index, n); \ 2476 } \ 2477 bit_buf >>= (n); \ 2478 num_bits -= (n); \ 2479 } \ 2480 MZ_MACRO_END 2481#define TINFL_GET_BITS(state_index, b, n) \ 2482 do { \ 2483 if (num_bits < (mz_uint)(n)) { \ 2484 TINFL_NEED_BITS(state_index, n); \ 2485 } \ 2486 b = bit_buf & ((1 << (n)) - 1); \ 2487 bit_buf >>= (n); \ 2488 num_bits -= (n); \ 2489 } \ 2490 MZ_MACRO_END 2491 2492// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes 2493// remaining in the input buffer falls below 2. 2494// It reads just enough bytes from the input stream that are needed to decode 2495// the next Huffman code (and absolutely no more). It works by trying to fully 2496// decode a 2497// Huffman code by using whatever bits are currently present in the bit buffer. 2498// If this fails, it reads another byte, and tries again until it succeeds or 2499// until the 2500// bit buffer contains >=15 bits (deflate's max. Huffman code size). 2501#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ 2502 do { \ 2503 temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ 2504 if (temp >= 0) { \ 2505 code_len = temp >> 9; \ 2506 if ((code_len) && (num_bits >= code_len)) break; \ 2507 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ 2508 code_len = TINFL_FAST_LOOKUP_BITS; \ 2509 do { \ 2510 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ 2511 } while ((temp < 0) && (num_bits >= (code_len + 1))); \ 2512 if (temp >= 0) break; \ 2513 } \ 2514 TINFL_GET_BYTE(state_index, c); \ 2515 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ 2516 num_bits += 8; \ 2517 } while (num_bits < 15); 2518 2519// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex 2520// than you would initially expect because the zlib API expects the decompressor 2521// to never read 2522// beyond the final byte of the deflate stream. (In other words, when this macro 2523// wants to read another byte from the input, it REALLY needs another byte in 2524// order to fully 2525// decode the next Huffman code.) Handling this properly is particularly 2526// important on raw deflate (non-zlib) streams, which aren't followed by a byte 2527// aligned adler-32. 2528// The slow path is only executed at the very end of the input buffer. 2529#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ 2530 do { \ 2531 int temp; \ 2532 mz_uint code_len, c; \ 2533 if (num_bits < 15) { \ 2534 if ((pIn_buf_end - pIn_buf_cur) < 2) { \ 2535 TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ 2536 } else { \ 2537 bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \ 2538 (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ 2539 pIn_buf_cur += 2; \ 2540 num_bits += 16; \ 2541 } \ 2542 } \ 2543 if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \ 2544 0) \ 2545 code_len = temp >> 9, temp &= 511; \ 2546 else { \ 2547 code_len = TINFL_FAST_LOOKUP_BITS; \ 2548 do { \ 2549 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ 2550 } while (temp < 0); \ 2551 } \ 2552 sym = temp; \ 2553 bit_buf >>= code_len; \ 2554 num_bits -= code_len; \ 2555 } \ 2556 MZ_MACRO_END 2557 2558tinfl_status tinfl_decompress(tinfl_decompressor *r, 2559 const mz_uint8 *pIn_buf_next, 2560 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, 2561 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, 2562 const mz_uint32 decomp_flags) { 2563 static const int s_length_base[31] = { 2564 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 2565 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; 2566 static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2567 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 2568 4, 4, 5, 5, 5, 5, 0, 0, 0}; 2569 static const int s_dist_base[32] = { 2570 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 2571 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2572 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; 2573 static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 2574 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 2575 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; 2576 static const mz_uint8 s_length_dezigzag[19] = { 2577 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; 2578 static const int s_min_table_sizes[3] = {257, 1, 4}; 2579 2580 tinfl_status status = TINFL_STATUS_FAILED; 2581 mz_uint32 num_bits, dist, counter, num_extra; 2582 tinfl_bit_buf_t bit_buf; 2583 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = 2584 pIn_buf_next + *pIn_buf_size; 2585 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = 2586 pOut_buf_next + *pOut_buf_size; 2587 size_t out_buf_size_mask = 2588 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) 2589 ? (size_t)-1 2590 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, 2591 dist_from_out_buf_start; 2592 2593 // Ensure the output buffer's size is a power of 2, unless the output buffer 2594 // is large enough to hold the entire output file (in which case it doesn't 2595 // matter). 2596 if (((out_buf_size_mask + 1) & out_buf_size_mask) || 2597 (pOut_buf_next < pOut_buf_start)) { 2598 *pIn_buf_size = *pOut_buf_size = 0; 2599 return TINFL_STATUS_BAD_PARAM; 2600 } 2601 2602 num_bits = r->m_num_bits; 2603 bit_buf = r->m_bit_buf; 2604 dist = r->m_dist; 2605 counter = r->m_counter; 2606 num_extra = r->m_num_extra; 2607 dist_from_out_buf_start = r->m_dist_from_out_buf_start; 2608 TINFL_CR_BEGIN 2609 2610 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; 2611 r->m_z_adler32 = r->m_check_adler32 = 1; 2612 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { 2613 TINFL_GET_BYTE(1, r->m_zhdr0); 2614 TINFL_GET_BYTE(2, r->m_zhdr1); 2615 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || 2616 (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); 2617 if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) 2618 counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || 2619 ((out_buf_size_mask + 1) < 2620 (size_t)(1ULL << (8U + (r->m_zhdr0 >> 4))))); 2621 if (counter) { 2622 TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); 2623 } 2624 } 2625 2626 do { 2627 TINFL_GET_BITS(3, r->m_final, 3); 2628 r->m_type = r->m_final >> 1; 2629 if (r->m_type == 0) { 2630 TINFL_SKIP_BITS(5, num_bits & 7); 2631 for (counter = 0; counter < 4; ++counter) { 2632 if (num_bits) 2633 TINFL_GET_BITS(6, r->m_raw_header[counter], 8); 2634 else 2635 TINFL_GET_BYTE(7, r->m_raw_header[counter]); 2636 } 2637 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != 2638 (mz_uint)(0xFFFF ^ 2639 (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { 2640 TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); 2641 } 2642 while ((counter) && (num_bits)) { 2643 TINFL_GET_BITS(51, dist, 8); 2644 while (pOut_buf_cur >= pOut_buf_end) { 2645 TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); 2646 } 2647 *pOut_buf_cur++ = (mz_uint8)dist; 2648 counter--; 2649 } 2650 while (counter) { 2651 size_t n; 2652 while (pOut_buf_cur >= pOut_buf_end) { 2653 TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); 2654 } 2655 while (pIn_buf_cur >= pIn_buf_end) { 2656 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { 2657 TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); 2658 } else { 2659 TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); 2660 } 2661 } 2662 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), 2663 (size_t)(pIn_buf_end - pIn_buf_cur)), 2664 counter); 2665 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); 2666 pIn_buf_cur += n; 2667 pOut_buf_cur += n; 2668 counter -= (mz_uint)n; 2669 } 2670 } else if (r->m_type == 3) { 2671 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); 2672 } else { 2673 if (r->m_type == 1) { 2674 mz_uint8 *p = r->m_tables[0].m_code_size; 2675 mz_uint i; 2676 r->m_table_sizes[0] = 288; 2677 r->m_table_sizes[1] = 32; 2678 TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); 2679 for (i = 0; i <= 143; ++i) *p++ = 8; 2680 for (; i <= 255; ++i) *p++ = 9; 2681 for (; i <= 279; ++i) *p++ = 7; 2682 for (; i <= 287; ++i) *p++ = 8; 2683 } else { 2684 for (counter = 0; counter < 3; counter++) { 2685 TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); 2686 r->m_table_sizes[counter] += s_min_table_sizes[counter]; 2687 } 2688 MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); 2689 for (counter = 0; counter < r->m_table_sizes[2]; counter++) { 2690 mz_uint s; 2691 TINFL_GET_BITS(14, s, 3); 2692 r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; 2693 } 2694 r->m_table_sizes[2] = 19; 2695 } 2696 for (; (int)r->m_type >= 0; r->m_type--) { 2697 int tree_next, tree_cur; 2698 tinfl_huff_table *pTable; 2699 mz_uint i, j, used_syms, total, sym_index, next_code[17], 2700 total_syms[16]; 2701 pTable = &r->m_tables[r->m_type]; 2702 MZ_CLEAR_OBJ(total_syms); 2703 MZ_CLEAR_OBJ(pTable->m_look_up); 2704 MZ_CLEAR_OBJ(pTable->m_tree); 2705 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) 2706 total_syms[pTable->m_code_size[i]]++; 2707 used_syms = 0, total = 0; 2708 next_code[0] = next_code[1] = 0; 2709 for (i = 1; i <= 15; ++i) { 2710 used_syms += total_syms[i]; 2711 next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); 2712 } 2713 if ((65536 != total) && (used_syms > 1)) { 2714 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); 2715 } 2716 for (tree_next = -1, sym_index = 0; 2717 sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { 2718 mz_uint rev_code = 0, l, cur_code, 2719 code_size = pTable->m_code_size[sym_index]; 2720 if (!code_size) continue; 2721 cur_code = next_code[code_size]++; 2722 for (l = code_size; l > 0; l--, cur_code >>= 1) 2723 rev_code = (rev_code << 1) | (cur_code & 1); 2724 if (code_size <= TINFL_FAST_LOOKUP_BITS) { 2725 mz_int16 k = (mz_int16)((code_size << 9) | sym_index); 2726 while (rev_code < TINFL_FAST_LOOKUP_SIZE) { 2727 pTable->m_look_up[rev_code] = k; 2728 rev_code += (1 << code_size); 2729 } 2730 continue; 2731 } 2732 if (0 == 2733 (tree_cur = pTable->m_look_up[rev_code & 2734 (TINFL_FAST_LOOKUP_SIZE - 1)])) { 2735 pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = 2736 (mz_int16)tree_next; 2737 tree_cur = tree_next; 2738 tree_next -= 2; 2739 } 2740 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); 2741 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { 2742 tree_cur -= ((rev_code >>= 1) & 1); 2743 if (!pTable->m_tree[-tree_cur - 1]) { 2744 pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; 2745 tree_cur = tree_next; 2746 tree_next -= 2; 2747 } else 2748 tree_cur = pTable->m_tree[-tree_cur - 1]; 2749 } 2750 tree_cur -= ((rev_code >>= 1) & 1); 2751 pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; 2752 } 2753 if (r->m_type == 2) { 2754 for (counter = 0; 2755 counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) { 2756 mz_uint s; 2757 TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); 2758 if (dist < 16) { 2759 r->m_len_codes[counter++] = (mz_uint8)dist; 2760 continue; 2761 } 2762 if ((dist == 16) && (!counter)) { 2763 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); 2764 } 2765 num_extra = "\02\03\07"[dist - 16]; 2766 TINFL_GET_BITS(18, s, num_extra); 2767 s += "\03\03\013"[dist - 16]; 2768 TINFL_MEMSET(r->m_len_codes + counter, 2769 (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); 2770 counter += s; 2771 } 2772 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { 2773 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); 2774 } 2775 TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, 2776 r->m_table_sizes[0]); 2777 TINFL_MEMCPY(r->m_tables[1].m_code_size, 2778 r->m_len_codes + r->m_table_sizes[0], 2779 r->m_table_sizes[1]); 2780 } 2781 } 2782 for (;;) { 2783 mz_uint8 *pSrc; 2784 for (;;) { 2785 if (((pIn_buf_end - pIn_buf_cur) < 4) || 2786 ((pOut_buf_end - pOut_buf_cur) < 2)) { 2787 TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); 2788 if (counter >= 256) break; 2789 while (pOut_buf_cur >= pOut_buf_end) { 2790 TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); 2791 } 2792 *pOut_buf_cur++ = (mz_uint8)counter; 2793 } else { 2794 int sym2; 2795 mz_uint code_len; 2796#if TINFL_USE_64BIT_BITBUF 2797 if (num_bits < 30) { 2798 bit_buf |= 2799 (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); 2800 pIn_buf_cur += 4; 2801 num_bits += 32; 2802 } 2803#else 2804 if (num_bits < 15) { 2805 bit_buf |= 2806 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); 2807 pIn_buf_cur += 2; 2808 num_bits += 16; 2809 } 2810#endif 2811 if ((sym2 = 2812 r->m_tables[0] 2813 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 2814 0) 2815 code_len = sym2 >> 9; 2816 else { 2817 code_len = TINFL_FAST_LOOKUP_BITS; 2818 do { 2819 sym2 = r->m_tables[0] 2820 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; 2821 } while (sym2 < 0); 2822 } 2823 counter = sym2; 2824 bit_buf >>= code_len; 2825 num_bits -= code_len; 2826 if (counter & 256) break; 2827 2828#if !TINFL_USE_64BIT_BITBUF 2829 if (num_bits < 15) { 2830 bit_buf |= 2831 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); 2832 pIn_buf_cur += 2; 2833 num_bits += 16; 2834 } 2835#endif 2836 if ((sym2 = 2837 r->m_tables[0] 2838 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 2839 0) 2840 code_len = sym2 >> 9; 2841 else { 2842 code_len = TINFL_FAST_LOOKUP_BITS; 2843 do { 2844 sym2 = r->m_tables[0] 2845 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; 2846 } while (sym2 < 0); 2847 } 2848 bit_buf >>= code_len; 2849 num_bits -= code_len; 2850 2851 pOut_buf_cur[0] = (mz_uint8)counter; 2852 if (sym2 & 256) { 2853 pOut_buf_cur++; 2854 counter = sym2; 2855 break; 2856 } 2857 pOut_buf_cur[1] = (mz_uint8)sym2; 2858 pOut_buf_cur += 2; 2859 } 2860 } 2861 if ((counter &= 511) == 256) break; 2862 2863 num_extra = s_length_extra[counter - 257]; 2864 counter = s_length_base[counter - 257]; 2865 if (num_extra) { 2866 mz_uint extra_bits; 2867 TINFL_GET_BITS(25, extra_bits, num_extra); 2868 counter += extra_bits; 2869 } 2870 2871 TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); 2872 num_extra = s_dist_extra[dist]; 2873 dist = s_dist_base[dist]; 2874 if (num_extra) { 2875 mz_uint extra_bits; 2876 TINFL_GET_BITS(27, extra_bits, num_extra); 2877 dist += extra_bits; 2878 } 2879 2880 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; 2881 if ((dist > dist_from_out_buf_start) && 2882 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { 2883 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); 2884 } 2885 2886 pSrc = pOut_buf_start + 2887 ((dist_from_out_buf_start - dist) & out_buf_size_mask); 2888 2889 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { 2890 while (counter--) { 2891 while (pOut_buf_cur >= pOut_buf_end) { 2892 TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); 2893 } 2894 *pOut_buf_cur++ = 2895 pOut_buf_start[(dist_from_out_buf_start++ - dist) & 2896 out_buf_size_mask]; 2897 } 2898 continue; 2899 } 2900#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES 2901 else if ((counter >= 9) && (counter <= dist)) { 2902 const mz_uint8 *pSrc_end = pSrc + (counter & ~7); 2903 do { 2904 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; 2905 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; 2906 pOut_buf_cur += 8; 2907 } while ((pSrc += 8) < pSrc_end); 2908 if ((counter &= 7) < 3) { 2909 if (counter) { 2910 pOut_buf_cur[0] = pSrc[0]; 2911 if (counter > 1) pOut_buf_cur[1] = pSrc[1]; 2912 pOut_buf_cur += counter; 2913 } 2914 continue; 2915 } 2916 } 2917#endif 2918 do { 2919 pOut_buf_cur[0] = pSrc[0]; 2920 pOut_buf_cur[1] = pSrc[1]; 2921 pOut_buf_cur[2] = pSrc[2]; 2922 pOut_buf_cur += 3; 2923 pSrc += 3; 2924 } while ((int)(counter -= 3) > 2); 2925 if ((int)counter > 0) { 2926 pOut_buf_cur[0] = pSrc[0]; 2927 if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1]; 2928 pOut_buf_cur += counter; 2929 } 2930 } 2931 } 2932 } while (!(r->m_final & 1)); 2933 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { 2934 TINFL_SKIP_BITS(32, num_bits & 7); 2935 for (counter = 0; counter < 4; ++counter) { 2936 mz_uint s; 2937 if (num_bits) 2938 TINFL_GET_BITS(41, s, 8); 2939 else 2940 TINFL_GET_BYTE(42, s); 2941 r->m_z_adler32 = (r->m_z_adler32 << 8) | s; 2942 } 2943 } 2944 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); 2945 TINFL_CR_FINISH 2946 2947common_exit: 2948 r->m_num_bits = num_bits; 2949 r->m_bit_buf = bit_buf; 2950 r->m_dist = dist; 2951 r->m_counter = counter; 2952 r->m_num_extra = num_extra; 2953 r->m_dist_from_out_buf_start = dist_from_out_buf_start; 2954 *pIn_buf_size = pIn_buf_cur - pIn_buf_next; 2955 *pOut_buf_size = pOut_buf_cur - pOut_buf_next; 2956 if ((decomp_flags & 2957 (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && 2958 (status >= 0)) { 2959 const mz_uint8 *ptr = pOut_buf_next; 2960 size_t buf_len = *pOut_buf_size; 2961 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, 2962 s2 = r->m_check_adler32 >> 16; 2963 size_t block_len = buf_len % 5552; 2964 while (buf_len) { 2965 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { 2966 s1 += ptr[0], s2 += s1; 2967 s1 += ptr[1], s2 += s1; 2968 s1 += ptr[2], s2 += s1; 2969 s1 += ptr[3], s2 += s1; 2970 s1 += ptr[4], s2 += s1; 2971 s1 += ptr[5], s2 += s1; 2972 s1 += ptr[6], s2 += s1; 2973 s1 += ptr[7], s2 += s1; 2974 } 2975 for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; 2976 s1 %= 65521U, s2 %= 65521U; 2977 buf_len -= block_len; 2978 block_len = 5552; 2979 } 2980 r->m_check_adler32 = (s2 << 16) + s1; 2981 if ((status == TINFL_STATUS_DONE) && 2982 (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && 2983 (r->m_check_adler32 != r->m_z_adler32)) 2984 status = TINFL_STATUS_ADLER32_MISMATCH; 2985 } 2986 return status; 2987} 2988 2989// Higher level helper functions. 2990void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, 2991 size_t *pOut_len, int flags) { 2992 tinfl_decompressor decomp; 2993 void *pBuf = NULL, *pNew_buf; 2994 size_t src_buf_ofs = 0, out_buf_capacity = 0; 2995 *pOut_len = 0; 2996 tinfl_init(&decomp); 2997 for (;;) { 2998 size_t src_buf_size = src_buf_len - src_buf_ofs, 2999 dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; 3000 tinfl_status status = tinfl_decompress( 3001 &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, 3002 (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, 3003 &dst_buf_size, 3004 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | 3005 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); 3006 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { 3007 MZ_FREE(pBuf); 3008 *pOut_len = 0; 3009 return NULL; 3010 } 3011 src_buf_ofs += src_buf_size; 3012 *pOut_len += dst_buf_size; 3013 if (status == TINFL_STATUS_DONE) break; 3014 new_out_buf_capacity = out_buf_capacity * 2; 3015 if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; 3016 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); 3017 if (!pNew_buf) { 3018 MZ_FREE(pBuf); 3019 *pOut_len = 0; 3020 return NULL; 3021 } 3022 pBuf = pNew_buf; 3023 out_buf_capacity = new_out_buf_capacity; 3024 } 3025 return pBuf; 3026} 3027 3028size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, 3029 const void *pSrc_buf, size_t src_buf_len, 3030 int flags) { 3031 tinfl_decompressor decomp; 3032 tinfl_status status; 3033 tinfl_init(&decomp); 3034 status = 3035 tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, 3036 (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, 3037 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | 3038 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); 3039 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED 3040 : out_buf_len; 3041} 3042 3043int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, 3044 tinfl_put_buf_func_ptr pPut_buf_func, 3045 void *pPut_buf_user, int flags) { 3046 int result = 0; 3047 tinfl_decompressor decomp; 3048 mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); 3049 size_t in_buf_ofs = 0, dict_ofs = 0; 3050 if (!pDict) return TINFL_STATUS_FAILED; 3051 tinfl_init(&decomp); 3052 for (;;) { 3053 size_t in_buf_size = *pIn_buf_size - in_buf_ofs, 3054 dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; 3055 tinfl_status status = 3056 tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, 3057 &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, 3058 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | 3059 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); 3060 in_buf_ofs += in_buf_size; 3061 if ((dst_buf_size) && 3062 (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) 3063 break; 3064 if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { 3065 result = (status == TINFL_STATUS_DONE); 3066 break; 3067 } 3068 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); 3069 } 3070 MZ_FREE(pDict); 3071 *pIn_buf_size = in_buf_ofs; 3072 return result; 3073} 3074 3075// ------------------- Low-level Compression (independent from all decompression 3076// API's) 3077 3078// Purposely making these tables static for faster init and thread safety. 3079static const mz_uint16 s_tdefl_len_sym[256] = { 3080 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 3081 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 3082 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 3083 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 3084 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 3085 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 3086 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, 3087 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 3088 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, 3089 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 3090 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, 3091 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 3092 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, 3093 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 3094 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 3095 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 3096 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 3097 285}; 3098 3099static const mz_uint8 s_tdefl_len_extra[256] = { 3100 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3101 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3102 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 3103 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3104 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3105 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3106 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3107 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3108 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3109 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3110 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0}; 3111 3112static const mz_uint8 s_tdefl_small_dist_sym[512] = { 3113 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 3114 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 3115 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 3116 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3117 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3118 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 3119 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 3120 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 3121 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 3122 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 3123 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3124 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3125 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 3126 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 3127 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 3128 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 3129 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 3130 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 3131 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 3132 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 3133 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 3134 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 3135 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 3136 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 3137 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 3138 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 3139 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17}; 3140 3141static const mz_uint8 s_tdefl_small_dist_extra[512] = { 3142 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3143 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3144 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3145 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3146 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3147 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3148 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3149 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3150 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3151 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3152 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3153 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3154 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3155 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3156 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3157 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3158 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3159 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3160 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3161 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3162 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; 3163 3164static const mz_uint8 s_tdefl_large_dist_sym[128] = { 3165 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 3166 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 3167 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 3168 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 3169 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 3170 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 3171 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29}; 3172 3173static const mz_uint8 s_tdefl_large_dist_extra[128] = { 3174 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 3175 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 3176 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3177 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 3178 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 3179 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 3180 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; 3181 3182// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted 3183// values. 3184typedef struct { 3185 mz_uint16 m_key, m_sym_index; 3186} tdefl_sym_freq; 3187static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, 3188 tdefl_sym_freq *pSyms0, 3189 tdefl_sym_freq *pSyms1) { 3190 mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; 3191 tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; 3192 MZ_CLEAR_OBJ(hist); 3193 for (i = 0; i < num_syms; i++) { 3194 mz_uint freq = pSyms0[i].m_key; 3195 hist[freq & 0xFF]++; 3196 hist[256 + ((freq >> 8) & 0xFF)]++; 3197 } 3198 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) 3199 total_passes--; 3200 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { 3201 const mz_uint32 *pHist = &hist[pass << 8]; 3202 mz_uint offsets[256], cur_ofs = 0; 3203 for (i = 0; i < 256; i++) { 3204 offsets[i] = cur_ofs; 3205 cur_ofs += pHist[i]; 3206 } 3207 for (i = 0; i < num_syms; i++) 3208 pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = 3209 pCur_syms[i]; 3210 { 3211 tdefl_sym_freq *t = pCur_syms; 3212 pCur_syms = pNew_syms; 3213 pNew_syms = t; 3214 } 3215 } 3216 return pCur_syms; 3217} 3218 3219// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, 3220// alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. 3221static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { 3222 int root, leaf, next, avbl, used, dpth; 3223 if (n == 0) 3224 return; 3225 else if (n == 1) { 3226 A[0].m_key = 1; 3227 return; 3228 } 3229 A[0].m_key += A[1].m_key; 3230 root = 0; 3231 leaf = 2; 3232 for (next = 1; next < n - 1; next++) { 3233 if (leaf >= n || A[root].m_key < A[leaf].m_key) { 3234 A[next].m_key = A[root].m_key; 3235 A[root++].m_key = (mz_uint16)next; 3236 } else 3237 A[next].m_key = A[leaf++].m_key; 3238 if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { 3239 A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); 3240 A[root++].m_key = (mz_uint16)next; 3241 } else 3242 A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); 3243 } 3244 A[n - 2].m_key = 0; 3245 for (next = n - 3; next >= 0; next--) 3246 A[next].m_key = A[A[next].m_key].m_key + 1; 3247 avbl = 1; 3248 used = dpth = 0; 3249 root = n - 2; 3250 next = n - 1; 3251 while (avbl > 0) { 3252 while (root >= 0 && (int)A[root].m_key == dpth) { 3253 used++; 3254 root--; 3255 } 3256 while (avbl > used) { 3257 A[next--].m_key = (mz_uint16)(dpth); 3258 avbl--; 3259 } 3260 avbl = 2 * used; 3261 dpth++; 3262 used = 0; 3263 } 3264} 3265 3266// Limits canonical Huffman code table's max code size. 3267enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; 3268static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, 3269 int code_list_len, 3270 int max_code_size) { 3271 int i; 3272 mz_uint32 total = 0; 3273 if (code_list_len <= 1) return; 3274 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) 3275 pNum_codes[max_code_size] += pNum_codes[i]; 3276 for (i = max_code_size; i > 0; i--) 3277 total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); 3278 while (total != (1UL << max_code_size)) { 3279 pNum_codes[max_code_size]--; 3280 for (i = max_code_size - 1; i > 0; i--) 3281 if (pNum_codes[i]) { 3282 pNum_codes[i]--; 3283 pNum_codes[i + 1] += 2; 3284 break; 3285 } 3286 total--; 3287 } 3288} 3289 3290static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, 3291 int table_len, int code_size_limit, 3292 int static_table) { 3293 int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; 3294 mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; 3295 MZ_CLEAR_OBJ(num_codes); 3296 if (static_table) { 3297 for (i = 0; i < table_len; i++) 3298 num_codes[d->m_huff_code_sizes[table_num][i]]++; 3299 } else { 3300 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], 3301 *pSyms; 3302 int num_used_syms = 0; 3303 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; 3304 for (i = 0; i < table_len; i++) 3305 if (pSym_count[i]) { 3306 syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; 3307 syms0[num_used_syms++].m_sym_index = (mz_uint16)i; 3308 } 3309 3310 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); 3311 tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); 3312 3313 for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; 3314 3315 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, 3316 code_size_limit); 3317 3318 MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); 3319 MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); 3320 for (i = 1, j = num_used_syms; i <= code_size_limit; i++) 3321 for (l = num_codes[i]; l > 0; l--) 3322 d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); 3323 } 3324 3325 next_code[1] = 0; 3326 for (j = 0, i = 2; i <= code_size_limit; i++) 3327 next_code[i] = j = ((j + num_codes[i - 1]) << 1); 3328 3329 for (i = 0; i < table_len; i++) { 3330 mz_uint rev_code = 0, code, code_size; 3331 if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; 3332 code = next_code[code_size]++; 3333 for (l = code_size; l > 0; l--, code >>= 1) 3334 rev_code = (rev_code << 1) | (code & 1); 3335 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; 3336 } 3337} 3338 3339#define TDEFL_PUT_BITS(b, l) \ 3340 do { \ 3341 mz_uint bits = b; \ 3342 mz_uint len = l; \ 3343 MZ_ASSERT(bits <= ((1U << len) - 1U)); \ 3344 d->m_bit_buffer |= (bits << d->m_bits_in); \ 3345 d->m_bits_in += len; \ 3346 while (d->m_bits_in >= 8) { \ 3347 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ 3348 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ 3349 d->m_bit_buffer >>= 8; \ 3350 d->m_bits_in -= 8; \ 3351 } \ 3352 } \ 3353 MZ_MACRO_END 3354 3355#define TDEFL_RLE_PREV_CODE_SIZE() \ 3356 { \ 3357 if (rle_repeat_count) { \ 3358 if (rle_repeat_count < 3) { \ 3359 d->m_huff_count[2][prev_code_size] = (mz_uint16)( \ 3360 d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ 3361 while (rle_repeat_count--) \ 3362 packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ 3363 } else { \ 3364 d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ 3365 packed_code_sizes[num_packed_code_sizes++] = 16; \ 3366 packed_code_sizes[num_packed_code_sizes++] = \ 3367 (mz_uint8)(rle_repeat_count - 3); \ 3368 } \ 3369 rle_repeat_count = 0; \ 3370 } \ 3371 } 3372 3373#define TDEFL_RLE_ZERO_CODE_SIZE() \ 3374 { \ 3375 if (rle_z_count) { \ 3376 if (rle_z_count < 3) { \ 3377 d->m_huff_count[2][0] = \ 3378 (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ 3379 while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ 3380 } else if (rle_z_count <= 10) { \ 3381 d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ 3382 packed_code_sizes[num_packed_code_sizes++] = 17; \ 3383 packed_code_sizes[num_packed_code_sizes++] = \ 3384 (mz_uint8)(rle_z_count - 3); \ 3385 } else { \ 3386 d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ 3387 packed_code_sizes[num_packed_code_sizes++] = 18; \ 3388 packed_code_sizes[num_packed_code_sizes++] = \ 3389 (mz_uint8)(rle_z_count - 11); \ 3390 } \ 3391 rle_z_count = 0; \ 3392 } \ 3393 } 3394 3395static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 3396 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; 3397 3398static void tdefl_start_dynamic_block(tdefl_compressor *d) { 3399 int num_lit_codes, num_dist_codes, num_bit_lengths; 3400 mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, 3401 rle_repeat_count, packed_code_sizes_index; 3402 mz_uint8 3403 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], 3404 packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], 3405 prev_code_size = 0xFF; 3406 3407 d->m_huff_count[0][256] = 1; 3408 3409 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); 3410 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); 3411 3412 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) 3413 if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; 3414 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) 3415 if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; 3416 3417 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); 3418 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], 3419 num_dist_codes); 3420 total_code_sizes_to_pack = num_lit_codes + num_dist_codes; 3421 num_packed_code_sizes = 0; 3422 rle_z_count = 0; 3423 rle_repeat_count = 0; 3424 3425 memset(&d->m_huff_count[2][0], 0, 3426 sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); 3427 for (i = 0; i < total_code_sizes_to_pack; i++) { 3428 mz_uint8 code_size = code_sizes_to_pack[i]; 3429 if (!code_size) { 3430 TDEFL_RLE_PREV_CODE_SIZE(); 3431 if (++rle_z_count == 138) { 3432 TDEFL_RLE_ZERO_CODE_SIZE(); 3433 } 3434 } else { 3435 TDEFL_RLE_ZERO_CODE_SIZE(); 3436 if (code_size != prev_code_size) { 3437 TDEFL_RLE_PREV_CODE_SIZE(); 3438 d->m_huff_count[2][code_size] = 3439 (mz_uint16)(d->m_huff_count[2][code_size] + 1); 3440 packed_code_sizes[num_packed_code_sizes++] = code_size; 3441 } else if (++rle_repeat_count == 6) { 3442 TDEFL_RLE_PREV_CODE_SIZE(); 3443 } 3444 } 3445 prev_code_size = code_size; 3446 } 3447 if (rle_repeat_count) { 3448 TDEFL_RLE_PREV_CODE_SIZE(); 3449 } else { 3450 TDEFL_RLE_ZERO_CODE_SIZE(); 3451 } 3452 3453 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); 3454 3455 TDEFL_PUT_BITS(2, 2); 3456 3457 TDEFL_PUT_BITS(num_lit_codes - 257, 5); 3458 TDEFL_PUT_BITS(num_dist_codes - 1, 5); 3459 3460 for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) 3461 if (d->m_huff_code_sizes 3462 [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) 3463 break; 3464 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); 3465 TDEFL_PUT_BITS(num_bit_lengths - 4, 4); 3466 for (i = 0; (int)i < num_bit_lengths; i++) 3467 TDEFL_PUT_BITS( 3468 d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); 3469 3470 for (packed_code_sizes_index = 0; 3471 packed_code_sizes_index < num_packed_code_sizes;) { 3472 mz_uint code = packed_code_sizes[packed_code_sizes_index++]; 3473 MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); 3474 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); 3475 if (code >= 16) 3476 TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], 3477 "\02\03\07"[code - 16]); 3478 } 3479} 3480 3481static void tdefl_start_static_block(tdefl_compressor *d) { 3482 mz_uint i; 3483 mz_uint8 *p = &d->m_huff_code_sizes[0][0]; 3484 3485 for (i = 0; i <= 143; ++i) *p++ = 8; 3486 for (; i <= 255; ++i) *p++ = 9; 3487 for (; i <= 279; ++i) *p++ = 7; 3488 for (; i <= 287; ++i) *p++ = 8; 3489 3490 memset(d->m_huff_code_sizes[1], 5, 32); 3491 3492 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); 3493 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); 3494 3495 TDEFL_PUT_BITS(1, 2); 3496} 3497 3498static const mz_uint mz_bitmasks[17] = { 3499 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 3500 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; 3501 3502#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \ 3503 MINIZ_HAS_64BIT_REGISTERS 3504static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { 3505 mz_uint flags; 3506 mz_uint8 *pLZ_codes; 3507 mz_uint8 *pOutput_buf = d->m_pOutput_buf; 3508 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; 3509 mz_uint64 bit_buffer = d->m_bit_buffer; 3510 mz_uint bits_in = d->m_bits_in; 3511 3512#define TDEFL_PUT_BITS_FAST(b, l) \ 3513 { \ 3514 bit_buffer |= (((mz_uint64)(b)) << bits_in); \ 3515 bits_in += (l); \ 3516 } 3517 3518 flags = 1; 3519 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; 3520 flags >>= 1) { 3521 if (flags == 1) flags = *pLZ_codes++ | 0x100; 3522 3523 if (flags & 1) { 3524 mz_uint s0, s1, n0, n1, sym, num_extra_bits; 3525 mz_uint match_len = pLZ_codes[0], 3526 match_dist = *(const mz_uint16 *)(pLZ_codes + 1); 3527 pLZ_codes += 3; 3528 3529 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); 3530 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], 3531 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); 3532 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], 3533 s_tdefl_len_extra[match_len]); 3534 3535 // This sequence coaxes MSVC into using cmov's vs. jmp's. 3536 s0 = s_tdefl_small_dist_sym[match_dist & 511]; 3537 n0 = s_tdefl_small_dist_extra[match_dist & 511]; 3538 s1 = s_tdefl_large_dist_sym[match_dist >> 8]; 3539 n1 = s_tdefl_large_dist_extra[match_dist >> 8]; 3540 sym = (match_dist < 512) ? s0 : s1; 3541 num_extra_bits = (match_dist < 512) ? n0 : n1; 3542 3543 MZ_ASSERT(d->m_huff_code_sizes[1][sym]); 3544 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], 3545 d->m_huff_code_sizes[1][sym]); 3546 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], 3547 num_extra_bits); 3548 } else { 3549 mz_uint lit = *pLZ_codes++; 3550 MZ_ASSERT(d->m_huff_code_sizes[0][lit]); 3551 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], 3552 d->m_huff_code_sizes[0][lit]); 3553 3554 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { 3555 flags >>= 1; 3556 lit = *pLZ_codes++; 3557 MZ_ASSERT(d->m_huff_code_sizes[0][lit]); 3558 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], 3559 d->m_huff_code_sizes[0][lit]); 3560 3561 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { 3562 flags >>= 1; 3563 lit = *pLZ_codes++; 3564 MZ_ASSERT(d->m_huff_code_sizes[0][lit]); 3565 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], 3566 d->m_huff_code_sizes[0][lit]); 3567 } 3568 } 3569 } 3570 3571 if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; 3572 3573 *(mz_uint64 *)pOutput_buf = bit_buffer; 3574 pOutput_buf += (bits_in >> 3); 3575 bit_buffer >>= (bits_in & ~7); 3576 bits_in &= 7; 3577 } 3578 3579#undef TDEFL_PUT_BITS_FAST 3580 3581 d->m_pOutput_buf = pOutput_buf; 3582 d->m_bits_in = 0; 3583 d->m_bit_buffer = 0; 3584 3585 while (bits_in) { 3586 mz_uint32 n = MZ_MIN(bits_in, 16); 3587 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); 3588 bit_buffer >>= n; 3589 bits_in -= n; 3590 } 3591 3592 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); 3593 3594 return (d->m_pOutput_buf < d->m_pOutput_buf_end); 3595} 3596#else 3597static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { 3598 mz_uint flags; 3599 mz_uint8 *pLZ_codes; 3600 3601 flags = 1; 3602 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; 3603 flags >>= 1) { 3604 if (flags == 1) flags = *pLZ_codes++ | 0x100; 3605 if (flags & 1) { 3606 mz_uint sym, num_extra_bits; 3607 mz_uint match_len = pLZ_codes[0], 3608 match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); 3609 pLZ_codes += 3; 3610 3611 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); 3612 TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], 3613 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); 3614 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], 3615 s_tdefl_len_extra[match_len]); 3616 3617 if (match_dist < 512) { 3618 sym = s_tdefl_small_dist_sym[match_dist]; 3619 num_extra_bits = s_tdefl_small_dist_extra[match_dist]; 3620 } else { 3621 sym = s_tdefl_large_dist_sym[match_dist >> 8]; 3622 num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; 3623 } 3624 MZ_ASSERT(d->m_huff_code_sizes[1][sym]); 3625 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); 3626 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); 3627 } else { 3628 mz_uint lit = *pLZ_codes++; 3629 MZ_ASSERT(d->m_huff_code_sizes[0][lit]); 3630 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); 3631 } 3632 } 3633 3634 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); 3635 3636 return (d->m_pOutput_buf < d->m_pOutput_buf_end); 3637} 3638#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && 3639 // MINIZ_HAS_64BIT_REGISTERS 3640 3641static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { 3642 if (static_block) 3643 tdefl_start_static_block(d); 3644 else 3645 tdefl_start_dynamic_block(d); 3646 return tdefl_compress_lz_codes(d); 3647} 3648 3649static int tdefl_flush_block(tdefl_compressor *d, int flush) { 3650 mz_uint saved_bit_buf, saved_bits_in; 3651 mz_uint8 *pSaved_output_buf; 3652 mz_bool comp_block_succeeded = MZ_FALSE; 3653 int n, use_raw_block = 3654 ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && 3655 (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; 3656 mz_uint8 *pOutput_buf_start = 3657 ((d->m_pPut_buf_func == NULL) && 3658 ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) 3659 ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) 3660 : d->m_output_buf; 3661 3662 d->m_pOutput_buf = pOutput_buf_start; 3663 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; 3664 3665 MZ_ASSERT(!d->m_output_flush_remaining); 3666 d->m_output_flush_ofs = 0; 3667 d->m_output_flush_remaining = 0; 3668 3669 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); 3670 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); 3671 3672 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { 3673 TDEFL_PUT_BITS(0x78, 8); 3674 TDEFL_PUT_BITS(0x01, 8); 3675 } 3676 3677 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); 3678 3679 pSaved_output_buf = d->m_pOutput_buf; 3680 saved_bit_buf = d->m_bit_buffer; 3681 saved_bits_in = d->m_bits_in; 3682 3683 if (!use_raw_block) 3684 comp_block_succeeded = 3685 tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || 3686 (d->m_total_lz_bytes < 48)); 3687 3688 // If the block gets expanded, forget the current contents of the output 3689 // buffer and send a raw block instead. 3690 if (((use_raw_block) || 3691 ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= 3692 d->m_total_lz_bytes))) && 3693 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { 3694 mz_uint i; 3695 d->m_pOutput_buf = pSaved_output_buf; 3696 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; 3697 TDEFL_PUT_BITS(0, 2); 3698 if (d->m_bits_in) { 3699 TDEFL_PUT_BITS(0, 8 - d->m_bits_in); 3700 } 3701 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { 3702 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); 3703 } 3704 for (i = 0; i < d->m_total_lz_bytes; ++i) { 3705 TDEFL_PUT_BITS( 3706 d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 3707 8); 3708 } 3709 } 3710 // Check for the extremely unlikely (if not impossible) case of the compressed 3711 // block not fitting into the output buffer when using dynamic codes. 3712 else if (!comp_block_succeeded) { 3713 d->m_pOutput_buf = pSaved_output_buf; 3714 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; 3715 tdefl_compress_block(d, MZ_TRUE); 3716 } 3717 3718 if (flush) { 3719 if (flush == TDEFL_FINISH) { 3720 if (d->m_bits_in) { 3721 TDEFL_PUT_BITS(0, 8 - d->m_bits_in); 3722 } 3723 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { 3724 mz_uint i, a = d->m_adler32; 3725 for (i = 0; i < 4; i++) { 3726 TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); 3727 a <<= 8; 3728 } 3729 } 3730 } else { 3731 mz_uint i, z = 0; 3732 TDEFL_PUT_BITS(0, 3); 3733 if (d->m_bits_in) { 3734 TDEFL_PUT_BITS(0, 8 - d->m_bits_in); 3735 } 3736 for (i = 2; i; --i, z ^= 0xFFFF) { 3737 TDEFL_PUT_BITS(z & 0xFFFF, 16); 3738 } 3739 } 3740 } 3741 3742 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); 3743 3744 memset(&d->m_huff_count[0][0], 0, 3745 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); 3746 memset(&d->m_huff_count[1][0], 0, 3747 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); 3748 3749 d->m_pLZ_code_buf = d->m_lz_code_buf + 1; 3750 d->m_pLZ_flags = d->m_lz_code_buf; 3751 d->m_num_flags_left = 8; 3752 d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; 3753 d->m_total_lz_bytes = 0; 3754 d->m_block_index++; 3755 3756 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { 3757 if (d->m_pPut_buf_func) { 3758 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; 3759 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) 3760 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); 3761 } else if (pOutput_buf_start == d->m_output_buf) { 3762 int bytes_to_copy = (int)MZ_MIN( 3763 (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); 3764 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, 3765 bytes_to_copy); 3766 d->m_out_buf_ofs += bytes_to_copy; 3767 if ((n -= bytes_to_copy) != 0) { 3768 d->m_output_flush_ofs = bytes_to_copy; 3769 d->m_output_flush_remaining = n; 3770 } 3771 } else { 3772 d->m_out_buf_ofs += n; 3773 } 3774 } 3775 3776 return d->m_output_flush_remaining; 3777} 3778 3779#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES 3780#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) 3781static MZ_FORCEINLINE void tdefl_find_match( 3782 tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, 3783 mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { 3784 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, 3785 match_len = *pMatch_len, probe_pos = pos, next_probe_pos, 3786 probe_len; 3787 mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; 3788 const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; 3789 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), 3790 s01 = TDEFL_READ_UNALIGNED_WORD(s); 3791 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); 3792 if (max_match_len <= match_len) return; 3793 for (;;) { 3794 for (;;) { 3795 if (--num_probes_left == 0) return; 3796#define TDEFL_PROBE \ 3797 next_probe_pos = d->m_next[probe_pos]; \ 3798 if ((!next_probe_pos) || \ 3799 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ 3800 return; \ 3801 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ 3802 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ 3803 break; 3804 TDEFL_PROBE; 3805 TDEFL_PROBE; 3806 TDEFL_PROBE; 3807 } 3808 if (!dist) break; 3809 q = (const mz_uint16 *)(d->m_dict + probe_pos); 3810 if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; 3811 p = s; 3812 probe_len = 32; 3813 do { 3814 } while ( 3815 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && 3816 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && 3817 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && 3818 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && 3819 (--probe_len > 0)); 3820 if (!probe_len) { 3821 *pMatch_dist = dist; 3822 *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); 3823 break; 3824 } else if ((probe_len = ((mz_uint)(p - s) * 2) + 3825 (mz_uint)(*(const mz_uint8 *)p == 3826 *(const mz_uint8 *)q)) > match_len) { 3827 *pMatch_dist = dist; 3828 if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == 3829 max_match_len) 3830 break; 3831 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); 3832 } 3833 } 3834} 3835#else 3836static MZ_FORCEINLINE void tdefl_find_match( 3837 tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, 3838 mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { 3839 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, 3840 match_len = *pMatch_len, probe_pos = pos, next_probe_pos, 3841 probe_len; 3842 mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; 3843 const mz_uint8 *s = d->m_dict + pos, *p, *q; 3844 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; 3845 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); 3846 if (max_match_len <= match_len) return; 3847 for (;;) { 3848 for (;;) { 3849 if (--num_probes_left == 0) return; 3850#define TDEFL_PROBE \ 3851 next_probe_pos = d->m_next[probe_pos]; \ 3852 if ((!next_probe_pos) || \ 3853 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ 3854 return; \ 3855 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ 3856 if ((d->m_dict[probe_pos + match_len] == c0) && \ 3857 (d->m_dict[probe_pos + match_len - 1] == c1)) \ 3858 break; 3859 TDEFL_PROBE; 3860 TDEFL_PROBE; 3861 TDEFL_PROBE; 3862 } 3863 if (!dist) break; 3864 p = s; 3865 q = d->m_dict + probe_pos; 3866 for (probe_len = 0; probe_len < max_match_len; probe_len++) 3867 if (*p++ != *q++) break; 3868 if (probe_len > match_len) { 3869 *pMatch_dist = dist; 3870 if ((*pMatch_len = match_len = probe_len) == max_match_len) return; 3871 c0 = d->m_dict[pos + match_len]; 3872 c1 = d->m_dict[pos + match_len - 1]; 3873 } 3874 } 3875} 3876#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES 3877 3878#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN 3879static mz_bool tdefl_compress_fast(tdefl_compressor *d) { 3880 // Faster, minimally featured LZRW1-style match+parse loop with better 3881 // register utilization. Intended for applications where raw throughput is 3882 // valued more highly than ratio. 3883 mz_uint lookahead_pos = d->m_lookahead_pos, 3884 lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, 3885 total_lz_bytes = d->m_total_lz_bytes, 3886 num_flags_left = d->m_num_flags_left; 3887 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; 3888 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; 3889 3890 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { 3891 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; 3892 mz_uint dst_pos = 3893 (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; 3894 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( 3895 d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); 3896 d->m_src_buf_left -= num_bytes_to_process; 3897 lookahead_size += num_bytes_to_process; 3898 3899 while (num_bytes_to_process) { 3900 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); 3901 memcpy(d->m_dict + dst_pos, d->m_pSrc, n); 3902 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) 3903 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, 3904 MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); 3905 d->m_pSrc += n; 3906 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; 3907 num_bytes_to_process -= n; 3908 } 3909 3910 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); 3911 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) 3912 break; 3913 3914 while (lookahead_size >= 4) { 3915 mz_uint cur_match_dist, cur_match_len = 1; 3916 mz_uint8 *pCur_dict = d->m_dict + cur_pos; 3917 mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; 3918 mz_uint hash = 3919 (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & 3920 TDEFL_LEVEL1_HASH_SIZE_MASK; 3921 mz_uint probe_pos = d->m_hash[hash]; 3922 d->m_hash[hash] = (mz_uint16)lookahead_pos; 3923 3924 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= 3925 dict_size) && 3926 ((*(const mz_uint32 *)(d->m_dict + 3927 (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 3928 0xFFFFFF) == first_trigram)) { 3929 const mz_uint16 *p = (const mz_uint16 *)pCur_dict; 3930 const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); 3931 mz_uint32 probe_len = 32; 3932 do { 3933 } while ((TDEFL_READ_UNALIGNED_WORD(++p) == 3934 TDEFL_READ_UNALIGNED_WORD(++q)) && 3935 (TDEFL_READ_UNALIGNED_WORD(++p) == 3936 TDEFL_READ_UNALIGNED_WORD(++q)) && 3937 (TDEFL_READ_UNALIGNED_WORD(++p) == 3938 TDEFL_READ_UNALIGNED_WORD(++q)) && 3939 (TDEFL_READ_UNALIGNED_WORD(++p) == 3940 TDEFL_READ_UNALIGNED_WORD(++q)) && 3941 (--probe_len > 0)); 3942 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + 3943 (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); 3944 if (!probe_len) 3945 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; 3946 3947 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || 3948 ((cur_match_len == TDEFL_MIN_MATCH_LEN) && 3949 (cur_match_dist >= 8U * 1024U))) { 3950 cur_match_len = 1; 3951 *pLZ_code_buf++ = (mz_uint8)first_trigram; 3952 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); 3953 d->m_huff_count[0][(mz_uint8)first_trigram]++; 3954 } else { 3955 mz_uint32 s0, s1; 3956 cur_match_len = MZ_MIN(cur_match_len, lookahead_size); 3957 3958 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && 3959 (cur_match_dist >= 1) && 3960 (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); 3961 3962 cur_match_dist--; 3963 3964 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); 3965 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; 3966 pLZ_code_buf += 3; 3967 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); 3968 3969 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; 3970 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; 3971 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; 3972 3973 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - 3974 TDEFL_MIN_MATCH_LEN]]++; 3975 } 3976 } else { 3977 *pLZ_code_buf++ = (mz_uint8)first_trigram; 3978 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); 3979 d->m_huff_count[0][(mz_uint8)first_trigram]++; 3980 } 3981 3982 if (--num_flags_left == 0) { 3983 num_flags_left = 8; 3984 pLZ_flags = pLZ_code_buf++; 3985 } 3986 3987 total_lz_bytes += cur_match_len; 3988 lookahead_pos += cur_match_len; 3989 dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); 3990 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; 3991 MZ_ASSERT(lookahead_size >= cur_match_len); 3992 lookahead_size -= cur_match_len; 3993 3994 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { 3995 int n; 3996 d->m_lookahead_pos = lookahead_pos; 3997 d->m_lookahead_size = lookahead_size; 3998 d->m_dict_size = dict_size; 3999 d->m_total_lz_bytes = total_lz_bytes; 4000 d->m_pLZ_code_buf = pLZ_code_buf; 4001 d->m_pLZ_flags = pLZ_flags; 4002 d->m_num_flags_left = num_flags_left; 4003 if ((n = tdefl_flush_block(d, 0)) != 0) 4004 return (n < 0) ? MZ_FALSE : MZ_TRUE; 4005 total_lz_bytes = d->m_total_lz_bytes; 4006 pLZ_code_buf = d->m_pLZ_code_buf; 4007 pLZ_flags = d->m_pLZ_flags; 4008 num_flags_left = d->m_num_flags_left; 4009 } 4010 } 4011 4012 while (lookahead_size) { 4013 mz_uint8 lit = d->m_dict[cur_pos]; 4014 4015 total_lz_bytes++; 4016 *pLZ_code_buf++ = lit; 4017 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); 4018 if (--num_flags_left == 0) { 4019 num_flags_left = 8; 4020 pLZ_flags = pLZ_code_buf++; 4021 } 4022 4023 d->m_huff_count[0][lit]++; 4024 4025 lookahead_pos++; 4026 dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); 4027 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; 4028 lookahead_size--; 4029 4030 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { 4031 int n; 4032 d->m_lookahead_pos = lookahead_pos; 4033 d->m_lookahead_size = lookahead_size; 4034 d->m_dict_size = dict_size; 4035 d->m_total_lz_bytes = total_lz_bytes; 4036 d->m_pLZ_code_buf = pLZ_code_buf; 4037 d->m_pLZ_flags = pLZ_flags; 4038 d->m_num_flags_left = num_flags_left; 4039 if ((n = tdefl_flush_block(d, 0)) != 0) 4040 return (n < 0) ? MZ_FALSE : MZ_TRUE; 4041 total_lz_bytes = d->m_total_lz_bytes; 4042 pLZ_code_buf = d->m_pLZ_code_buf; 4043 pLZ_flags = d->m_pLZ_flags; 4044 num_flags_left = d->m_num_flags_left; 4045 } 4046 } 4047 } 4048 4049 d->m_lookahead_pos = lookahead_pos; 4050 d->m_lookahead_size = lookahead_size; 4051 d->m_dict_size = dict_size; 4052 d->m_total_lz_bytes = total_lz_bytes; 4053 d->m_pLZ_code_buf = pLZ_code_buf; 4054 d->m_pLZ_flags = pLZ_flags; 4055 d->m_num_flags_left = num_flags_left; 4056 return MZ_TRUE; 4057} 4058#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN 4059 4060static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, 4061 mz_uint8 lit) { 4062 d->m_total_lz_bytes++; 4063 *d->m_pLZ_code_buf++ = lit; 4064 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); 4065 if (--d->m_num_flags_left == 0) { 4066 d->m_num_flags_left = 8; 4067 d->m_pLZ_flags = d->m_pLZ_code_buf++; 4068 } 4069 d->m_huff_count[0][lit]++; 4070} 4071 4072static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, 4073 mz_uint match_len, 4074 mz_uint match_dist) { 4075 mz_uint32 s0, s1; 4076 4077 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && 4078 (match_dist <= TDEFL_LZ_DICT_SIZE)); 4079 4080 d->m_total_lz_bytes += match_len; 4081 4082 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); 4083 4084 match_dist -= 1; 4085 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); 4086 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); 4087 d->m_pLZ_code_buf += 3; 4088 4089 *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); 4090 if (--d->m_num_flags_left == 0) { 4091 d->m_num_flags_left = 8; 4092 d->m_pLZ_flags = d->m_pLZ_code_buf++; 4093 } 4094 4095 s0 = s_tdefl_small_dist_sym[match_dist & 511]; 4096 s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; 4097 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; 4098 4099 if (match_len >= TDEFL_MIN_MATCH_LEN) 4100 d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; 4101} 4102 4103static mz_bool tdefl_compress_normal(tdefl_compressor *d) { 4104 const mz_uint8 *pSrc = d->m_pSrc; 4105 size_t src_buf_left = d->m_src_buf_left; 4106 tdefl_flush flush = d->m_flush; 4107 4108 while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { 4109 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; 4110 // Update dictionary and hash chains. Keeps the lookahead size equal to 4111 // TDEFL_MAX_MATCH_LEN. 4112 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { 4113 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & 4114 TDEFL_LZ_DICT_SIZE_MASK, 4115 ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; 4116 mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] 4117 << TDEFL_LZ_HASH_SHIFT) ^ 4118 d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; 4119 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( 4120 src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); 4121 const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; 4122 src_buf_left -= num_bytes_to_process; 4123 d->m_lookahead_size += num_bytes_to_process; 4124 while (pSrc != pSrc_end) { 4125 mz_uint8 c = *pSrc++; 4126 d->m_dict[dst_pos] = c; 4127 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) 4128 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; 4129 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); 4130 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; 4131 d->m_hash[hash] = (mz_uint16)(ins_pos); 4132 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; 4133 ins_pos++; 4134 } 4135 } else { 4136 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { 4137 mz_uint8 c = *pSrc++; 4138 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & 4139 TDEFL_LZ_DICT_SIZE_MASK; 4140 src_buf_left--; 4141 d->m_dict[dst_pos] = c; 4142 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) 4143 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; 4144 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { 4145 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; 4146 mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] 4147 << (TDEFL_LZ_HASH_SHIFT * 2)) ^ 4148 (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] 4149 << TDEFL_LZ_HASH_SHIFT) ^ 4150 c) & 4151 (TDEFL_LZ_HASH_SIZE - 1); 4152 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; 4153 d->m_hash[hash] = (mz_uint16)(ins_pos); 4154 } 4155 } 4156 } 4157 d->m_dict_size = 4158 MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); 4159 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; 4160 4161 // Simple lazy/greedy parsing state machine. 4162 len_to_move = 1; 4163 cur_match_dist = 0; 4164 cur_match_len = 4165 d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); 4166 cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; 4167 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { 4168 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { 4169 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; 4170 cur_match_len = 0; 4171 while (cur_match_len < d->m_lookahead_size) { 4172 if (d->m_dict[cur_pos + cur_match_len] != c) break; 4173 cur_match_len++; 4174 } 4175 if (cur_match_len < TDEFL_MIN_MATCH_LEN) 4176 cur_match_len = 0; 4177 else 4178 cur_match_dist = 1; 4179 } 4180 } else { 4181 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, 4182 d->m_lookahead_size, &cur_match_dist, &cur_match_len); 4183 } 4184 if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && 4185 (cur_match_dist >= 8U * 1024U)) || 4186 (cur_pos == cur_match_dist) || 4187 ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { 4188 cur_match_dist = cur_match_len = 0; 4189 } 4190 if (d->m_saved_match_len) { 4191 if (cur_match_len > d->m_saved_match_len) { 4192 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); 4193 if (cur_match_len >= 128) { 4194 tdefl_record_match(d, cur_match_len, cur_match_dist); 4195 d->m_saved_match_len = 0; 4196 len_to_move = cur_match_len; 4197 } else { 4198 d->m_saved_lit = d->m_dict[cur_pos]; 4199 d->m_saved_match_dist = cur_match_dist; 4200 d->m_saved_match_len = cur_match_len; 4201 } 4202 } else { 4203 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); 4204 len_to_move = d->m_saved_match_len - 1; 4205 d->m_saved_match_len = 0; 4206 } 4207 } else if (!cur_match_dist) 4208 tdefl_record_literal(d, 4209 d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); 4210 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || 4211 (cur_match_len >= 128)) { 4212 tdefl_record_match(d, cur_match_len, cur_match_dist); 4213 len_to_move = cur_match_len; 4214 } else { 4215 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; 4216 d->m_saved_match_dist = cur_match_dist; 4217 d->m_saved_match_len = cur_match_len; 4218 } 4219 // Move the lookahead forward by len_to_move bytes. 4220 d->m_lookahead_pos += len_to_move; 4221 MZ_ASSERT(d->m_lookahead_size >= len_to_move); 4222 d->m_lookahead_size -= len_to_move; 4223 d->m_dict_size = 4224 MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); 4225 // Check if it's time to flush the current LZ codes to the internal output 4226 // buffer. 4227 if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || 4228 ((d->m_total_lz_bytes > 31 * 1024) && 4229 (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= 4230 d->m_total_lz_bytes) || 4231 (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { 4232 int n; 4233 d->m_pSrc = pSrc; 4234 d->m_src_buf_left = src_buf_left; 4235 if ((n = tdefl_flush_block(d, 0)) != 0) 4236 return (n < 0) ? MZ_FALSE : MZ_TRUE; 4237 } 4238 } 4239 4240 d->m_pSrc = pSrc; 4241 d->m_src_buf_left = src_buf_left; 4242 return MZ_TRUE; 4243} 4244 4245static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { 4246 if (d->m_pIn_buf_size) { 4247 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; 4248 } 4249 4250 if (d->m_pOut_buf_size) { 4251 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, 4252 d->m_output_flush_remaining); 4253 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, 4254 d->m_output_buf + d->m_output_flush_ofs, n); 4255 d->m_output_flush_ofs += (mz_uint)n; 4256 d->m_output_flush_remaining -= (mz_uint)n; 4257 d->m_out_buf_ofs += n; 4258 4259 *d->m_pOut_buf_size = d->m_out_buf_ofs; 4260 } 4261 4262 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE 4263 : TDEFL_STATUS_OKAY; 4264} 4265 4266tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, 4267 size_t *pIn_buf_size, void *pOut_buf, 4268 size_t *pOut_buf_size, tdefl_flush flush) { 4269 if (!d) { 4270 if (pIn_buf_size) *pIn_buf_size = 0; 4271 if (pOut_buf_size) *pOut_buf_size = 0; 4272 return TDEFL_STATUS_BAD_PARAM; 4273 } 4274 4275 d->m_pIn_buf = pIn_buf; 4276 d->m_pIn_buf_size = pIn_buf_size; 4277 d->m_pOut_buf = pOut_buf; 4278 d->m_pOut_buf_size = pOut_buf_size; 4279 d->m_pSrc = (const mz_uint8 *)(pIn_buf); 4280 d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; 4281 d->m_out_buf_ofs = 0; 4282 d->m_flush = flush; 4283 4284 if (((d->m_pPut_buf_func != NULL) == 4285 ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || 4286 (d->m_prev_return_status != TDEFL_STATUS_OKAY) || 4287 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || 4288 (pIn_buf_size && *pIn_buf_size && !pIn_buf) || 4289 (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { 4290 if (pIn_buf_size) *pIn_buf_size = 0; 4291 if (pOut_buf_size) *pOut_buf_size = 0; 4292 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); 4293 } 4294 d->m_wants_to_finish |= (flush == TDEFL_FINISH); 4295 4296 if ((d->m_output_flush_remaining) || (d->m_finished)) 4297 return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); 4298 4299#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN 4300 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && 4301 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && 4302 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | 4303 TDEFL_RLE_MATCHES)) == 0)) { 4304 if (!tdefl_compress_fast(d)) return d->m_prev_return_status; 4305 } else 4306#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN 4307 { 4308 if (!tdefl_compress_normal(d)) return d->m_prev_return_status; 4309 } 4310 4311 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && 4312 (pIn_buf)) 4313 d->m_adler32 = 4314 (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, 4315 d->m_pSrc - (const mz_uint8 *)pIn_buf); 4316 4317 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && 4318 (!d->m_output_flush_remaining)) { 4319 if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; 4320 d->m_finished = (flush == TDEFL_FINISH); 4321 if (flush == TDEFL_FULL_FLUSH) { 4322 MZ_CLEAR_OBJ(d->m_hash); 4323 MZ_CLEAR_OBJ(d->m_next); 4324 d->m_dict_size = 0; 4325 } 4326 } 4327 4328 return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); 4329} 4330 4331tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, 4332 size_t in_buf_size, tdefl_flush flush) { 4333 MZ_ASSERT(d->m_pPut_buf_func); 4334 return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); 4335} 4336 4337tdefl_status tdefl_init(tdefl_compressor *d, 4338 tdefl_put_buf_func_ptr pPut_buf_func, 4339 void *pPut_buf_user, int flags) { 4340 d->m_pPut_buf_func = pPut_buf_func; 4341 d->m_pPut_buf_user = pPut_buf_user; 4342 d->m_flags = (mz_uint)(flags); 4343 d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; 4344 d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; 4345 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; 4346 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); 4347 d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = 4348 d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; 4349 d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = 4350 d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; 4351 d->m_pLZ_code_buf = d->m_lz_code_buf + 1; 4352 d->m_pLZ_flags = d->m_lz_code_buf; 4353 d->m_num_flags_left = 8; 4354 d->m_pOutput_buf = d->m_output_buf; 4355 d->m_pOutput_buf_end = d->m_output_buf; 4356 d->m_prev_return_status = TDEFL_STATUS_OKAY; 4357 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; 4358 d->m_adler32 = 1; 4359 d->m_pIn_buf = NULL; 4360 d->m_pOut_buf = NULL; 4361 d->m_pIn_buf_size = NULL; 4362 d->m_pOut_buf_size = NULL; 4363 d->m_flush = TDEFL_NO_FLUSH; 4364 d->m_pSrc = NULL; 4365 d->m_src_buf_left = 0; 4366 d->m_out_buf_ofs = 0; 4367 memset(&d->m_huff_count[0][0], 0, 4368 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); 4369 memset(&d->m_huff_count[1][0], 0, 4370 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); 4371 return TDEFL_STATUS_OKAY; 4372} 4373 4374tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { 4375 return d->m_prev_return_status; 4376} 4377 4378mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } 4379 4380mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, 4381 tdefl_put_buf_func_ptr pPut_buf_func, 4382 void *pPut_buf_user, int flags) { 4383 tdefl_compressor *pComp; 4384 mz_bool succeeded; 4385 if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; 4386 pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); 4387 if (!pComp) return MZ_FALSE; 4388 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == 4389 TDEFL_STATUS_OKAY); 4390 succeeded = 4391 succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == 4392 TDEFL_STATUS_DONE); 4393 MZ_FREE(pComp); 4394 return succeeded; 4395} 4396 4397typedef struct { 4398 size_t m_size, m_capacity; 4399 mz_uint8 *m_pBuf; 4400 mz_bool m_expandable; 4401} tdefl_output_buffer; 4402 4403static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, 4404 void *pUser) { 4405 tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; 4406 size_t new_size = p->m_size + len; 4407 if (new_size > p->m_capacity) { 4408 size_t new_capacity = p->m_capacity; 4409 mz_uint8 *pNew_buf; 4410 if (!p->m_expandable) return MZ_FALSE; 4411 do { 4412 new_capacity = MZ_MAX(128U, new_capacity << 1U); 4413 } while (new_size > new_capacity); 4414 pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); 4415 if (!pNew_buf) return MZ_FALSE; 4416 p->m_pBuf = pNew_buf; 4417 p->m_capacity = new_capacity; 4418 } 4419 memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); 4420 p->m_size = new_size; 4421 return MZ_TRUE; 4422} 4423 4424void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, 4425 size_t *pOut_len, int flags) { 4426 tdefl_output_buffer out_buf; 4427 MZ_CLEAR_OBJ(out_buf); 4428 if (!pOut_len) 4429 return MZ_FALSE; 4430 else 4431 *pOut_len = 0; 4432 out_buf.m_expandable = MZ_TRUE; 4433 if (!tdefl_compress_mem_to_output( 4434 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) 4435 return NULL; 4436 *pOut_len = out_buf.m_size; 4437 return out_buf.m_pBuf; 4438} 4439 4440size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, 4441 const void *pSrc_buf, size_t src_buf_len, 4442 int flags) { 4443 tdefl_output_buffer out_buf; 4444 MZ_CLEAR_OBJ(out_buf); 4445 if (!pOut_buf) return 0; 4446 out_buf.m_pBuf = (mz_uint8 *)pOut_buf; 4447 out_buf.m_capacity = out_buf_len; 4448 if (!tdefl_compress_mem_to_output( 4449 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) 4450 return 0; 4451 return out_buf.m_size; 4452} 4453 4454#ifndef MINIZ_NO_ZLIB_APIS 4455static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, 4456 128, 256, 512, 768, 1500}; 4457 4458// level may actually range from [0,10] (10 is a "hidden" max level, where we 4459// want a bit more compression and it's fine if throughput to fall off a cliff 4460// on some files). 4461mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, 4462 int strategy) { 4463 mz_uint comp_flags = 4464 s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | 4465 ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); 4466 if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; 4467 4468 if (!level) 4469 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; 4470 else if (strategy == MZ_FILTERED) 4471 comp_flags |= TDEFL_FILTER_MATCHES; 4472 else if (strategy == MZ_HUFFMAN_ONLY) 4473 comp_flags &= ~TDEFL_MAX_PROBES_MASK; 4474 else if (strategy == MZ_FIXED) 4475 comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; 4476 else if (strategy == MZ_RLE) 4477 comp_flags |= TDEFL_RLE_MATCHES; 4478 4479 return comp_flags; 4480} 4481#endif // MINIZ_NO_ZLIB_APIS 4482 4483#ifdef _MSC_VER 4484#pragma warning(push) 4485#pragma warning(disable : 4204) // nonstandard extension used : non-constant 4486 // aggregate initializer (also supported by GNU 4487 // C and C99, so no big deal) 4488#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to 4489 // 'int', possible loss of data 4490#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to 4491 // 'int', possible loss of data 4492#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is 4493 // deprecated. Instead, use the ISO C and C++ 4494 // conformant name: _strdup. 4495#endif 4496 4497// Simple PNG writer function by Alex Evans, 2011. Released into the public 4498// domain: https://gist.github.com/908299, more context at 4499// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. 4500// This is actually a modification of Alex's original code so PNG files 4501// generated by this function pass pngcheck. 4502void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, 4503 int h, int num_chans, 4504 size_t *pLen_out, 4505 mz_uint level, mz_bool flip) { 4506 // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was 4507 // defined. 4508 static const mz_uint s_tdefl_png_num_probes[11] = { 4509 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; 4510 tdefl_compressor *pComp = 4511 (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); 4512 tdefl_output_buffer out_buf; 4513 int i, bpl = w * num_chans, y, z; 4514 mz_uint32 c; 4515 *pLen_out = 0; 4516 if (!pComp) return NULL; 4517 MZ_CLEAR_OBJ(out_buf); 4518 out_buf.m_expandable = MZ_TRUE; 4519 out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); 4520 if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { 4521 MZ_FREE(pComp); 4522 return NULL; 4523 } 4524 // write dummy header 4525 for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); 4526 // compress image data 4527 tdefl_init( 4528 pComp, tdefl_output_buffer_putter, &out_buf, 4529 s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); 4530 for (y = 0; y < h; ++y) { 4531 tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); 4532 tdefl_compress_buffer(pComp, 4533 (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, 4534 bpl, TDEFL_NO_FLUSH); 4535 } 4536 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != 4537 TDEFL_STATUS_DONE) { 4538 MZ_FREE(pComp); 4539 MZ_FREE(out_buf.m_pBuf); 4540 return NULL; 4541 } 4542 // write real header 4543 *pLen_out = out_buf.m_size - 41; 4544 { 4545 static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; 4546 mz_uint8 pnghdr[41] = {0x89, 4547 0x50, 4548 0x4e, 4549 0x47, 4550 0x0d, 4551 0x0a, 4552 0x1a, 4553 0x0a, 4554 0x00, 4555 0x00, 4556 0x00, 4557 0x0d, 4558 0x49, 4559 0x48, 4560 0x44, 4561 0x52, 4562 0, 4563 0, 4564 (mz_uint8)(w >> 8), 4565 (mz_uint8)w, 4566 0, 4567 0, 4568 (mz_uint8)(h >> 8), 4569 (mz_uint8)h, 4570 8, 4571 chans[num_chans], 4572 0, 4573 0, 4574 0, 4575 0, 4576 0, 4577 0, 4578 0, 4579 (mz_uint8)(*pLen_out >> 24), 4580 (mz_uint8)(*pLen_out >> 16), 4581 (mz_uint8)(*pLen_out >> 8), 4582 (mz_uint8)*pLen_out, 4583 0x49, 4584 0x44, 4585 0x41, 4586 0x54}; 4587 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); 4588 for (i = 0; i < 4; ++i, c <<= 8) 4589 ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); 4590 memcpy(out_buf.m_pBuf, pnghdr, 41); 4591 } 4592 // write footer (IDAT CRC-32, followed by IEND chunk) 4593 if (!tdefl_output_buffer_putter( 4594 "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { 4595 *pLen_out = 0; 4596 MZ_FREE(pComp); 4597 MZ_FREE(out_buf.m_pBuf); 4598 return NULL; 4599 } 4600 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, 4601 *pLen_out + 4); 4602 for (i = 0; i < 4; ++i, c <<= 8) 4603 (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); 4604 // compute final size of file, grab compressed data buffer and return 4605 *pLen_out += 57; 4606 MZ_FREE(pComp); 4607 return out_buf.m_pBuf; 4608} 4609void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, 4610 int num_chans, size_t *pLen_out) { 4611 // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we 4612 // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's 4613 // where #defined out) 4614 return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, 4615 pLen_out, 6, MZ_FALSE); 4616} 4617 4618// ------------------- .ZIP archive reading 4619 4620#ifndef MINIZ_NO_ARCHIVE_APIS 4621#error "No arvhive APIs" 4622 4623#ifdef MINIZ_NO_STDIO 4624#define MZ_FILE void * 4625#else 4626#include <stdio.h> 4627#include <sys/stat.h> 4628 4629#if defined(_MSC_VER) || defined(__MINGW64__) 4630static FILE *mz_fopen(const char *pFilename, const char *pMode) { 4631 FILE *pFile = NULL; 4632 fopen_s(&pFile, pFilename, pMode); 4633 return pFile; 4634} 4635static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { 4636 FILE *pFile = NULL; 4637 if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL; 4638 return pFile; 4639} 4640#ifndef MINIZ_NO_TIME 4641#include <sys/utime.h> 4642#endif 4643#define MZ_FILE FILE 4644#define MZ_FOPEN mz_fopen 4645#define MZ_FCLOSE fclose 4646#define MZ_FREAD fread 4647#define MZ_FWRITE fwrite 4648#define MZ_FTELL64 _ftelli64 4649#define MZ_FSEEK64 _fseeki64 4650#define MZ_FILE_STAT_STRUCT _stat 4651#define MZ_FILE_STAT _stat 4652#define MZ_FFLUSH fflush 4653#define MZ_FREOPEN mz_freopen 4654#define MZ_DELETE_FILE remove 4655#elif defined(__MINGW32__) 4656#ifndef MINIZ_NO_TIME 4657#include <sys/utime.h> 4658#endif 4659#define MZ_FILE FILE 4660#define MZ_FOPEN(f, m) fopen(f, m) 4661#define MZ_FCLOSE fclose 4662#define MZ_FREAD fread 4663#define MZ_FWRITE fwrite 4664#define MZ_FTELL64 ftello64 4665#define MZ_FSEEK64 fseeko64 4666#define MZ_FILE_STAT_STRUCT _stat 4667#define MZ_FILE_STAT _stat 4668#define MZ_FFLUSH fflush 4669#define MZ_FREOPEN(f, m, s) freopen(f, m, s) 4670#define MZ_DELETE_FILE remove 4671#elif defined(__TINYC__) 4672#ifndef MINIZ_NO_TIME 4673#include <sys/utime.h> 4674#endif 4675#define MZ_FILE FILE 4676#define MZ_FOPEN(f, m) fopen(f, m) 4677#define MZ_FCLOSE fclose 4678#define MZ_FREAD fread 4679#define MZ_FWRITE fwrite 4680#define MZ_FTELL64 ftell 4681#define MZ_FSEEK64 fseek 4682#define MZ_FILE_STAT_STRUCT stat 4683#define MZ_FILE_STAT stat 4684#define MZ_FFLUSH fflush 4685#define MZ_FREOPEN(f, m, s) freopen(f, m, s) 4686#define MZ_DELETE_FILE remove 4687#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) && _LARGEFILE64_SOURCE 4688#ifndef MINIZ_NO_TIME 4689#include <utime.h> 4690#endif 4691#define MZ_FILE FILE 4692#define MZ_FOPEN(f, m) fopen64(f, m) 4693#define MZ_FCLOSE fclose 4694#define MZ_FREAD fread 4695#define MZ_FWRITE fwrite 4696#define MZ_FTELL64 ftello64 4697#define MZ_FSEEK64 fseeko64 4698#define MZ_FILE_STAT_STRUCT stat64 4699#define MZ_FILE_STAT stat64 4700#define MZ_FFLUSH fflush 4701#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) 4702#define MZ_DELETE_FILE remove 4703#else 4704#ifndef MINIZ_NO_TIME 4705#include <utime.h> 4706#endif 4707#define MZ_FILE FILE 4708#define MZ_FOPEN(f, m) fopen(f, m) 4709#define MZ_FCLOSE fclose 4710#define MZ_FREAD fread 4711#define MZ_FWRITE fwrite 4712#define MZ_FTELL64 ftello 4713#define MZ_FSEEK64 fseeko 4714#define MZ_FILE_STAT_STRUCT stat 4715#define MZ_FILE_STAT stat 4716#define MZ_FFLUSH fflush 4717#define MZ_FREOPEN(f, m, s) freopen(f, m, s) 4718#define MZ_DELETE_FILE remove 4719#endif // #ifdef _MSC_VER 4720#endif // #ifdef MINIZ_NO_STDIO 4721 4722#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) 4723 4724// Various ZIP archive enums. To completely avoid cross platform compiler 4725// alignment and platform endian issues, miniz.c doesn't use structs for any of 4726// this stuff. 4727enum { 4728 // ZIP archive identifiers and record sizes 4729 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, 4730 MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, 4731 MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, 4732 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, 4733 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, 4734 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, 4735 // Central directory header record offsets 4736 MZ_ZIP_CDH_SIG_OFS = 0, 4737 MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, 4738 MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, 4739 MZ_ZIP_CDH_BIT_FLAG_OFS = 8, 4740 MZ_ZIP_CDH_METHOD_OFS = 10, 4741 MZ_ZIP_CDH_FILE_TIME_OFS = 12, 4742 MZ_ZIP_CDH_FILE_DATE_OFS = 14, 4743 MZ_ZIP_CDH_CRC32_OFS = 16, 4744 MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, 4745 MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, 4746 MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, 4747 MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, 4748 MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, 4749 MZ_ZIP_CDH_DISK_START_OFS = 34, 4750 MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, 4751 MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, 4752 MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, 4753 // Local directory header offsets 4754 MZ_ZIP_LDH_SIG_OFS = 0, 4755 MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, 4756 MZ_ZIP_LDH_BIT_FLAG_OFS = 6, 4757 MZ_ZIP_LDH_METHOD_OFS = 8, 4758 MZ_ZIP_LDH_FILE_TIME_OFS = 10, 4759 MZ_ZIP_LDH_FILE_DATE_OFS = 12, 4760 MZ_ZIP_LDH_CRC32_OFS = 14, 4761 MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, 4762 MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, 4763 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, 4764 MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, 4765 // End of central directory offsets 4766 MZ_ZIP_ECDH_SIG_OFS = 0, 4767 MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, 4768 MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, 4769 MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, 4770 MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, 4771 MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, 4772 MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, 4773 MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, 4774}; 4775 4776typedef struct { 4777 void *m_p; 4778 size_t m_size, m_capacity; 4779 mz_uint m_element_size; 4780} mz_zip_array; 4781 4782struct mz_zip_internal_state_tag { 4783 mz_zip_array m_central_dir; 4784 mz_zip_array m_central_dir_offsets; 4785 mz_zip_array m_sorted_central_dir_offsets; 4786 MZ_FILE *m_pFile; 4787 void *m_pMem; 4788 size_t m_mem_size; 4789 size_t m_mem_capacity; 4790}; 4791 4792#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \ 4793 (array_ptr)->m_element_size = element_size 4794#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \ 4795 ((element_type *)((array_ptr)->m_p))[index] 4796 4797static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, 4798 mz_zip_array *pArray) { 4799 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); 4800 memset(pArray, 0, sizeof(mz_zip_array)); 4801} 4802 4803static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, 4804 mz_zip_array *pArray, 4805 size_t min_new_capacity, 4806 mz_uint growing) { 4807 void *pNew_p; 4808 size_t new_capacity = min_new_capacity; 4809 MZ_ASSERT(pArray->m_element_size); 4810 if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; 4811 if (growing) { 4812 new_capacity = MZ_MAX(1, pArray->m_capacity); 4813 while (new_capacity < min_new_capacity) new_capacity *= 2; 4814 } 4815 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, 4816 pArray->m_element_size, new_capacity))) 4817 return MZ_FALSE; 4818 pArray->m_p = pNew_p; 4819 pArray->m_capacity = new_capacity; 4820 return MZ_TRUE; 4821} 4822 4823static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, 4824 mz_zip_array *pArray, 4825 size_t new_capacity, 4826 mz_uint growing) { 4827 if (new_capacity > pArray->m_capacity) { 4828 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) 4829 return MZ_FALSE; 4830 } 4831 return MZ_TRUE; 4832} 4833 4834static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, 4835 mz_zip_array *pArray, 4836 size_t new_size, 4837 mz_uint growing) { 4838 if (new_size > pArray->m_capacity) { 4839 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) 4840 return MZ_FALSE; 4841 } 4842 pArray->m_size = new_size; 4843 return MZ_TRUE; 4844} 4845 4846static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, 4847 mz_zip_array *pArray, 4848 size_t n) { 4849 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); 4850} 4851 4852static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, 4853 mz_zip_array *pArray, 4854 const void *pElements, 4855 size_t n) { 4856 size_t orig_size = pArray->m_size; 4857 if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) 4858 return MZ_FALSE; 4859 memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, 4860 pElements, n * pArray->m_element_size); 4861 return MZ_TRUE; 4862} 4863 4864#ifndef MINIZ_NO_TIME 4865static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) { 4866 struct tm tm; 4867 memset(&tm, 0, sizeof(tm)); 4868 tm.tm_isdst = -1; 4869 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; 4870 tm.tm_mon = ((dos_date >> 5) & 15) - 1; 4871 tm.tm_mday = dos_date & 31; 4872 tm.tm_hour = (dos_time >> 11) & 31; 4873 tm.tm_min = (dos_time >> 5) & 63; 4874 tm.tm_sec = (dos_time << 1) & 62; 4875 return mktime(&tm); 4876} 4877 4878static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, 4879 mz_uint16 *pDOS_date) { 4880#ifdef _MSC_VER 4881 struct tm tm_struct; 4882 struct tm *tm = &tm_struct; 4883 errno_t err = localtime_s(tm, &time); 4884 if (err) { 4885 *pDOS_date = 0; 4886 *pDOS_time = 0; 4887 return; 4888 } 4889#else 4890 struct tm *tm = localtime(&time); 4891#endif 4892 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + 4893 ((tm->tm_sec) >> 1)); 4894 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + 4895 ((tm->tm_mon + 1) << 5) + tm->tm_mday); 4896} 4897#endif 4898 4899#ifndef MINIZ_NO_STDIO 4900static mz_bool mz_zip_get_file_modified_time(const char *pFilename, 4901 mz_uint16 *pDOS_time, 4902 mz_uint16 *pDOS_date) { 4903#ifdef MINIZ_NO_TIME 4904 (void)pFilename; 4905 *pDOS_date = *pDOS_time = 0; 4906#else 4907 struct MZ_FILE_STAT_STRUCT file_stat; 4908 // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 4909 // bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. 4910 if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; 4911 mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); 4912#endif // #ifdef MINIZ_NO_TIME 4913 return MZ_TRUE; 4914} 4915 4916#ifndef MINIZ_NO_TIME 4917static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, 4918 time_t modified_time) { 4919 struct utimbuf t; 4920 t.actime = access_time; 4921 t.modtime = modified_time; 4922 return !utime(pFilename, &t); 4923} 4924#endif // #ifndef MINIZ_NO_TIME 4925#endif // #ifndef MINIZ_NO_STDIO 4926 4927static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, 4928 mz_uint32 flags) { 4929 (void)flags; 4930 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) 4931 return MZ_FALSE; 4932 4933 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; 4934 if (!pZip->m_pFree) pZip->m_pFree = def_free_func; 4935 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; 4936 4937 pZip->m_zip_mode = MZ_ZIP_MODE_READING; 4938 pZip->m_archive_size = 0; 4939 pZip->m_central_directory_file_ofs = 0; 4940 pZip->m_total_files = 0; 4941 4942 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( 4943 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) 4944 return MZ_FALSE; 4945 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); 4946 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, 4947 sizeof(mz_uint8)); 4948 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, 4949 sizeof(mz_uint32)); 4950 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, 4951 sizeof(mz_uint32)); 4952 return MZ_TRUE; 4953} 4954 4955static MZ_FORCEINLINE mz_bool 4956mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, 4957 const mz_zip_array *pCentral_dir_offsets, 4958 mz_uint l_index, mz_uint r_index) { 4959 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( 4960 pCentral_dir_array, mz_uint8, 4961 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, 4962 l_index)), 4963 *pE; 4964 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT( 4965 pCentral_dir_array, mz_uint8, 4966 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); 4967 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), 4968 r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); 4969 mz_uint8 l = 0, r = 0; 4970 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; 4971 pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; 4972 pE = pL + MZ_MIN(l_len, r_len); 4973 while (pL < pE) { 4974 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; 4975 pL++; 4976 pR++; 4977 } 4978 return (pL == pE) ? (l_len < r_len) : (l < r); 4979} 4980 4981#define MZ_SWAP_UINT32(a, b) \ 4982 do { \ 4983 mz_uint32 t = a; \ 4984 a = b; \ 4985 b = t; \ 4986 } \ 4987 MZ_MACRO_END 4988 4989// Heap sort of lowercased filenames, used to help accelerate plain central 4990// directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), 4991// but it could allocate memory.) 4992static void mz_zip_reader_sort_central_dir_offsets_by_filename( 4993 mz_zip_archive *pZip) { 4994 mz_zip_internal_state *pState = pZip->m_pState; 4995 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; 4996 const mz_zip_array *pCentral_dir = &pState->m_central_dir; 4997 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( 4998 &pState->m_sorted_central_dir_offsets, mz_uint32, 0); 4999 const int size = pZip->m_total_files; 5000 int start = (size - 2) >> 1, end; 5001 while (start >= 0) { 5002 int child, root = start; 5003 for (;;) { 5004 if ((child = (root << 1) + 1) >= size) break; 5005 child += 5006 (((child + 1) < size) && 5007 (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, 5008 pIndices[child], pIndices[child + 1]))); 5009 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, 5010 pIndices[root], pIndices[child])) 5011 break; 5012 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); 5013 root = child; 5014 } 5015 start--; 5016 } 5017 5018 end = size - 1; 5019 while (end > 0) { 5020 int child, root = 0; 5021 MZ_SWAP_UINT32(pIndices[end], pIndices[0]); 5022 for (;;) { 5023 if ((child = (root << 1) + 1) >= end) break; 5024 child += 5025 (((child + 1) < end) && 5026 mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, 5027 pIndices[child], pIndices[child + 1])); 5028 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, 5029 pIndices[root], pIndices[child])) 5030 break; 5031 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); 5032 root = child; 5033 } 5034 end--; 5035 } 5036} 5037 5038static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, 5039 mz_uint32 flags) { 5040 mz_uint cdir_size, num_this_disk, cdir_disk_index; 5041 mz_uint64 cdir_ofs; 5042 mz_int64 cur_file_ofs; 5043 const mz_uint8 *p; 5044 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; 5045 mz_uint8 *pBuf = (mz_uint8 *)buf_u32; 5046 mz_bool sort_central_dir = 5047 ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); 5048 // Basic sanity checks - reject files which are too small, and check the first 5049 // 4 bytes of the file to make sure a local header is there. 5050 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) 5051 return MZ_FALSE; 5052 // Find the end of central directory record by scanning the file from the end 5053 // towards the beginning. 5054 cur_file_ofs = 5055 MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); 5056 for (;;) { 5057 int i, 5058 n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); 5059 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) 5060 return MZ_FALSE; 5061 for (i = n - 4; i >= 0; --i) 5062 if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break; 5063 if (i >= 0) { 5064 cur_file_ofs += i; 5065 break; 5066 } 5067 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= 5068 (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) 5069 return MZ_FALSE; 5070 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); 5071 } 5072 // Read and verify the end of central directory record. 5073 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, 5074 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != 5075 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) 5076 return MZ_FALSE; 5077 if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != 5078 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || 5079 ((pZip->m_total_files = 5080 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != 5081 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) 5082 return MZ_FALSE; 5083 5084 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); 5085 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); 5086 if (((num_this_disk | cdir_disk_index) != 0) && 5087 ((num_this_disk != 1) || (cdir_disk_index != 1))) 5088 return MZ_FALSE; 5089 5090 if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < 5091 pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) 5092 return MZ_FALSE; 5093 5094 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); 5095 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE; 5096 5097 pZip->m_central_directory_file_ofs = cdir_ofs; 5098 5099 if (pZip->m_total_files) { 5100 mz_uint i, n; 5101 5102 // Read the entire central directory into a heap block, and allocate another 5103 // heap block to hold the unsorted central dir file record offsets, and 5104 // another to hold the sorted indices. 5105 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, 5106 MZ_FALSE)) || 5107 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, 5108 pZip->m_total_files, MZ_FALSE))) 5109 return MZ_FALSE; 5110 5111 if (sort_central_dir) { 5112 if (!mz_zip_array_resize(pZip, 5113 &pZip->m_pState->m_sorted_central_dir_offsets, 5114 pZip->m_total_files, MZ_FALSE)) 5115 return MZ_FALSE; 5116 } 5117 5118 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, 5119 pZip->m_pState->m_central_dir.m_p, 5120 cdir_size) != cdir_size) 5121 return MZ_FALSE; 5122 5123 // Now create an index into the central directory file records, do some 5124 // basic sanity checking on each record, and check for zip64 entries (which 5125 // are not yet supported). 5126 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; 5127 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { 5128 mz_uint total_header_size, comp_size, decomp_size, disk_index; 5129 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || 5130 (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) 5131 return MZ_FALSE; 5132 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, 5133 i) = 5134 (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); 5135 if (sort_central_dir) 5136 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, 5137 mz_uint32, i) = i; 5138 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); 5139 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); 5140 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && 5141 (decomp_size != comp_size)) || 5142 (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || 5143 (comp_size == 0xFFFFFFFF)) 5144 return MZ_FALSE; 5145 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); 5146 if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE; 5147 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + 5148 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) 5149 return MZ_FALSE; 5150 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + 5151 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + 5152 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + 5153 MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > 5154 n) 5155 return MZ_FALSE; 5156 n -= total_header_size; 5157 p += total_header_size; 5158 } 5159 } 5160 5161 if (sort_central_dir) 5162 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); 5163 5164 return MZ_TRUE; 5165} 5166 5167mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, 5168 mz_uint32 flags) { 5169 if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE; 5170 if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; 5171 pZip->m_archive_size = size; 5172 if (!mz_zip_reader_read_central_dir(pZip, flags)) { 5173 mz_zip_reader_end(pZip); 5174 return MZ_FALSE; 5175 } 5176 return MZ_TRUE; 5177} 5178 5179static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, 5180 void *pBuf, size_t n) { 5181 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; 5182 size_t s = (file_ofs >= pZip->m_archive_size) 5183 ? 0 5184 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); 5185 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); 5186 return s; 5187} 5188 5189mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, 5190 size_t size, mz_uint32 flags) { 5191 if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; 5192 pZip->m_archive_size = size; 5193 pZip->m_pRead = mz_zip_mem_read_func; 5194 pZip->m_pIO_opaque = pZip; 5195#ifdef __cplusplus 5196 pZip->m_pState->m_pMem = const_cast<void *>(pMem); 5197#else 5198 pZip->m_pState->m_pMem = (void *)pMem; 5199#endif 5200 pZip->m_pState->m_mem_size = size; 5201 if (!mz_zip_reader_read_central_dir(pZip, flags)) { 5202 mz_zip_reader_end(pZip); 5203 return MZ_FALSE; 5204 } 5205 return MZ_TRUE; 5206} 5207 5208#ifndef MINIZ_NO_STDIO 5209static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, 5210 void *pBuf, size_t n) { 5211 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; 5212 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); 5213 if (((mz_int64)file_ofs < 0) || 5214 (((cur_ofs != (mz_int64)file_ofs)) && 5215 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) 5216 return 0; 5217 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); 5218} 5219 5220mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, 5221 mz_uint32 flags) { 5222 mz_uint64 file_size; 5223 MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); 5224 if (!pFile) return MZ_FALSE; 5225 if (MZ_FSEEK64(pFile, 0, SEEK_END)) { 5226 MZ_FCLOSE(pFile); 5227 return MZ_FALSE; 5228 } 5229 file_size = MZ_FTELL64(pFile); 5230 if (!mz_zip_reader_init_internal(pZip, flags)) { 5231 MZ_FCLOSE(pFile); 5232 return MZ_FALSE; 5233 } 5234 pZip->m_pRead = mz_zip_file_read_func; 5235 pZip->m_pIO_opaque = pZip; 5236 pZip->m_pState->m_pFile = pFile; 5237 pZip->m_archive_size = file_size; 5238 if (!mz_zip_reader_read_central_dir(pZip, flags)) { 5239 mz_zip_reader_end(pZip); 5240 return MZ_FALSE; 5241 } 5242 return MZ_TRUE; 5243} 5244#endif // #ifndef MINIZ_NO_STDIO 5245 5246mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { 5247 return pZip ? pZip->m_total_files : 0; 5248} 5249 5250static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh( 5251 mz_zip_archive *pZip, mz_uint file_index) { 5252 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || 5253 (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) 5254 return NULL; 5255 return &MZ_ZIP_ARRAY_ELEMENT( 5256 &pZip->m_pState->m_central_dir, mz_uint8, 5257 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, 5258 file_index)); 5259} 5260 5261mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, 5262 mz_uint file_index) { 5263 mz_uint m_bit_flag; 5264 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); 5265 if (!p) return MZ_FALSE; 5266 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); 5267 return (m_bit_flag & 1); 5268} 5269 5270mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, 5271 mz_uint file_index) { 5272 mz_uint filename_len, external_attr; 5273 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); 5274 if (!p) return MZ_FALSE; 5275 5276 // First see if the filename ends with a '/' character. 5277 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); 5278 if (filename_len) { 5279 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') 5280 return MZ_TRUE; 5281 } 5282 5283 // Bugfix: This code was also checking if the internal attribute was non-zero, 5284 // which wasn't correct. 5285 // Most/all zip writers (hopefully) set DOS file/directory attributes in the 5286 // low 16-bits, so check for the DOS directory flag and ignore the source OS 5287 // ID in the created by field. 5288 // FIXME: Remove this check? Is it necessary - we already check the filename. 5289 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); 5290 if ((external_attr & 0x10) != 0) return MZ_TRUE; 5291 5292 return MZ_FALSE; 5293} 5294 5295mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, 5296 mz_zip_archive_file_stat *pStat) { 5297 mz_uint n; 5298 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); 5299 if ((!p) || (!pStat)) return MZ_FALSE; 5300 5301 // Unpack the central directory record. 5302 pStat->m_file_index = file_index; 5303 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT( 5304 &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); 5305 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); 5306 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); 5307 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); 5308 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); 5309#ifndef MINIZ_NO_TIME 5310 pStat->m_time = 5311 mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), 5312 MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); 5313#endif 5314 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); 5315 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); 5316 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); 5317 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); 5318 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); 5319 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); 5320 5321 // Copy as much of the filename and comment as possible. 5322 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); 5323 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); 5324 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); 5325 pStat->m_filename[n] = '\0'; 5326 5327 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); 5328 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); 5329 pStat->m_comment_size = n; 5330 memcpy(pStat->m_comment, 5331 p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + 5332 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + 5333 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), 5334 n); 5335 pStat->m_comment[n] = '\0'; 5336 5337 return MZ_TRUE; 5338} 5339 5340mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, 5341 char *pFilename, mz_uint filename_buf_size) { 5342 mz_uint n; 5343 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); 5344 if (!p) { 5345 if (filename_buf_size) pFilename[0] = '\0'; 5346 return 0; 5347 } 5348 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); 5349 if (filename_buf_size) { 5350 n = MZ_MIN(n, filename_buf_size - 1); 5351 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); 5352 pFilename[n] = '\0'; 5353 } 5354 return n + 1; 5355} 5356 5357static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, 5358 const char *pB, 5359 mz_uint len, 5360 mz_uint flags) { 5361 mz_uint i; 5362 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); 5363 for (i = 0; i < len; ++i) 5364 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE; 5365 return MZ_TRUE; 5366} 5367 5368static MZ_FORCEINLINE int mz_zip_reader_filename_compare( 5369 const mz_zip_array *pCentral_dir_array, 5370 const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, 5371 mz_uint r_len) { 5372 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( 5373 pCentral_dir_array, mz_uint8, 5374 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, 5375 l_index)), 5376 *pE; 5377 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); 5378 mz_uint8 l = 0, r = 0; 5379 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; 5380 pE = pL + MZ_MIN(l_len, r_len); 5381 while (pL < pE) { 5382 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; 5383 pL++; 5384 pR++; 5385 } 5386 return (pL == pE) ? (int)(l_len - r_len) : (l - r); 5387} 5388 5389static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, 5390 const char *pFilename) { 5391 mz_zip_internal_state *pState = pZip->m_pState; 5392 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; 5393 const mz_zip_array *pCentral_dir = &pState->m_central_dir; 5394 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( 5395 &pState->m_sorted_central_dir_offsets, mz_uint32, 0); 5396 const int size = pZip->m_total_files; 5397 const mz_uint filename_len = (mz_uint)strlen(pFilename); 5398 int l = 0, h = size - 1; 5399 while (l <= h) { 5400 int m = (l + h) >> 1, file_index = pIndices[m], 5401 comp = 5402 mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, 5403 file_index, pFilename, filename_len); 5404 if (!comp) 5405 return file_index; 5406 else if (comp < 0) 5407 l = m + 1; 5408 else 5409 h = m - 1; 5410 } 5411 return -1; 5412} 5413 5414int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, 5415 const char *pComment, mz_uint flags) { 5416 mz_uint file_index; 5417 size_t name_len, comment_len; 5418 if ((!pZip) || (!pZip->m_pState) || (!pName) || 5419 (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) 5420 return -1; 5421 if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && 5422 (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) 5423 return mz_zip_reader_locate_file_binary_search(pZip, pName); 5424 name_len = strlen(pName); 5425 if (name_len > 0xFFFF) return -1; 5426 comment_len = pComment ? strlen(pComment) : 0; 5427 if (comment_len > 0xFFFF) return -1; 5428 for (file_index = 0; file_index < pZip->m_total_files; file_index++) { 5429 const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT( 5430 &pZip->m_pState->m_central_dir, mz_uint8, 5431 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, 5432 file_index)); 5433 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); 5434 const char *pFilename = 5435 (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; 5436 if (filename_len < name_len) continue; 5437 if (comment_len) { 5438 mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), 5439 file_comment_len = 5440 MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); 5441 const char *pFile_comment = pFilename + filename_len + file_extra_len; 5442 if ((file_comment_len != comment_len) || 5443 (!mz_zip_reader_string_equal(pComment, pFile_comment, 5444 file_comment_len, flags))) 5445 continue; 5446 } 5447 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { 5448 int ofs = filename_len - 1; 5449 do { 5450 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || 5451 (pFilename[ofs] == ':')) 5452 break; 5453 } while (--ofs >= 0); 5454 ofs++; 5455 pFilename += ofs; 5456 filename_len -= ofs; 5457 } 5458 if ((filename_len == name_len) && 5459 (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) 5460 return file_index; 5461 } 5462 return -1; 5463} 5464 5465mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, 5466 mz_uint file_index, void *pBuf, 5467 size_t buf_size, mz_uint flags, 5468 void *pUser_read_buf, 5469 size_t user_read_buf_size) { 5470 int status = TINFL_STATUS_DONE; 5471 mz_uint64 needed_size, cur_file_ofs, comp_remaining, 5472 out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; 5473 mz_zip_archive_file_stat file_stat; 5474 void *pRead_buf; 5475 mz_uint32 5476 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / 5477 sizeof(mz_uint32)]; 5478 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; 5479 tinfl_decompressor inflator; 5480 5481 if ((buf_size) && (!pBuf)) return MZ_FALSE; 5482 5483 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; 5484 5485 // Empty file, or a directory (but not always a directory - I've seen odd zips 5486 // with directories that have compressed data which inflates to 0 bytes) 5487 if (!file_stat.m_comp_size) return MZ_TRUE; 5488 5489 // Entry is a subdirectory (I've seen old zips with dir entries which have 5490 // compressed deflate data which inflates to 0 bytes, but these entries claim 5491 // to uncompress to 512 bytes in the headers). 5492 // I'm torn how to handle this case - should it fail instead? 5493 if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; 5494 5495 // Encryption and patch files are not supported. 5496 if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; 5497 5498 // This function only supports stored and deflate. 5499 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && 5500 (file_stat.m_method != MZ_DEFLATED)) 5501 return MZ_FALSE; 5502 5503 // Ensure supplied output buffer is large enough. 5504 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size 5505 : file_stat.m_uncomp_size; 5506 if (buf_size < needed_size) return MZ_FALSE; 5507 5508 // Read and parse the local directory entry. 5509 cur_file_ofs = file_stat.m_local_header_ofs; 5510 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, 5511 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != 5512 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) 5513 return MZ_FALSE; 5514 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) 5515 return MZ_FALSE; 5516 5517 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + 5518 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + 5519 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); 5520 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) 5521 return MZ_FALSE; 5522 5523 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { 5524 // The file is stored or the caller has requested the compressed data. 5525 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, 5526 (size_t)needed_size) != needed_size) 5527 return MZ_FALSE; 5528 return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || 5529 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, 5530 (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); 5531 } 5532 5533 // Decompress the file either directly from memory or from a file input 5534 // buffer. 5535 tinfl_init(&inflator); 5536 5537 if (pZip->m_pState->m_pMem) { 5538 // Read directly from the archive in memory. 5539 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; 5540 read_buf_size = read_buf_avail = file_stat.m_comp_size; 5541 comp_remaining = 0; 5542 } else if (pUser_read_buf) { 5543 // Use a user provided read buffer. 5544 if (!user_read_buf_size) return MZ_FALSE; 5545 pRead_buf = (mz_uint8 *)pUser_read_buf; 5546 read_buf_size = user_read_buf_size; 5547 read_buf_avail = 0; 5548 comp_remaining = file_stat.m_comp_size; 5549 } else { 5550 // Temporarily allocate a read buffer. 5551 read_buf_size = 5552 MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); 5553#ifdef _MSC_VER 5554 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && 5555 (read_buf_size > 0x7FFFFFFF)) 5556#else 5557 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) 5558#endif 5559 return MZ_FALSE; 5560 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, 5561 (size_t)read_buf_size))) 5562 return MZ_FALSE; 5563 read_buf_avail = 0; 5564 comp_remaining = file_stat.m_comp_size; 5565 } 5566 5567 do { 5568 size_t in_buf_size, 5569 out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); 5570 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { 5571 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); 5572 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, 5573 (size_t)read_buf_avail) != read_buf_avail) { 5574 status = TINFL_STATUS_FAILED; 5575 break; 5576 } 5577 cur_file_ofs += read_buf_avail; 5578 comp_remaining -= read_buf_avail; 5579 read_buf_ofs = 0; 5580 } 5581 in_buf_size = (size_t)read_buf_avail; 5582 status = tinfl_decompress( 5583 &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, 5584 (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, 5585 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | 5586 (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); 5587 read_buf_avail -= in_buf_size; 5588 read_buf_ofs += in_buf_size; 5589 out_buf_ofs += out_buf_size; 5590 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); 5591 5592 if (status == TINFL_STATUS_DONE) { 5593 // Make sure the entire file was decompressed, and check its CRC. 5594 if ((out_buf_ofs != file_stat.m_uncomp_size) || 5595 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, 5596 (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) 5597 status = TINFL_STATUS_FAILED; 5598 } 5599 5600 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) 5601 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); 5602 5603 return status == TINFL_STATUS_DONE; 5604} 5605 5606mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( 5607 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, 5608 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { 5609 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); 5610 if (file_index < 0) return MZ_FALSE; 5611 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, 5612 flags, pUser_read_buf, 5613 user_read_buf_size); 5614} 5615 5616mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, 5617 void *pBuf, size_t buf_size, 5618 mz_uint flags) { 5619 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, 5620 flags, NULL, 0); 5621} 5622 5623mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, 5624 const char *pFilename, void *pBuf, 5625 size_t buf_size, mz_uint flags) { 5626 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, 5627 buf_size, flags, NULL, 0); 5628} 5629 5630void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, 5631 size_t *pSize, mz_uint flags) { 5632 mz_uint64 comp_size, uncomp_size, alloc_size; 5633 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); 5634 void *pBuf; 5635 5636 if (pSize) *pSize = 0; 5637 if (!p) return NULL; 5638 5639 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); 5640 uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); 5641 5642 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; 5643#ifdef _MSC_VER 5644 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) 5645#else 5646 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) 5647#endif 5648 return NULL; 5649 if (NULL == 5650 (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) 5651 return NULL; 5652 5653 if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, 5654 flags)) { 5655 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); 5656 return NULL; 5657 } 5658 5659 if (pSize) *pSize = (size_t)alloc_size; 5660 return pBuf; 5661} 5662 5663void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, 5664 const char *pFilename, size_t *pSize, 5665 mz_uint flags) { 5666 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); 5667 if (file_index < 0) { 5668 if (pSize) *pSize = 0; 5669 return MZ_FALSE; 5670 } 5671 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); 5672} 5673 5674mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, 5675 mz_uint file_index, 5676 mz_file_write_func pCallback, 5677 void *pOpaque, mz_uint flags) { 5678 int status = TINFL_STATUS_DONE; 5679 mz_uint file_crc32 = MZ_CRC32_INIT; 5680 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, 5681 out_buf_ofs = 0, cur_file_ofs; 5682 mz_zip_archive_file_stat file_stat; 5683 void *pRead_buf = NULL; 5684 void *pWrite_buf = NULL; 5685 mz_uint32 5686 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / 5687 sizeof(mz_uint32)]; 5688 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; 5689 5690 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; 5691 5692 // Empty file, or a directory (but not always a directory - I've seen odd zips 5693 // with directories that have compressed data which inflates to 0 bytes) 5694 if (!file_stat.m_comp_size) return MZ_TRUE; 5695 5696 // Entry is a subdirectory (I've seen old zips with dir entries which have 5697 // compressed deflate data which inflates to 0 bytes, but these entries claim 5698 // to uncompress to 512 bytes in the headers). 5699 // I'm torn how to handle this case - should it fail instead? 5700 if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; 5701 5702 // Encryption and patch files are not supported. 5703 if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; 5704 5705 // This function only supports stored and deflate. 5706 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && 5707 (file_stat.m_method != MZ_DEFLATED)) 5708 return MZ_FALSE; 5709 5710 // Read and parse the local directory entry. 5711 cur_file_ofs = file_stat.m_local_header_ofs; 5712 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, 5713 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != 5714 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) 5715 return MZ_FALSE; 5716 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) 5717 return MZ_FALSE; 5718 5719 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + 5720 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + 5721 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); 5722 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) 5723 return MZ_FALSE; 5724 5725 // Decompress the file either directly from memory or from a file input 5726 // buffer. 5727 if (pZip->m_pState->m_pMem) { 5728 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; 5729 read_buf_size = read_buf_avail = file_stat.m_comp_size; 5730 comp_remaining = 0; 5731 } else { 5732 read_buf_size = 5733 MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); 5734 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, 5735 (size_t)read_buf_size))) 5736 return MZ_FALSE; 5737 read_buf_avail = 0; 5738 comp_remaining = file_stat.m_comp_size; 5739 } 5740 5741 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { 5742 // The file is stored or the caller has requested the compressed data. 5743 if (pZip->m_pState->m_pMem) { 5744#ifdef _MSC_VER 5745 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && 5746 (file_stat.m_comp_size > 0xFFFFFFFF)) 5747#else 5748 if (((sizeof(size_t) == sizeof(mz_uint32))) && 5749 (file_stat.m_comp_size > 0xFFFFFFFF)) 5750#endif 5751 return MZ_FALSE; 5752 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, 5753 (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) 5754 status = TINFL_STATUS_FAILED; 5755 else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) 5756 file_crc32 = 5757 (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, 5758 (size_t)file_stat.m_comp_size); 5759 cur_file_ofs += file_stat.m_comp_size; 5760 out_buf_ofs += file_stat.m_comp_size; 5761 comp_remaining = 0; 5762 } else { 5763 while (comp_remaining) { 5764 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); 5765 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, 5766 (size_t)read_buf_avail) != read_buf_avail) { 5767 status = TINFL_STATUS_FAILED; 5768 break; 5769 } 5770 5771 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) 5772 file_crc32 = (mz_uint32)mz_crc32( 5773 file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); 5774 5775 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, 5776 (size_t)read_buf_avail) != read_buf_avail) { 5777 status = TINFL_STATUS_FAILED; 5778 break; 5779 } 5780 cur_file_ofs += read_buf_avail; 5781 out_buf_ofs += read_buf_avail; 5782 comp_remaining -= read_buf_avail; 5783 } 5784 } 5785 } else { 5786 tinfl_decompressor inflator; 5787 tinfl_init(&inflator); 5788 5789 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, 5790 TINFL_LZ_DICT_SIZE))) 5791 status = TINFL_STATUS_FAILED; 5792 else { 5793 do { 5794 mz_uint8 *pWrite_buf_cur = 5795 (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); 5796 size_t in_buf_size, 5797 out_buf_size = 5798 TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); 5799 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { 5800 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); 5801 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, 5802 (size_t)read_buf_avail) != read_buf_avail) { 5803 status = TINFL_STATUS_FAILED; 5804 break; 5805 } 5806 cur_file_ofs += read_buf_avail; 5807 comp_remaining -= read_buf_avail; 5808 read_buf_ofs = 0; 5809 } 5810 5811 in_buf_size = (size_t)read_buf_avail; 5812 status = tinfl_decompress( 5813 &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, 5814 (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, 5815 comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); 5816 read_buf_avail -= in_buf_size; 5817 read_buf_ofs += in_buf_size; 5818 5819 if (out_buf_size) { 5820 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != 5821 out_buf_size) { 5822 status = TINFL_STATUS_FAILED; 5823 break; 5824 } 5825 file_crc32 = 5826 (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); 5827 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { 5828 status = TINFL_STATUS_FAILED; 5829 break; 5830 } 5831 } 5832 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || 5833 (status == TINFL_STATUS_HAS_MORE_OUTPUT)); 5834 } 5835 } 5836 5837 if ((status == TINFL_STATUS_DONE) && 5838 (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { 5839 // Make sure the entire file was decompressed, and check its CRC. 5840 if ((out_buf_ofs != file_stat.m_uncomp_size) || 5841 (file_crc32 != file_stat.m_crc32)) 5842 status = TINFL_STATUS_FAILED; 5843 } 5844 5845 if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); 5846 if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); 5847 5848 return status == TINFL_STATUS_DONE; 5849} 5850 5851mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, 5852 const char *pFilename, 5853 mz_file_write_func pCallback, 5854 void *pOpaque, mz_uint flags) { 5855 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); 5856 if (file_index < 0) return MZ_FALSE; 5857 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, 5858 flags); 5859} 5860 5861#ifndef MINIZ_NO_STDIO 5862static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, 5863 const void *pBuf, size_t n) { 5864 (void)ofs; 5865 return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); 5866} 5867 5868mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, 5869 const char *pDst_filename, 5870 mz_uint flags) { 5871 mz_bool status; 5872 mz_zip_archive_file_stat file_stat; 5873 MZ_FILE *pFile; 5874 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; 5875 pFile = MZ_FOPEN(pDst_filename, "wb"); 5876 if (!pFile) return MZ_FALSE; 5877 status = mz_zip_reader_extract_to_callback( 5878 pZip, file_index, mz_zip_file_write_callback, pFile, flags); 5879 if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE; 5880#ifndef MINIZ_NO_TIME 5881 if (status) 5882 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); 5883#endif 5884 return status; 5885} 5886#endif // #ifndef MINIZ_NO_STDIO 5887 5888mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { 5889 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || 5890 (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) 5891 return MZ_FALSE; 5892 5893 if (pZip->m_pState) { 5894 mz_zip_internal_state *pState = pZip->m_pState; 5895 pZip->m_pState = NULL; 5896 mz_zip_array_clear(pZip, &pState->m_central_dir); 5897 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); 5898 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); 5899 5900#ifndef MINIZ_NO_STDIO 5901 if (pState->m_pFile) { 5902 MZ_FCLOSE(pState->m_pFile); 5903 pState->m_pFile = NULL; 5904 } 5905#endif // #ifndef MINIZ_NO_STDIO 5906 5907 pZip->m_pFree(pZip->m_pAlloc_opaque, pState); 5908 } 5909 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; 5910 5911 return MZ_TRUE; 5912} 5913 5914#ifndef MINIZ_NO_STDIO 5915mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, 5916 const char *pArchive_filename, 5917 const char *pDst_filename, 5918 mz_uint flags) { 5919 int file_index = 5920 mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); 5921 if (file_index < 0) return MZ_FALSE; 5922 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); 5923} 5924#endif 5925 5926// ------------------- .ZIP archive writing 5927 5928#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS 5929 5930static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { 5931 p[0] = (mz_uint8)v; 5932 p[1] = (mz_uint8)(v >> 8); 5933} 5934static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { 5935 p[0] = (mz_uint8)v; 5936 p[1] = (mz_uint8)(v >> 8); 5937 p[2] = (mz_uint8)(v >> 16); 5938 p[3] = (mz_uint8)(v >> 24); 5939} 5940#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) 5941#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) 5942 5943mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { 5944 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || 5945 (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) 5946 return MZ_FALSE; 5947 5948 if (pZip->m_file_offset_alignment) { 5949 // Ensure user specified file offset alignment is a power of 2. 5950 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) 5951 return MZ_FALSE; 5952 } 5953 5954 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; 5955 if (!pZip->m_pFree) pZip->m_pFree = def_free_func; 5956 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; 5957 5958 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; 5959 pZip->m_archive_size = existing_size; 5960 pZip->m_central_directory_file_ofs = 0; 5961 pZip->m_total_files = 0; 5962 5963 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( 5964 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) 5965 return MZ_FALSE; 5966 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); 5967 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, 5968 sizeof(mz_uint8)); 5969 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, 5970 sizeof(mz_uint32)); 5971 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, 5972 sizeof(mz_uint32)); 5973 return MZ_TRUE; 5974} 5975 5976static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, 5977 const void *pBuf, size_t n) { 5978 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; 5979 mz_zip_internal_state *pState = pZip->m_pState; 5980 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); 5981#ifdef _MSC_VER 5982 if ((!n) || 5983 ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) 5984#else 5985 if ((!n) || 5986 ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) 5987#endif 5988 return 0; 5989 if (new_size > pState->m_mem_capacity) { 5990 void *pNew_block; 5991 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); 5992 while (new_capacity < new_size) new_capacity *= 2; 5993 if (NULL == (pNew_block = pZip->m_pRealloc( 5994 pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) 5995 return 0; 5996 pState->m_pMem = pNew_block; 5997 pState->m_mem_capacity = new_capacity; 5998 } 5999 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); 6000 pState->m_mem_size = (size_t)new_size; 6001 return n; 6002} 6003 6004mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, 6005 size_t size_to_reserve_at_beginning, 6006 size_t initial_allocation_size) { 6007 pZip->m_pWrite = mz_zip_heap_write_func; 6008 pZip->m_pIO_opaque = pZip; 6009 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; 6010 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, 6011 size_to_reserve_at_beginning))) { 6012 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc( 6013 pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { 6014 mz_zip_writer_end(pZip); 6015 return MZ_FALSE; 6016 } 6017 pZip->m_pState->m_mem_capacity = initial_allocation_size; 6018 } 6019 return MZ_TRUE; 6020} 6021 6022#ifndef MINIZ_NO_STDIO 6023static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, 6024 const void *pBuf, size_t n) { 6025 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; 6026 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); 6027 if (((mz_int64)file_ofs < 0) || 6028 (((cur_ofs != (mz_int64)file_ofs)) && 6029 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) 6030 return 0; 6031 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); 6032} 6033 6034mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, 6035 mz_uint64 size_to_reserve_at_beginning) { 6036 MZ_FILE *pFile; 6037 pZip->m_pWrite = mz_zip_file_write_func; 6038 pZip->m_pIO_opaque = pZip; 6039 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; 6040 if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) { 6041 mz_zip_writer_end(pZip); 6042 return MZ_FALSE; 6043 } 6044 pZip->m_pState->m_pFile = pFile; 6045 if (size_to_reserve_at_beginning) { 6046 mz_uint64 cur_ofs = 0; 6047 char buf[4096]; 6048 MZ_CLEAR_OBJ(buf); 6049 do { 6050 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); 6051 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { 6052 mz_zip_writer_end(pZip); 6053 return MZ_FALSE; 6054 } 6055 cur_ofs += n; 6056 size_to_reserve_at_beginning -= n; 6057 } while (size_to_reserve_at_beginning); 6058 } 6059 return MZ_TRUE; 6060} 6061#endif // #ifndef MINIZ_NO_STDIO 6062 6063mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, 6064 const char *pFilename) { 6065 mz_zip_internal_state *pState; 6066 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) 6067 return MZ_FALSE; 6068 // No sense in trying to write to an archive that's already at the support max 6069 // size 6070 if ((pZip->m_total_files == 0xFFFF) || 6071 ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + 6072 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) 6073 return MZ_FALSE; 6074 6075 pState = pZip->m_pState; 6076 6077 if (pState->m_pFile) { 6078#ifdef MINIZ_NO_STDIO 6079 pFilename; 6080 return MZ_FALSE; 6081#else 6082 // Archive is being read from stdio - try to reopen as writable. 6083 if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; 6084 if (!pFilename) return MZ_FALSE; 6085 pZip->m_pWrite = mz_zip_file_write_func; 6086 if (NULL == 6087 (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { 6088 // The mz_zip_archive is now in a bogus state because pState->m_pFile is 6089 // NULL, so just close it. 6090 mz_zip_reader_end(pZip); 6091 return MZ_FALSE; 6092 } 6093#endif // #ifdef MINIZ_NO_STDIO 6094 } else if (pState->m_pMem) { 6095 // Archive lives in a memory block. Assume it's from the heap that we can 6096 // resize using the realloc callback. 6097 if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; 6098 pState->m_mem_capacity = pState->m_mem_size; 6099 pZip->m_pWrite = mz_zip_heap_write_func; 6100 } 6101 // Archive is being read via a user provided read function - make sure the 6102 // user has specified a write function too. 6103 else if (!pZip->m_pWrite) 6104 return MZ_FALSE; 6105 6106 // Start writing new files at the archive's current central directory 6107 // location. 6108 pZip->m_archive_size = pZip->m_central_directory_file_ofs; 6109 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; 6110 pZip->m_central_directory_file_ofs = 0; 6111 6112 return MZ_TRUE; 6113} 6114 6115mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, 6116 const void *pBuf, size_t buf_size, 6117 mz_uint level_and_flags) { 6118 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, 6119 level_and_flags, 0, 0); 6120} 6121 6122typedef struct { 6123 mz_zip_archive *m_pZip; 6124 mz_uint64 m_cur_archive_file_ofs; 6125 mz_uint64 m_comp_size; 6126} mz_zip_writer_add_state; 6127 6128static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, 6129 void *pUser) { 6130 mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; 6131 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, 6132 pState->m_cur_archive_file_ofs, pBuf, 6133 len) != len) 6134 return MZ_FALSE; 6135 pState->m_cur_archive_file_ofs += len; 6136 pState->m_comp_size += len; 6137 return MZ_TRUE; 6138} 6139 6140static mz_bool mz_zip_writer_create_local_dir_header( 6141 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, 6142 mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, 6143 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, 6144 mz_uint16 dos_time, mz_uint16 dos_date) { 6145 (void)pZip; 6146 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); 6147 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); 6148 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); 6149 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); 6150 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); 6151 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); 6152 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); 6153 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); 6154 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); 6155 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); 6156 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); 6157 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); 6158 return MZ_TRUE; 6159} 6160 6161static mz_bool mz_zip_writer_create_central_dir_header( 6162 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, 6163 mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, 6164 mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, 6165 mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, 6166 mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { 6167 (void)pZip; 6168 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); 6169 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); 6170 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); 6171 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); 6172 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); 6173 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); 6174 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); 6175 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); 6176 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); 6177 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); 6178 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); 6179 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); 6180 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); 6181 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); 6182 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); 6183 return MZ_TRUE; 6184} 6185 6186static mz_bool mz_zip_writer_add_to_central_dir( 6187 mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, 6188 const void *pExtra, mz_uint16 extra_size, const void *pComment, 6189 mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, 6190 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, 6191 mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, 6192 mz_uint32 ext_attributes) { 6193 mz_zip_internal_state *pState = pZip->m_pState; 6194 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; 6195 size_t orig_central_dir_size = pState->m_central_dir.m_size; 6196 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; 6197 6198 // No zip64 support yet 6199 if ((local_header_ofs > 0xFFFFFFFF) || 6200 (((mz_uint64)pState->m_central_dir.m_size + 6201 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + 6202 comment_size) > 0xFFFFFFFF)) 6203 return MZ_FALSE; 6204 6205 if (!mz_zip_writer_create_central_dir_header( 6206 pZip, central_dir_header, filename_size, extra_size, comment_size, 6207 uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, 6208 dos_date, local_header_ofs, ext_attributes)) 6209 return MZ_FALSE; 6210 6211 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, 6212 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || 6213 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, 6214 filename_size)) || 6215 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, 6216 extra_size)) || 6217 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, 6218 comment_size)) || 6219 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, 6220 ¢ral_dir_ofs, 1))) { 6221 // Try to push the central directory array back into its original state. 6222 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, 6223 MZ_FALSE); 6224 return MZ_FALSE; 6225 } 6226 6227 return MZ_TRUE; 6228} 6229 6230static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { 6231 // Basic ZIP archive filename validity checks: Valid filenames cannot start 6232 // with a forward slash, cannot contain a drive letter, and cannot use 6233 // DOS-style backward slashes. 6234 if (*pArchive_name == '/') return MZ_FALSE; 6235 while (*pArchive_name) { 6236 if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE; 6237 pArchive_name++; 6238 } 6239 return MZ_TRUE; 6240} 6241 6242static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment( 6243 mz_zip_archive *pZip) { 6244 mz_uint32 n; 6245 if (!pZip->m_file_offset_alignment) return 0; 6246 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); 6247 return (pZip->m_file_offset_alignment - n) & 6248 (pZip->m_file_offset_alignment - 1); 6249} 6250 6251static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, 6252 mz_uint64 cur_file_ofs, mz_uint32 n) { 6253 char buf[4096]; 6254 memset(buf, 0, MZ_MIN(sizeof(buf), n)); 6255 while (n) { 6256 mz_uint32 s = MZ_MIN(sizeof(buf), n); 6257 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) 6258 return MZ_FALSE; 6259 cur_file_ofs += s; 6260 n -= s; 6261 } 6262 return MZ_TRUE; 6263} 6264 6265mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, 6266 const char *pArchive_name, const void *pBuf, 6267 size_t buf_size, const void *pComment, 6268 mz_uint16 comment_size, 6269 mz_uint level_and_flags, mz_uint64 uncomp_size, 6270 mz_uint32 uncomp_crc32) { 6271 mz_uint16 method = 0, dos_time = 0, dos_date = 0; 6272 mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; 6273 mz_uint64 local_dir_header_ofs = pZip->m_archive_size, 6274 cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; 6275 size_t archive_name_size; 6276 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; 6277 tdefl_compressor *pComp = NULL; 6278 mz_bool store_data_uncompressed; 6279 mz_zip_internal_state *pState; 6280 6281 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; 6282 level = level_and_flags & 0xF; 6283 store_data_uncompressed = 6284 ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); 6285 6286 if ((!pZip) || (!pZip->m_pState) || 6287 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || 6288 (!pArchive_name) || ((comment_size) && (!pComment)) || 6289 (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) 6290 return MZ_FALSE; 6291 6292 pState = pZip->m_pState; 6293 6294 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) 6295 return MZ_FALSE; 6296 // No zip64 support yet 6297 if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE; 6298 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; 6299 6300#ifndef MINIZ_NO_TIME 6301 { 6302 time_t cur_time; 6303 time(&cur_time); 6304 mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); 6305 } 6306#endif // #ifndef MINIZ_NO_TIME 6307 6308 archive_name_size = strlen(pArchive_name); 6309 if (archive_name_size > 0xFFFF) return MZ_FALSE; 6310 6311 num_alignment_padding_bytes = 6312 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); 6313 6314 // no zip64 support yet 6315 if ((pZip->m_total_files == 0xFFFF) || 6316 ((pZip->m_archive_size + num_alignment_padding_bytes + 6317 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + 6318 comment_size + archive_name_size) > 0xFFFFFFFF)) 6319 return MZ_FALSE; 6320 6321 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { 6322 // Set DOS Subdirectory attribute bit. 6323 ext_attributes |= 0x10; 6324 // Subdirectories cannot contain data. 6325 if ((buf_size) || (uncomp_size)) return MZ_FALSE; 6326 } 6327 6328 // Try to do any allocations before writing to the archive, so if an 6329 // allocation fails the file remains unmodified. (A good idea if we're doing 6330 // an in-place modification.) 6331 if ((!mz_zip_array_ensure_room( 6332 pZip, &pState->m_central_dir, 6333 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || 6334 (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) 6335 return MZ_FALSE; 6336 6337 if ((!store_data_uncompressed) && (buf_size)) { 6338 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc( 6339 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) 6340 return MZ_FALSE; 6341 } 6342 6343 if (!mz_zip_writer_write_zeros( 6344 pZip, cur_archive_file_ofs, 6345 num_alignment_padding_bytes + sizeof(local_dir_header))) { 6346 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); 6347 return MZ_FALSE; 6348 } 6349 local_dir_header_ofs += num_alignment_padding_bytes; 6350 if (pZip->m_file_offset_alignment) { 6351 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 6352 0); 6353 } 6354 cur_archive_file_ofs += 6355 num_alignment_padding_bytes + sizeof(local_dir_header); 6356 6357 MZ_CLEAR_OBJ(local_dir_header); 6358 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, 6359 archive_name_size) != archive_name_size) { 6360 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); 6361 return MZ_FALSE; 6362 } 6363 cur_archive_file_ofs += archive_name_size; 6364 6365 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { 6366 uncomp_crc32 = 6367 (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); 6368 uncomp_size = buf_size; 6369 if (uncomp_size <= 3) { 6370 level = 0; 6371 store_data_uncompressed = MZ_TRUE; 6372 } 6373 } 6374 6375 if (store_data_uncompressed) { 6376 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, 6377 buf_size) != buf_size) { 6378 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); 6379 return MZ_FALSE; 6380 } 6381 6382 cur_archive_file_ofs += buf_size; 6383 comp_size = buf_size; 6384 6385 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED; 6386 } else if (buf_size) { 6387 mz_zip_writer_add_state state; 6388 6389 state.m_pZip = pZip; 6390 state.m_cur_archive_file_ofs = cur_archive_file_ofs; 6391 state.m_comp_size = 0; 6392 6393 if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, 6394 tdefl_create_comp_flags_from_zip_params( 6395 level, -15, MZ_DEFAULT_STRATEGY)) != 6396 TDEFL_STATUS_OKAY) || 6397 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != 6398 TDEFL_STATUS_DONE)) { 6399 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); 6400 return MZ_FALSE; 6401 } 6402 6403 comp_size = state.m_comp_size; 6404 cur_archive_file_ofs = state.m_cur_archive_file_ofs; 6405 6406 method = MZ_DEFLATED; 6407 } 6408 6409 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); 6410 pComp = NULL; 6411 6412 // no zip64 support yet 6413 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) 6414 return MZ_FALSE; 6415 6416 if (!mz_zip_writer_create_local_dir_header( 6417 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, 6418 comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) 6419 return MZ_FALSE; 6420 6421 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, 6422 sizeof(local_dir_header)) != sizeof(local_dir_header)) 6423 return MZ_FALSE; 6424 6425 if (!mz_zip_writer_add_to_central_dir( 6426 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, 6427 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, 6428 dos_time, dos_date, local_dir_header_ofs, ext_attributes)) 6429 return MZ_FALSE; 6430 6431 pZip->m_total_files++; 6432 pZip->m_archive_size = cur_archive_file_ofs; 6433 6434 return MZ_TRUE; 6435} 6436 6437#ifndef MINIZ_NO_STDIO 6438mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, 6439 const char *pSrc_filename, const void *pComment, 6440 mz_uint16 comment_size, 6441 mz_uint level_and_flags) { 6442 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; 6443 mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; 6444 mz_uint64 local_dir_header_ofs = pZip->m_archive_size, 6445 cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, 6446 comp_size = 0; 6447 size_t archive_name_size; 6448 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; 6449 MZ_FILE *pSrc_file = NULL; 6450 6451 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; 6452 level = level_and_flags & 0xF; 6453 6454 if ((!pZip) || (!pZip->m_pState) || 6455 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || 6456 ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) 6457 return MZ_FALSE; 6458 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE; 6459 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; 6460 6461 archive_name_size = strlen(pArchive_name); 6462 if (archive_name_size > 0xFFFF) return MZ_FALSE; 6463 6464 num_alignment_padding_bytes = 6465 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); 6466 6467 // no zip64 support yet 6468 if ((pZip->m_total_files == 0xFFFF) || 6469 ((pZip->m_archive_size + num_alignment_padding_bytes + 6470 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + 6471 comment_size + archive_name_size) > 0xFFFFFFFF)) 6472 return MZ_FALSE; 6473 6474 if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) 6475 return MZ_FALSE; 6476 6477 pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); 6478 if (!pSrc_file) return MZ_FALSE; 6479 MZ_FSEEK64(pSrc_file, 0, SEEK_END); 6480 uncomp_size = MZ_FTELL64(pSrc_file); 6481 MZ_FSEEK64(pSrc_file, 0, SEEK_SET); 6482 6483 if (uncomp_size > 0xFFFFFFFF) { 6484 // No zip64 support yet 6485 MZ_FCLOSE(pSrc_file); 6486 return MZ_FALSE; 6487 } 6488 if (uncomp_size <= 3) level = 0; 6489 6490 if (!mz_zip_writer_write_zeros( 6491 pZip, cur_archive_file_ofs, 6492 num_alignment_padding_bytes + sizeof(local_dir_header))) { 6493 MZ_FCLOSE(pSrc_file); 6494 return MZ_FALSE; 6495 } 6496 local_dir_header_ofs += num_alignment_padding_bytes; 6497 if (pZip->m_file_offset_alignment) { 6498 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 6499 0); 6500 } 6501 cur_archive_file_ofs += 6502 num_alignment_padding_bytes + sizeof(local_dir_header); 6503 6504 MZ_CLEAR_OBJ(local_dir_header); 6505 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, 6506 archive_name_size) != archive_name_size) { 6507 MZ_FCLOSE(pSrc_file); 6508 return MZ_FALSE; 6509 } 6510 cur_archive_file_ofs += archive_name_size; 6511 6512 if (uncomp_size) { 6513 mz_uint64 uncomp_remaining = uncomp_size; 6514 void *pRead_buf = 6515 pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); 6516 if (!pRead_buf) { 6517 MZ_FCLOSE(pSrc_file); 6518 return MZ_FALSE; 6519 } 6520 6521 if (!level) { 6522 while (uncomp_remaining) { 6523 mz_uint n = 6524 (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); 6525 if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || 6526 (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, 6527 n) != n)) { 6528 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); 6529 MZ_FCLOSE(pSrc_file); 6530 return MZ_FALSE; 6531 } 6532 uncomp_crc32 = 6533 (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); 6534 uncomp_remaining -= n; 6535 cur_archive_file_ofs += n; 6536 } 6537 comp_size = uncomp_size; 6538 } else { 6539 mz_bool result = MZ_FALSE; 6540 mz_zip_writer_add_state state; 6541 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc( 6542 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); 6543 if (!pComp) { 6544 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); 6545 MZ_FCLOSE(pSrc_file); 6546 return MZ_FALSE; 6547 } 6548 6549 state.m_pZip = pZip; 6550 state.m_cur_archive_file_ofs = cur_archive_file_ofs; 6551 state.m_comp_size = 0; 6552 6553 if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, 6554 tdefl_create_comp_flags_from_zip_params( 6555 level, -15, MZ_DEFAULT_STRATEGY)) != 6556 TDEFL_STATUS_OKAY) { 6557 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); 6558 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); 6559 MZ_FCLOSE(pSrc_file); 6560 return MZ_FALSE; 6561 } 6562 6563 for (;;) { 6564 size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, 6565 (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); 6566 tdefl_status status; 6567 6568 if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) 6569 break; 6570 6571 uncomp_crc32 = (mz_uint32)mz_crc32( 6572 uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); 6573 uncomp_remaining -= in_buf_size; 6574 6575 status = tdefl_compress_buffer( 6576 pComp, pRead_buf, in_buf_size, 6577 uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); 6578 if (status == TDEFL_STATUS_DONE) { 6579 result = MZ_TRUE; 6580 break; 6581 } else if (status != TDEFL_STATUS_OKAY) 6582 break; 6583 } 6584 6585 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); 6586 6587 if (!result) { 6588 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); 6589 MZ_FCLOSE(pSrc_file); 6590 return MZ_FALSE; 6591 } 6592 6593 comp_size = state.m_comp_size; 6594 cur_archive_file_ofs = state.m_cur_archive_file_ofs; 6595 6596 method = MZ_DEFLATED; 6597 } 6598 6599 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); 6600 } 6601 6602 MZ_FCLOSE(pSrc_file); 6603 pSrc_file = NULL; 6604 6605 // no zip64 support yet 6606 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) 6607 return MZ_FALSE; 6608 6609 if (!mz_zip_writer_create_local_dir_header( 6610 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, 6611 comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) 6612 return MZ_FALSE; 6613 6614 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, 6615 sizeof(local_dir_header)) != sizeof(local_dir_header)) 6616 return MZ_FALSE; 6617 6618 if (!mz_zip_writer_add_to_central_dir( 6619 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, 6620 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, 6621 dos_time, dos_date, local_dir_header_ofs, ext_attributes)) 6622 return MZ_FALSE; 6623 6624 pZip->m_total_files++; 6625 pZip->m_archive_size = cur_archive_file_ofs; 6626 6627 return MZ_TRUE; 6628} 6629#endif // #ifndef MINIZ_NO_STDIO 6630 6631mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, 6632 mz_zip_archive *pSource_zip, 6633 mz_uint file_index) { 6634 mz_uint n, bit_flags, num_alignment_padding_bytes; 6635 mz_uint64 comp_bytes_remaining, local_dir_header_ofs; 6636 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; 6637 mz_uint32 6638 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / 6639 sizeof(mz_uint32)]; 6640 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; 6641 mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; 6642 size_t orig_central_dir_size; 6643 mz_zip_internal_state *pState; 6644 void *pBuf; 6645 const mz_uint8 *pSrc_central_header; 6646 6647 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) 6648 return MZ_FALSE; 6649 if (NULL == 6650 (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) 6651 return MZ_FALSE; 6652 pState = pZip->m_pState; 6653 6654 num_alignment_padding_bytes = 6655 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); 6656 6657 // no zip64 support yet 6658 if ((pZip->m_total_files == 0xFFFF) || 6659 ((pZip->m_archive_size + num_alignment_padding_bytes + 6660 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 6661 0xFFFFFFFF)) 6662 return MZ_FALSE; 6663 6664 cur_src_file_ofs = 6665 MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); 6666 cur_dst_file_ofs = pZip->m_archive_size; 6667 6668 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, 6669 pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != 6670 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) 6671 return MZ_FALSE; 6672 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) 6673 return MZ_FALSE; 6674 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; 6675 6676 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, 6677 num_alignment_padding_bytes)) 6678 return MZ_FALSE; 6679 cur_dst_file_ofs += num_alignment_padding_bytes; 6680 local_dir_header_ofs = cur_dst_file_ofs; 6681 if (pZip->m_file_offset_alignment) { 6682 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 6683 0); 6684 } 6685 6686 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, 6687 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != 6688 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) 6689 return MZ_FALSE; 6690 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; 6691 6692 n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + 6693 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); 6694 comp_bytes_remaining = 6695 n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); 6696 6697 if (NULL == (pBuf = pZip->m_pAlloc( 6698 pZip->m_pAlloc_opaque, 1, 6699 (size_t)MZ_MAX(sizeof(mz_uint32) * 4, 6700 MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, 6701 comp_bytes_remaining))))) 6702 return MZ_FALSE; 6703 6704 while (comp_bytes_remaining) { 6705 n = (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); 6706 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, 6707 n) != n) { 6708 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); 6709 return MZ_FALSE; 6710 } 6711 cur_src_file_ofs += n; 6712 6713 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { 6714 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); 6715 return MZ_FALSE; 6716 } 6717 cur_dst_file_ofs += n; 6718 6719 comp_bytes_remaining -= n; 6720 } 6721 6722 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); 6723 if (bit_flags & 8) { 6724 // Copy data descriptor 6725 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, 6726 sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { 6727 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); 6728 return MZ_FALSE; 6729 } 6730 6731 n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); 6732 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { 6733 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); 6734 return MZ_FALSE; 6735 } 6736 6737 cur_src_file_ofs += n; 6738 cur_dst_file_ofs += n; 6739 } 6740 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); 6741 6742 // no zip64 support yet 6743 if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE; 6744 6745 orig_central_dir_size = pState->m_central_dir.m_size; 6746 6747 memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); 6748 MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, 6749 local_dir_header_ofs); 6750 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, 6751 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) 6752 return MZ_FALSE; 6753 6754 n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + 6755 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + 6756 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); 6757 if (!mz_zip_array_push_back( 6758 pZip, &pState->m_central_dir, 6759 pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) { 6760 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, 6761 MZ_FALSE); 6762 return MZ_FALSE; 6763 } 6764 6765 if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE; 6766 n = (mz_uint32)orig_central_dir_size; 6767 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { 6768 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, 6769 MZ_FALSE); 6770 return MZ_FALSE; 6771 } 6772 6773 pZip->m_total_files++; 6774 pZip->m_archive_size = cur_dst_file_ofs; 6775 6776 return MZ_TRUE; 6777} 6778 6779mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { 6780 mz_zip_internal_state *pState; 6781 mz_uint64 central_dir_ofs, central_dir_size; 6782 mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; 6783 6784 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) 6785 return MZ_FALSE; 6786 6787 pState = pZip->m_pState; 6788 6789 // no zip64 support yet 6790 if ((pZip->m_total_files > 0xFFFF) || 6791 ((pZip->m_archive_size + pState->m_central_dir.m_size + 6792 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) 6793 return MZ_FALSE; 6794 6795 central_dir_ofs = 0; 6796 central_dir_size = 0; 6797 if (pZip->m_total_files) { 6798 // Write central directory 6799 central_dir_ofs = pZip->m_archive_size; 6800 central_dir_size = pState->m_central_dir.m_size; 6801 pZip->m_central_directory_file_ofs = central_dir_ofs; 6802 if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, 6803 pState->m_central_dir.m_p, 6804 (size_t)central_dir_size) != central_dir_size) 6805 return MZ_FALSE; 6806 pZip->m_archive_size += central_dir_size; 6807 } 6808 6809 // Write end of central directory record 6810 MZ_CLEAR_OBJ(hdr); 6811 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, 6812 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); 6813 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, 6814 pZip->m_total_files); 6815 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); 6816 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); 6817 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); 6818 6819 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, 6820 sizeof(hdr)) != sizeof(hdr)) 6821 return MZ_FALSE; 6822#ifndef MINIZ_NO_STDIO 6823 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE; 6824#endif // #ifndef MINIZ_NO_STDIO 6825 6826 pZip->m_archive_size += sizeof(hdr); 6827 6828 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; 6829 return MZ_TRUE; 6830} 6831 6832mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, 6833 size_t *pSize) { 6834 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE; 6835 if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE; 6836 if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE; 6837 6838 *pBuf = pZip->m_pState->m_pMem; 6839 *pSize = pZip->m_pState->m_mem_size; 6840 pZip->m_pState->m_pMem = NULL; 6841 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; 6842 return MZ_TRUE; 6843} 6844 6845mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { 6846 mz_zip_internal_state *pState; 6847 mz_bool status = MZ_TRUE; 6848 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || 6849 ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && 6850 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) 6851 return MZ_FALSE; 6852 6853 pState = pZip->m_pState; 6854 pZip->m_pState = NULL; 6855 mz_zip_array_clear(pZip, &pState->m_central_dir); 6856 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); 6857 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); 6858 6859#ifndef MINIZ_NO_STDIO 6860 if (pState->m_pFile) { 6861 MZ_FCLOSE(pState->m_pFile); 6862 pState->m_pFile = NULL; 6863 } 6864#endif // #ifndef MINIZ_NO_STDIO 6865 6866 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { 6867 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); 6868 pState->m_pMem = NULL; 6869 } 6870 6871 pZip->m_pFree(pZip->m_pAlloc_opaque, pState); 6872 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; 6873 return status; 6874} 6875 6876#ifndef MINIZ_NO_STDIO 6877mz_bool mz_zip_add_mem_to_archive_file_in_place( 6878 const char *pZip_filename, const char *pArchive_name, const void *pBuf, 6879 size_t buf_size, const void *pComment, mz_uint16 comment_size, 6880 mz_uint level_and_flags) { 6881 mz_bool status, created_new_archive = MZ_FALSE; 6882 mz_zip_archive zip_archive; 6883 struct MZ_FILE_STAT_STRUCT file_stat; 6884 MZ_CLEAR_OBJ(zip_archive); 6885 if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; 6886 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || 6887 ((comment_size) && (!pComment)) || 6888 ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) 6889 return MZ_FALSE; 6890 if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; 6891 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { 6892 // Create a new archive. 6893 if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) 6894 return MZ_FALSE; 6895 created_new_archive = MZ_TRUE; 6896 } else { 6897 // Append to an existing archive. 6898 if (!mz_zip_reader_init_file( 6899 &zip_archive, pZip_filename, 6900 level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) 6901 return MZ_FALSE; 6902 if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) { 6903 mz_zip_reader_end(&zip_archive); 6904 return MZ_FALSE; 6905 } 6906 } 6907 status = 6908 mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, 6909 pComment, comment_size, level_and_flags, 0, 0); 6910 // Always finalize, even if adding failed for some reason, so we have a valid 6911 // central directory. (This may not always succeed, but we can try.) 6912 if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE; 6913 if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE; 6914 if ((!status) && (created_new_archive)) { 6915 // It's a new archive and something went wrong, so just delete it. 6916 int ignoredStatus = MZ_DELETE_FILE(pZip_filename); 6917 (void)ignoredStatus; 6918 } 6919 return status; 6920} 6921 6922void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, 6923 const char *pArchive_name, 6924 size_t *pSize, mz_uint flags) { 6925 int file_index; 6926 mz_zip_archive zip_archive; 6927 void *p = NULL; 6928 6929 if (pSize) *pSize = 0; 6930 6931 if ((!pZip_filename) || (!pArchive_name)) return NULL; 6932 6933 MZ_CLEAR_OBJ(zip_archive); 6934 if (!mz_zip_reader_init_file( 6935 &zip_archive, pZip_filename, 6936 flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) 6937 return NULL; 6938 6939 if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, 6940 flags)) >= 0) 6941 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); 6942 6943 mz_zip_reader_end(&zip_archive); 6944 return p; 6945} 6946 6947#endif // #ifndef MINIZ_NO_STDIO 6948 6949#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS 6950 6951#endif // #ifndef MINIZ_NO_ARCHIVE_APIS 6952 6953#ifdef __cplusplus 6954} 6955#endif 6956 6957#ifdef _MSC_VER 6958#pragma warning(pop) 6959#endif 6960 6961#endif // MINIZ_HEADER_FILE_ONLY 6962 6963/* 6964 This is free and unencumbered software released into the public domain. 6965 6966 Anyone is free to copy, modify, publish, use, compile, sell, or 6967 distribute this software, either in source code form or as a compiled 6968 binary, for any purpose, commercial or non-commercial, and by any 6969 means. 6970 6971 In jurisdictions that recognize copyright laws, the author or authors 6972 of this software dedicate any and all copyright interest in the 6973 software to the public domain. We make this dedication for the benefit 6974 of the public at large and to the detriment of our heirs and 6975 successors. We intend this dedication to be an overt act of 6976 relinquishment in perpetuity of all present and future rights to this 6977 software under copyright law. 6978 6979 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 6980 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 6981 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 6982 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 6983 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 6984 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 6985 OTHER DEALINGS IN THE SOFTWARE. 6986 6987 For more information, please refer to <http://unlicense.org/> 6988*/ 6989 6990// ---------------------- end of miniz ---------------------------------------- 6991 6992#ifdef __clang__ 6993#pragma clang diagnostic pop 6994#endif 6995 6996} // namespace miniz 6997#else 6998 6999// Reuse MINIZ_LITTE_ENDIAN macro 7000 7001#if defined(__sparcv9) 7002// Big endian 7003#else 7004#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU 7005// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. 7006#define MINIZ_LITTLE_ENDIAN 1 7007#endif 7008#endif 7009 7010#endif // TINYEXR_USE_MINIZ 7011 7012// static bool IsBigEndian(void) { 7013// union { 7014// unsigned int i; 7015// char c[4]; 7016// } bint = {0x01020304}; 7017// 7018// return bint.c[0] == 1; 7019//} 7020 7021static void SetErrorMessage(const std::string &msg, const char **err) { 7022 if (err) { 7023#ifdef _WIN32 7024 (*err) = _strdup(msg.c_str()); 7025#else 7026 (*err) = strdup(msg.c_str()); 7027#endif 7028 } 7029} 7030 7031static const int kEXRVersionSize = 8; 7032 7033static void cpy2(unsigned short *dst_val, const unsigned short *src_val) { 7034 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); 7035 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); 7036 7037 dst[0] = src[0]; 7038 dst[1] = src[1]; 7039} 7040 7041static void swap2(unsigned short *val) { 7042#ifdef MINIZ_LITTLE_ENDIAN 7043 (void)val; 7044#else 7045 unsigned short tmp = *val; 7046 unsigned char *dst = reinterpret_cast<unsigned char *>(val); 7047 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp); 7048 7049 dst[0] = src[1]; 7050 dst[1] = src[0]; 7051#endif 7052} 7053 7054#ifdef __clang__ 7055#pragma clang diagnostic push 7056#pragma clang diagnostic ignored "-Wunused-function" 7057#endif 7058 7059#ifdef __GNUC__ 7060#pragma GCC diagnostic push 7061#pragma GCC diagnostic ignored "-Wunused-function" 7062#endif 7063static void cpy4(int *dst_val, const int *src_val) { 7064 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); 7065 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); 7066 7067 dst[0] = src[0]; 7068 dst[1] = src[1]; 7069 dst[2] = src[2]; 7070 dst[3] = src[3]; 7071} 7072 7073static void cpy4(unsigned int *dst_val, const unsigned int *src_val) { 7074 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); 7075 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); 7076 7077 dst[0] = src[0]; 7078 dst[1] = src[1]; 7079 dst[2] = src[2]; 7080 dst[3] = src[3]; 7081} 7082 7083static void cpy4(float *dst_val, const float *src_val) { 7084 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); 7085 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); 7086 7087 dst[0] = src[0]; 7088 dst[1] = src[1]; 7089 dst[2] = src[2]; 7090 dst[3] = src[3]; 7091} 7092#ifdef __clang__ 7093#pragma clang diagnostic pop 7094#endif 7095 7096#ifdef __GNUC__ 7097#pragma GCC diagnostic pop 7098#endif 7099 7100static void swap4(unsigned int *val) { 7101#ifdef MINIZ_LITTLE_ENDIAN 7102 (void)val; 7103#else 7104 unsigned int tmp = *val; 7105 unsigned char *dst = reinterpret_cast<unsigned char *>(val); 7106 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp); 7107 7108 dst[0] = src[3]; 7109 dst[1] = src[2]; 7110 dst[2] = src[1]; 7111 dst[3] = src[0]; 7112#endif 7113} 7114 7115#if 0 7116static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) { 7117 unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); 7118 const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); 7119 7120 dst[0] = src[0]; 7121 dst[1] = src[1]; 7122 dst[2] = src[2]; 7123 dst[3] = src[3]; 7124 dst[4] = src[4]; 7125 dst[5] = src[5]; 7126 dst[6] = src[6]; 7127 dst[7] = src[7]; 7128} 7129#endif 7130 7131static void swap8(tinyexr::tinyexr_uint64 *val) { 7132#ifdef MINIZ_LITTLE_ENDIAN 7133 (void)val; 7134#else 7135 tinyexr::tinyexr_uint64 tmp = (*val); 7136 unsigned char *dst = reinterpret_cast<unsigned char *>(val); 7137 unsigned char *src = reinterpret_cast<unsigned char *>(&tmp); 7138 7139 dst[0] = src[7]; 7140 dst[1] = src[6]; 7141 dst[2] = src[5]; 7142 dst[3] = src[4]; 7143 dst[4] = src[3]; 7144 dst[5] = src[2]; 7145 dst[6] = src[1]; 7146 dst[7] = src[0]; 7147#endif 7148} 7149 7150// https://gist.github.com/rygorous/2156668 7151// Reuse MINIZ_LITTLE_ENDIAN flag from miniz. 7152union FP32 { 7153 unsigned int u; 7154 float f; 7155 struct { 7156#if MINIZ_LITTLE_ENDIAN 7157 unsigned int Mantissa : 23; 7158 unsigned int Exponent : 8; 7159 unsigned int Sign : 1; 7160#else 7161 unsigned int Sign : 1; 7162 unsigned int Exponent : 8; 7163 unsigned int Mantissa : 23; 7164#endif 7165 } s; 7166}; 7167 7168#ifdef __clang__ 7169#pragma clang diagnostic push 7170#pragma clang diagnostic ignored "-Wpadded" 7171#endif 7172 7173union FP16 { 7174 unsigned short u; 7175 struct { 7176#if MINIZ_LITTLE_ENDIAN 7177 unsigned int Mantissa : 10; 7178 unsigned int Exponent : 5; 7179 unsigned int Sign : 1; 7180#else 7181 unsigned int Sign : 1; 7182 unsigned int Exponent : 5; 7183 unsigned int Mantissa : 10; 7184#endif 7185 } s; 7186}; 7187 7188#ifdef __clang__ 7189#pragma clang diagnostic pop 7190#endif 7191 7192static FP32 half_to_float(FP16 h) { 7193 static const FP32 magic = {113 << 23}; 7194 static const unsigned int shifted_exp = 0x7c00 7195 << 13; // exponent mask after shift 7196 FP32 o; 7197 7198 o.u = (h.u & 0x7fffU) << 13U; // exponent/mantissa bits 7199 unsigned int exp_ = shifted_exp & o.u; // just the exponent 7200 o.u += (127 - 15) << 23; // exponent adjust 7201 7202 // handle exponent special cases 7203 if (exp_ == shifted_exp) // Inf/NaN? 7204 o.u += (128 - 16) << 23; // extra exp adjust 7205 else if (exp_ == 0) // Zero/Denormal? 7206 { 7207 o.u += 1 << 23; // extra exp adjust 7208 o.f -= magic.f; // renormalize 7209 } 7210 7211 o.u |= (h.u & 0x8000U) << 16U; // sign bit 7212 return o; 7213} 7214 7215static FP16 float_to_half_full(FP32 f) { 7216 FP16 o = {0}; 7217 7218 // Based on ISPC reference code (with minor modifications) 7219 if (f.s.Exponent == 0) // Signed zero/denormal (which will underflow) 7220 o.s.Exponent = 0; 7221 else if (f.s.Exponent == 255) // Inf or NaN (all exponent bits set) 7222 { 7223 o.s.Exponent = 31; 7224 o.s.Mantissa = f.s.Mantissa ? 0x200 : 0; // NaN->qNaN and Inf->Inf 7225 } else // Normalized number 7226 { 7227 // Exponent unbias the single, then bias the halfp 7228 int newexp = f.s.Exponent - 127 + 15; 7229 if (newexp >= 31) // Overflow, return signed infinity 7230 o.s.Exponent = 31; 7231 else if (newexp <= 0) // Underflow 7232 { 7233 if ((14 - newexp) <= 24) // Mantissa might be non-zero 7234 { 7235 unsigned int mant = f.s.Mantissa | 0x800000; // Hidden 1 bit 7236 o.s.Mantissa = mant >> (14 - newexp); 7237 if ((mant >> (13 - newexp)) & 1) // Check for rounding 7238 o.u++; // Round, might overflow into exp bit, but this is OK 7239 } 7240 } else { 7241 o.s.Exponent = static_cast<unsigned int>(newexp); 7242 o.s.Mantissa = f.s.Mantissa >> 13; 7243 if (f.s.Mantissa & 0x1000) // Check for rounding 7244 o.u++; // Round, might overflow to inf, this is OK 7245 } 7246 } 7247 7248 o.s.Sign = f.s.Sign; 7249 return o; 7250} 7251 7252// NOTE: From OpenEXR code 7253// #define IMF_INCREASING_Y 0 7254// #define IMF_DECREASING_Y 1 7255// #define IMF_RAMDOM_Y 2 7256// 7257// #define IMF_NO_COMPRESSION 0 7258// #define IMF_RLE_COMPRESSION 1 7259// #define IMF_ZIPS_COMPRESSION 2 7260// #define IMF_ZIP_COMPRESSION 3 7261// #define IMF_PIZ_COMPRESSION 4 7262// #define IMF_PXR24_COMPRESSION 5 7263// #define IMF_B44_COMPRESSION 6 7264// #define IMF_B44A_COMPRESSION 7 7265 7266#ifdef __clang__ 7267#pragma clang diagnostic push 7268 7269#if __has_warning("-Wzero-as-null-pointer-constant") 7270#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" 7271#endif 7272 7273#endif 7274 7275static const char *ReadString(std::string *s, const char *ptr, size_t len) { 7276 // Read untile NULL(\0). 7277 const char *p = ptr; 7278 const char *q = ptr; 7279 while ((size_t(q - ptr) < len) && (*q) != 0) { 7280 q++; 7281 } 7282 7283 if (size_t(q - ptr) >= len) { 7284 (*s) = std::string(); 7285 return NULL; 7286 } 7287 7288 (*s) = std::string(p, q); 7289 7290 return q + 1; // skip '\0' 7291} 7292 7293static bool ReadAttribute(std::string *name, std::string *type, 7294 std::vector<unsigned char> *data, size_t *marker_size, 7295 const char *marker, size_t size) { 7296 size_t name_len = strnlen(marker, size); 7297 if (name_len == size) { 7298 // String does not have a terminating character. 7299 return false; 7300 } 7301 *name = std::string(marker, name_len); 7302 7303 marker += name_len + 1; 7304 size -= name_len + 1; 7305 7306 size_t type_len = strnlen(marker, size); 7307 if (type_len == size) { 7308 return false; 7309 } 7310 *type = std::string(marker, type_len); 7311 7312 marker += type_len + 1; 7313 size -= type_len + 1; 7314 7315 if (size < sizeof(uint32_t)) { 7316 return false; 7317 } 7318 7319 uint32_t data_len; 7320 memcpy(&data_len, marker, sizeof(uint32_t)); 7321 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len)); 7322 7323 if (data_len == 0) { 7324 if ((*type).compare("string") == 0) { 7325 // Accept empty string attribute. 7326 7327 marker += sizeof(uint32_t); 7328 size -= sizeof(uint32_t); 7329 7330 *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t); 7331 7332 data->resize(1); 7333 (*data)[0] = '\0'; 7334 7335 return true; 7336 } else { 7337 return false; 7338 } 7339 } 7340 7341 marker += sizeof(uint32_t); 7342 size -= sizeof(uint32_t); 7343 7344 if (size < data_len) { 7345 return false; 7346 } 7347 7348 data->resize(static_cast<size_t>(data_len)); 7349 memcpy(&data->at(0), marker, static_cast<size_t>(data_len)); 7350 7351 *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t) + data_len; 7352 return true; 7353} 7354 7355static void WriteAttributeToMemory(std::vector<unsigned char> *out, 7356 const char *name, const char *type, 7357 const unsigned char *data, int len) { 7358 out->insert(out->end(), name, name + strlen(name) + 1); 7359 out->insert(out->end(), type, type + strlen(type) + 1); 7360 7361 int outLen = len; 7362 tinyexr::swap4(reinterpret_cast<unsigned int *>(&outLen)); 7363 out->insert(out->end(), reinterpret_cast<unsigned char *>(&outLen), 7364 reinterpret_cast<unsigned char *>(&outLen) + sizeof(int)); 7365 out->insert(out->end(), data, data + len); 7366} 7367 7368struct ChannelInfo { 7369 std::string name; // less than 255 bytes long 7370 int pixel_type; 7371 int x_sampling; 7372 int y_sampling; 7373 unsigned char p_linear; 7374 unsigned char pad[3]; 7375}; 7376 7377struct HeaderInfo { 7378 std::vector<tinyexr::ChannelInfo> channels; 7379 std::vector<EXRAttribute> attributes; 7380 7381 int data_window[4]; 7382 int line_order; 7383 int display_window[4]; 7384 float screen_window_center[2]; 7385 float screen_window_width; 7386 float pixel_aspect_ratio; 7387 7388 int chunk_count; 7389 7390 // Tiled format 7391 int tile_size_x; 7392 int tile_size_y; 7393 int tile_level_mode; 7394 int tile_rounding_mode; 7395 7396 unsigned int header_len; 7397 7398 int compression_type; 7399 7400 void clear() { 7401 channels.clear(); 7402 attributes.clear(); 7403 7404 data_window[0] = 0; 7405 data_window[1] = 0; 7406 data_window[2] = 0; 7407 data_window[3] = 0; 7408 line_order = 0; 7409 display_window[0] = 0; 7410 display_window[1] = 0; 7411 display_window[2] = 0; 7412 display_window[3] = 0; 7413 screen_window_center[0] = 0.0f; 7414 screen_window_center[1] = 0.0f; 7415 screen_window_width = 0.0f; 7416 pixel_aspect_ratio = 0.0f; 7417 7418 chunk_count = 0; 7419 7420 // Tiled format 7421 tile_size_x = 0; 7422 tile_size_y = 0; 7423 tile_level_mode = 0; 7424 tile_rounding_mode = 0; 7425 7426 header_len = 0; 7427 compression_type = 0; 7428 } 7429}; 7430 7431static bool ReadChannelInfo(std::vector<ChannelInfo> &channels, 7432 const std::vector<unsigned char> &data) { 7433 const char *p = reinterpret_cast<const char *>(&data.at(0)); 7434 7435 for (;;) { 7436 if ((*p) == 0) { 7437 break; 7438 } 7439 ChannelInfo info; 7440 7441 tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) - 7442 (p - reinterpret_cast<const char *>(data.data())); 7443 if (data_len < 0) { 7444 return false; 7445 } 7446 7447 p = ReadString(&info.name, p, size_t(data_len)); 7448 if ((p == NULL) && (info.name.empty())) { 7449 // Buffer overrun. Issue #51. 7450 return false; 7451 } 7452 7453 const unsigned char *data_end = 7454 reinterpret_cast<const unsigned char *>(p) + 16; 7455 if (data_end >= (data.data() + data.size())) { 7456 return false; 7457 } 7458 7459 memcpy(&info.pixel_type, p, sizeof(int)); 7460 p += 4; 7461 info.p_linear = static_cast<unsigned char>(p[0]); // uchar 7462 p += 1 + 3; // reserved: uchar[3] 7463 memcpy(&info.x_sampling, p, sizeof(int)); // int 7464 p += 4; 7465 memcpy(&info.y_sampling, p, sizeof(int)); // int 7466 p += 4; 7467 7468 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.pixel_type)); 7469 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.x_sampling)); 7470 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info.y_sampling)); 7471 7472 channels.push_back(info); 7473 } 7474 7475 return true; 7476} 7477 7478static void WriteChannelInfo(std::vector<unsigned char> &data, 7479 const std::vector<ChannelInfo> &channels) { 7480 size_t sz = 0; 7481 7482 // Calculate total size. 7483 for (size_t c = 0; c < channels.size(); c++) { 7484 sz += strlen(channels[c].name.c_str()) + 1; // +1 for \0 7485 sz += 16; // 4 * int 7486 } 7487 data.resize(sz + 1); 7488 7489 unsigned char *p = &data.at(0); 7490 7491 for (size_t c = 0; c < channels.size(); c++) { 7492 memcpy(p, channels[c].name.c_str(), strlen(channels[c].name.c_str())); 7493 p += strlen(channels[c].name.c_str()); 7494 (*p) = '\0'; 7495 p++; 7496 7497 int pixel_type = channels[c].pixel_type; 7498 int x_sampling = channels[c].x_sampling; 7499 int y_sampling = channels[c].y_sampling; 7500 tinyexr::swap4(reinterpret_cast<unsigned int *>(&pixel_type)); 7501 tinyexr::swap4(reinterpret_cast<unsigned int *>(&x_sampling)); 7502 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y_sampling)); 7503 7504 memcpy(p, &pixel_type, sizeof(int)); 7505 p += sizeof(int); 7506 7507 (*p) = channels[c].p_linear; 7508 p += 4; 7509 7510 memcpy(p, &x_sampling, sizeof(int)); 7511 p += sizeof(int); 7512 7513 memcpy(p, &y_sampling, sizeof(int)); 7514 p += sizeof(int); 7515 } 7516 7517 (*p) = '\0'; 7518} 7519 7520static void CompressZip(unsigned char *dst, 7521 tinyexr::tinyexr_uint64 &compressedSize, 7522 const unsigned char *src, unsigned long src_size) { 7523 std::vector<unsigned char> tmpBuf(src_size); 7524 7525 // 7526 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's 7527 // ImfZipCompressor.cpp 7528 // 7529 7530 // 7531 // Reorder the pixel data. 7532 // 7533 7534 const char *srcPtr = reinterpret_cast<const char *>(src); 7535 7536 { 7537 char *t1 = reinterpret_cast<char *>(&tmpBuf.at(0)); 7538 char *t2 = reinterpret_cast<char *>(&tmpBuf.at(0)) + (src_size + 1) / 2; 7539 const char *stop = srcPtr + src_size; 7540 7541 for (;;) { 7542 if (srcPtr < stop) 7543 *(t1++) = *(srcPtr++); 7544 else 7545 break; 7546 7547 if (srcPtr < stop) 7548 *(t2++) = *(srcPtr++); 7549 else 7550 break; 7551 } 7552 } 7553 7554 // 7555 // Predictor. 7556 // 7557 7558 { 7559 unsigned char *t = &tmpBuf.at(0) + 1; 7560 unsigned char *stop = &tmpBuf.at(0) + src_size; 7561 int p = t[-1]; 7562 7563 while (t < stop) { 7564 int d = int(t[0]) - p + (128 + 256); 7565 p = t[0]; 7566 t[0] = static_cast<unsigned char>(d); 7567 ++t; 7568 } 7569 } 7570 7571#if TINYEXR_USE_MINIZ 7572 // 7573 // Compress the data using miniz 7574 // 7575 7576 miniz::mz_ulong outSize = miniz::mz_compressBound(src_size); 7577 int ret = miniz::mz_compress( 7578 dst, &outSize, static_cast<const unsigned char *>(&tmpBuf.at(0)), 7579 src_size); 7580 TEXR_ASSERT(ret == miniz::MZ_OK); 7581 (void)ret; 7582 7583 compressedSize = outSize; 7584#else 7585 uLong outSize = compressBound(static_cast<uLong>(src_size)); 7586 int ret = compress(dst, &outSize, static_cast<const Bytef *>(&tmpBuf.at(0)), 7587 src_size); 7588 TEXR_ASSERT(ret == Z_OK); 7589 7590 compressedSize = outSize; 7591#endif 7592 7593 // Use uncompressed data when compressed data is larger than uncompressed. 7594 // (Issue 40) 7595 if (compressedSize >= src_size) { 7596 compressedSize = src_size; 7597 memcpy(dst, src, src_size); 7598 } 7599} 7600 7601static bool DecompressZip(unsigned char *dst, 7602 unsigned long *uncompressed_size /* inout */, 7603 const unsigned char *src, unsigned long src_size) { 7604 if ((*uncompressed_size) == src_size) { 7605 // Data is not compressed(Issue 40). 7606 memcpy(dst, src, src_size); 7607 return true; 7608 } 7609 std::vector<unsigned char> tmpBuf(*uncompressed_size); 7610 7611#if TINYEXR_USE_MINIZ 7612 int ret = 7613 miniz::mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size); 7614 if (miniz::MZ_OK != ret) { 7615 return false; 7616 } 7617#else 7618 int ret = uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size); 7619 if (Z_OK != ret) { 7620 return false; 7621 } 7622#endif 7623 7624 // 7625 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's 7626 // ImfZipCompressor.cpp 7627 // 7628 7629 // Predictor. 7630 { 7631 unsigned char *t = &tmpBuf.at(0) + 1; 7632 unsigned char *stop = &tmpBuf.at(0) + (*uncompressed_size); 7633 7634 while (t < stop) { 7635 int d = int(t[-1]) + int(t[0]) - 128; 7636 t[0] = static_cast<unsigned char>(d); 7637 ++t; 7638 } 7639 } 7640 7641 // Reorder the pixel data. 7642 { 7643 const char *t1 = reinterpret_cast<const char *>(&tmpBuf.at(0)); 7644 const char *t2 = reinterpret_cast<const char *>(&tmpBuf.at(0)) + 7645 (*uncompressed_size + 1) / 2; 7646 char *s = reinterpret_cast<char *>(dst); 7647 char *stop = s + (*uncompressed_size); 7648 7649 for (;;) { 7650 if (s < stop) 7651 *(s++) = *(t1++); 7652 else 7653 break; 7654 7655 if (s < stop) 7656 *(s++) = *(t2++); 7657 else 7658 break; 7659 } 7660 } 7661 7662 return true; 7663} 7664 7665// RLE code from OpenEXR -------------------------------------- 7666 7667#ifdef __clang__ 7668#pragma clang diagnostic push 7669#pragma clang diagnostic ignored "-Wsign-conversion" 7670#if __has_warning("-Wextra-semi-stmt") 7671#pragma clang diagnostic ignored "-Wextra-semi-stmt" 7672#endif 7673#endif 7674 7675#ifdef _MSC_VER 7676#pragma warning(push) 7677#pragma warning(disable : 4204) // nonstandard extension used : non-constant 7678 // aggregate initializer (also supported by GNU 7679 // C and C99, so no big deal) 7680#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to 7681 // 'int', possible loss of data 7682#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to 7683 // 'int', possible loss of data 7684#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is 7685 // deprecated. Instead, use the ISO C and C++ 7686 // conformant name: _strdup. 7687#endif 7688 7689const int MIN_RUN_LENGTH = 3; 7690const int MAX_RUN_LENGTH = 127; 7691 7692// 7693// Compress an array of bytes, using run-length encoding, 7694// and return the length of the compressed data. 7695// 7696 7697static int rleCompress(int inLength, const char in[], signed char out[]) { 7698 const char *inEnd = in + inLength; 7699 const char *runStart = in; 7700 const char *runEnd = in + 1; 7701 signed char *outWrite = out; 7702 7703 while (runStart < inEnd) { 7704 while (runEnd < inEnd && *runStart == *runEnd && 7705 runEnd - runStart - 1 < MAX_RUN_LENGTH) { 7706 ++runEnd; 7707 } 7708 7709 if (runEnd - runStart >= MIN_RUN_LENGTH) { 7710 // 7711 // Compressable run 7712 // 7713 7714 *outWrite++ = static_cast<char>(runEnd - runStart) - 1; 7715 *outWrite++ = *(reinterpret_cast<const signed char *>(runStart)); 7716 runStart = runEnd; 7717 } else { 7718 // 7719 // Uncompressable run 7720 // 7721 7722 while (runEnd < inEnd && 7723 ((runEnd + 1 >= inEnd || *runEnd != *(runEnd + 1)) || 7724 (runEnd + 2 >= inEnd || *(runEnd + 1) != *(runEnd + 2))) && 7725 runEnd - runStart < MAX_RUN_LENGTH) { 7726 ++runEnd; 7727 } 7728 7729 *outWrite++ = static_cast<char>(runStart - runEnd); 7730 7731 while (runStart < runEnd) { 7732 *outWrite++ = *(reinterpret_cast<const signed char *>(runStart++)); 7733 } 7734 } 7735 7736 ++runEnd; 7737 } 7738 7739 return static_cast<int>(outWrite - out); 7740} 7741 7742// 7743// Uncompress an array of bytes compressed with rleCompress(). 7744// Returns the length of the oncompressed data, or 0 if the 7745// length of the uncompressed data would be more than maxLength. 7746// 7747 7748static int rleUncompress(int inLength, int maxLength, const signed char in[], 7749 char out[]) { 7750 char *outStart = out; 7751 7752 while (inLength > 0) { 7753 if (*in < 0) { 7754 int count = -(static_cast<int>(*in++)); 7755 inLength -= count + 1; 7756 7757 // Fixes #116: Add bounds check to in buffer. 7758 if ((0 > (maxLength -= count)) || (inLength < 0)) return 0; 7759 7760 memcpy(out, in, count); 7761 out += count; 7762 in += count; 7763 } else { 7764 int count = *in++; 7765 inLength -= 2; 7766 7767 if (0 > (maxLength -= count + 1) || inLength < 0) return 0; 7768 7769 memset(out, *reinterpret_cast<const char *>(in), count + 1); 7770 out += count + 1; 7771 7772 in++; 7773 } 7774 } 7775 7776 return static_cast<int>(out - outStart); 7777} 7778 7779#ifdef __clang__ 7780#pragma clang diagnostic pop 7781#endif 7782 7783// End of RLE code from OpenEXR ----------------------------------- 7784 7785static void CompressRle(unsigned char *dst, 7786 tinyexr::tinyexr_uint64 &compressedSize, 7787 const unsigned char *src, unsigned long src_size) { 7788 std::vector<unsigned char> tmpBuf(src_size); 7789 7790 // 7791 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's 7792 // ImfRleCompressor.cpp 7793 // 7794 7795 // 7796 // Reorder the pixel data. 7797 // 7798 7799 const char *srcPtr = reinterpret_cast<const char *>(src); 7800 7801 { 7802 char *t1 = reinterpret_cast<char *>(&tmpBuf.at(0)); 7803 char *t2 = reinterpret_cast<char *>(&tmpBuf.at(0)) + (src_size + 1) / 2; 7804 const char *stop = srcPtr + src_size; 7805 7806 for (;;) { 7807 if (srcPtr < stop) 7808 *(t1++) = *(srcPtr++); 7809 else 7810 break; 7811 7812 if (srcPtr < stop) 7813 *(t2++) = *(srcPtr++); 7814 else 7815 break; 7816 } 7817 } 7818 7819 // 7820 // Predictor. 7821 // 7822 7823 { 7824 unsigned char *t = &tmpBuf.at(0) + 1; 7825 unsigned char *stop = &tmpBuf.at(0) + src_size; 7826 int p = t[-1]; 7827 7828 while (t < stop) { 7829 int d = int(t[0]) - p + (128 + 256); 7830 p = t[0]; 7831 t[0] = static_cast<unsigned char>(d); 7832 ++t; 7833 } 7834 } 7835 7836 // outSize will be (srcSiz * 3) / 2 at max. 7837 int outSize = rleCompress(static_cast<int>(src_size), 7838 reinterpret_cast<const char *>(&tmpBuf.at(0)), 7839 reinterpret_cast<signed char *>(dst)); 7840 TEXR_ASSERT(outSize > 0); 7841 7842 compressedSize = static_cast<tinyexr::tinyexr_uint64>(outSize); 7843 7844 // Use uncompressed data when compressed data is larger than uncompressed. 7845 // (Issue 40) 7846 if (compressedSize >= src_size) { 7847 compressedSize = src_size; 7848 memcpy(dst, src, src_size); 7849 } 7850} 7851 7852static bool DecompressRle(unsigned char *dst, 7853 const unsigned long uncompressed_size, 7854 const unsigned char *src, unsigned long src_size) { 7855 if (uncompressed_size == src_size) { 7856 // Data is not compressed(Issue 40). 7857 memcpy(dst, src, src_size); 7858 return true; 7859 } 7860 7861 // Workaround for issue #112. 7862 // TODO(syoyo): Add more robust out-of-bounds check in `rleUncompress`. 7863 if (src_size <= 2) { 7864 return false; 7865 } 7866 7867 std::vector<unsigned char> tmpBuf(uncompressed_size); 7868 7869 int ret = rleUncompress(static_cast<int>(src_size), 7870 static_cast<int>(uncompressed_size), 7871 reinterpret_cast<const signed char *>(src), 7872 reinterpret_cast<char *>(&tmpBuf.at(0))); 7873 if (ret != static_cast<int>(uncompressed_size)) { 7874 return false; 7875 } 7876 7877 // 7878 // Apply EXR-specific? postprocess. Grabbed from OpenEXR's 7879 // ImfRleCompressor.cpp 7880 // 7881 7882 // Predictor. 7883 { 7884 unsigned char *t = &tmpBuf.at(0) + 1; 7885 unsigned char *stop = &tmpBuf.at(0) + uncompressed_size; 7886 7887 while (t < stop) { 7888 int d = int(t[-1]) + int(t[0]) - 128; 7889 t[0] = static_cast<unsigned char>(d); 7890 ++t; 7891 } 7892 } 7893 7894 // Reorder the pixel data. 7895 { 7896 const char *t1 = reinterpret_cast<const char *>(&tmpBuf.at(0)); 7897 const char *t2 = reinterpret_cast<const char *>(&tmpBuf.at(0)) + 7898 (uncompressed_size + 1) / 2; 7899 char *s = reinterpret_cast<char *>(dst); 7900 char *stop = s + uncompressed_size; 7901 7902 for (;;) { 7903 if (s < stop) 7904 *(s++) = *(t1++); 7905 else 7906 break; 7907 7908 if (s < stop) 7909 *(s++) = *(t2++); 7910 else 7911 break; 7912 } 7913 } 7914 7915 return true; 7916} 7917 7918#if TINYEXR_USE_PIZ 7919 7920#ifdef __clang__ 7921#pragma clang diagnostic push 7922#pragma clang diagnostic ignored "-Wc++11-long-long" 7923#pragma clang diagnostic ignored "-Wold-style-cast" 7924#pragma clang diagnostic ignored "-Wpadded" 7925#pragma clang diagnostic ignored "-Wsign-conversion" 7926#pragma clang diagnostic ignored "-Wc++11-extensions" 7927#pragma clang diagnostic ignored "-Wconversion" 7928#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" 7929 7930#if __has_warning("-Wcast-qual") 7931#pragma clang diagnostic ignored "-Wcast-qual" 7932#endif 7933 7934#if __has_warning("-Wextra-semi-stmt") 7935#pragma clang diagnostic ignored "-Wextra-semi-stmt" 7936#endif 7937 7938#endif 7939 7940// 7941// PIZ compress/uncompress, based on OpenEXR's ImfPizCompressor.cpp 7942// 7943// ----------------------------------------------------------------- 7944// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas 7945// Digital Ltd. LLC) 7946// (3 clause BSD license) 7947// 7948 7949struct PIZChannelData { 7950 unsigned short *start; 7951 unsigned short *end; 7952 int nx; 7953 int ny; 7954 int ys; 7955 int size; 7956}; 7957 7958//----------------------------------------------------------------------------- 7959// 7960// 16-bit Haar Wavelet encoding and decoding 7961// 7962// The source code in this file is derived from the encoding 7963// and decoding routines written by Christian Rouet for his 7964// PIZ image file format. 7965// 7966//----------------------------------------------------------------------------- 7967 7968// 7969// Wavelet basis functions without modulo arithmetic; they produce 7970// the best compression ratios when the wavelet-transformed data are 7971// Huffman-encoded, but the wavelet transform works only for 14-bit 7972// data (untransformed data values must be less than (1 << 14)). 7973// 7974 7975inline void wenc14(unsigned short a, unsigned short b, unsigned short &l, 7976 unsigned short &h) { 7977 short as = static_cast<short>(a); 7978 short bs = static_cast<short>(b); 7979 7980 short ms = (as + bs) >> 1; 7981 short ds = as - bs; 7982 7983 l = static_cast<unsigned short>(ms); 7984 h = static_cast<unsigned short>(ds); 7985} 7986 7987inline void wdec14(unsigned short l, unsigned short h, unsigned short &a, 7988 unsigned short &b) { 7989 short ls = static_cast<short>(l); 7990 short hs = static_cast<short>(h); 7991 7992 int hi = hs; 7993 int ai = ls + (hi & 1) + (hi >> 1); 7994 7995 short as = static_cast<short>(ai); 7996 short bs = static_cast<short>(ai - hi); 7997 7998 a = static_cast<unsigned short>(as); 7999 b = static_cast<unsigned short>(bs); 8000} 8001 8002// 8003// Wavelet basis functions with modulo arithmetic; they work with full 8004// 16-bit data, but Huffman-encoding the wavelet-transformed data doesn't 8005// compress the data quite as well. 8006// 8007 8008const int NBITS = 16; 8009const int A_OFFSET = 1 << (NBITS - 1); 8010const int M_OFFSET = 1 << (NBITS - 1); 8011const int MOD_MASK = (1 << NBITS) - 1; 8012 8013inline void wenc16(unsigned short a, unsigned short b, unsigned short &l, 8014 unsigned short &h) { 8015 int ao = (a + A_OFFSET) & MOD_MASK; 8016 int m = ((ao + b) >> 1); 8017 int d = ao - b; 8018 8019 if (d < 0) m = (m + M_OFFSET) & MOD_MASK; 8020 8021 d &= MOD_MASK; 8022 8023 l = static_cast<unsigned short>(m); 8024 h = static_cast<unsigned short>(d); 8025} 8026 8027inline void wdec16(unsigned short l, unsigned short h, unsigned short &a, 8028 unsigned short &b) { 8029 int m = l; 8030 int d = h; 8031 int bb = (m - (d >> 1)) & MOD_MASK; 8032 int aa = (d + bb - A_OFFSET) & MOD_MASK; 8033 b = static_cast<unsigned short>(bb); 8034 a = static_cast<unsigned short>(aa); 8035} 8036 8037// 8038// 2D Wavelet encoding: 8039// 8040 8041static void wav2Encode( 8042 unsigned short *in, // io: values are transformed in place 8043 int nx, // i : x size 8044 int ox, // i : x offset 8045 int ny, // i : y size 8046 int oy, // i : y offset 8047 unsigned short mx) // i : maximum in[x][y] value 8048{ 8049 bool w14 = (mx < (1 << 14)); 8050 int n = (nx > ny) ? ny : nx; 8051 int p = 1; // == 1 << level 8052 int p2 = 2; // == 1 << (level+1) 8053 8054 // 8055 // Hierachical loop on smaller dimension n 8056 // 8057 8058 while (p2 <= n) { 8059 unsigned short *py = in; 8060 unsigned short *ey = in + oy * (ny - p2); 8061 int oy1 = oy * p; 8062 int oy2 = oy * p2; 8063 int ox1 = ox * p; 8064 int ox2 = ox * p2; 8065 unsigned short i00, i01, i10, i11; 8066 8067 // 8068 // Y loop 8069 // 8070 8071 for (; py <= ey; py += oy2) { 8072 unsigned short *px = py; 8073 unsigned short *ex = py + ox * (nx - p2); 8074 8075 // 8076 // X loop 8077 // 8078 8079 for (; px <= ex; px += ox2) { 8080 unsigned short *p01 = px + ox1; 8081 unsigned short *p10 = px + oy1; 8082 unsigned short *p11 = p10 + ox1; 8083 8084 // 8085 // 2D wavelet encoding 8086 // 8087 8088 if (w14) { 8089 wenc14(*px, *p01, i00, i01); 8090 wenc14(*p10, *p11, i10, i11); 8091 wenc14(i00, i10, *px, *p10); 8092 wenc14(i01, i11, *p01, *p11); 8093 } else { 8094 wenc16(*px, *p01, i00, i01); 8095 wenc16(*p10, *p11, i10, i11); 8096 wenc16(i00, i10, *px, *p10); 8097 wenc16(i01, i11, *p01, *p11); 8098 } 8099 } 8100 8101 // 8102 // Encode (1D) odd column (still in Y loop) 8103 // 8104 8105 if (nx & p) { 8106 unsigned short *p10 = px + oy1; 8107 8108 if (w14) 8109 wenc14(*px, *p10, i00, *p10); 8110 else 8111 wenc16(*px, *p10, i00, *p10); 8112 8113 *px = i00; 8114 } 8115 } 8116 8117 // 8118 // Encode (1D) odd line (must loop in X) 8119 // 8120 8121 if (ny & p) { 8122 unsigned short *px = py; 8123 unsigned short *ex = py + ox * (nx - p2); 8124 8125 for (; px <= ex; px += ox2) { 8126 unsigned short *p01 = px + ox1; 8127 8128 if (w14) 8129 wenc14(*px, *p01, i00, *p01); 8130 else 8131 wenc16(*px, *p01, i00, *p01); 8132 8133 *px = i00; 8134 } 8135 } 8136 8137 // 8138 // Next level 8139 // 8140 8141 p = p2; 8142 p2 <<= 1; 8143 } 8144} 8145 8146// 8147// 2D Wavelet decoding: 8148// 8149 8150static void wav2Decode( 8151 unsigned short *in, // io: values are transformed in place 8152 int nx, // i : x size 8153 int ox, // i : x offset 8154 int ny, // i : y size 8155 int oy, // i : y offset 8156 unsigned short mx) // i : maximum in[x][y] value 8157{ 8158 bool w14 = (mx < (1 << 14)); 8159 int n = (nx > ny) ? ny : nx; 8160 int p = 1; 8161 int p2; 8162 8163 // 8164 // Search max level 8165 // 8166 8167 while (p <= n) p <<= 1; 8168 8169 p >>= 1; 8170 p2 = p; 8171 p >>= 1; 8172 8173 // 8174 // Hierarchical loop on smaller dimension n 8175 // 8176 8177 while (p >= 1) { 8178 unsigned short *py = in; 8179 unsigned short *ey = in + oy * (ny - p2); 8180 int oy1 = oy * p; 8181 int oy2 = oy * p2; 8182 int ox1 = ox * p; 8183 int ox2 = ox * p2; 8184 unsigned short i00, i01, i10, i11; 8185 8186 // 8187 // Y loop 8188 // 8189 8190 for (; py <= ey; py += oy2) { 8191 unsigned short *px = py; 8192 unsigned short *ex = py + ox * (nx - p2); 8193 8194 // 8195 // X loop 8196 // 8197 8198 for (; px <= ex; px += ox2) { 8199 unsigned short *p01 = px + ox1; 8200 unsigned short *p10 = px + oy1; 8201 unsigned short *p11 = p10 + ox1; 8202 8203 // 8204 // 2D wavelet decoding 8205 // 8206 8207 if (w14) { 8208 wdec14(*px, *p10, i00, i10); 8209 wdec14(*p01, *p11, i01, i11); 8210 wdec14(i00, i01, *px, *p01); 8211 wdec14(i10, i11, *p10, *p11); 8212 } else { 8213 wdec16(*px, *p10, i00, i10); 8214 wdec16(*p01, *p11, i01, i11); 8215 wdec16(i00, i01, *px, *p01); 8216 wdec16(i10, i11, *p10, *p11); 8217 } 8218 } 8219 8220 // 8221 // Decode (1D) odd column (still in Y loop) 8222 // 8223 8224 if (nx & p) { 8225 unsigned short *p10 = px + oy1; 8226 8227 if (w14) 8228 wdec14(*px, *p10, i00, *p10); 8229 else 8230 wdec16(*px, *p10, i00, *p10); 8231 8232 *px = i00; 8233 } 8234 } 8235 8236 // 8237 // Decode (1D) odd line (must loop in X) 8238 // 8239 8240 if (ny & p) { 8241 unsigned short *px = py; 8242 unsigned short *ex = py + ox * (nx - p2); 8243 8244 for (; px <= ex; px += ox2) { 8245 unsigned short *p01 = px + ox1; 8246 8247 if (w14) 8248 wdec14(*px, *p01, i00, *p01); 8249 else 8250 wdec16(*px, *p01, i00, *p01); 8251 8252 *px = i00; 8253 } 8254 } 8255 8256 // 8257 // Next level 8258 // 8259 8260 p2 = p; 8261 p >>= 1; 8262 } 8263} 8264 8265//----------------------------------------------------------------------------- 8266// 8267// 16-bit Huffman compression and decompression. 8268// 8269// The source code in this file is derived from the 8-bit 8270// Huffman compression and decompression routines written 8271// by Christian Rouet for his PIZ image file format. 8272// 8273//----------------------------------------------------------------------------- 8274 8275// Adds some modification for tinyexr. 8276 8277const int HUF_ENCBITS = 16; // literal (value) bit length 8278const int HUF_DECBITS = 14; // decoding bit size (>= 8) 8279 8280const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1; // encoding table size 8281const int HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size 8282const int HUF_DECMASK = HUF_DECSIZE - 1; 8283 8284struct HufDec { // short code long code 8285 //------------------------------- 8286 int len : 8; // code length 0 8287 int lit : 24; // lit p size 8288 int *p; // 0 lits 8289}; 8290 8291inline long long hufLength(long long code) { return code & 63; } 8292 8293inline long long hufCode(long long code) { return code >> 6; } 8294 8295inline void outputBits(int nBits, long long bits, long long &c, int &lc, 8296 char *&out) { 8297 c <<= nBits; 8298 lc += nBits; 8299 8300 c |= bits; 8301 8302 while (lc >= 8) *out++ = static_cast<char>((c >> (lc -= 8))); 8303} 8304 8305inline long long getBits(int nBits, long long &c, int &lc, const char *&in) { 8306 while (lc < nBits) { 8307 c = (c << 8) | *(reinterpret_cast<const unsigned char *>(in++)); 8308 lc += 8; 8309 } 8310 8311 lc -= nBits; 8312 return (c >> lc) & ((1 << nBits) - 1); 8313} 8314 8315// 8316// ENCODING TABLE BUILDING & (UN)PACKING 8317// 8318 8319// 8320// Build a "canonical" Huffman code table: 8321// - for each (uncompressed) symbol, hcode contains the length 8322// of the corresponding code (in the compressed data) 8323// - canonical codes are computed and stored in hcode 8324// - the rules for constructing canonical codes are as follows: 8325// * shorter codes (if filled with zeroes to the right) 8326// have a numerically higher value than longer codes 8327// * for codes with the same length, numerical values 8328// increase with numerical symbol values 8329// - because the canonical code table can be constructed from 8330// symbol lengths alone, the code table can be transmitted 8331// without sending the actual code values 8332// - see http://www.compressconsult.com/huffman/ 8333// 8334 8335static void hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE]) { 8336 long long n[59]; 8337 8338 // 8339 // For each i from 0 through 58, count the 8340 // number of different codes of length i, and 8341 // store the count in n[i]. 8342 // 8343 8344 for (int i = 0; i <= 58; ++i) n[i] = 0; 8345 8346 for (int i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1; 8347 8348 // 8349 // For each i from 58 through 1, compute the 8350 // numerically lowest code with length i, and 8351 // store that code in n[i]. 8352 // 8353 8354 long long c = 0; 8355 8356 for (int i = 58; i > 0; --i) { 8357 long long nc = ((c + n[i]) >> 1); 8358 n[i] = c; 8359 c = nc; 8360 } 8361 8362 // 8363 // hcode[i] contains the length, l, of the 8364 // code for symbol i. Assign the next available 8365 // code of length l to the symbol and store both 8366 // l and the code in hcode[i]. 8367 // 8368 8369 for (int i = 0; i < HUF_ENCSIZE; ++i) { 8370 int l = static_cast<int>(hcode[i]); 8371 8372 if (l > 0) hcode[i] = l | (n[l]++ << 6); 8373 } 8374} 8375 8376// 8377// Compute Huffman codes (based on frq input) and store them in frq: 8378// - code structure is : [63:lsb - 6:msb] | [5-0: bit length]; 8379// - max code length is 58 bits; 8380// - codes outside the range [im-iM] have a null length (unused values); 8381// - original frequencies are destroyed; 8382// - encoding tables are used by hufEncode() and hufBuildDecTable(); 8383// 8384 8385struct FHeapCompare { 8386 bool operator()(long long *a, long long *b) { return *a > *b; } 8387}; 8388 8389static void hufBuildEncTable( 8390 long long *frq, // io: input frequencies [HUF_ENCSIZE], output table 8391 int *im, // o: min frq index 8392 int *iM) // o: max frq index 8393{ 8394 // 8395 // This function assumes that when it is called, array frq 8396 // indicates the frequency of all possible symbols in the data 8397 // that are to be Huffman-encoded. (frq[i] contains the number 8398 // of occurrences of symbol i in the data.) 8399 // 8400 // The loop below does three things: 8401 // 8402 // 1) Finds the minimum and maximum indices that point 8403 // to non-zero entries in frq: 8404 // 8405 // frq[im] != 0, and frq[i] == 0 for all i < im 8406 // frq[iM] != 0, and frq[i] == 0 for all i > iM 8407 // 8408 // 2) Fills array fHeap with pointers to all non-zero 8409 // entries in frq. 8410 // 8411 // 3) Initializes array hlink such that hlink[i] == i 8412 // for all array entries. 8413 // 8414 8415 std::vector<int> hlink(HUF_ENCSIZE); 8416 std::vector<long long *> fHeap(HUF_ENCSIZE); 8417 8418 *im = 0; 8419 8420 while (!frq[*im]) (*im)++; 8421 8422 int nf = 0; 8423 8424 for (int i = *im; i < HUF_ENCSIZE; i++) { 8425 hlink[i] = i; 8426 8427 if (frq[i]) { 8428 fHeap[nf] = &frq[i]; 8429 nf++; 8430 *iM = i; 8431 } 8432 } 8433 8434 // 8435 // Add a pseudo-symbol, with a frequency count of 1, to frq; 8436 // adjust the fHeap and hlink array accordingly. Function 8437 // hufEncode() uses the pseudo-symbol for run-length encoding. 8438 // 8439 8440 (*iM)++; 8441 frq[*iM] = 1; 8442 fHeap[nf] = &frq[*iM]; 8443 nf++; 8444 8445 // 8446 // Build an array, scode, such that scode[i] contains the number 8447 // of bits assigned to symbol i. Conceptually this is done by 8448 // constructing a tree whose leaves are the symbols with non-zero 8449 // frequency: 8450 // 8451 // Make a heap that contains all symbols with a non-zero frequency, 8452 // with the least frequent symbol on top. 8453 // 8454 // Repeat until only one symbol is left on the heap: 8455 // 8456 // Take the two least frequent symbols off the top of the heap. 8457 // Create a new node that has first two nodes as children, and 8458 // whose frequency is the sum of the frequencies of the first 8459 // two nodes. Put the new node back into the heap. 8460 // 8461 // The last node left on the heap is the root of the tree. For each 8462 // leaf node, the distance between the root and the leaf is the length 8463 // of the code for the corresponding symbol. 8464 // 8465 // The loop below doesn't actually build the tree; instead we compute 8466 // the distances of the leaves from the root on the fly. When a new 8467 // node is added to the heap, then that node's descendants are linked 8468 // into a single linear list that starts at the new node, and the code 8469 // lengths of the descendants (that is, their distance from the root 8470 // of the tree) are incremented by one. 8471 // 8472 8473 std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); 8474 8475 std::vector<long long> scode(HUF_ENCSIZE); 8476 memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE); 8477 8478 while (nf > 1) { 8479 // 8480 // Find the indices, mm and m, of the two smallest non-zero frq 8481 // values in fHeap, add the smallest frq to the second-smallest 8482 // frq, and remove the smallest frq value from fHeap. 8483 // 8484 8485 int mm = fHeap[0] - frq; 8486 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); 8487 --nf; 8488 8489 int m = fHeap[0] - frq; 8490 std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); 8491 8492 frq[m] += frq[mm]; 8493 std::push_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); 8494 8495 // 8496 // The entries in scode are linked into lists with the 8497 // entries in hlink serving as "next" pointers and with 8498 // the end of a list marked by hlink[j] == j. 8499 // 8500 // Traverse the lists that start at scode[m] and scode[mm]. 8501 // For each element visited, increment the length of the 8502 // corresponding code by one bit. (If we visit scode[j] 8503 // during the traversal, then the code for symbol j becomes 8504 // one bit longer.) 8505 // 8506 // Merge the lists that start at scode[m] and scode[mm] 8507 // into a single list that starts at scode[m]. 8508 // 8509 8510 // 8511 // Add a bit to all codes in the first list. 8512 // 8513 8514 for (int j = m;; j = hlink[j]) { 8515 scode[j]++; 8516 8517 TEXR_ASSERT(scode[j] <= 58); 8518 8519 if (hlink[j] == j) { 8520 // 8521 // Merge the two lists. 8522 // 8523 8524 hlink[j] = mm; 8525 break; 8526 } 8527 } 8528 8529 // 8530 // Add a bit to all codes in the second list 8531 // 8532 8533 for (int j = mm;; j = hlink[j]) { 8534 scode[j]++; 8535 8536 TEXR_ASSERT(scode[j] <= 58); 8537 8538 if (hlink[j] == j) break; 8539 } 8540 } 8541 8542 // 8543 // Build a canonical Huffman code table, replacing the code 8544 // lengths in scode with (code, code length) pairs. Copy the 8545 // code table from scode into frq. 8546 // 8547 8548 hufCanonicalCodeTable(scode.data()); 8549 memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE); 8550} 8551 8552// 8553// Pack an encoding table: 8554// - only code lengths, not actual codes, are stored 8555// - runs of zeroes are compressed as follows: 8556// 8557// unpacked packed 8558// -------------------------------- 8559// 1 zero 0 (6 bits) 8560// 2 zeroes 59 8561// 3 zeroes 60 8562// 4 zeroes 61 8563// 5 zeroes 62 8564// n zeroes (6 or more) 63 n-6 (6 + 8 bits) 8565// 8566 8567const int SHORT_ZEROCODE_RUN = 59; 8568const int LONG_ZEROCODE_RUN = 63; 8569const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN; 8570const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN; 8571 8572static void hufPackEncTable( 8573 const long long *hcode, // i : encoding table [HUF_ENCSIZE] 8574 int im, // i : min hcode index 8575 int iM, // i : max hcode index 8576 char **pcode) // o: ptr to packed table (updated) 8577{ 8578 char *p = *pcode; 8579 long long c = 0; 8580 int lc = 0; 8581 8582 for (; im <= iM; im++) { 8583 int l = hufLength(hcode[im]); 8584 8585 if (l == 0) { 8586 int zerun = 1; 8587 8588 while ((im < iM) && (zerun < LONGEST_LONG_RUN)) { 8589 if (hufLength(hcode[im + 1]) > 0) break; 8590 im++; 8591 zerun++; 8592 } 8593 8594 if (zerun >= 2) { 8595 if (zerun >= SHORTEST_LONG_RUN) { 8596 outputBits(6, LONG_ZEROCODE_RUN, c, lc, p); 8597 outputBits(8, zerun - SHORTEST_LONG_RUN, c, lc, p); 8598 } else { 8599 outputBits(6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p); 8600 } 8601 continue; 8602 } 8603 } 8604 8605 outputBits(6, l, c, lc, p); 8606 } 8607 8608 if (lc > 0) *p++ = (unsigned char)(c << (8 - lc)); 8609 8610 *pcode = p; 8611} 8612 8613// 8614// Unpack an encoding table packed by hufPackEncTable(): 8615// 8616 8617static bool hufUnpackEncTable( 8618 const char **pcode, // io: ptr to packed table (updated) 8619 int ni, // i : input size (in bytes) 8620 int im, // i : min hcode index 8621 int iM, // i : max hcode index 8622 long long *hcode) // o: encoding table [HUF_ENCSIZE] 8623{ 8624 memset(hcode, 0, sizeof(long long) * HUF_ENCSIZE); 8625 8626 const char *p = *pcode; 8627 long long c = 0; 8628 int lc = 0; 8629 8630 for (; im <= iM; im++) { 8631 if (p - *pcode >= ni) { 8632 return false; 8633 } 8634 8635 long long l = hcode[im] = getBits(6, c, lc, p); // code length 8636 8637 if (l == (long long)LONG_ZEROCODE_RUN) { 8638 if (p - *pcode > ni) { 8639 return false; 8640 } 8641 8642 int zerun = getBits(8, c, lc, p) + SHORTEST_LONG_RUN; 8643 8644 if (im + zerun > iM + 1) { 8645 return false; 8646 } 8647 8648 while (zerun--) hcode[im++] = 0; 8649 8650 im--; 8651 } else if (l >= (long long)SHORT_ZEROCODE_RUN) { 8652 int zerun = l - SHORT_ZEROCODE_RUN + 2; 8653 8654 if (im + zerun > iM + 1) { 8655 return false; 8656 } 8657 8658 while (zerun--) hcode[im++] = 0; 8659 8660 im--; 8661 } 8662 } 8663 8664 *pcode = const_cast<char *>(p); 8665 8666 hufCanonicalCodeTable(hcode); 8667 8668 return true; 8669} 8670 8671// 8672// DECODING TABLE BUILDING 8673// 8674 8675// 8676// Clear a newly allocated decoding table so that it contains only zeroes. 8677// 8678 8679static void hufClearDecTable(HufDec *hdecod) // io: (allocated by caller) 8680// decoding table [HUF_DECSIZE] 8681{ 8682 for (int i = 0; i < HUF_DECSIZE; i++) { 8683 hdecod[i].len = 0; 8684 hdecod[i].lit = 0; 8685 hdecod[i].p = NULL; 8686 } 8687 // memset(hdecod, 0, sizeof(HufDec) * HUF_DECSIZE); 8688} 8689 8690// 8691// Build a decoding hash table based on the encoding table hcode: 8692// - short codes (<= HUF_DECBITS) are resolved with a single table access; 8693// - long code entry allocations are not optimized, because long codes are 8694// unfrequent; 8695// - decoding tables are used by hufDecode(); 8696// 8697 8698static bool hufBuildDecTable(const long long *hcode, // i : encoding table 8699 int im, // i : min index in hcode 8700 int iM, // i : max index in hcode 8701 HufDec *hdecod) // o: (allocated by caller) 8702// decoding table [HUF_DECSIZE] 8703{ 8704 // 8705 // Init hashtable & loop on all codes. 8706 // Assumes that hufClearDecTable(hdecod) has already been called. 8707 // 8708 8709 for (; im <= iM; im++) { 8710 long long c = hufCode(hcode[im]); 8711 int l = hufLength(hcode[im]); 8712 8713 if (c >> l) { 8714 // 8715 // Error: c is supposed to be an l-bit code, 8716 // but c contains a value that is greater 8717 // than the largest l-bit number. 8718 // 8719 8720 // invalidTableEntry(); 8721 return false; 8722 } 8723 8724 if (l > HUF_DECBITS) { 8725 // 8726 // Long code: add a secondary entry 8727 // 8728 8729 HufDec *pl = hdecod + (c >> (l - HUF_DECBITS)); 8730 8731 if (pl->len) { 8732 // 8733 // Error: a short code has already 8734 // been stored in table entry *pl. 8735 // 8736 8737 // invalidTableEntry(); 8738 return false; 8739 } 8740 8741 pl->lit++; 8742 8743 if (pl->p) { 8744 int *p = pl->p; 8745 pl->p = new int[pl->lit]; 8746 8747 for (int i = 0; i < pl->lit - 1; ++i) pl->p[i] = p[i]; 8748 8749 delete[] p; 8750 } else { 8751 pl->p = new int[1]; 8752 } 8753 8754 pl->p[pl->lit - 1] = im; 8755 } else if (l) { 8756 // 8757 // Short code: init all primary entries 8758 // 8759 8760 HufDec *pl = hdecod + (c << (HUF_DECBITS - l)); 8761 8762 for (long long i = 1ULL << (HUF_DECBITS - l); i > 0; i--, pl++) { 8763 if (pl->len || pl->p) { 8764 // 8765 // Error: a short code or a long code has 8766 // already been stored in table entry *pl. 8767 // 8768 8769 // invalidTableEntry(); 8770 return false; 8771 } 8772 8773 pl->len = l; 8774 pl->lit = im; 8775 } 8776 } 8777 } 8778 8779 return true; 8780} 8781 8782// 8783// Free the long code entries of a decoding table built by hufBuildDecTable() 8784// 8785 8786static void hufFreeDecTable(HufDec *hdecod) // io: Decoding table 8787{ 8788 for (int i = 0; i < HUF_DECSIZE; i++) { 8789 if (hdecod[i].p) { 8790 delete[] hdecod[i].p; 8791 hdecod[i].p = 0; 8792 } 8793 } 8794} 8795 8796// 8797// ENCODING 8798// 8799 8800inline void outputCode(long long code, long long &c, int &lc, char *&out) { 8801 outputBits(hufLength(code), hufCode(code), c, lc, out); 8802} 8803 8804inline void sendCode(long long sCode, int runCount, long long runCode, 8805 long long &c, int &lc, char *&out) { 8806 // 8807 // Output a run of runCount instances of the symbol sCount. 8808 // Output the symbols explicitly, or if that is shorter, output 8809 // the sCode symbol once followed by a runCode symbol and runCount 8810 // expressed as an 8-bit number. 8811 // 8812 8813 if (hufLength(sCode) + hufLength(runCode) + 8 < hufLength(sCode) * runCount) { 8814 outputCode(sCode, c, lc, out); 8815 outputCode(runCode, c, lc, out); 8816 outputBits(8, runCount, c, lc, out); 8817 } else { 8818 while (runCount-- >= 0) outputCode(sCode, c, lc, out); 8819 } 8820} 8821 8822// 8823// Encode (compress) ni values based on the Huffman encoding table hcode: 8824// 8825 8826static int hufEncode // return: output size (in bits) 8827 (const long long *hcode, // i : encoding table 8828 const unsigned short *in, // i : uncompressed input buffer 8829 const int ni, // i : input buffer size (in bytes) 8830 int rlc, // i : rl code 8831 char *out) // o: compressed output buffer 8832{ 8833 char *outStart = out; 8834 long long c = 0; // bits not yet written to out 8835 int lc = 0; // number of valid bits in c (LSB) 8836 int s = in[0]; 8837 int cs = 0; 8838 8839 // 8840 // Loop on input values 8841 // 8842 8843 for (int i = 1; i < ni; i++) { 8844 // 8845 // Count same values or send code 8846 // 8847 8848 if (s == in[i] && cs < 255) { 8849 cs++; 8850 } else { 8851 sendCode(hcode[s], cs, hcode[rlc], c, lc, out); 8852 cs = 0; 8853 } 8854 8855 s = in[i]; 8856 } 8857 8858 // 8859 // Send remaining code 8860 // 8861 8862 sendCode(hcode[s], cs, hcode[rlc], c, lc, out); 8863 8864 if (lc) *out = (c << (8 - lc)) & 0xff; 8865 8866 return (out - outStart) * 8 + lc; 8867} 8868 8869// 8870// DECODING 8871// 8872 8873// 8874// In order to force the compiler to inline them, 8875// getChar() and getCode() are implemented as macros 8876// instead of "inline" functions. 8877// 8878 8879#define getChar(c, lc, in) \ 8880 { \ 8881 c = (c << 8) | *(unsigned char *)(in++); \ 8882 lc += 8; \ 8883 } 8884 8885#if 0 8886#define getCode(po, rlc, c, lc, in, out, ob, oe) \ 8887 { \ 8888 if (po == rlc) { \ 8889 if (lc < 8) getChar(c, lc, in); \ 8890 \ 8891 lc -= 8; \ 8892 \ 8893 unsigned char cs = (c >> lc); \ 8894 \ 8895 if (out + cs > oe) return false; \ 8896 \ 8897 /* TinyEXR issue 78 */ \ 8898 unsigned short s = out[-1]; \ 8899 \ 8900 while (cs-- > 0) *out++ = s; \ 8901 } else if (out < oe) { \ 8902 *out++ = po; \ 8903 } else { \ 8904 return false; \ 8905 } \ 8906 } 8907#else 8908static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in, 8909 const char *in_end, unsigned short *&out, 8910 const unsigned short *ob, const unsigned short *oe) { 8911 (void)ob; 8912 if (po == rlc) { 8913 if (lc < 8) { 8914 /* TinyEXR issue 78 */ 8915 if ((in + 1) >= in_end) { 8916 return false; 8917 } 8918 8919 getChar(c, lc, in); 8920 } 8921 8922 lc -= 8; 8923 8924 unsigned char cs = (c >> lc); 8925 8926 if (out + cs > oe) return false; 8927 8928 // Bounds check for safety 8929 // Issue 100. 8930 if ((out - 1) < ob) return false; 8931 unsigned short s = out[-1]; 8932 8933 while (cs-- > 0) *out++ = s; 8934 } else if (out < oe) { 8935 *out++ = po; 8936 } else { 8937 return false; 8938 } 8939 return true; 8940} 8941#endif 8942 8943// 8944// Decode (uncompress) ni bits based on encoding & decoding tables: 8945// 8946 8947static bool hufDecode(const long long *hcode, // i : encoding table 8948 const HufDec *hdecod, // i : decoding table 8949 const char *in, // i : compressed input buffer 8950 int ni, // i : input size (in bits) 8951 int rlc, // i : run-length code 8952 int no, // i : expected output size (in bytes) 8953 unsigned short *out) // o: uncompressed output buffer 8954{ 8955 long long c = 0; 8956 int lc = 0; 8957 unsigned short *outb = out; // begin 8958 unsigned short *oe = out + no; // end 8959 const char *ie = in + (ni + 7) / 8; // input byte size 8960 8961 // 8962 // Loop on input bytes 8963 // 8964 8965 while (in < ie) { 8966 getChar(c, lc, in); 8967 8968 // 8969 // Access decoding table 8970 // 8971 8972 while (lc >= HUF_DECBITS) { 8973 const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK]; 8974 8975 if (pl.len) { 8976 // 8977 // Get short code 8978 // 8979 8980 lc -= pl.len; 8981 // std::cout << "lit = " << pl.lit << std::endl; 8982 // std::cout << "rlc = " << rlc << std::endl; 8983 // std::cout << "c = " << c << std::endl; 8984 // std::cout << "lc = " << lc << std::endl; 8985 // std::cout << "in = " << in << std::endl; 8986 // std::cout << "out = " << out << std::endl; 8987 // std::cout << "oe = " << oe << std::endl; 8988 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { 8989 return false; 8990 } 8991 } else { 8992 if (!pl.p) { 8993 return false; 8994 } 8995 // invalidCode(); // wrong code 8996 8997 // 8998 // Search long code 8999 // 9000 9001 int j; 9002 9003 for (j = 0; j < pl.lit; j++) { 9004 int l = hufLength(hcode[pl.p[j]]); 9005 9006 while (lc < l && in < ie) // get more bits 9007 getChar(c, lc, in); 9008 9009 if (lc >= l) { 9010 if (hufCode(hcode[pl.p[j]]) == 9011 ((c >> (lc - l)) & (((long long)(1) << l) - 1))) { 9012 // 9013 // Found : get long code 9014 // 9015 9016 lc -= l; 9017 if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) { 9018 return false; 9019 } 9020 break; 9021 } 9022 } 9023 } 9024 9025 if (j == pl.lit) { 9026 return false; 9027 // invalidCode(); // Not found 9028 } 9029 } 9030 } 9031 } 9032 9033 // 9034 // Get remaining (short) codes 9035 // 9036 9037 int i = (8 - ni) & 7; 9038 c >>= i; 9039 lc -= i; 9040 9041 while (lc > 0) { 9042 const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK]; 9043 9044 if (pl.len) { 9045 lc -= pl.len; 9046 if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { 9047 return false; 9048 } 9049 } else { 9050 return false; 9051 // invalidCode(); // wrong (long) code 9052 } 9053 } 9054 9055 if (out - outb != no) { 9056 return false; 9057 } 9058 // notEnoughData (); 9059 9060 return true; 9061} 9062 9063static void countFrequencies(std::vector<long long> &freq, 9064 const unsigned short data[/*n*/], int n) { 9065 for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0; 9066 9067 for (int i = 0; i < n; ++i) ++freq[data[i]]; 9068} 9069 9070static void writeUInt(char buf[4], unsigned int i) { 9071 unsigned char *b = (unsigned char *)buf; 9072 9073 b[0] = i; 9074 b[1] = i >> 8; 9075 b[2] = i >> 16; 9076 b[3] = i >> 24; 9077} 9078 9079static unsigned int readUInt(const char buf[4]) { 9080 const unsigned char *b = (const unsigned char *)buf; 9081 9082 return (b[0] & 0x000000ff) | ((b[1] << 8) & 0x0000ff00) | 9083 ((b[2] << 16) & 0x00ff0000) | ((b[3] << 24) & 0xff000000); 9084} 9085 9086// 9087// EXTERNAL INTERFACE 9088// 9089 9090static int hufCompress(const unsigned short raw[], int nRaw, 9091 char compressed[]) { 9092 if (nRaw == 0) return 0; 9093 9094 std::vector<long long> freq(HUF_ENCSIZE); 9095 9096 countFrequencies(freq, raw, nRaw); 9097 9098 int im = 0; 9099 int iM = 0; 9100 hufBuildEncTable(freq.data(), &im, &iM); 9101 9102 char *tableStart = compressed + 20; 9103 char *tableEnd = tableStart; 9104 hufPackEncTable(freq.data(), im, iM, &tableEnd); 9105 int tableLength = tableEnd - tableStart; 9106 9107 char *dataStart = tableEnd; 9108 int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart); 9109 int data_length = (nBits + 7) / 8; 9110 9111 writeUInt(compressed, im); 9112 writeUInt(compressed + 4, iM); 9113 writeUInt(compressed + 8, tableLength); 9114 writeUInt(compressed + 12, nBits); 9115 writeUInt(compressed + 16, 0); // room for future extensions 9116 9117 return dataStart + data_length - compressed; 9118} 9119 9120static bool hufUncompress(const char compressed[], int nCompressed, 9121 std::vector<unsigned short> *raw) { 9122 if (nCompressed == 0) { 9123 if (raw->size() != 0) return false; 9124 9125 return false; 9126 } 9127 9128 int im = readUInt(compressed); 9129 int iM = readUInt(compressed + 4); 9130 // int tableLength = readUInt (compressed + 8); 9131 int nBits = readUInt(compressed + 12); 9132 9133 if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) return false; 9134 9135 const char *ptr = compressed + 20; 9136 9137 // 9138 // Fast decoder needs at least 2x64-bits of compressed data, and 9139 // needs to be run-able on this platform. Otherwise, fall back 9140 // to the original decoder 9141 // 9142 9143 // if (FastHufDecoder::enabled() && nBits > 128) 9144 //{ 9145 // FastHufDecoder fhd (ptr, nCompressed - (ptr - compressed), im, iM, iM); 9146 // fhd.decode ((unsigned char*)ptr, nBits, raw, nRaw); 9147 //} 9148 // else 9149 { 9150 std::vector<long long> freq(HUF_ENCSIZE); 9151 std::vector<HufDec> hdec(HUF_DECSIZE); 9152 9153 hufClearDecTable(&hdec.at(0)); 9154 9155 hufUnpackEncTable(&ptr, nCompressed - (ptr - compressed), im, iM, 9156 &freq.at(0)); 9157 9158 { 9159 if (nBits > 8 * (nCompressed - (ptr - compressed))) { 9160 return false; 9161 } 9162 9163 hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0)); 9164 hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(), 9165 raw->data()); 9166 } 9167 // catch (...) 9168 //{ 9169 // hufFreeDecTable (hdec); 9170 // throw; 9171 //} 9172 9173 hufFreeDecTable(&hdec.at(0)); 9174 } 9175 9176 return true; 9177} 9178 9179// 9180// Functions to compress the range of values in the pixel data 9181// 9182 9183const int USHORT_RANGE = (1 << 16); 9184const int BITMAP_SIZE = (USHORT_RANGE >> 3); 9185 9186static void bitmapFromData(const unsigned short data[/*nData*/], int nData, 9187 unsigned char bitmap[BITMAP_SIZE], 9188 unsigned short &minNonZero, 9189 unsigned short &maxNonZero) { 9190 for (int i = 0; i < BITMAP_SIZE; ++i) bitmap[i] = 0; 9191 9192 for (int i = 0; i < nData; ++i) bitmap[data[i] >> 3] |= (1 << (data[i] & 7)); 9193 9194 bitmap[0] &= ~1; // zero is not explicitly stored in 9195 // the bitmap; we assume that the 9196 // data always contain zeroes 9197 minNonZero = BITMAP_SIZE - 1; 9198 maxNonZero = 0; 9199 9200 for (int i = 0; i < BITMAP_SIZE; ++i) { 9201 if (bitmap[i]) { 9202 if (minNonZero > i) minNonZero = i; 9203 if (maxNonZero < i) maxNonZero = i; 9204 } 9205 } 9206} 9207 9208static unsigned short forwardLutFromBitmap( 9209 const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) { 9210 int k = 0; 9211 9212 for (int i = 0; i < USHORT_RANGE; ++i) { 9213 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) 9214 lut[i] = k++; 9215 else 9216 lut[i] = 0; 9217 } 9218 9219 return k - 1; // maximum value stored in lut[], 9220} // i.e. number of ones in bitmap minus 1 9221 9222static unsigned short reverseLutFromBitmap( 9223 const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) { 9224 int k = 0; 9225 9226 for (int i = 0; i < USHORT_RANGE; ++i) { 9227 if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) lut[k++] = i; 9228 } 9229 9230 int n = k - 1; 9231 9232 while (k < USHORT_RANGE) lut[k++] = 0; 9233 9234 return n; // maximum k where lut[k] is non-zero, 9235} // i.e. number of ones in bitmap minus 1 9236 9237static void applyLut(const unsigned short lut[USHORT_RANGE], 9238 unsigned short data[/*nData*/], int nData) { 9239 for (int i = 0; i < nData; ++i) data[i] = lut[data[i]]; 9240} 9241 9242#ifdef __clang__ 9243#pragma clang diagnostic pop 9244#endif // __clang__ 9245 9246#ifdef _MSC_VER 9247#pragma warning(pop) 9248#endif 9249 9250static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize, 9251 const unsigned char *inPtr, size_t inSize, 9252 const std::vector<ChannelInfo> &channelInfo, 9253 int data_width, int num_lines) { 9254 std::vector<unsigned char> bitmap(BITMAP_SIZE); 9255 unsigned short minNonZero; 9256 unsigned short maxNonZero; 9257 9258#if !MINIZ_LITTLE_ENDIAN 9259 // @todo { PIZ compression on BigEndian architecture. } 9260 TEXR_ASSERT(0); 9261 return false; 9262#endif 9263 9264 // Assume `inSize` is multiple of 2 or 4. 9265 std::vector<unsigned short> tmpBuffer(inSize / sizeof(unsigned short)); 9266 9267 std::vector<PIZChannelData> channelData(channelInfo.size()); 9268 unsigned short *tmpBufferEnd = &tmpBuffer.at(0); 9269 9270 for (size_t c = 0; c < channelData.size(); c++) { 9271 PIZChannelData &cd = channelData[c]; 9272 9273 cd.start = tmpBufferEnd; 9274 cd.end = cd.start; 9275 9276 cd.nx = data_width; 9277 cd.ny = num_lines; 9278 // cd.ys = c.channel().ySampling; 9279 9280 size_t pixelSize = sizeof(int); // UINT and FLOAT 9281 if (channelInfo[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { 9282 pixelSize = sizeof(short); 9283 } 9284 9285 cd.size = static_cast<int>(pixelSize / sizeof(short)); 9286 9287 tmpBufferEnd += cd.nx * cd.ny * cd.size; 9288 } 9289 9290 const unsigned char *ptr = inPtr; 9291 for (int y = 0; y < num_lines; ++y) { 9292 for (size_t i = 0; i < channelData.size(); ++i) { 9293 PIZChannelData &cd = channelData[i]; 9294 9295 // if (modp (y, cd.ys) != 0) 9296 // continue; 9297 9298 size_t n = static_cast<size_t>(cd.nx * cd.size); 9299 memcpy(cd.end, ptr, n * sizeof(unsigned short)); 9300 ptr += n * sizeof(unsigned short); 9301 cd.end += n; 9302 } 9303 } 9304 9305 bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), 9306 bitmap.data(), minNonZero, maxNonZero); 9307 9308 std::vector<unsigned short> lut(USHORT_RANGE); 9309 unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data()); 9310 applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size())); 9311 9312 // 9313 // Store range compression info in _outBuffer 9314 // 9315 9316 char *buf = reinterpret_cast<char *>(outPtr); 9317 9318 memcpy(buf, &minNonZero, sizeof(unsigned short)); 9319 buf += sizeof(unsigned short); 9320 memcpy(buf, &maxNonZero, sizeof(unsigned short)); 9321 buf += sizeof(unsigned short); 9322 9323 if (minNonZero <= maxNonZero) { 9324 memcpy(buf, reinterpret_cast<char *>(&bitmap[0] + minNonZero), 9325 maxNonZero - minNonZero + 1); 9326 buf += maxNonZero - minNonZero + 1; 9327 } 9328 9329 // 9330 // Apply wavelet encoding 9331 // 9332 9333 for (size_t i = 0; i < channelData.size(); ++i) { 9334 PIZChannelData &cd = channelData[i]; 9335 9336 for (int j = 0; j < cd.size; ++j) { 9337 wav2Encode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, 9338 maxValue); 9339 } 9340 } 9341 9342 // 9343 // Apply Huffman encoding; append the result to _outBuffer 9344 // 9345 9346 // length header(4byte), then huff data. Initialize length header with zero, 9347 // then later fill it by `length`. 9348 char *lengthPtr = buf; 9349 int zero = 0; 9350 memcpy(buf, &zero, sizeof(int)); 9351 buf += sizeof(int); 9352 9353 int length = 9354 hufCompress(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), buf); 9355 memcpy(lengthPtr, &length, sizeof(int)); 9356 9357 (*outSize) = static_cast<unsigned int>( 9358 (reinterpret_cast<unsigned char *>(buf) - outPtr) + 9359 static_cast<unsigned int>(length)); 9360 9361 // Use uncompressed data when compressed data is larger than uncompressed. 9362 // (Issue 40) 9363 if ((*outSize) >= inSize) { 9364 (*outSize) = static_cast<unsigned int>(inSize); 9365 memcpy(outPtr, inPtr, inSize); 9366 } 9367 return true; 9368} 9369 9370static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, 9371 size_t tmpBufSize, size_t inLen, int num_channels, 9372 const EXRChannelInfo *channels, int data_width, 9373 int num_lines) { 9374 if (inLen == tmpBufSize) { 9375 // Data is not compressed(Issue 40). 9376 memcpy(outPtr, inPtr, inLen); 9377 return true; 9378 } 9379 9380 std::vector<unsigned char> bitmap(BITMAP_SIZE); 9381 unsigned short minNonZero; 9382 unsigned short maxNonZero; 9383 9384#if !MINIZ_LITTLE_ENDIAN 9385 // @todo { PIZ compression on BigEndian architecture. } 9386 TEXR_ASSERT(0); 9387 return false; 9388#endif 9389 9390 memset(bitmap.data(), 0, BITMAP_SIZE); 9391 9392 const unsigned char *ptr = inPtr; 9393 // minNonZero = *(reinterpret_cast<const unsigned short *>(ptr)); 9394 tinyexr::cpy2(&minNonZero, reinterpret_cast<const unsigned short *>(ptr)); 9395 // maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2)); 9396 tinyexr::cpy2(&maxNonZero, reinterpret_cast<const unsigned short *>(ptr + 2)); 9397 ptr += 4; 9398 9399 if (maxNonZero >= BITMAP_SIZE) { 9400 return false; 9401 } 9402 9403 if (minNonZero <= maxNonZero) { 9404 memcpy(reinterpret_cast<char *>(&bitmap[0] + minNonZero), ptr, 9405 maxNonZero - minNonZero + 1); 9406 ptr += maxNonZero - minNonZero + 1; 9407 } 9408 9409 std::vector<unsigned short> lut(USHORT_RANGE); 9410 memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE); 9411 unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data()); 9412 9413 // 9414 // Huffman decoding 9415 // 9416 9417 int length; 9418 9419 // length = *(reinterpret_cast<const int *>(ptr)); 9420 tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr)); 9421 ptr += sizeof(int); 9422 9423 if (size_t((ptr - inPtr) + length) > inLen) { 9424 return false; 9425 } 9426 9427 std::vector<unsigned short> tmpBuffer(tmpBufSize); 9428 hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer); 9429 9430 // 9431 // Wavelet decoding 9432 // 9433 9434 std::vector<PIZChannelData> channelData(static_cast<size_t>(num_channels)); 9435 9436 unsigned short *tmpBufferEnd = &tmpBuffer.at(0); 9437 9438 for (size_t i = 0; i < static_cast<size_t>(num_channels); ++i) { 9439 const EXRChannelInfo &chan = channels[i]; 9440 9441 size_t pixelSize = sizeof(int); // UINT and FLOAT 9442 if (chan.pixel_type == TINYEXR_PIXELTYPE_HALF) { 9443 pixelSize = sizeof(short); 9444 } 9445 9446 channelData[i].start = tmpBufferEnd; 9447 channelData[i].end = channelData[i].start; 9448 channelData[i].nx = data_width; 9449 channelData[i].ny = num_lines; 9450 // channelData[i].ys = 1; 9451 channelData[i].size = static_cast<int>(pixelSize / sizeof(short)); 9452 9453 tmpBufferEnd += channelData[i].nx * channelData[i].ny * channelData[i].size; 9454 } 9455 9456 for (size_t i = 0; i < channelData.size(); ++i) { 9457 PIZChannelData &cd = channelData[i]; 9458 9459 for (int j = 0; j < cd.size; ++j) { 9460 wav2Decode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, 9461 maxValue); 9462 } 9463 } 9464 9465 // 9466 // Expand the pixel data to their original range 9467 // 9468 9469 applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBufSize)); 9470 9471 for (int y = 0; y < num_lines; y++) { 9472 for (size_t i = 0; i < channelData.size(); ++i) { 9473 PIZChannelData &cd = channelData[i]; 9474 9475 // if (modp (y, cd.ys) != 0) 9476 // continue; 9477 9478 size_t n = static_cast<size_t>(cd.nx * cd.size); 9479 memcpy(outPtr, cd.end, static_cast<size_t>(n * sizeof(unsigned short))); 9480 outPtr += n * sizeof(unsigned short); 9481 cd.end += n; 9482 } 9483 } 9484 9485 return true; 9486} 9487#endif // TINYEXR_USE_PIZ 9488 9489#if TINYEXR_USE_ZFP 9490struct ZFPCompressionParam { 9491 double rate; 9492 int precision; 9493 double tolerance; 9494 int type; // TINYEXR_ZFP_COMPRESSIONTYPE_* 9495 9496 ZFPCompressionParam() { 9497 type = TINYEXR_ZFP_COMPRESSIONTYPE_RATE; 9498 rate = 2.0; 9499 precision = 0; 9500 tolerance = 0.0f; 9501 } 9502}; 9503 9504bool FindZFPCompressionParam(ZFPCompressionParam *param, 9505 const EXRAttribute *attributes, 9506 int num_attributes) { 9507 bool foundType = false; 9508 9509 for (int i = 0; i < num_attributes; i++) { 9510 if ((strcmp(attributes[i].name, "zfpCompressionType") == 0) && 9511 (attributes[i].size == 1)) { 9512 param->type = static_cast<int>(attributes[i].value[0]); 9513 9514 foundType = true; 9515 } 9516 } 9517 9518 if (!foundType) { 9519 return false; 9520 } 9521 9522 if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { 9523 for (int i = 0; i < num_attributes; i++) { 9524 if ((strcmp(attributes[i].name, "zfpCompressionRate") == 0) && 9525 (attributes[i].size == 8)) { 9526 param->rate = *(reinterpret_cast<double *>(attributes[i].value)); 9527 return true; 9528 } 9529 } 9530 } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { 9531 for (int i = 0; i < num_attributes; i++) { 9532 if ((strcmp(attributes[i].name, "zfpCompressionPrecision") == 0) && 9533 (attributes[i].size == 4)) { 9534 param->rate = *(reinterpret_cast<int *>(attributes[i].value)); 9535 return true; 9536 } 9537 } 9538 } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { 9539 for (int i = 0; i < num_attributes; i++) { 9540 if ((strcmp(attributes[i].name, "zfpCompressionTolerance") == 0) && 9541 (attributes[i].size == 8)) { 9542 param->tolerance = *(reinterpret_cast<double *>(attributes[i].value)); 9543 return true; 9544 } 9545 } 9546 } else { 9547 TEXR_ASSERT(0); 9548 } 9549 9550 return false; 9551} 9552 9553// Assume pixel format is FLOAT for all channels. 9554static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines, 9555 int num_channels, const unsigned char *src, 9556 unsigned long src_size, 9557 const ZFPCompressionParam ¶m) { 9558 size_t uncompressed_size = dst_width * dst_num_lines * num_channels; 9559 9560 if (uncompressed_size == src_size) { 9561 // Data is not compressed(Issue 40). 9562 memcpy(dst, src, src_size); 9563 } 9564 9565 zfp_stream *zfp = NULL; 9566 zfp_field *field = NULL; 9567 9568 TEXR_ASSERT((dst_width % 4) == 0); 9569 TEXR_ASSERT((dst_num_lines % 4) == 0); 9570 9571 if ((dst_width & 3U) || (dst_num_lines & 3U)) { 9572 return false; 9573 } 9574 9575 field = 9576 zfp_field_2d(reinterpret_cast<void *>(const_cast<unsigned char *>(src)), 9577 zfp_type_float, dst_width, dst_num_lines * num_channels); 9578 zfp = zfp_stream_open(NULL); 9579 9580 if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { 9581 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimention */ 2, 9582 /* write random access */ 0); 9583 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { 9584 zfp_stream_set_precision(zfp, param.precision, zfp_type_float); 9585 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { 9586 zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float); 9587 } else { 9588 TEXR_ASSERT(0); 9589 } 9590 9591 size_t buf_size = zfp_stream_maximum_size(zfp, field); 9592 std::vector<unsigned char> buf(buf_size); 9593 memcpy(&buf.at(0), src, src_size); 9594 9595 bitstream *stream = stream_open(&buf.at(0), buf_size); 9596 zfp_stream_set_bit_stream(zfp, stream); 9597 zfp_stream_rewind(zfp); 9598 9599 size_t image_size = dst_width * dst_num_lines; 9600 9601 for (int c = 0; c < num_channels; c++) { 9602 // decompress 4x4 pixel block. 9603 for (int y = 0; y < dst_num_lines; y += 4) { 9604 for (int x = 0; x < dst_width; x += 4) { 9605 float fblock[16]; 9606 zfp_decode_block_float_2(zfp, fblock); 9607 for (int j = 0; j < 4; j++) { 9608 for (int i = 0; i < 4; i++) { 9609 dst[c * image_size + ((y + j) * dst_width + (x + i))] = 9610 fblock[j * 4 + i]; 9611 } 9612 } 9613 } 9614 } 9615 } 9616 9617 zfp_field_free(field); 9618 zfp_stream_close(zfp); 9619 stream_close(stream); 9620 9621 return true; 9622} 9623 9624// Assume pixel format is FLOAT for all channels. 9625bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize, 9626 const float *inPtr, int width, int num_lines, int num_channels, 9627 const ZFPCompressionParam ¶m) { 9628 zfp_stream *zfp = NULL; 9629 zfp_field *field = NULL; 9630 9631 TEXR_ASSERT((width % 4) == 0); 9632 TEXR_ASSERT((num_lines % 4) == 0); 9633 9634 if ((width & 3U) || (num_lines & 3U)) { 9635 return false; 9636 } 9637 9638 // create input array. 9639 field = zfp_field_2d(reinterpret_cast<void *>(const_cast<float *>(inPtr)), 9640 zfp_type_float, width, num_lines * num_channels); 9641 9642 zfp = zfp_stream_open(NULL); 9643 9644 if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { 9645 zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0); 9646 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { 9647 zfp_stream_set_precision(zfp, param.precision, zfp_type_float); 9648 } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { 9649 zfp_stream_set_accuracy(zfp, param.tolerance, zfp_type_float); 9650 } else { 9651 TEXR_ASSERT(0); 9652 } 9653 9654 size_t buf_size = zfp_stream_maximum_size(zfp, field); 9655 9656 outBuf->resize(buf_size); 9657 9658 bitstream *stream = stream_open(&outBuf->at(0), buf_size); 9659 zfp_stream_set_bit_stream(zfp, stream); 9660 zfp_field_free(field); 9661 9662 size_t image_size = width * num_lines; 9663 9664 for (int c = 0; c < num_channels; c++) { 9665 // compress 4x4 pixel block. 9666 for (int y = 0; y < num_lines; y += 4) { 9667 for (int x = 0; x < width; x += 4) { 9668 float fblock[16]; 9669 for (int j = 0; j < 4; j++) { 9670 for (int i = 0; i < 4; i++) { 9671 fblock[j * 4 + i] = 9672 inPtr[c * image_size + ((y + j) * width + (x + i))]; 9673 } 9674 } 9675 zfp_encode_block_float_2(zfp, fblock); 9676 } 9677 } 9678 } 9679 9680 zfp_stream_flush(zfp); 9681 (*outSize) = zfp_stream_compressed_size(zfp); 9682 9683 zfp_stream_close(zfp); 9684 9685 return true; 9686} 9687 9688#endif 9689 9690// 9691// ----------------------------------------------------------------- 9692// 9693 9694// TODO(syoyo): Refactor function arguments. 9695static bool DecodePixelData(/* out */ unsigned char **out_images, 9696 const int *requested_pixel_types, 9697 const unsigned char *data_ptr, size_t data_len, 9698 int compression_type, int line_order, int width, 9699 int height, int x_stride, int y, int line_no, 9700 int num_lines, size_t pixel_data_size, 9701 size_t num_attributes, 9702 const EXRAttribute *attributes, size_t num_channels, 9703 const EXRChannelInfo *channels, 9704 const std::vector<size_t> &channel_offset_list) { 9705 if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ 9706#if TINYEXR_USE_PIZ 9707 if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) { 9708 // Invalid input #90 9709 return false; 9710 } 9711 9712 // Allocate original data size. 9713 std::vector<unsigned char> outBuf(static_cast<size_t>( 9714 static_cast<size_t>(width * num_lines) * pixel_data_size)); 9715 size_t tmpBufLen = outBuf.size(); 9716 9717 bool ret = tinyexr::DecompressPiz( 9718 reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen, 9719 data_len, static_cast<int>(num_channels), channels, width, num_lines); 9720 9721 if (!ret) { 9722 return false; 9723 } 9724 9725 // For PIZ_COMPRESSION: 9726 // pixel sample data for channel 0 for scanline 0 9727 // pixel sample data for channel 1 for scanline 0 9728 // pixel sample data for channel ... for scanline 0 9729 // pixel sample data for channel n for scanline 0 9730 // pixel sample data for channel 0 for scanline 1 9731 // pixel sample data for channel 1 for scanline 1 9732 // pixel sample data for channel ... for scanline 1 9733 // pixel sample data for channel n for scanline 1 9734 // ... 9735 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) { 9736 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { 9737 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 9738 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>( 9739 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + 9740 channel_offset_list[c] * static_cast<size_t>(width))); 9741 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 9742 FP16 hf; 9743 9744 // hf.u = line_ptr[u]; 9745 // use `cpy` to avoid unaligned memory access when compiler's 9746 // optimization is on. 9747 tinyexr::cpy2(&(hf.u), line_ptr + u); 9748 9749 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); 9750 9751 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { 9752 unsigned short *image = 9753 reinterpret_cast<unsigned short **>(out_images)[c]; 9754 if (line_order == 0) { 9755 image += (static_cast<size_t>(line_no) + v) * 9756 static_cast<size_t>(x_stride) + 9757 u; 9758 } else { 9759 image += static_cast<size_t>( 9760 (height - 1 - (line_no + static_cast<int>(v)))) * 9761 static_cast<size_t>(x_stride) + 9762 u; 9763 } 9764 *image = hf.u; 9765 } else { // HALF -> FLOAT 9766 FP32 f32 = half_to_float(hf); 9767 float *image = reinterpret_cast<float **>(out_images)[c]; 9768 size_t offset = 0; 9769 if (line_order == 0) { 9770 offset = (static_cast<size_t>(line_no) + v) * 9771 static_cast<size_t>(x_stride) + 9772 u; 9773 } else { 9774 offset = static_cast<size_t>( 9775 (height - 1 - (line_no + static_cast<int>(v)))) * 9776 static_cast<size_t>(x_stride) + 9777 u; 9778 } 9779 image += offset; 9780 *image = f32.f; 9781 } 9782 } 9783 } 9784 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { 9785 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); 9786 9787 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 9788 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>( 9789 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + 9790 channel_offset_list[c] * static_cast<size_t>(width))); 9791 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 9792 unsigned int val; 9793 // val = line_ptr[u]; 9794 tinyexr::cpy4(&val, line_ptr + u); 9795 9796 tinyexr::swap4(&val); 9797 9798 unsigned int *image = 9799 reinterpret_cast<unsigned int **>(out_images)[c]; 9800 if (line_order == 0) { 9801 image += (static_cast<size_t>(line_no) + v) * 9802 static_cast<size_t>(x_stride) + 9803 u; 9804 } else { 9805 image += static_cast<size_t>( 9806 (height - 1 - (line_no + static_cast<int>(v)))) * 9807 static_cast<size_t>(x_stride) + 9808 u; 9809 } 9810 *image = val; 9811 } 9812 } 9813 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { 9814 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); 9815 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 9816 const float *line_ptr = reinterpret_cast<float *>(&outBuf.at( 9817 v * pixel_data_size * static_cast<size_t>(x_stride) + 9818 channel_offset_list[c] * static_cast<size_t>(x_stride))); 9819 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 9820 float val; 9821 // val = line_ptr[u]; 9822 tinyexr::cpy4(&val, line_ptr + u); 9823 9824 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); 9825 9826 float *image = reinterpret_cast<float **>(out_images)[c]; 9827 if (line_order == 0) { 9828 image += (static_cast<size_t>(line_no) + v) * 9829 static_cast<size_t>(x_stride) + 9830 u; 9831 } else { 9832 image += static_cast<size_t>( 9833 (height - 1 - (line_no + static_cast<int>(v)))) * 9834 static_cast<size_t>(x_stride) + 9835 u; 9836 } 9837 *image = val; 9838 } 9839 } 9840 } else { 9841 TEXR_ASSERT(0); 9842 } 9843 } 9844#else 9845 TEXR_ASSERT(0 && "PIZ is enabled in this build"); 9846 return false; 9847#endif 9848 9849 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS || 9850 compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { 9851 // Allocate original data size. 9852 std::vector<unsigned char> outBuf(static_cast<size_t>(width) * 9853 static_cast<size_t>(num_lines) * 9854 pixel_data_size); 9855 9856 unsigned long dstLen = static_cast<unsigned long>(outBuf.size()); 9857 TEXR_ASSERT(dstLen > 0); 9858 if (!tinyexr::DecompressZip( 9859 reinterpret_cast<unsigned char *>(&outBuf.at(0)), &dstLen, data_ptr, 9860 static_cast<unsigned long>(data_len))) { 9861 return false; 9862 } 9863 9864 // For ZIP_COMPRESSION: 9865 // pixel sample data for channel 0 for scanline 0 9866 // pixel sample data for channel 1 for scanline 0 9867 // pixel sample data for channel ... for scanline 0 9868 // pixel sample data for channel n for scanline 0 9869 // pixel sample data for channel 0 for scanline 1 9870 // pixel sample data for channel 1 for scanline 1 9871 // pixel sample data for channel ... for scanline 1 9872 // pixel sample data for channel n for scanline 1 9873 // ... 9874 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) { 9875 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { 9876 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 9877 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>( 9878 &outBuf.at(v * static_cast<size_t>(pixel_data_size) * 9879 static_cast<size_t>(width) + 9880 channel_offset_list[c] * static_cast<size_t>(width))); 9881 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 9882 tinyexr::FP16 hf; 9883 9884 // hf.u = line_ptr[u]; 9885 tinyexr::cpy2(&(hf.u), line_ptr + u); 9886 9887 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); 9888 9889 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { 9890 unsigned short *image = 9891 reinterpret_cast<unsigned short **>(out_images)[c]; 9892 if (line_order == 0) { 9893 image += (static_cast<size_t>(line_no) + v) * 9894 static_cast<size_t>(x_stride) + 9895 u; 9896 } else { 9897 image += (static_cast<size_t>(height) - 1U - 9898 (static_cast<size_t>(line_no) + v)) * 9899 static_cast<size_t>(x_stride) + 9900 u; 9901 } 9902 *image = hf.u; 9903 } else { // HALF -> FLOAT 9904 tinyexr::FP32 f32 = half_to_float(hf); 9905 float *image = reinterpret_cast<float **>(out_images)[c]; 9906 size_t offset = 0; 9907 if (line_order == 0) { 9908 offset = (static_cast<size_t>(line_no) + v) * 9909 static_cast<size_t>(x_stride) + 9910 u; 9911 } else { 9912 offset = (static_cast<size_t>(height) - 1U - 9913 (static_cast<size_t>(line_no) + v)) * 9914 static_cast<size_t>(x_stride) + 9915 u; 9916 } 9917 image += offset; 9918 9919 *image = f32.f; 9920 } 9921 } 9922 } 9923 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { 9924 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); 9925 9926 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 9927 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>( 9928 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + 9929 channel_offset_list[c] * static_cast<size_t>(width))); 9930 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 9931 unsigned int val; 9932 // val = line_ptr[u]; 9933 tinyexr::cpy4(&val, line_ptr + u); 9934 9935 tinyexr::swap4(&val); 9936 9937 unsigned int *image = 9938 reinterpret_cast<unsigned int **>(out_images)[c]; 9939 if (line_order == 0) { 9940 image += (static_cast<size_t>(line_no) + v) * 9941 static_cast<size_t>(x_stride) + 9942 u; 9943 } else { 9944 image += (static_cast<size_t>(height) - 1U - 9945 (static_cast<size_t>(line_no) + v)) * 9946 static_cast<size_t>(x_stride) + 9947 u; 9948 } 9949 *image = val; 9950 } 9951 } 9952 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { 9953 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); 9954 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 9955 const float *line_ptr = reinterpret_cast<float *>( 9956 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + 9957 channel_offset_list[c] * static_cast<size_t>(width))); 9958 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 9959 float val; 9960 // val = line_ptr[u]; 9961 tinyexr::cpy4(&val, line_ptr + u); 9962 9963 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); 9964 9965 float *image = reinterpret_cast<float **>(out_images)[c]; 9966 if (line_order == 0) { 9967 image += (static_cast<size_t>(line_no) + v) * 9968 static_cast<size_t>(x_stride) + 9969 u; 9970 } else { 9971 image += (static_cast<size_t>(height) - 1U - 9972 (static_cast<size_t>(line_no) + v)) * 9973 static_cast<size_t>(x_stride) + 9974 u; 9975 } 9976 *image = val; 9977 } 9978 } 9979 } else { 9980 TEXR_ASSERT(0); 9981 return false; 9982 } 9983 } 9984 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) { 9985 // Allocate original data size. 9986 std::vector<unsigned char> outBuf(static_cast<size_t>(width) * 9987 static_cast<size_t>(num_lines) * 9988 pixel_data_size); 9989 9990 unsigned long dstLen = static_cast<unsigned long>(outBuf.size()); 9991 if (dstLen == 0) { 9992 return false; 9993 } 9994 9995 if (!tinyexr::DecompressRle( 9996 reinterpret_cast<unsigned char *>(&outBuf.at(0)), dstLen, data_ptr, 9997 static_cast<unsigned long>(data_len))) { 9998 return false; 9999 } 10000 10001 // For RLE_COMPRESSION: 10002 // pixel sample data for channel 0 for scanline 0 10003 // pixel sample data for channel 1 for scanline 0 10004 // pixel sample data for channel ... for scanline 0 10005 // pixel sample data for channel n for scanline 0 10006 // pixel sample data for channel 0 for scanline 1 10007 // pixel sample data for channel 1 for scanline 1 10008 // pixel sample data for channel ... for scanline 1 10009 // pixel sample data for channel n for scanline 1 10010 // ... 10011 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) { 10012 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { 10013 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 10014 const unsigned short *line_ptr = reinterpret_cast<unsigned short *>( 10015 &outBuf.at(v * static_cast<size_t>(pixel_data_size) * 10016 static_cast<size_t>(width) + 10017 channel_offset_list[c] * static_cast<size_t>(width))); 10018 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 10019 tinyexr::FP16 hf; 10020 10021 // hf.u = line_ptr[u]; 10022 tinyexr::cpy2(&(hf.u), line_ptr + u); 10023 10024 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); 10025 10026 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { 10027 unsigned short *image = 10028 reinterpret_cast<unsigned short **>(out_images)[c]; 10029 if (line_order == 0) { 10030 image += (static_cast<size_t>(line_no) + v) * 10031 static_cast<size_t>(x_stride) + 10032 u; 10033 } else { 10034 image += (static_cast<size_t>(height) - 1U - 10035 (static_cast<size_t>(line_no) + v)) * 10036 static_cast<size_t>(x_stride) + 10037 u; 10038 } 10039 *image = hf.u; 10040 } else { // HALF -> FLOAT 10041 tinyexr::FP32 f32 = half_to_float(hf); 10042 float *image = reinterpret_cast<float **>(out_images)[c]; 10043 if (line_order == 0) { 10044 image += (static_cast<size_t>(line_no) + v) * 10045 static_cast<size_t>(x_stride) + 10046 u; 10047 } else { 10048 image += (static_cast<size_t>(height) - 1U - 10049 (static_cast<size_t>(line_no) + v)) * 10050 static_cast<size_t>(x_stride) + 10051 u; 10052 } 10053 *image = f32.f; 10054 } 10055 } 10056 } 10057 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { 10058 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); 10059 10060 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 10061 const unsigned int *line_ptr = reinterpret_cast<unsigned int *>( 10062 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + 10063 channel_offset_list[c] * static_cast<size_t>(width))); 10064 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 10065 unsigned int val; 10066 // val = line_ptr[u]; 10067 tinyexr::cpy4(&val, line_ptr + u); 10068 10069 tinyexr::swap4(&val); 10070 10071 unsigned int *image = 10072 reinterpret_cast<unsigned int **>(out_images)[c]; 10073 if (line_order == 0) { 10074 image += (static_cast<size_t>(line_no) + v) * 10075 static_cast<size_t>(x_stride) + 10076 u; 10077 } else { 10078 image += (static_cast<size_t>(height) - 1U - 10079 (static_cast<size_t>(line_no) + v)) * 10080 static_cast<size_t>(x_stride) + 10081 u; 10082 } 10083 *image = val; 10084 } 10085 } 10086 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { 10087 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); 10088 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 10089 const float *line_ptr = reinterpret_cast<float *>( 10090 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + 10091 channel_offset_list[c] * static_cast<size_t>(width))); 10092 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 10093 float val; 10094 // val = line_ptr[u]; 10095 tinyexr::cpy4(&val, line_ptr + u); 10096 10097 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); 10098 10099 float *image = reinterpret_cast<float **>(out_images)[c]; 10100 if (line_order == 0) { 10101 image += (static_cast<size_t>(line_no) + v) * 10102 static_cast<size_t>(x_stride) + 10103 u; 10104 } else { 10105 image += (static_cast<size_t>(height) - 1U - 10106 (static_cast<size_t>(line_no) + v)) * 10107 static_cast<size_t>(x_stride) + 10108 u; 10109 } 10110 *image = val; 10111 } 10112 } 10113 } else { 10114 TEXR_ASSERT(0); 10115 return false; 10116 } 10117 } 10118 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { 10119#if TINYEXR_USE_ZFP 10120 tinyexr::ZFPCompressionParam zfp_compression_param; 10121 if (!FindZFPCompressionParam(&zfp_compression_param, attributes, 10122 num_attributes)) { 10123 TEXR_ASSERT(0); 10124 return false; 10125 } 10126 10127 // Allocate original data size. 10128 std::vector<unsigned char> outBuf(static_cast<size_t>(width) * 10129 static_cast<size_t>(num_lines) * 10130 pixel_data_size); 10131 10132 unsigned long dstLen = outBuf.size(); 10133 TEXR_ASSERT(dstLen > 0); 10134 tinyexr::DecompressZfp(reinterpret_cast<float *>(&outBuf.at(0)), width, 10135 num_lines, num_channels, data_ptr, 10136 static_cast<unsigned long>(data_len), 10137 zfp_compression_param); 10138 10139 // For ZFP_COMPRESSION: 10140 // pixel sample data for channel 0 for scanline 0 10141 // pixel sample data for channel 1 for scanline 0 10142 // pixel sample data for channel ... for scanline 0 10143 // pixel sample data for channel n for scanline 0 10144 // pixel sample data for channel 0 for scanline 1 10145 // pixel sample data for channel 1 for scanline 1 10146 // pixel sample data for channel ... for scanline 1 10147 // pixel sample data for channel n for scanline 1 10148 // ... 10149 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) { 10150 TEXR_ASSERT(channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT); 10151 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { 10152 TEXR_ASSERT(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); 10153 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 10154 const float *line_ptr = reinterpret_cast<float *>( 10155 &outBuf.at(v * pixel_data_size * static_cast<size_t>(width) + 10156 channel_offset_list[c] * static_cast<size_t>(width))); 10157 for (size_t u = 0; u < static_cast<size_t>(width); u++) { 10158 float val; 10159 tinyexr::cpy4(&val, line_ptr + u); 10160 10161 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); 10162 10163 float *image = reinterpret_cast<float **>(out_images)[c]; 10164 if (line_order == 0) { 10165 image += (static_cast<size_t>(line_no) + v) * 10166 static_cast<size_t>(x_stride) + 10167 u; 10168 } else { 10169 image += (static_cast<size_t>(height) - 1U - 10170 (static_cast<size_t>(line_no) + v)) * 10171 static_cast<size_t>(x_stride) + 10172 u; 10173 } 10174 *image = val; 10175 } 10176 } 10177 } else { 10178 TEXR_ASSERT(0); 10179 return false; 10180 } 10181 } 10182#else 10183 (void)attributes; 10184 (void)num_attributes; 10185 (void)num_channels; 10186 TEXR_ASSERT(0); 10187 return false; 10188#endif 10189 } else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) { 10190 for (size_t c = 0; c < num_channels; c++) { 10191 for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) { 10192 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { 10193 const unsigned short *line_ptr = 10194 reinterpret_cast<const unsigned short *>( 10195 data_ptr + v * pixel_data_size * size_t(width) + 10196 channel_offset_list[c] * static_cast<size_t>(width)); 10197 10198 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { 10199 unsigned short *outLine = 10200 reinterpret_cast<unsigned short *>(out_images[c]); 10201 if (line_order == 0) { 10202 outLine += (size_t(y) + v) * size_t(x_stride); 10203 } else { 10204 outLine += 10205 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); 10206 } 10207 10208 for (int u = 0; u < width; u++) { 10209 tinyexr::FP16 hf; 10210 10211 // hf.u = line_ptr[u]; 10212 tinyexr::cpy2(&(hf.u), line_ptr + u); 10213 10214 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); 10215 10216 outLine[u] = hf.u; 10217 } 10218 } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { 10219 float *outLine = reinterpret_cast<float *>(out_images[c]); 10220 if (line_order == 0) { 10221 outLine += (size_t(y) + v) * size_t(x_stride); 10222 } else { 10223 outLine += 10224 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); 10225 } 10226 10227 if (reinterpret_cast<const unsigned char *>(line_ptr + width) > 10228 (data_ptr + data_len)) { 10229 // Insufficient data size 10230 return false; 10231 } 10232 10233 for (int u = 0; u < width; u++) { 10234 tinyexr::FP16 hf; 10235 10236 // address may not be aliged. use byte-wise copy for safety.#76 10237 // hf.u = line_ptr[u]; 10238 tinyexr::cpy2(&(hf.u), line_ptr + u); 10239 10240 tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u)); 10241 10242 tinyexr::FP32 f32 = half_to_float(hf); 10243 10244 outLine[u] = f32.f; 10245 } 10246 } else { 10247 TEXR_ASSERT(0); 10248 return false; 10249 } 10250 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { 10251 const float *line_ptr = reinterpret_cast<const float *>( 10252 data_ptr + v * pixel_data_size * size_t(width) + 10253 channel_offset_list[c] * static_cast<size_t>(width)); 10254 10255 float *outLine = reinterpret_cast<float *>(out_images[c]); 10256 if (line_order == 0) { 10257 outLine += (size_t(y) + v) * size_t(x_stride); 10258 } else { 10259 outLine += 10260 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); 10261 } 10262 10263 if (reinterpret_cast<const unsigned char *>(line_ptr + width) > 10264 (data_ptr + data_len)) { 10265 // Insufficient data size 10266 return false; 10267 } 10268 10269 for (int u = 0; u < width; u++) { 10270 float val; 10271 tinyexr::cpy4(&val, line_ptr + u); 10272 10273 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); 10274 10275 outLine[u] = val; 10276 } 10277 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { 10278 const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>( 10279 data_ptr + v * pixel_data_size * size_t(width) + 10280 channel_offset_list[c] * static_cast<size_t>(width)); 10281 10282 unsigned int *outLine = 10283 reinterpret_cast<unsigned int *>(out_images[c]); 10284 if (line_order == 0) { 10285 outLine += (size_t(y) + v) * size_t(x_stride); 10286 } else { 10287 outLine += 10288 (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); 10289 } 10290 10291 for (int u = 0; u < width; u++) { 10292 if (reinterpret_cast<const unsigned char *>(line_ptr + u) >= 10293 (data_ptr + data_len)) { 10294 // Corrupsed data? 10295 return false; 10296 } 10297 10298 unsigned int val; 10299 tinyexr::cpy4(&val, line_ptr + u); 10300 10301 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); 10302 10303 outLine[u] = val; 10304 } 10305 } 10306 } 10307 } 10308 } 10309 10310 return true; 10311} 10312 10313static bool DecodeTiledPixelData( 10314 unsigned char **out_images, int *width, int *height, 10315 const int *requested_pixel_types, const unsigned char *data_ptr, 10316 size_t data_len, int compression_type, int line_order, int data_width, 10317 int data_height, int tile_offset_x, int tile_offset_y, int tile_size_x, 10318 int tile_size_y, size_t pixel_data_size, size_t num_attributes, 10319 const EXRAttribute *attributes, size_t num_channels, 10320 const EXRChannelInfo *channels, 10321 const std::vector<size_t> &channel_offset_list) { 10322 TEXR_ASSERT(tile_offset_x * tile_size_x < data_width); 10323 TEXR_ASSERT(tile_offset_y * tile_size_y < data_height); 10324 10325 // Compute actual image size in a tile. 10326 if ((tile_offset_x + 1) * tile_size_x >= data_width) { 10327 (*width) = data_width - (tile_offset_x * tile_size_x); 10328 } else { 10329 (*width) = tile_size_x; 10330 } 10331 10332 if ((tile_offset_y + 1) * tile_size_y >= data_height) { 10333 (*height) = data_height - (tile_offset_y * tile_size_y); 10334 } else { 10335 (*height) = tile_size_y; 10336 } 10337 10338 // Image size = tile size. 10339 return DecodePixelData(out_images, requested_pixel_types, data_ptr, data_len, 10340 compression_type, line_order, (*width), tile_size_y, 10341 /* stride */ tile_size_x, /* y */ 0, /* line_no */ 0, 10342 (*height), pixel_data_size, num_attributes, attributes, 10343 num_channels, channels, channel_offset_list); 10344} 10345 10346static bool ComputeChannelLayout(std::vector<size_t> *channel_offset_list, 10347 int *pixel_data_size, size_t *channel_offset, 10348 int num_channels, 10349 const EXRChannelInfo *channels) { 10350 channel_offset_list->resize(static_cast<size_t>(num_channels)); 10351 10352 (*pixel_data_size) = 0; 10353 (*channel_offset) = 0; 10354 10355 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) { 10356 (*channel_offset_list)[c] = (*channel_offset); 10357 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { 10358 (*pixel_data_size) += sizeof(unsigned short); 10359 (*channel_offset) += sizeof(unsigned short); 10360 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { 10361 (*pixel_data_size) += sizeof(float); 10362 (*channel_offset) += sizeof(float); 10363 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { 10364 (*pixel_data_size) += sizeof(unsigned int); 10365 (*channel_offset) += sizeof(unsigned int); 10366 } else { 10367 // ??? 10368 return false; 10369 } 10370 } 10371 return true; 10372} 10373 10374static unsigned char **AllocateImage(int num_channels, 10375 const EXRChannelInfo *channels, 10376 const int *requested_pixel_types, 10377 int data_width, int data_height) { 10378 unsigned char **images = 10379 reinterpret_cast<unsigned char **>(static_cast<float **>( 10380 malloc(sizeof(float *) * static_cast<size_t>(num_channels)))); 10381 10382 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) { 10383 size_t data_len = 10384 static_cast<size_t>(data_width) * static_cast<size_t>(data_height); 10385 if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { 10386 // pixel_data_size += sizeof(unsigned short); 10387 // channel_offset += sizeof(unsigned short); 10388 // Alloc internal image for half type. 10389 if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { 10390 images[c] = 10391 reinterpret_cast<unsigned char *>(static_cast<unsigned short *>( 10392 malloc(sizeof(unsigned short) * data_len))); 10393 } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { 10394 images[c] = reinterpret_cast<unsigned char *>( 10395 static_cast<float *>(malloc(sizeof(float) * data_len))); 10396 } else { 10397 TEXR_ASSERT(0); 10398 } 10399 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { 10400 // pixel_data_size += sizeof(float); 10401 // channel_offset += sizeof(float); 10402 images[c] = reinterpret_cast<unsigned char *>( 10403 static_cast<float *>(malloc(sizeof(float) * data_len))); 10404 } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { 10405 // pixel_data_size += sizeof(unsigned int); 10406 // channel_offset += sizeof(unsigned int); 10407 images[c] = reinterpret_cast<unsigned char *>( 10408 static_cast<unsigned int *>(malloc(sizeof(unsigned int) * data_len))); 10409 } else { 10410 TEXR_ASSERT(0); 10411 } 10412 } 10413 10414 return images; 10415} 10416 10417static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, 10418 const EXRVersion *version, std::string *err, 10419 const unsigned char *buf, size_t size) { 10420 const char *marker = reinterpret_cast<const char *>(&buf[0]); 10421 10422 if (empty_header) { 10423 (*empty_header) = false; 10424 } 10425 10426 if (version->multipart) { 10427 if (size > 0 && marker[0] == '\0') { 10428 // End of header list. 10429 if (empty_header) { 10430 (*empty_header) = true; 10431 } 10432 return TINYEXR_SUCCESS; 10433 } 10434 } 10435 10436 // According to the spec, the header of every OpenEXR file must contain at 10437 // least the following attributes: 10438 // 10439 // channels chlist 10440 // compression compression 10441 // dataWindow box2i 10442 // displayWindow box2i 10443 // lineOrder lineOrder 10444 // pixelAspectRatio float 10445 // screenWindowCenter v2f 10446 // screenWindowWidth float 10447 bool has_channels = false; 10448 bool has_compression = false; 10449 bool has_data_window = false; 10450 bool has_display_window = false; 10451 bool has_line_order = false; 10452 bool has_pixel_aspect_ratio = false; 10453 bool has_screen_window_center = false; 10454 bool has_screen_window_width = false; 10455 10456 info->data_window[0] = 0; 10457 info->data_window[1] = 0; 10458 info->data_window[2] = 0; 10459 info->data_window[3] = 0; 10460 info->line_order = 0; // @fixme 10461 info->display_window[0] = 0; 10462 info->display_window[1] = 0; 10463 info->display_window[2] = 0; 10464 info->display_window[3] = 0; 10465 info->screen_window_center[0] = 0.0f; 10466 info->screen_window_center[1] = 0.0f; 10467 info->screen_window_width = -1.0f; 10468 info->pixel_aspect_ratio = -1.0f; 10469 10470 info->tile_size_x = -1; 10471 info->tile_size_y = -1; 10472 info->tile_level_mode = -1; 10473 info->tile_rounding_mode = -1; 10474 10475 info->attributes.clear(); 10476 10477 // Read attributes 10478 size_t orig_size = size; 10479 for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) { 10480 if (0 == size) { 10481 if (err) { 10482 (*err) += "Insufficient data size for attributes.\n"; 10483 } 10484 return TINYEXR_ERROR_INVALID_DATA; 10485 } else if (marker[0] == '\0') { 10486 size--; 10487 break; 10488 } 10489 10490 std::string attr_name; 10491 std::string attr_type; 10492 std::vector<unsigned char> data; 10493 size_t marker_size; 10494 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, 10495 marker, size)) { 10496 if (err) { 10497 (*err) += "Failed to read attribute.\n"; 10498 } 10499 return TINYEXR_ERROR_INVALID_DATA; 10500 } 10501 marker += marker_size; 10502 size -= marker_size; 10503 10504 if (version->tiled && attr_name.compare("tiles") == 0) { 10505 unsigned int x_size, y_size; 10506 unsigned char tile_mode; 10507 TEXR_ASSERT(data.size() == 9); 10508 memcpy(&x_size, &data.at(0), sizeof(int)); 10509 memcpy(&y_size, &data.at(4), sizeof(int)); 10510 tile_mode = data[8]; 10511 tinyexr::swap4(&x_size); 10512 tinyexr::swap4(&y_size); 10513 10514 info->tile_size_x = static_cast<int>(x_size); 10515 info->tile_size_y = static_cast<int>(y_size); 10516 10517 // mode = levelMode + roundingMode * 16 10518 info->tile_level_mode = tile_mode & 0x3; 10519 info->tile_rounding_mode = (tile_mode >> 4) & 0x1; 10520 10521 } else if (attr_name.compare("compression") == 0) { 10522 bool ok = false; 10523 if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) { 10524 ok = true; 10525 } 10526 10527 if (data[0] == TINYEXR_COMPRESSIONTYPE_PIZ) { 10528#if TINYEXR_USE_PIZ 10529 ok = true; 10530#else 10531 if (err) { 10532 (*err) = "PIZ compression is not supported."; 10533 } 10534 return TINYEXR_ERROR_UNSUPPORTED_FORMAT; 10535#endif 10536 } 10537 10538 if (data[0] == TINYEXR_COMPRESSIONTYPE_ZFP) { 10539#if TINYEXR_USE_ZFP 10540 ok = true; 10541#else 10542 if (err) { 10543 (*err) = "ZFP compression is not supported."; 10544 } 10545 return TINYEXR_ERROR_UNSUPPORTED_FORMAT; 10546#endif 10547 } 10548 10549 if (!ok) { 10550 if (err) { 10551 (*err) = "Unknown compression type."; 10552 } 10553 return TINYEXR_ERROR_UNSUPPORTED_FORMAT; 10554 } 10555 10556 info->compression_type = static_cast<int>(data[0]); 10557 has_compression = true; 10558 10559 } else if (attr_name.compare("channels") == 0) { 10560 // name: zero-terminated string, from 1 to 255 bytes long 10561 // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2 10562 // pLinear: unsigned char, possible values are 0 and 1 10563 // reserved: three chars, should be zero 10564 // xSampling: int 10565 // ySampling: int 10566 10567 if (!ReadChannelInfo(info->channels, data)) { 10568 if (err) { 10569 (*err) += "Failed to parse channel info.\n"; 10570 } 10571 return TINYEXR_ERROR_INVALID_DATA; 10572 } 10573 10574 if (info->channels.size() < 1) { 10575 if (err) { 10576 (*err) += "# of channels is zero.\n"; 10577 } 10578 return TINYEXR_ERROR_INVALID_DATA; 10579 } 10580 10581 has_channels = true; 10582 10583 } else if (attr_name.compare("dataWindow") == 0) { 10584 if (data.size() >= 16) { 10585 memcpy(&info->data_window[0], &data.at(0), sizeof(int)); 10586 memcpy(&info->data_window[1], &data.at(4), sizeof(int)); 10587 memcpy(&info->data_window[2], &data.at(8), sizeof(int)); 10588 memcpy(&info->data_window[3], &data.at(12), sizeof(int)); 10589 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[0])); 10590 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[1])); 10591 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[2])); 10592 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[3])); 10593 has_data_window = true; 10594 } 10595 } else if (attr_name.compare("displayWindow") == 0) { 10596 if (data.size() >= 16) { 10597 memcpy(&info->display_window[0], &data.at(0), sizeof(int)); 10598 memcpy(&info->display_window[1], &data.at(4), sizeof(int)); 10599 memcpy(&info->display_window[2], &data.at(8), sizeof(int)); 10600 memcpy(&info->display_window[3], &data.at(12), sizeof(int)); 10601 tinyexr::swap4( 10602 reinterpret_cast<unsigned int *>(&info->display_window[0])); 10603 tinyexr::swap4( 10604 reinterpret_cast<unsigned int *>(&info->display_window[1])); 10605 tinyexr::swap4( 10606 reinterpret_cast<unsigned int *>(&info->display_window[2])); 10607 tinyexr::swap4( 10608 reinterpret_cast<unsigned int *>(&info->display_window[3])); 10609 10610 has_display_window = true; 10611 } 10612 } else if (attr_name.compare("lineOrder") == 0) { 10613 if (data.size() >= 1) { 10614 info->line_order = static_cast<int>(data[0]); 10615 has_line_order = true; 10616 } 10617 } else if (attr_name.compare("pixelAspectRatio") == 0) { 10618 if (data.size() >= sizeof(float)) { 10619 memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float)); 10620 tinyexr::swap4( 10621 reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio)); 10622 has_pixel_aspect_ratio = true; 10623 } 10624 } else if (attr_name.compare("screenWindowCenter") == 0) { 10625 if (data.size() >= 8) { 10626 memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float)); 10627 memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float)); 10628 tinyexr::swap4( 10629 reinterpret_cast<unsigned int *>(&info->screen_window_center[0])); 10630 tinyexr::swap4( 10631 reinterpret_cast<unsigned int *>(&info->screen_window_center[1])); 10632 has_screen_window_center = true; 10633 } 10634 } else if (attr_name.compare("screenWindowWidth") == 0) { 10635 if (data.size() >= sizeof(float)) { 10636 memcpy(&info->screen_window_width, &data.at(0), sizeof(float)); 10637 tinyexr::swap4( 10638 reinterpret_cast<unsigned int *>(&info->screen_window_width)); 10639 10640 has_screen_window_width = true; 10641 } 10642 } else if (attr_name.compare("chunkCount") == 0) { 10643 if (data.size() >= sizeof(int)) { 10644 memcpy(&info->chunk_count, &data.at(0), sizeof(int)); 10645 tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count)); 10646 } 10647 } else { 10648 // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES) 10649 if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) { 10650 EXRAttribute attrib; 10651#ifdef _MSC_VER 10652 strncpy_s(attrib.name, attr_name.c_str(), 255); 10653 strncpy_s(attrib.type, attr_type.c_str(), 255); 10654#else 10655 strncpy(attrib.name, attr_name.c_str(), 255); 10656 strncpy(attrib.type, attr_type.c_str(), 255); 10657#endif 10658 attrib.name[255] = '\0'; 10659 attrib.type[255] = '\0'; 10660 attrib.size = static_cast<int>(data.size()); 10661 attrib.value = static_cast<unsigned char *>(malloc(data.size())); 10662 memcpy(reinterpret_cast<char *>(attrib.value), &data.at(0), 10663 data.size()); 10664 info->attributes.push_back(attrib); 10665 } 10666 } 10667 } 10668 10669 // Check if required attributes exist 10670 { 10671 std::stringstream ss_err; 10672 10673 if (!has_compression) { 10674 ss_err << "\"compression\" attribute not found in the header." 10675 << std::endl; 10676 } 10677 10678 if (!has_channels) { 10679 ss_err << "\"channels\" attribute not found in the header." << std::endl; 10680 } 10681 10682 if (!has_line_order) { 10683 ss_err << "\"lineOrder\" attribute not found in the header." << std::endl; 10684 } 10685 10686 if (!has_display_window) { 10687 ss_err << "\"displayWindow\" attribute not found in the header." 10688 << std::endl; 10689 } 10690 10691 if (!has_data_window) { 10692 ss_err << "\"dataWindow\" attribute not found in the header or invalid." 10693 << std::endl; 10694 } 10695 10696 if (!has_pixel_aspect_ratio) { 10697 ss_err << "\"pixelAspectRatio\" attribute not found in the header." 10698 << std::endl; 10699 } 10700 10701 if (!has_screen_window_width) { 10702 ss_err << "\"screenWindowWidth\" attribute not found in the header." 10703 << std::endl; 10704 } 10705 10706 if (!has_screen_window_center) { 10707 ss_err << "\"screenWindowCenter\" attribute not found in the header." 10708 << std::endl; 10709 } 10710 10711 if (!(ss_err.str().empty())) { 10712 if (err) { 10713 (*err) += ss_err.str(); 10714 } 10715 return TINYEXR_ERROR_INVALID_HEADER; 10716 } 10717 } 10718 10719 info->header_len = static_cast<unsigned int>(orig_size - size); 10720 10721 return TINYEXR_SUCCESS; 10722} 10723 10724// C++ HeaderInfo to C EXRHeader conversion. 10725static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) { 10726 exr_header->pixel_aspect_ratio = info.pixel_aspect_ratio; 10727 exr_header->screen_window_center[0] = info.screen_window_center[0]; 10728 exr_header->screen_window_center[1] = info.screen_window_center[1]; 10729 exr_header->screen_window_width = info.screen_window_width; 10730 exr_header->chunk_count = info.chunk_count; 10731 exr_header->display_window[0] = info.display_window[0]; 10732 exr_header->display_window[1] = info.display_window[1]; 10733 exr_header->display_window[2] = info.display_window[2]; 10734 exr_header->display_window[3] = info.display_window[3]; 10735 exr_header->data_window[0] = info.data_window[0]; 10736 exr_header->data_window[1] = info.data_window[1]; 10737 exr_header->data_window[2] = info.data_window[2]; 10738 exr_header->data_window[3] = info.data_window[3]; 10739 exr_header->line_order = info.line_order; 10740 exr_header->compression_type = info.compression_type; 10741 10742 exr_header->tile_size_x = info.tile_size_x; 10743 exr_header->tile_size_y = info.tile_size_y; 10744 exr_header->tile_level_mode = info.tile_level_mode; 10745 exr_header->tile_rounding_mode = info.tile_rounding_mode; 10746 10747 exr_header->num_channels = static_cast<int>(info.channels.size()); 10748 10749 exr_header->channels = static_cast<EXRChannelInfo *>(malloc( 10750 sizeof(EXRChannelInfo) * static_cast<size_t>(exr_header->num_channels))); 10751 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) { 10752#ifdef _MSC_VER 10753 strncpy_s(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); 10754#else 10755 strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); 10756#endif 10757 // manually add '\0' for safety. 10758 exr_header->channels[c].name[255] = '\0'; 10759 10760 exr_header->channels[c].pixel_type = info.channels[c].pixel_type; 10761 exr_header->channels[c].p_linear = info.channels[c].p_linear; 10762 exr_header->channels[c].x_sampling = info.channels[c].x_sampling; 10763 exr_header->channels[c].y_sampling = info.channels[c].y_sampling; 10764 } 10765 10766 exr_header->pixel_types = static_cast<int *>( 10767 malloc(sizeof(int) * static_cast<size_t>(exr_header->num_channels))); 10768 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) { 10769 exr_header->pixel_types[c] = info.channels[c].pixel_type; 10770 } 10771 10772 // Initially fill with values of `pixel_types` 10773 exr_header->requested_pixel_types = static_cast<int *>( 10774 malloc(sizeof(int) * static_cast<size_t>(exr_header->num_channels))); 10775 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) { 10776 exr_header->requested_pixel_types[c] = info.channels[c].pixel_type; 10777 } 10778 10779 exr_header->num_custom_attributes = static_cast<int>(info.attributes.size()); 10780 10781 if (exr_header->num_custom_attributes > 0) { 10782 // TODO(syoyo): Report warning when # of attributes exceeds 10783 // `TINYEXR_MAX_CUSTOM_ATTRIBUTES` 10784 if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) { 10785 exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES; 10786 } 10787 10788 exr_header->custom_attributes = static_cast<EXRAttribute *>(malloc( 10789 sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes))); 10790 10791 for (size_t i = 0; i < info.attributes.size(); i++) { 10792 memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name, 10793 256); 10794 memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type, 10795 256); 10796 exr_header->custom_attributes[i].size = info.attributes[i].size; 10797 // Just copy poiner 10798 exr_header->custom_attributes[i].value = info.attributes[i].value; 10799 } 10800 10801 } else { 10802 exr_header->custom_attributes = NULL; 10803 } 10804 10805 exr_header->header_len = info.header_len; 10806} 10807 10808static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, 10809 const std::vector<tinyexr::tinyexr_uint64> &offsets, 10810 const unsigned char *head, const size_t size, 10811 std::string *err) { 10812 int num_channels = exr_header->num_channels; 10813 10814 int num_scanline_blocks = 1; 10815 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { 10816 num_scanline_blocks = 16; 10817 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { 10818 num_scanline_blocks = 32; 10819 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { 10820 num_scanline_blocks = 16; 10821 } 10822 10823 int data_width = exr_header->data_window[2] - exr_header->data_window[0] + 1; 10824 int data_height = exr_header->data_window[3] - exr_header->data_window[1] + 1; 10825 10826 if ((data_width < 0) || (data_height < 0)) { 10827 if (err) { 10828 std::stringstream ss; 10829 ss << "Invalid data width or data height: " << data_width << ", " 10830 << data_height << std::endl; 10831 (*err) += ss.str(); 10832 } 10833 return TINYEXR_ERROR_INVALID_DATA; 10834 } 10835 10836 // Do not allow too large data_width and data_height. header invalid? 10837 { 10838 const int threshold = 1024 * 8192; // heuristics 10839 if ((data_width > threshold) || (data_height > threshold)) { 10840 if (err) { 10841 std::stringstream ss; 10842 ss << "data_with or data_height too large. data_width: " << data_width 10843 << ", " 10844 << "data_height = " << data_height << std::endl; 10845 (*err) += ss.str(); 10846 } 10847 return TINYEXR_ERROR_INVALID_DATA; 10848 } 10849 } 10850 10851 size_t num_blocks = offsets.size(); 10852 10853 std::vector<size_t> channel_offset_list; 10854 int pixel_data_size = 0; 10855 size_t channel_offset = 0; 10856 if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size, 10857 &channel_offset, num_channels, 10858 exr_header->channels)) { 10859 if (err) { 10860 (*err) += "Failed to compute channel layout.\n"; 10861 } 10862 return TINYEXR_ERROR_INVALID_DATA; 10863 } 10864 10865 bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety. 10866 10867 if (exr_header->tiled) { 10868 // value check 10869 if (exr_header->tile_size_x < 0) { 10870 if (err) { 10871 std::stringstream ss; 10872 ss << "Invalid tile size x : " << exr_header->tile_size_x << "\n"; 10873 (*err) += ss.str(); 10874 } 10875 return TINYEXR_ERROR_INVALID_HEADER; 10876 } 10877 10878 if (exr_header->tile_size_y < 0) { 10879 if (err) { 10880 std::stringstream ss; 10881 ss << "Invalid tile size y : " << exr_header->tile_size_y << "\n"; 10882 (*err) += ss.str(); 10883 } 10884 return TINYEXR_ERROR_INVALID_HEADER; 10885 } 10886 10887 size_t num_tiles = offsets.size(); // = # of blocks 10888 10889 exr_image->tiles = static_cast<EXRTile *>( 10890 calloc(sizeof(EXRTile), static_cast<size_t>(num_tiles))); 10891 10892 int err_code = TINYEXR_SUCCESS; 10893 10894#if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0) 10895 10896 std::vector<std::thread> workers; 10897 std::atomic<size_t> tile_count(0); 10898 10899 int num_threads = std::max(1, int(std::thread::hardware_concurrency())); 10900 if (num_threads > int(num_tiles)) { 10901 num_threads = int(num_tiles); 10902 } 10903 10904 for (int t = 0; t < num_threads; t++) { 10905 workers.emplace_back(std::thread([&]() { 10906 size_t tile_idx = 0; 10907 while ((tile_idx = tile_count++) < num_tiles) { 10908 10909#else 10910 for (size_t tile_idx = 0; tile_idx < num_tiles; tile_idx++) { 10911#endif 10912 // Allocate memory for each tile. 10913 exr_image->tiles[tile_idx].images = tinyexr::AllocateImage( 10914 num_channels, exr_header->channels, 10915 exr_header->requested_pixel_types, exr_header->tile_size_x, 10916 exr_header->tile_size_y); 10917 10918 // 16 byte: tile coordinates 10919 // 4 byte : data size 10920 // ~ : data(uncompressed or compressed) 10921 if (offsets[tile_idx] + sizeof(int) * 5 > size) { 10922 // TODO(LTE): atomic 10923 if (err) { 10924 (*err) += "Insufficient data size.\n"; 10925 } 10926 err_code = TINYEXR_ERROR_INVALID_DATA; 10927 break; 10928 } 10929 10930 size_t data_size = 10931 size_t(size - (offsets[tile_idx] + sizeof(int) * 5)); 10932 const unsigned char *data_ptr = 10933 reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]); 10934 10935 int tile_coordinates[4]; 10936 memcpy(tile_coordinates, data_ptr, sizeof(int) * 4); 10937 tinyexr::swap4( 10938 reinterpret_cast<unsigned int *>(&tile_coordinates[0])); 10939 tinyexr::swap4( 10940 reinterpret_cast<unsigned int *>(&tile_coordinates[1])); 10941 tinyexr::swap4( 10942 reinterpret_cast<unsigned int *>(&tile_coordinates[2])); 10943 tinyexr::swap4( 10944 reinterpret_cast<unsigned int *>(&tile_coordinates[3])); 10945 10946 // @todo{ LoD } 10947 if (tile_coordinates[2] != 0) { 10948 err_code = TINYEXR_ERROR_UNSUPPORTED_FEATURE; 10949 break; 10950 } 10951 if (tile_coordinates[3] != 0) { 10952 err_code = TINYEXR_ERROR_UNSUPPORTED_FEATURE; 10953 break; 10954 } 10955 10956 int data_len; 10957 memcpy(&data_len, data_ptr + 16, 10958 sizeof(int)); // 16 = sizeof(tile_coordinates) 10959 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len)); 10960 10961 if (data_len < 4 || size_t(data_len) > data_size) { 10962 // TODO(LTE): atomic 10963 if (err) { 10964 (*err) += "Insufficient data length.\n"; 10965 } 10966 err_code = TINYEXR_ERROR_INVALID_DATA; 10967 break; 10968 } 10969 10970 // Move to data addr: 20 = 16 + 4; 10971 data_ptr += 20; 10972 10973 bool ret = tinyexr::DecodeTiledPixelData( 10974 exr_image->tiles[tile_idx].images, 10975 &(exr_image->tiles[tile_idx].width), 10976 &(exr_image->tiles[tile_idx].height), 10977 exr_header->requested_pixel_types, data_ptr, 10978 static_cast<size_t>(data_len), exr_header->compression_type, 10979 exr_header->line_order, data_width, data_height, 10980 tile_coordinates[0], tile_coordinates[1], exr_header->tile_size_x, 10981 exr_header->tile_size_y, static_cast<size_t>(pixel_data_size), 10982 static_cast<size_t>(exr_header->num_custom_attributes), 10983 exr_header->custom_attributes, 10984 static_cast<size_t>(exr_header->num_channels), 10985 exr_header->channels, channel_offset_list); 10986 10987 if (!ret) { 10988 // TODO(LTE): atomic 10989 if (err) { 10990 (*err) += "Failed to decode tile data.\n"; 10991 } 10992 err_code = TINYEXR_ERROR_INVALID_DATA; 10993 } 10994 10995 exr_image->tiles[tile_idx].offset_x = tile_coordinates[0]; 10996 exr_image->tiles[tile_idx].offset_y = tile_coordinates[1]; 10997 exr_image->tiles[tile_idx].level_x = tile_coordinates[2]; 10998 exr_image->tiles[tile_idx].level_y = tile_coordinates[3]; 10999 11000#if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0) 11001 } 11002 })); 11003 } // num_thread loop 11004 11005 for (auto &t : workers) { 11006 t.join(); 11007 } 11008 11009#else 11010 } 11011#endif 11012 11013 if (err_code != TINYEXR_SUCCESS) { 11014 return err_code; 11015 } 11016 11017 exr_image->num_tiles = static_cast<int>(num_tiles); 11018 } else { // scanline format 11019 11020 // Don't allow too large image(256GB * pixel_data_size or more). Workaround 11021 // for #104. 11022 size_t total_data_len = 11023 size_t(data_width) * size_t(data_height) * size_t(num_channels); 11024 const bool total_data_len_overflown = 11025 sizeof(void *) == 8 ? (total_data_len >= 0x4000000000) : false; 11026 if ((total_data_len == 0) || total_data_len_overflown) { 11027 if (err) { 11028 std::stringstream ss; 11029 ss << "Image data size is zero or too large: width = " << data_width 11030 << ", height = " << data_height << ", channels = " << num_channels 11031 << std::endl; 11032 (*err) += ss.str(); 11033 } 11034 return TINYEXR_ERROR_INVALID_DATA; 11035 } 11036 11037 exr_image->images = tinyexr::AllocateImage( 11038 num_channels, exr_header->channels, exr_header->requested_pixel_types, 11039 data_width, data_height); 11040 11041#if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0) 11042 std::vector<std::thread> workers; 11043 std::atomic<int> y_count(0); 11044 11045 int num_threads = std::max(1, int(std::thread::hardware_concurrency())); 11046 if (num_threads > int(num_blocks)) { 11047 num_threads = int(num_blocks); 11048 } 11049 11050 for (int t = 0; t < num_threads; t++) { 11051 workers.emplace_back(std::thread([&]() { 11052 int y = 0; 11053 while ((y = y_count++) < int(num_blocks)) { 11054 11055#else 11056 11057#if TINYEXR_USE_OPENMP 11058#pragma omp parallel for 11059#endif 11060 for (int y = 0; y < static_cast<int>(num_blocks); y++) { 11061 11062#endif 11063 size_t y_idx = static_cast<size_t>(y); 11064 11065 if (offsets[y_idx] + sizeof(int) * 2 > size) { 11066 invalid_data = true; 11067 } else { 11068 // 4 byte: scan line 11069 // 4 byte: data size 11070 // ~ : pixel data(uncompressed or compressed) 11071 size_t data_size = 11072 size_t(size - (offsets[y_idx] + sizeof(int) * 2)); 11073 const unsigned char *data_ptr = 11074 reinterpret_cast<const unsigned char *>(head + offsets[y_idx]); 11075 11076 int line_no; 11077 memcpy(&line_no, data_ptr, sizeof(int)); 11078 int data_len; 11079 memcpy(&data_len, data_ptr + 4, sizeof(int)); 11080 tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no)); 11081 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len)); 11082 11083 if (size_t(data_len) > data_size) { 11084 invalid_data = true; 11085 11086 } else if ((line_no > (2 << 20)) || (line_no < -(2 << 20))) { 11087 // Too large value. Assume this is invalid 11088 // 2**20 = 1048576 = heuristic value. 11089 invalid_data = true; 11090 } else if (data_len == 0) { 11091 // TODO(syoyo): May be ok to raise the threshold for example 11092 // `data_len < 4` 11093 invalid_data = true; 11094 } else { 11095 // line_no may be negative. 11096 int end_line_no = (std::min)(line_no + num_scanline_blocks, 11097 (exr_header->data_window[3] + 1)); 11098 11099 int num_lines = end_line_no - line_no; 11100 11101 if (num_lines <= 0) { 11102 invalid_data = true; 11103 } else { 11104 // Move to data addr: 8 = 4 + 4; 11105 data_ptr += 8; 11106 11107 // Adjust line_no with data_window.bmin.y 11108 11109 // overflow check 11110 tinyexr_int64 lno = 11111 static_cast<tinyexr_int64>(line_no) - 11112 static_cast<tinyexr_int64>(exr_header->data_window[1]); 11113 if (lno > std::numeric_limits<int>::max()) { 11114 line_no = -1; // invalid 11115 } else if (lno < -std::numeric_limits<int>::max()) { 11116 line_no = -1; // invalid 11117 } else { 11118 line_no -= exr_header->data_window[1]; 11119 } 11120 11121 if (line_no < 0) { 11122 invalid_data = true; 11123 } else { 11124 if (!tinyexr::DecodePixelData( 11125 exr_image->images, exr_header->requested_pixel_types, 11126 data_ptr, static_cast<size_t>(data_len), 11127 exr_header->compression_type, exr_header->line_order, 11128 data_width, data_height, data_width, y, line_no, 11129 num_lines, static_cast<size_t>(pixel_data_size), 11130 static_cast<size_t>( 11131 exr_header->num_custom_attributes), 11132 exr_header->custom_attributes, 11133 static_cast<size_t>(exr_header->num_channels), 11134 exr_header->channels, channel_offset_list)) { 11135 invalid_data = true; 11136 } 11137 } 11138 } 11139 } 11140 } 11141 11142#if (__cplusplus > 199711L) && (TINYEXR_USE_THREAD > 0) 11143 } 11144 })); 11145 } 11146 11147 for (auto &t : workers) { 11148 t.join(); 11149 } 11150#else 11151 } // omp parallel 11152#endif 11153 } 11154 11155 if (invalid_data) { 11156 if (err) { 11157 std::stringstream ss; 11158 (*err) += "Invalid data found when decoding pixels.\n"; 11159 } 11160 return TINYEXR_ERROR_INVALID_DATA; 11161 } 11162 11163 // Overwrite `pixel_type` with `requested_pixel_type`. 11164 { 11165 for (int c = 0; c < exr_header->num_channels; c++) { 11166 exr_header->pixel_types[c] = exr_header->requested_pixel_types[c]; 11167 } 11168 } 11169 11170 { 11171 exr_image->num_channels = num_channels; 11172 11173 exr_image->width = data_width; 11174 exr_image->height = data_height; 11175 } 11176 11177 return TINYEXR_SUCCESS; 11178} 11179 11180static bool ReconstructLineOffsets( 11181 std::vector<tinyexr::tinyexr_uint64> *offsets, size_t n, 11182 const unsigned char *head, const unsigned char *marker, const size_t size) { 11183 TEXR_ASSERT(head < marker); 11184 TEXR_ASSERT(offsets->size() == n); 11185 11186 for (size_t i = 0; i < n; i++) { 11187 size_t offset = static_cast<size_t>(marker - head); 11188 // Offset should not exceed whole EXR file/data size. 11189 if ((offset + sizeof(tinyexr::tinyexr_uint64)) >= size) { 11190 return false; 11191 } 11192 11193 int y; 11194 unsigned int data_len; 11195 11196 memcpy(&y, marker, sizeof(int)); 11197 memcpy(&data_len, marker + 4, sizeof(unsigned int)); 11198 11199 if (data_len >= size) { 11200 return false; 11201 } 11202 11203 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y)); 11204 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len)); 11205 11206 (*offsets)[i] = offset; 11207 11208 marker += data_len + 8; // 8 = 4 bytes(y) + 4 bytes(data_len) 11209 } 11210 11211 return true; 11212} 11213 11214static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header, 11215 const unsigned char *head, 11216 const unsigned char *marker, const size_t size, 11217 const char **err) { 11218 if (exr_image == NULL || exr_header == NULL || head == NULL || 11219 marker == NULL || (size <= tinyexr::kEXRVersionSize)) { 11220 tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err); 11221 return TINYEXR_ERROR_INVALID_ARGUMENT; 11222 } 11223 11224 int num_scanline_blocks = 1; 11225 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { 11226 num_scanline_blocks = 16; 11227 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { 11228 num_scanline_blocks = 32; 11229 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { 11230 num_scanline_blocks = 16; 11231 } 11232 11233 int data_width = exr_header->data_window[2] - exr_header->data_window[0]; 11234 if (data_width >= std::numeric_limits<int>::max()) { 11235 // Issue 63 11236 tinyexr::SetErrorMessage("Invalid data width value", err); 11237 return TINYEXR_ERROR_INVALID_DATA; 11238 } 11239 data_width++; 11240 11241 int data_height = exr_header->data_window[3] - exr_header->data_window[1]; 11242 if (data_height >= std::numeric_limits<int>::max()) { 11243 tinyexr::SetErrorMessage("Invalid data height value", err); 11244 return TINYEXR_ERROR_INVALID_DATA; 11245 } 11246 data_height++; 11247 11248 if ((data_width < 0) || (data_height < 0)) { 11249 tinyexr::SetErrorMessage("data width or data height is negative.", err); 11250 return TINYEXR_ERROR_INVALID_DATA; 11251 } 11252 11253 // Do not allow too large data_width and data_height. header invalid? 11254 { 11255 const int threshold = 1024 * 8192; // heuristics 11256 if (data_width > threshold) { 11257 tinyexr::SetErrorMessage("data width too large.", err); 11258 return TINYEXR_ERROR_INVALID_DATA; 11259 } 11260 if (data_height > threshold) { 11261 tinyexr::SetErrorMessage("data height too large.", err); 11262 return TINYEXR_ERROR_INVALID_DATA; 11263 } 11264 } 11265 11266 // Read offset tables. 11267 size_t num_blocks = 0; 11268 11269 if (exr_header->chunk_count > 0) { 11270 // Use `chunkCount` attribute. 11271 num_blocks = static_cast<size_t>(exr_header->chunk_count); 11272 } else if (exr_header->tiled) { 11273 // @todo { LoD } 11274 size_t num_x_tiles = static_cast<size_t>(data_width) / 11275 static_cast<size_t>(exr_header->tile_size_x); 11276 if (num_x_tiles * static_cast<size_t>(exr_header->tile_size_x) < 11277 static_cast<size_t>(data_width)) { 11278 num_x_tiles++; 11279 } 11280 size_t num_y_tiles = static_cast<size_t>(data_height) / 11281 static_cast<size_t>(exr_header->tile_size_y); 11282 if (num_y_tiles * static_cast<size_t>(exr_header->tile_size_y) < 11283 static_cast<size_t>(data_height)) { 11284 num_y_tiles++; 11285 } 11286 11287 num_blocks = num_x_tiles * num_y_tiles; 11288 } else { 11289 num_blocks = static_cast<size_t>(data_height) / 11290 static_cast<size_t>(num_scanline_blocks); 11291 if (num_blocks * static_cast<size_t>(num_scanline_blocks) < 11292 static_cast<size_t>(data_height)) { 11293 num_blocks++; 11294 } 11295 } 11296 11297 std::vector<tinyexr::tinyexr_uint64> offsets(num_blocks); 11298 11299 for (size_t y = 0; y < num_blocks; y++) { 11300 tinyexr::tinyexr_uint64 offset; 11301 // Issue #81 11302 if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) { 11303 tinyexr::SetErrorMessage("Insufficient data size in offset table.", err); 11304 return TINYEXR_ERROR_INVALID_DATA; 11305 } 11306 11307 memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64)); 11308 tinyexr::swap8(&offset); 11309 if (offset >= size) { 11310 tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err); 11311 return TINYEXR_ERROR_INVALID_DATA; 11312 } 11313 marker += sizeof(tinyexr::tinyexr_uint64); // = 8 11314 offsets[y] = offset; 11315 } 11316 11317 // If line offsets are invalid, we try to reconstruct it. 11318 // See OpenEXR/IlmImf/ImfScanLineInputFile.cpp::readLineOffsets() for details. 11319 for (size_t y = 0; y < num_blocks; y++) { 11320 if (offsets[y] <= 0) { 11321 // TODO(syoyo) Report as warning? 11322 // if (err) { 11323 // stringstream ss; 11324 // ss << "Incomplete lineOffsets." << std::endl; 11325 // (*err) += ss.str(); 11326 //} 11327 bool ret = 11328 ReconstructLineOffsets(&offsets, num_blocks, head, marker, size); 11329 if (ret) { 11330 // OK 11331 break; 11332 } else { 11333 tinyexr::SetErrorMessage( 11334 "Cannot reconstruct lineOffset table in DecodeEXRImage.", err); 11335 return TINYEXR_ERROR_INVALID_DATA; 11336 } 11337 } 11338 } 11339 11340 { 11341 std::string e; 11342 int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e); 11343 11344 if (ret != TINYEXR_SUCCESS) { 11345 if (!e.empty()) { 11346 tinyexr::SetErrorMessage(e, err); 11347 } 11348 11349#if 1 11350 FreeEXRImage(exr_image); 11351#else 11352 // release memory(if exists) 11353 if ((exr_header->num_channels > 0) && exr_image && exr_image->images) { 11354 for (size_t c = 0; c < size_t(exr_header->num_channels); c++) { 11355 if (exr_image->images[c]) { 11356 free(exr_image->images[c]); 11357 exr_image->images[c] = NULL; 11358 } 11359 } 11360 free(exr_image->images); 11361 exr_image->images = NULL; 11362 } 11363#endif 11364 } 11365 11366 return ret; 11367 } 11368} 11369 11370static void GetLayers(const EXRHeader& exr_header, std::vector<std::string>& layer_names) { 11371 // Naive implementation 11372 // Group channels by layers 11373 // go over all channel names, split by periods 11374 // collect unique names 11375 layer_names.clear(); 11376 for (int c = 0; c < exr_header.num_channels; c++) { 11377 std::string full_name(exr_header.channels[c].name); 11378 const size_t pos = full_name.find_last_of('.'); 11379 if (pos != std::string::npos && pos != 0 && pos + 1 < full_name.size()) { 11380 full_name.erase(pos); 11381 if (std::find(layer_names.begin(), layer_names.end(), full_name) == layer_names.end()) 11382 layer_names.push_back(full_name); 11383 } 11384 } 11385} 11386 11387struct LayerChannel { 11388 explicit LayerChannel (size_t i, std::string n) 11389 : index(i) 11390 , name(n) 11391 {} 11392 size_t index; 11393 std::string name; 11394}; 11395 11396static void ChannelsInLayer(const EXRHeader& exr_header, const std::string layer_name, std::vector<LayerChannel>& channels) { 11397 channels.clear(); 11398 for (int c = 0; c < exr_header.num_channels; c++) { 11399 std::string ch_name(exr_header.channels[c].name); 11400 if (layer_name.empty()) { 11401 const size_t pos = ch_name.find_last_of('.'); 11402 if (pos != std::string::npos && pos < ch_name.size()) { 11403 ch_name = ch_name.substr(pos + 1); 11404 } 11405 } else { 11406 const size_t pos = ch_name.find(layer_name + '.'); 11407 if (pos == std::string::npos) 11408 continue; 11409 if (pos == 0) { 11410 ch_name = ch_name.substr(layer_name.size() + 1); 11411 } 11412 } 11413 LayerChannel ch(size_t(c), ch_name); 11414 channels.push_back(ch); 11415 } 11416} 11417 11418} // namespace tinyexr 11419 11420int EXRLayers(const char *filename, const char **layer_names[], int *num_layers, const char **err) { 11421 EXRVersion exr_version; 11422 EXRHeader exr_header; 11423 InitEXRHeader(&exr_header); 11424 11425 { 11426 int ret = ParseEXRVersionFromFile(&exr_version, filename); 11427 if (ret != TINYEXR_SUCCESS) { 11428 tinyexr::SetErrorMessage("Invalid EXR header.", err); 11429 return ret; 11430 } 11431 11432 if (exr_version.multipart || exr_version.non_image) { 11433 tinyexr::SetErrorMessage( 11434 "Loading multipart or DeepImage is not supported in LoadEXR() API", 11435 err); 11436 return TINYEXR_ERROR_INVALID_DATA; // @fixme. 11437 } 11438 } 11439 11440 int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err); 11441 if (ret != TINYEXR_SUCCESS) { 11442 FreeEXRHeader(&exr_header); 11443 return ret; 11444 } 11445 11446 std::vector<std::string> layer_vec; 11447 tinyexr::GetLayers(exr_header, layer_vec); 11448 11449 (*num_layers) = int(layer_vec.size()); 11450 (*layer_names) = static_cast<const char **>( 11451 malloc(sizeof(const char *) * static_cast<size_t>(layer_vec.size()))); 11452 for (size_t c = 0; c < static_cast<size_t>(layer_vec.size()); c++) { 11453#ifdef _MSC_VER 11454 (*layer_names)[c] = _strdup(layer_vec[c].c_str()); 11455#else 11456 (*layer_names)[c] = strdup(layer_vec[c].c_str()); 11457#endif 11458 } 11459 11460 FreeEXRHeader(&exr_header); 11461 return TINYEXR_SUCCESS; 11462} 11463 11464int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, 11465 const char **err) { 11466 return LoadEXRWithLayer(out_rgba, width, height, filename, /* layername */NULL, err); 11467} 11468 11469int LoadEXRWithLayer(float **out_rgba, int *width, int *height, const char *filename, const char *layername, 11470 const char **err) { 11471 if (out_rgba == NULL) { 11472 tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err); 11473 return TINYEXR_ERROR_INVALID_ARGUMENT; 11474 } 11475 11476 EXRVersion exr_version; 11477 EXRImage exr_image; 11478 EXRHeader exr_header; 11479 InitEXRHeader(&exr_header); 11480 InitEXRImage(&exr_image); 11481 11482 { 11483 int ret = ParseEXRVersionFromFile(&exr_version, filename); 11484 if (ret != TINYEXR_SUCCESS) { 11485 std::stringstream ss; 11486 ss << "Failed to open EXR file or read version info from EXR file. code(" << ret << ")"; 11487 tinyexr::SetErrorMessage(ss.str(), err); 11488 return ret; 11489 } 11490 11491 if (exr_version.multipart || exr_version.non_image) { 11492 tinyexr::SetErrorMessage( 11493 "Loading multipart or DeepImage is not supported in LoadEXR() API", 11494 err); 11495 return TINYEXR_ERROR_INVALID_DATA; // @fixme. 11496 } 11497 } 11498 11499 { 11500 int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err); 11501 if (ret != TINYEXR_SUCCESS) { 11502 FreeEXRHeader(&exr_header); 11503 return ret; 11504 } 11505 } 11506 11507 // Read HALF channel as FLOAT. 11508 for (int i = 0; i < exr_header.num_channels; i++) { 11509 if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { 11510 exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; 11511 } 11512 } 11513 11514 // TODO: Probably limit loading to layers (channels) selected by layer index 11515 { 11516 int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err); 11517 if (ret != TINYEXR_SUCCESS) { 11518 FreeEXRHeader(&exr_header); 11519 return ret; 11520 } 11521 } 11522 11523 // RGBA 11524 int idxR = -1; 11525 int idxG = -1; 11526 int idxB = -1; 11527 int idxA = -1; 11528 11529 std::vector<std::string> layer_names; 11530 tinyexr::GetLayers(exr_header, layer_names); 11531 11532 std::vector<tinyexr::LayerChannel> channels; 11533 tinyexr::ChannelsInLayer(exr_header, layername == NULL ? "" : std::string(layername), channels); 11534 11535 if (channels.size() < 1) { 11536 tinyexr::SetErrorMessage("Layer Not Found", err); 11537 FreeEXRHeader(&exr_header); 11538 FreeEXRImage(&exr_image); 11539 return TINYEXR_ERROR_LAYER_NOT_FOUND; 11540 } 11541 11542 size_t ch_count = channels.size() < 4 ? channels.size() : 4; 11543 for (size_t c = 0; c < ch_count; c++) { 11544 const tinyexr::LayerChannel &ch = channels[c]; 11545 11546 if (ch.name == "R") { 11547 idxR = int(ch.index); 11548 } 11549 else if (ch.name == "G") { 11550 idxG = int(ch.index); 11551 } 11552 else if (ch.name == "B") { 11553 idxB = int(ch.index); 11554 } 11555 else if (ch.name == "A") { 11556 idxA = int(ch.index); 11557 } 11558 } 11559 11560 if (channels.size() == 1) { 11561 int chIdx = int(channels.front().index); 11562 // Grayscale channel only. 11563 11564 (*out_rgba) = reinterpret_cast<float *>( 11565 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * 11566 static_cast<size_t>(exr_image.height))); 11567 11568 if (exr_header.tiled) { 11569 for (int it = 0; it < exr_image.num_tiles; it++) { 11570 for (int j = 0; j < exr_header.tile_size_y; j++) { 11571 for (int i = 0; i < exr_header.tile_size_x; i++) { 11572 const int ii = 11573 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; 11574 const int jj = 11575 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; 11576 const int idx = ii + jj * exr_image.width; 11577 11578 // out of region check. 11579 if (ii >= exr_image.width) { 11580 continue; 11581 } 11582 if (jj >= exr_image.height) { 11583 continue; 11584 } 11585 const int srcIdx = i + j * exr_header.tile_size_x; 11586 unsigned char **src = exr_image.tiles[it].images; 11587 (*out_rgba)[4 * idx + 0] = 11588 reinterpret_cast<float **>(src)[chIdx][srcIdx]; 11589 (*out_rgba)[4 * idx + 1] = 11590 reinterpret_cast<float **>(src)[chIdx][srcIdx]; 11591 (*out_rgba)[4 * idx + 2] = 11592 reinterpret_cast<float **>(src)[chIdx][srcIdx]; 11593 (*out_rgba)[4 * idx + 3] = 11594 reinterpret_cast<float **>(src)[chIdx][srcIdx]; 11595 } 11596 } 11597 } 11598 } else { 11599 for (int i = 0; i < exr_image.width * exr_image.height; i++) { 11600 const float val = reinterpret_cast<float **>(exr_image.images)[chIdx][i]; 11601 (*out_rgba)[4 * i + 0] = val; 11602 (*out_rgba)[4 * i + 1] = val; 11603 (*out_rgba)[4 * i + 2] = val; 11604 (*out_rgba)[4 * i + 3] = val; 11605 } 11606 } 11607 } else { 11608 // Assume RGB(A) 11609 11610 if (idxR == -1) { 11611 tinyexr::SetErrorMessage("R channel not found", err); 11612 11613 FreeEXRHeader(&exr_header); 11614 FreeEXRImage(&exr_image); 11615 return TINYEXR_ERROR_INVALID_DATA; 11616 } 11617 11618 if (idxG == -1) { 11619 tinyexr::SetErrorMessage("G channel not found", err); 11620 FreeEXRHeader(&exr_header); 11621 FreeEXRImage(&exr_image); 11622 return TINYEXR_ERROR_INVALID_DATA; 11623 } 11624 11625 if (idxB == -1) { 11626 tinyexr::SetErrorMessage("B channel not found", err); 11627 FreeEXRHeader(&exr_header); 11628 FreeEXRImage(&exr_image); 11629 return TINYEXR_ERROR_INVALID_DATA; 11630 } 11631 11632 (*out_rgba) = reinterpret_cast<float *>( 11633 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * 11634 static_cast<size_t>(exr_image.height))); 11635 if (exr_header.tiled) { 11636 for (int it = 0; it < exr_image.num_tiles; it++) { 11637 for (int j = 0; j < exr_header.tile_size_y; j++) { 11638 for (int i = 0; i < exr_header.tile_size_x; i++) { 11639 const int ii = 11640 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; 11641 const int jj = 11642 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; 11643 const int idx = ii + jj * exr_image.width; 11644 11645 // out of region check. 11646 if (ii >= exr_image.width) { 11647 continue; 11648 } 11649 if (jj >= exr_image.height) { 11650 continue; 11651 } 11652 const int srcIdx = i + j * exr_header.tile_size_x; 11653 unsigned char **src = exr_image.tiles[it].images; 11654 (*out_rgba)[4 * idx + 0] = 11655 reinterpret_cast<float **>(src)[idxR][srcIdx]; 11656 (*out_rgba)[4 * idx + 1] = 11657 reinterpret_cast<float **>(src)[idxG][srcIdx]; 11658 (*out_rgba)[4 * idx + 2] = 11659 reinterpret_cast<float **>(src)[idxB][srcIdx]; 11660 if (idxA != -1) { 11661 (*out_rgba)[4 * idx + 3] = 11662 reinterpret_cast<float **>(src)[idxA][srcIdx]; 11663 } else { 11664 (*out_rgba)[4 * idx + 3] = 1.0; 11665 } 11666 } 11667 } 11668 } 11669 } else { 11670 for (int i = 0; i < exr_image.width * exr_image.height; i++) { 11671 (*out_rgba)[4 * i + 0] = 11672 reinterpret_cast<float **>(exr_image.images)[idxR][i]; 11673 (*out_rgba)[4 * i + 1] = 11674 reinterpret_cast<float **>(exr_image.images)[idxG][i]; 11675 (*out_rgba)[4 * i + 2] = 11676 reinterpret_cast<float **>(exr_image.images)[idxB][i]; 11677 if (idxA != -1) { 11678 (*out_rgba)[4 * i + 3] = 11679 reinterpret_cast<float **>(exr_image.images)[idxA][i]; 11680 } else { 11681 (*out_rgba)[4 * i + 3] = 1.0; 11682 } 11683 } 11684 } 11685 } 11686 11687 (*width) = exr_image.width; 11688 (*height) = exr_image.height; 11689 11690 FreeEXRHeader(&exr_header); 11691 FreeEXRImage(&exr_image); 11692 11693 return TINYEXR_SUCCESS; 11694} 11695 11696int IsEXR(const char *filename) { 11697 EXRVersion exr_version; 11698 11699 int ret = ParseEXRVersionFromFile(&exr_version, filename); 11700 if (ret != TINYEXR_SUCCESS) { 11701 return ret; 11702 } 11703 11704 return TINYEXR_SUCCESS; 11705} 11706 11707int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, 11708 const unsigned char *memory, size_t size, 11709 const char **err) { 11710 if (memory == NULL || exr_header == NULL) { 11711 tinyexr::SetErrorMessage( 11712 "Invalid argument. `memory` or `exr_header` argument is null in " 11713 "ParseEXRHeaderFromMemory()", 11714 err); 11715 11716 // Invalid argument 11717 return TINYEXR_ERROR_INVALID_ARGUMENT; 11718 } 11719 11720 if (size < tinyexr::kEXRVersionSize) { 11721 tinyexr::SetErrorMessage("Insufficient header/data size.\n", err); 11722 return TINYEXR_ERROR_INVALID_DATA; 11723 } 11724 11725 const unsigned char *marker = memory + tinyexr::kEXRVersionSize; 11726 size_t marker_size = size - tinyexr::kEXRVersionSize; 11727 11728 tinyexr::HeaderInfo info; 11729 info.clear(); 11730 11731 std::string err_str; 11732 int ret = ParseEXRHeader(&info, NULL, version, &err_str, marker, marker_size); 11733 11734 if (ret != TINYEXR_SUCCESS) { 11735 if (err && !err_str.empty()) { 11736 tinyexr::SetErrorMessage(err_str, err); 11737 } 11738 } 11739 11740 ConvertHeader(exr_header, info); 11741 11742 // transfoer `tiled` from version. 11743 exr_header->tiled = version->tiled; 11744 11745 return ret; 11746} 11747 11748int LoadEXRFromMemory(float **out_rgba, int *width, int *height, 11749 const unsigned char *memory, size_t size, 11750 const char **err) { 11751 if (out_rgba == NULL || memory == NULL) { 11752 tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err); 11753 return TINYEXR_ERROR_INVALID_ARGUMENT; 11754 } 11755 11756 EXRVersion exr_version; 11757 EXRImage exr_image; 11758 EXRHeader exr_header; 11759 11760 InitEXRHeader(&exr_header); 11761 11762 int ret = ParseEXRVersionFromMemory(&exr_version, memory, size); 11763 if (ret != TINYEXR_SUCCESS) { 11764 std::stringstream ss; 11765 ss << "Failed to parse EXR version. code(" << ret << ")"; 11766 tinyexr::SetErrorMessage(ss.str(), err); 11767 return ret; 11768 } 11769 11770 ret = ParseEXRHeaderFromMemory(&exr_header, &exr_version, memory, size, err); 11771 if (ret != TINYEXR_SUCCESS) { 11772 return ret; 11773 } 11774 11775 // Read HALF channel as FLOAT. 11776 for (int i = 0; i < exr_header.num_channels; i++) { 11777 if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { 11778 exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; 11779 } 11780 } 11781 11782 InitEXRImage(&exr_image); 11783 ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err); 11784 if (ret != TINYEXR_SUCCESS) { 11785 return ret; 11786 } 11787 11788 // RGBA 11789 int idxR = -1; 11790 int idxG = -1; 11791 int idxB = -1; 11792 int idxA = -1; 11793 for (int c = 0; c < exr_header.num_channels; c++) { 11794 if (strcmp(exr_header.channels[c].name, "R") == 0) { 11795 idxR = c; 11796 } else if (strcmp(exr_header.channels[c].name, "G") == 0) { 11797 idxG = c; 11798 } else if (strcmp(exr_header.channels[c].name, "B") == 0) { 11799 idxB = c; 11800 } else if (strcmp(exr_header.channels[c].name, "A") == 0) { 11801 idxA = c; 11802 } 11803 } 11804 11805 // TODO(syoyo): Refactor removing same code as used in LoadEXR(). 11806 if (exr_header.num_channels == 1) { 11807 // Grayscale channel only. 11808 11809 (*out_rgba) = reinterpret_cast<float *>( 11810 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * 11811 static_cast<size_t>(exr_image.height))); 11812 11813 if (exr_header.tiled) { 11814 for (int it = 0; it < exr_image.num_tiles; it++) { 11815 for (int j = 0; j < exr_header.tile_size_y; j++) { 11816 for (int i = 0; i < exr_header.tile_size_x; i++) { 11817 const int ii = 11818 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; 11819 const int jj = 11820 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; 11821 const int idx = ii + jj * exr_image.width; 11822 11823 // out of region check. 11824 if (ii >= exr_image.width) { 11825 continue; 11826 } 11827 if (jj >= exr_image.height) { 11828 continue; 11829 } 11830 const int srcIdx = i + j * exr_header.tile_size_x; 11831 unsigned char **src = exr_image.tiles[it].images; 11832 (*out_rgba)[4 * idx + 0] = 11833 reinterpret_cast<float **>(src)[0][srcIdx]; 11834 (*out_rgba)[4 * idx + 1] = 11835 reinterpret_cast<float **>(src)[0][srcIdx]; 11836 (*out_rgba)[4 * idx + 2] = 11837 reinterpret_cast<float **>(src)[0][srcIdx]; 11838 (*out_rgba)[4 * idx + 3] = 11839 reinterpret_cast<float **>(src)[0][srcIdx]; 11840 } 11841 } 11842 } 11843 } else { 11844 for (int i = 0; i < exr_image.width * exr_image.height; i++) { 11845 const float val = reinterpret_cast<float **>(exr_image.images)[0][i]; 11846 (*out_rgba)[4 * i + 0] = val; 11847 (*out_rgba)[4 * i + 1] = val; 11848 (*out_rgba)[4 * i + 2] = val; 11849 (*out_rgba)[4 * i + 3] = val; 11850 } 11851 } 11852 11853 } else { 11854 // TODO(syoyo): Support non RGBA image. 11855 11856 if (idxR == -1) { 11857 tinyexr::SetErrorMessage("R channel not found", err); 11858 11859 // @todo { free exr_image } 11860 return TINYEXR_ERROR_INVALID_DATA; 11861 } 11862 11863 if (idxG == -1) { 11864 tinyexr::SetErrorMessage("G channel not found", err); 11865 // @todo { free exr_image } 11866 return TINYEXR_ERROR_INVALID_DATA; 11867 } 11868 11869 if (idxB == -1) { 11870 tinyexr::SetErrorMessage("B channel not found", err); 11871 // @todo { free exr_image } 11872 return TINYEXR_ERROR_INVALID_DATA; 11873 } 11874 11875 (*out_rgba) = reinterpret_cast<float *>( 11876 malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) * 11877 static_cast<size_t>(exr_image.height))); 11878 11879 if (exr_header.tiled) { 11880 for (int it = 0; it < exr_image.num_tiles; it++) { 11881 for (int j = 0; j < exr_header.tile_size_y; j++) 11882 for (int i = 0; i < exr_header.tile_size_x; i++) { 11883 const int ii = 11884 exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; 11885 const int jj = 11886 exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; 11887 const int idx = ii + jj * exr_image.width; 11888 11889 // out of region check. 11890 if (ii >= exr_image.width) { 11891 continue; 11892 } 11893 if (jj >= exr_image.height) { 11894 continue; 11895 } 11896 const int srcIdx = i + j * exr_header.tile_size_x; 11897 unsigned char **src = exr_image.tiles[it].images; 11898 (*out_rgba)[4 * idx + 0] = 11899 reinterpret_cast<float **>(src)[idxR][srcIdx]; 11900 (*out_rgba)[4 * idx + 1] = 11901 reinterpret_cast<float **>(src)[idxG][srcIdx]; 11902 (*out_rgba)[4 * idx + 2] = 11903 reinterpret_cast<float **>(src)[idxB][srcIdx]; 11904 if (idxA != -1) { 11905 (*out_rgba)[4 * idx + 3] = 11906 reinterpret_cast<float **>(src)[idxA][srcIdx]; 11907 } else { 11908 (*out_rgba)[4 * idx + 3] = 1.0; 11909 } 11910 } 11911 } 11912 } else { 11913 for (int i = 0; i < exr_image.width * exr_image.height; i++) { 11914 (*out_rgba)[4 * i + 0] = 11915 reinterpret_cast<float **>(exr_image.images)[idxR][i]; 11916 (*out_rgba)[4 * i + 1] = 11917 reinterpret_cast<float **>(exr_image.images)[idxG][i]; 11918 (*out_rgba)[4 * i + 2] = 11919 reinterpret_cast<float **>(exr_image.images)[idxB][i]; 11920 if (idxA != -1) { 11921 (*out_rgba)[4 * i + 3] = 11922 reinterpret_cast<float **>(exr_image.images)[idxA][i]; 11923 } else { 11924 (*out_rgba)[4 * i + 3] = 1.0; 11925 } 11926 } 11927 } 11928 } 11929 11930 (*width) = exr_image.width; 11931 (*height) = exr_image.height; 11932 11933 FreeEXRHeader(&exr_header); 11934 FreeEXRImage(&exr_image); 11935 11936 return TINYEXR_SUCCESS; 11937} 11938 11939int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header, 11940 const char *filename, const char **err) { 11941 if (exr_image == NULL) { 11942 tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err); 11943 return TINYEXR_ERROR_INVALID_ARGUMENT; 11944 } 11945 11946#ifdef _WIN32 11947 FILE *fp = NULL; 11948 fopen_s(&fp, filename, "rb"); 11949#else 11950 FILE *fp = fopen(filename, "rb"); 11951#endif 11952 if (!fp) { 11953 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); 11954 return TINYEXR_ERROR_CANT_OPEN_FILE; 11955 } 11956 11957 size_t filesize; 11958 // Compute size 11959 fseek(fp, 0, SEEK_END); 11960 filesize = static_cast<size_t>(ftell(fp)); 11961 fseek(fp, 0, SEEK_SET); 11962 11963 if (filesize < 16) { 11964 fclose(fp); 11965 tinyexr::SetErrorMessage("File size too short " + std::string(filename), 11966 err); 11967 return TINYEXR_ERROR_INVALID_FILE; 11968 } 11969 11970 std::vector<unsigned char> buf(filesize); // @todo { use mmap } 11971 { 11972 size_t ret; 11973 ret = fread(&buf[0], 1, filesize, fp); 11974 TEXR_ASSERT(ret == filesize); 11975 fclose(fp); 11976 (void)ret; 11977 } 11978 11979 return LoadEXRImageFromMemory(exr_image, exr_header, &buf.at(0), filesize, 11980 err); 11981} 11982 11983int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header, 11984 const unsigned char *memory, const size_t size, 11985 const char **err) { 11986 if (exr_image == NULL || memory == NULL || 11987 (size < tinyexr::kEXRVersionSize)) { 11988 tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory", 11989 err); 11990 return TINYEXR_ERROR_INVALID_ARGUMENT; 11991 } 11992 11993 if (exr_header->header_len == 0) { 11994 tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); 11995 return TINYEXR_ERROR_INVALID_ARGUMENT; 11996 } 11997 11998 const unsigned char *head = memory; 11999 const unsigned char *marker = reinterpret_cast<const unsigned char *>( 12000 memory + exr_header->header_len + 12001 8); // +8 for magic number + version header. 12002 return tinyexr::DecodeEXRImage(exr_image, exr_header, head, marker, size, 12003 err); 12004} 12005 12006size_t SaveEXRImageToMemory(const EXRImage *exr_image, 12007 const EXRHeader *exr_header, 12008 unsigned char **memory_out, const char **err) { 12009 if (exr_image == NULL || memory_out == NULL || 12010 exr_header->compression_type < 0) { 12011 tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err); 12012 return 0; 12013 } 12014 12015#if !TINYEXR_USE_PIZ 12016 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { 12017 tinyexr::SetErrorMessage("PIZ compression is not supported in this build", 12018 err); 12019 return 0; 12020 } 12021#endif 12022 12023#if !TINYEXR_USE_ZFP 12024 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { 12025 tinyexr::SetErrorMessage("ZFP compression is not supported in this build", 12026 err); 12027 return 0; 12028 } 12029#endif 12030 12031#if TINYEXR_USE_ZFP 12032 for (size_t i = 0; i < static_cast<size_t>(exr_header->num_channels); i++) { 12033 if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) { 12034 tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression", 12035 err); 12036 return 0; 12037 } 12038 } 12039#endif 12040 12041 std::vector<unsigned char> memory; 12042 12043 // Header 12044 { 12045 const char header[] = {0x76, 0x2f, 0x31, 0x01}; 12046 memory.insert(memory.end(), header, header + 4); 12047 } 12048 12049 // Version, scanline. 12050 { 12051 char marker[] = {2, 0, 0, 0}; 12052 /* @todo 12053 if (exr_header->tiled) { 12054 marker[1] |= 0x2; 12055 } 12056 if (exr_header->long_name) { 12057 marker[1] |= 0x4; 12058 } 12059 if (exr_header->non_image) { 12060 marker[1] |= 0x8; 12061 } 12062 if (exr_header->multipart) { 12063 marker[1] |= 0x10; 12064 } 12065 */ 12066 memory.insert(memory.end(), marker, marker + 4); 12067 } 12068 12069 int num_scanlines = 1; 12070 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { 12071 num_scanlines = 16; 12072 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { 12073 num_scanlines = 32; 12074 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { 12075 num_scanlines = 16; 12076 } 12077 12078 // Write attributes. 12079 std::vector<tinyexr::ChannelInfo> channels; 12080 { 12081 std::vector<unsigned char> data; 12082 12083 for (int c = 0; c < exr_header->num_channels; c++) { 12084 tinyexr::ChannelInfo info; 12085 info.p_linear = 0; 12086 info.pixel_type = exr_header->requested_pixel_types[c]; 12087 info.x_sampling = 1; 12088 info.y_sampling = 1; 12089 info.name = std::string(exr_header->channels[c].name); 12090 channels.push_back(info); 12091 } 12092 12093 tinyexr::WriteChannelInfo(data, channels); 12094 12095 tinyexr::WriteAttributeToMemory(&memory, "channels", "chlist", &data.at(0), 12096 static_cast<int>(data.size())); 12097 } 12098 12099 { 12100 int comp = exr_header->compression_type; 12101 tinyexr::swap4(reinterpret_cast<unsigned int *>(&comp)); 12102 tinyexr::WriteAttributeToMemory( 12103 &memory, "compression", "compression", 12104 reinterpret_cast<const unsigned char *>(&comp), 1); 12105 } 12106 12107 { 12108 int data[4] = {0, 0, exr_image->width - 1, exr_image->height - 1}; 12109 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[0])); 12110 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[1])); 12111 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[2])); 12112 tinyexr::swap4(reinterpret_cast<unsigned int *>(&data[3])); 12113 tinyexr::WriteAttributeToMemory( 12114 &memory, "dataWindow", "box2i", 12115 reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4); 12116 tinyexr::WriteAttributeToMemory( 12117 &memory, "displayWindow", "box2i", 12118 reinterpret_cast<const unsigned char *>(data), sizeof(int) * 4); 12119 } 12120 12121 { 12122 unsigned char line_order = 0; // @fixme { read line_order from EXRHeader } 12123 tinyexr::WriteAttributeToMemory(&memory, "lineOrder", "lineOrder", 12124 &line_order, 1); 12125 } 12126 12127 { 12128 float aspectRatio = 1.0f; 12129 tinyexr::swap4(reinterpret_cast<unsigned int *>(&aspectRatio)); 12130 tinyexr::WriteAttributeToMemory( 12131 &memory, "pixelAspectRatio", "float", 12132 reinterpret_cast<const unsigned char *>(&aspectRatio), sizeof(float)); 12133 } 12134 12135 { 12136 float center[2] = {0.0f, 0.0f}; 12137 tinyexr::swap4(reinterpret_cast<unsigned int *>(¢er[0])); 12138 tinyexr::swap4(reinterpret_cast<unsigned int *>(¢er[1])); 12139 tinyexr::WriteAttributeToMemory( 12140 &memory, "screenWindowCenter", "v2f", 12141 reinterpret_cast<const unsigned char *>(center), 2 * sizeof(float)); 12142 } 12143 12144 { 12145 float w = static_cast<float>(exr_image->width); 12146 tinyexr::swap4(reinterpret_cast<unsigned int *>(&w)); 12147 tinyexr::WriteAttributeToMemory(&memory, "screenWindowWidth", "float", 12148 reinterpret_cast<const unsigned char *>(&w), 12149 sizeof(float)); 12150 } 12151 12152 // Custom attributes 12153 if (exr_header->num_custom_attributes > 0) { 12154 for (int i = 0; i < exr_header->num_custom_attributes; i++) { 12155 tinyexr::WriteAttributeToMemory( 12156 &memory, exr_header->custom_attributes[i].name, 12157 exr_header->custom_attributes[i].type, 12158 reinterpret_cast<const unsigned char *>( 12159 exr_header->custom_attributes[i].value), 12160 exr_header->custom_attributes[i].size); 12161 } 12162 } 12163 12164 { // end of header 12165 unsigned char e = 0; 12166 memory.push_back(e); 12167 } 12168 12169 int num_blocks = exr_image->height / num_scanlines; 12170 if (num_blocks * num_scanlines < exr_image->height) { 12171 num_blocks++; 12172 } 12173 12174 std::vector<tinyexr::tinyexr_uint64> offsets(static_cast<size_t>(num_blocks)); 12175 12176 size_t headerSize = memory.size(); 12177 tinyexr::tinyexr_uint64 offset = 12178 headerSize + 12179 static_cast<size_t>(num_blocks) * 12180 sizeof( 12181 tinyexr::tinyexr_int64); // sizeof(header) + sizeof(offsetTable) 12182 12183 std::vector<std::vector<unsigned char> > data_list( 12184 static_cast<size_t>(num_blocks)); 12185 std::vector<size_t> channel_offset_list( 12186 static_cast<size_t>(exr_header->num_channels)); 12187 12188 int pixel_data_size = 0; 12189 size_t channel_offset = 0; 12190 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) { 12191 channel_offset_list[c] = channel_offset; 12192 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { 12193 pixel_data_size += sizeof(unsigned short); 12194 channel_offset += sizeof(unsigned short); 12195 } else if (exr_header->requested_pixel_types[c] == 12196 TINYEXR_PIXELTYPE_FLOAT) { 12197 pixel_data_size += sizeof(float); 12198 channel_offset += sizeof(float); 12199 } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT) { 12200 pixel_data_size += sizeof(unsigned int); 12201 channel_offset += sizeof(unsigned int); 12202 } else { 12203 TEXR_ASSERT(0); 12204 } 12205 } 12206 12207#if TINYEXR_USE_ZFP 12208 tinyexr::ZFPCompressionParam zfp_compression_param; 12209 12210 // Use ZFP compression parameter from custom attributes(if such a parameter 12211 // exists) 12212 { 12213 bool ret = tinyexr::FindZFPCompressionParam( 12214 &zfp_compression_param, exr_header->custom_attributes, 12215 exr_header->num_custom_attributes); 12216 12217 if (!ret) { 12218 // Use predefined compression parameter. 12219 zfp_compression_param.type = 0; 12220 zfp_compression_param.rate = 2; 12221 } 12222 } 12223#endif 12224 12225 // TOOD(LTE): C++11 thread 12226 12227// Use signed int since some OpenMP compiler doesn't allow unsigned type for 12228// `parallel for` 12229#if TINYEXR_USE_OPENMP 12230#pragma omp parallel for 12231#endif 12232 for (int i = 0; i < num_blocks; i++) { 12233 size_t ii = static_cast<size_t>(i); 12234 int start_y = num_scanlines * i; 12235 int endY = (std::min)(num_scanlines * (i + 1), exr_image->height); 12236 int h = endY - start_y; 12237 12238 std::vector<unsigned char> buf( 12239 static_cast<size_t>(exr_image->width * h * pixel_data_size)); 12240 12241 for (size_t c = 0; c < static_cast<size_t>(exr_header->num_channels); c++) { 12242 if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { 12243 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { 12244 for (int y = 0; y < h; y++) { 12245 // Assume increasing Y 12246 float *line_ptr = reinterpret_cast<float *>(&buf.at( 12247 static_cast<size_t>(pixel_data_size * y * exr_image->width) + 12248 channel_offset_list[c] * 12249 static_cast<size_t>(exr_image->width))); 12250 for (int x = 0; x < exr_image->width; x++) { 12251 tinyexr::FP16 h16; 12252 h16.u = reinterpret_cast<unsigned short **>( 12253 exr_image->images)[c][(y + start_y) * exr_image->width + x]; 12254 12255 tinyexr::FP32 f32 = half_to_float(h16); 12256 12257 tinyexr::swap4(reinterpret_cast<unsigned int *>(&f32.f)); 12258 12259 // line_ptr[x] = f32.f; 12260 tinyexr::cpy4(line_ptr + x, &(f32.f)); 12261 } 12262 } 12263 } else if (exr_header->requested_pixel_types[c] == 12264 TINYEXR_PIXELTYPE_HALF) { 12265 for (int y = 0; y < h; y++) { 12266 // Assume increasing Y 12267 unsigned short *line_ptr = reinterpret_cast<unsigned short *>( 12268 &buf.at(static_cast<size_t>(pixel_data_size * y * 12269 exr_image->width) + 12270 channel_offset_list[c] * 12271 static_cast<size_t>(exr_image->width))); 12272 for (int x = 0; x < exr_image->width; x++) { 12273 unsigned short val = reinterpret_cast<unsigned short **>( 12274 exr_image->images)[c][(y + start_y) * exr_image->width + x]; 12275 12276 tinyexr::swap2(&val); 12277 12278 // line_ptr[x] = val; 12279 tinyexr::cpy2(line_ptr + x, &val); 12280 } 12281 } 12282 } else { 12283 TEXR_ASSERT(0); 12284 } 12285 12286 } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { 12287 if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { 12288 for (int y = 0; y < h; y++) { 12289 // Assume increasing Y 12290 unsigned short *line_ptr = reinterpret_cast<unsigned short *>( 12291 &buf.at(static_cast<size_t>(pixel_data_size * y * 12292 exr_image->width) + 12293 channel_offset_list[c] * 12294 static_cast<size_t>(exr_image->width))); 12295 for (int x = 0; x < exr_image->width; x++) { 12296 tinyexr::FP32 f32; 12297 f32.f = reinterpret_cast<float **>( 12298 exr_image->images)[c][(y + start_y) * exr_image->width + x]; 12299 12300 tinyexr::FP16 h16; 12301 h16 = float_to_half_full(f32); 12302 12303 tinyexr::swap2(reinterpret_cast<unsigned short *>(&h16.u)); 12304 12305 // line_ptr[x] = h16.u; 12306 tinyexr::cpy2(line_ptr + x, &(h16.u)); 12307 } 12308 } 12309 } else if (exr_header->requested_pixel_types[c] == 12310 TINYEXR_PIXELTYPE_FLOAT) { 12311 for (int y = 0; y < h; y++) { 12312 // Assume increasing Y 12313 float *line_ptr = reinterpret_cast<float *>(&buf.at( 12314 static_cast<size_t>(pixel_data_size * y * exr_image->width) + 12315 channel_offset_list[c] * 12316 static_cast<size_t>(exr_image->width))); 12317 for (int x = 0; x < exr_image->width; x++) { 12318 float val = reinterpret_cast<float **>( 12319 exr_image->images)[c][(y + start_y) * exr_image->width + x]; 12320 12321 tinyexr::swap4(reinterpret_cast<unsigned int *>(&val)); 12322 12323 // line_ptr[x] = val; 12324 tinyexr::cpy4(line_ptr + x, &val); 12325 } 12326 } 12327 } else { 12328 TEXR_ASSERT(0); 12329 } 12330 } else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_UINT) { 12331 for (int y = 0; y < h; y++) { 12332 // Assume increasing Y 12333 unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at( 12334 static_cast<size_t>(pixel_data_size * y * exr_image->width) + 12335 channel_offset_list[c] * static_cast<size_t>(exr_image->width))); 12336 for (int x = 0; x < exr_image->width; x++) { 12337 unsigned int val = reinterpret_cast<unsigned int **>( 12338 exr_image->images)[c][(y + start_y) * exr_image->width + x]; 12339 12340 tinyexr::swap4(&val); 12341 12342 // line_ptr[x] = val; 12343 tinyexr::cpy4(line_ptr + x, &val); 12344 } 12345 } 12346 } 12347 } 12348 12349 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_NONE) { 12350 // 4 byte: scan line 12351 // 4 byte: data size 12352 // ~ : pixel data(uncompressed) 12353 std::vector<unsigned char> header(8); 12354 unsigned int data_len = static_cast<unsigned int>(buf.size()); 12355 memcpy(&header.at(0), &start_y, sizeof(int)); 12356 memcpy(&header.at(4), &data_len, sizeof(unsigned int)); 12357 12358 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0))); 12359 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4))); 12360 12361 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); 12362 data_list[ii].insert(data_list[ii].end(), buf.begin(), 12363 buf.begin() + data_len); 12364 12365 } else if ((exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || 12366 (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) { 12367#if TINYEXR_USE_MINIZ 12368 std::vector<unsigned char> block(tinyexr::miniz::mz_compressBound( 12369 static_cast<unsigned long>(buf.size()))); 12370#else 12371 std::vector<unsigned char> block( 12372 compressBound(static_cast<uLong>(buf.size()))); 12373#endif 12374 tinyexr::tinyexr_uint64 outSize = block.size(); 12375 12376 tinyexr::CompressZip(&block.at(0), outSize, 12377 reinterpret_cast<const unsigned char *>(&buf.at(0)), 12378 static_cast<unsigned long>(buf.size())); 12379 12380 // 4 byte: scan line 12381 // 4 byte: data size 12382 // ~ : pixel data(compressed) 12383 std::vector<unsigned char> header(8); 12384 unsigned int data_len = static_cast<unsigned int>(outSize); // truncate 12385 memcpy(&header.at(0), &start_y, sizeof(int)); 12386 memcpy(&header.at(4), &data_len, sizeof(unsigned int)); 12387 12388 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0))); 12389 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4))); 12390 12391 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); 12392 data_list[ii].insert(data_list[ii].end(), block.begin(), 12393 block.begin() + data_len); 12394 12395 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_RLE) { 12396 // (buf.size() * 3) / 2 would be enough. 12397 std::vector<unsigned char> block((buf.size() * 3) / 2); 12398 12399 tinyexr::tinyexr_uint64 outSize = block.size(); 12400 12401 tinyexr::CompressRle(&block.at(0), outSize, 12402 reinterpret_cast<const unsigned char *>(&buf.at(0)), 12403 static_cast<unsigned long>(buf.size())); 12404 12405 // 4 byte: scan line 12406 // 4 byte: data size 12407 // ~ : pixel data(compressed) 12408 std::vector<unsigned char> header(8); 12409 unsigned int data_len = static_cast<unsigned int>(outSize); // truncate 12410 memcpy(&header.at(0), &start_y, sizeof(int)); 12411 memcpy(&header.at(4), &data_len, sizeof(unsigned int)); 12412 12413 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0))); 12414 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4))); 12415 12416 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); 12417 data_list[ii].insert(data_list[ii].end(), block.begin(), 12418 block.begin() + data_len); 12419 12420 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { 12421#if TINYEXR_USE_PIZ 12422 unsigned int bufLen = 12423 8192 + static_cast<unsigned int>( 12424 2 * static_cast<unsigned int>( 12425 buf.size())); // @fixme { compute good bound. } 12426 std::vector<unsigned char> block(bufLen); 12427 unsigned int outSize = static_cast<unsigned int>(block.size()); 12428 12429 CompressPiz(&block.at(0), &outSize, 12430 reinterpret_cast<const unsigned char *>(&buf.at(0)), 12431 buf.size(), channels, exr_image->width, h); 12432 12433 // 4 byte: scan line 12434 // 4 byte: data size 12435 // ~ : pixel data(compressed) 12436 std::vector<unsigned char> header(8); 12437 unsigned int data_len = outSize; 12438 memcpy(&header.at(0), &start_y, sizeof(int)); 12439 memcpy(&header.at(4), &data_len, sizeof(unsigned int)); 12440 12441 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0))); 12442 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4))); 12443 12444 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); 12445 data_list[ii].insert(data_list[ii].end(), block.begin(), 12446 block.begin() + data_len); 12447 12448#else 12449 TEXR_ASSERT(0); 12450#endif 12451 } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { 12452#if TINYEXR_USE_ZFP 12453 std::vector<unsigned char> block; 12454 unsigned int outSize; 12455 12456 tinyexr::CompressZfp( 12457 &block, &outSize, reinterpret_cast<const float *>(&buf.at(0)), 12458 exr_image->width, h, exr_header->num_channels, zfp_compression_param); 12459 12460 // 4 byte: scan line 12461 // 4 byte: data size 12462 // ~ : pixel data(compressed) 12463 std::vector<unsigned char> header(8); 12464 unsigned int data_len = outSize; 12465 memcpy(&header.at(0), &start_y, sizeof(int)); 12466 memcpy(&header.at(4), &data_len, sizeof(unsigned int)); 12467 12468 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(0))); 12469 tinyexr::swap4(reinterpret_cast<unsigned int *>(&header.at(4))); 12470 12471 data_list[ii].insert(data_list[ii].end(), header.begin(), header.end()); 12472 data_list[ii].insert(data_list[ii].end(), block.begin(), 12473 block.begin() + data_len); 12474 12475#else 12476 TEXR_ASSERT(0); 12477#endif 12478 } else { 12479 TEXR_ASSERT(0); 12480 } 12481 } // omp parallel 12482 12483 for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) { 12484 offsets[i] = offset; 12485 tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offsets[i])); 12486 offset += data_list[i].size(); 12487 } 12488 12489 size_t totalSize = static_cast<size_t>(offset); 12490 { 12491 memory.insert( 12492 memory.end(), reinterpret_cast<unsigned char *>(&offsets.at(0)), 12493 reinterpret_cast<unsigned char *>(&offsets.at(0)) + 12494 sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(num_blocks)); 12495 } 12496 12497 if (memory.size() == 0) { 12498 tinyexr::SetErrorMessage("Output memory size is zero", err); 12499 return 0; 12500 } 12501 12502 (*memory_out) = static_cast<unsigned char *>(malloc(totalSize)); 12503 memcpy((*memory_out), &memory.at(0), memory.size()); 12504 unsigned char *memory_ptr = *memory_out + memory.size(); 12505 12506 for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) { 12507 memcpy(memory_ptr, &data_list[i].at(0), data_list[i].size()); 12508 memory_ptr += data_list[i].size(); 12509 } 12510 12511 return totalSize; // OK 12512} 12513 12514int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header, 12515 const char *filename, const char **err) { 12516 if (exr_image == NULL || filename == NULL || 12517 exr_header->compression_type < 0) { 12518 tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err); 12519 return TINYEXR_ERROR_INVALID_ARGUMENT; 12520 } 12521 12522#if !TINYEXR_USE_PIZ 12523 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { 12524 tinyexr::SetErrorMessage("PIZ compression is not supported in this build", 12525 err); 12526 return TINYEXR_ERROR_UNSUPPORTED_FEATURE; 12527 } 12528#endif 12529 12530#if !TINYEXR_USE_ZFP 12531 if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { 12532 tinyexr::SetErrorMessage("ZFP compression is not supported in this build", 12533 err); 12534 return TINYEXR_ERROR_UNSUPPORTED_FEATURE; 12535 } 12536#endif 12537 12538#ifdef _WIN32 12539 FILE *fp = NULL; 12540 fopen_s(&fp, filename, "wb"); 12541#else 12542 FILE *fp = fopen(filename, "wb"); 12543#endif 12544 if (!fp) { 12545 tinyexr::SetErrorMessage("Cannot write a file", err); 12546 return TINYEXR_ERROR_CANT_WRITE_FILE; 12547 } 12548 12549 unsigned char *mem = NULL; 12550 size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err); 12551 if (mem_size == 0) { 12552 fclose(fp); 12553 return TINYEXR_ERROR_SERIALZATION_FAILED; 12554 } 12555 12556 size_t written_size = 0; 12557 if ((mem_size > 0) && mem) { 12558 written_size = fwrite(mem, 1, mem_size, fp); 12559 } 12560 free(mem); 12561 12562 fclose(fp); 12563 12564 if (written_size != mem_size) { 12565 tinyexr::SetErrorMessage("Cannot write a file", err); 12566 return TINYEXR_ERROR_CANT_WRITE_FILE; 12567 } 12568 12569 return TINYEXR_SUCCESS; 12570} 12571 12572int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { 12573 if (deep_image == NULL) { 12574 tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err); 12575 return TINYEXR_ERROR_INVALID_ARGUMENT; 12576 } 12577 12578#ifdef _MSC_VER 12579 FILE *fp = NULL; 12580 errno_t errcode = fopen_s(&fp, filename, "rb"); 12581 if ((0 != errcode) || (!fp)) { 12582 tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), 12583 err); 12584 return TINYEXR_ERROR_CANT_OPEN_FILE; 12585 } 12586#else 12587 FILE *fp = fopen(filename, "rb"); 12588 if (!fp) { 12589 tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), 12590 err); 12591 return TINYEXR_ERROR_CANT_OPEN_FILE; 12592 } 12593#endif 12594 12595 size_t filesize; 12596 // Compute size 12597 fseek(fp, 0, SEEK_END); 12598 filesize = static_cast<size_t>(ftell(fp)); 12599 fseek(fp, 0, SEEK_SET); 12600 12601 if (filesize == 0) { 12602 fclose(fp); 12603 tinyexr::SetErrorMessage("File size is zero : " + std::string(filename), 12604 err); 12605 return TINYEXR_ERROR_INVALID_FILE; 12606 } 12607 12608 std::vector<char> buf(filesize); // @todo { use mmap } 12609 { 12610 size_t ret; 12611 ret = fread(&buf[0], 1, filesize, fp); 12612 TEXR_ASSERT(ret == filesize); 12613 (void)ret; 12614 } 12615 fclose(fp); 12616 12617 const char *head = &buf[0]; 12618 const char *marker = &buf[0]; 12619 12620 // Header check. 12621 { 12622 const char header[] = {0x76, 0x2f, 0x31, 0x01}; 12623 12624 if (memcmp(marker, header, 4) != 0) { 12625 tinyexr::SetErrorMessage("Invalid magic number", err); 12626 return TINYEXR_ERROR_INVALID_MAGIC_NUMBER; 12627 } 12628 marker += 4; 12629 } 12630 12631 // Version, scanline. 12632 { 12633 // ver 2.0, scanline, deep bit on(0x800) 12634 // must be [2, 0, 0, 0] 12635 if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) { 12636 tinyexr::SetErrorMessage("Unsupported version or scanline", err); 12637 return TINYEXR_ERROR_UNSUPPORTED_FORMAT; 12638 } 12639 12640 marker += 4; 12641 } 12642 12643 int dx = -1; 12644 int dy = -1; 12645 int dw = -1; 12646 int dh = -1; 12647 int num_scanline_blocks = 1; // 16 for ZIP compression. 12648 int compression_type = -1; 12649 int num_channels = -1; 12650 std::vector<tinyexr::ChannelInfo> channels; 12651 12652 // Read attributes 12653 size_t size = filesize - tinyexr::kEXRVersionSize; 12654 for (;;) { 12655 if (0 == size) { 12656 return TINYEXR_ERROR_INVALID_DATA; 12657 } else if (marker[0] == '\0') { 12658 marker++; 12659 size--; 12660 break; 12661 } 12662 12663 std::string attr_name; 12664 std::string attr_type; 12665 std::vector<unsigned char> data; 12666 size_t marker_size; 12667 if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, 12668 marker, size)) { 12669 std::stringstream ss; 12670 ss << "Failed to parse attribute\n"; 12671 tinyexr::SetErrorMessage(ss.str(), err); 12672 return TINYEXR_ERROR_INVALID_DATA; 12673 } 12674 marker += marker_size; 12675 size -= marker_size; 12676 12677 if (attr_name.compare("compression") == 0) { 12678 compression_type = data[0]; 12679 if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) { 12680 std::stringstream ss; 12681 ss << "Unsupported compression type : " << compression_type; 12682 tinyexr::SetErrorMessage(ss.str(), err); 12683 return TINYEXR_ERROR_UNSUPPORTED_FORMAT; 12684 } 12685 12686 if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { 12687 num_scanline_blocks = 16; 12688 } 12689 12690 } else if (attr_name.compare("channels") == 0) { 12691 // name: zero-terminated string, from 1 to 255 bytes long 12692 // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2 12693 // pLinear: unsigned char, possible values are 0 and 1 12694 // reserved: three chars, should be zero 12695 // xSampling: int 12696 // ySampling: int 12697 12698 if (!tinyexr::ReadChannelInfo(channels, data)) { 12699 tinyexr::SetErrorMessage("Failed to parse channel info", err); 12700 return TINYEXR_ERROR_INVALID_DATA; 12701 } 12702 12703 num_channels = static_cast<int>(channels.size()); 12704 12705 if (num_channels < 1) { 12706 tinyexr::SetErrorMessage("Invalid channels format", err); 12707 return TINYEXR_ERROR_INVALID_DATA; 12708 } 12709 12710 } else if (attr_name.compare("dataWindow") == 0) { 12711 memcpy(&dx, &data.at(0), sizeof(int)); 12712 memcpy(&dy, &data.at(4), sizeof(int)); 12713 memcpy(&dw, &data.at(8), sizeof(int)); 12714 memcpy(&dh, &data.at(12), sizeof(int)); 12715 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dx)); 12716 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dy)); 12717 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dw)); 12718 tinyexr::swap4(reinterpret_cast<unsigned int *>(&dh)); 12719 12720 } else if (attr_name.compare("displayWindow") == 0) { 12721 int x; 12722 int y; 12723 int w; 12724 int h; 12725 memcpy(&x, &data.at(0), sizeof(int)); 12726 memcpy(&y, &data.at(4), sizeof(int)); 12727 memcpy(&w, &data.at(8), sizeof(int)); 12728 memcpy(&h, &data.at(12), sizeof(int)); 12729 tinyexr::swap4(reinterpret_cast<unsigned int *>(&x)); 12730 tinyexr::swap4(reinterpret_cast<unsigned int *>(&y)); 12731 tinyexr::swap4(reinterpret_cast<unsigned int *>(&w)); 12732 tinyexr::swap4(reinterpret_cast<unsigned int *>(&h)); 12733 } 12734 } 12735 12736 TEXR_ASSERT(dx >= 0); 12737 TEXR_ASSERT(dy >= 0); 12738 TEXR_ASSERT(dw >= 0); 12739 TEXR_ASSERT(dh >= 0); 12740 TEXR_ASSERT(num_channels >= 1); 12741 12742 int data_width = dw - dx + 1; 12743 int data_height = dh - dy + 1; 12744 12745 std::vector<float> image( 12746 static_cast<size_t>(data_width * data_height * 4)); // 4 = RGBA 12747 12748 // Read offset tables. 12749 int num_blocks = data_height / num_scanline_blocks; 12750 if (num_blocks * num_scanline_blocks < data_height) { 12751 num_blocks++; 12752 } 12753 12754 std::vector<tinyexr::tinyexr_int64> offsets(static_cast<size_t>(num_blocks)); 12755 12756 for (size_t y = 0; y < static_cast<size_t>(num_blocks); y++) { 12757 tinyexr::tinyexr_int64 offset; 12758 memcpy(&offset, marker, sizeof(tinyexr::tinyexr_int64)); 12759 tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offset)); 12760 marker += sizeof(tinyexr::tinyexr_int64); // = 8 12761 offsets[y] = offset; 12762 } 12763 12764#if TINYEXR_USE_PIZ 12765 if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) || 12766 (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) || 12767 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || 12768 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) || 12769 (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ)) { 12770#else 12771 if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) || 12772 (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) || 12773 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || 12774 (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) { 12775#endif 12776 // OK 12777 } else { 12778 tinyexr::SetErrorMessage("Unsupported compression format", err); 12779 return TINYEXR_ERROR_UNSUPPORTED_FORMAT; 12780 } 12781 12782 deep_image->image = static_cast<float ***>( 12783 malloc(sizeof(float **) * static_cast<size_t>(num_channels))); 12784 for (int c = 0; c < num_channels; c++) { 12785 deep_image->image[c] = static_cast<float **>( 12786 malloc(sizeof(float *) * static_cast<size_t>(data_height))); 12787 for (int y = 0; y < data_height; y++) { 12788 } 12789 } 12790 12791 deep_image->offset_table = static_cast<int **>( 12792 malloc(sizeof(int *) * static_cast<size_t>(data_height))); 12793 for (int y = 0; y < data_height; y++) { 12794 deep_image->offset_table[y] = static_cast<int *>( 12795 malloc(sizeof(int) * static_cast<size_t>(data_width))); 12796 } 12797 12798 for (size_t y = 0; y < static_cast<size_t>(num_blocks); y++) { 12799 const unsigned char *data_ptr = 12800 reinterpret_cast<const unsigned char *>(head + offsets[y]); 12801 12802 // int: y coordinate 12803 // int64: packed size of pixel offset table 12804 // int64: packed size of sample data 12805 // int64: unpacked size of sample data 12806 // compressed pixel offset table 12807 // compressed sample data 12808 int line_no; 12809 tinyexr::tinyexr_int64 packedOffsetTableSize; 12810 tinyexr::tinyexr_int64 packedSampleDataSize; 12811 tinyexr::tinyexr_int64 unpackedSampleDataSize; 12812 memcpy(&line_no, data_ptr, sizeof(int)); 12813 memcpy(&packedOffsetTableSize, data_ptr + 4, 12814 sizeof(tinyexr::tinyexr_int64)); 12815 memcpy(&packedSampleDataSize, data_ptr + 12, 12816 sizeof(tinyexr::tinyexr_int64)); 12817 memcpy(&unpackedSampleDataSize, data_ptr + 20, 12818 sizeof(tinyexr::tinyexr_int64)); 12819 12820 tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no)); 12821 tinyexr::swap8( 12822 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&packedOffsetTableSize)); 12823 tinyexr::swap8( 12824 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&packedSampleDataSize)); 12825 tinyexr::swap8( 12826 reinterpret_cast<tinyexr::tinyexr_uint64 *>(&unpackedSampleDataSize)); 12827 12828 std::vector<int> pixelOffsetTable(static_cast<size_t>(data_width)); 12829 12830 // decode pixel offset table. 12831 { 12832 unsigned long dstLen = 12833 static_cast<unsigned long>(pixelOffsetTable.size() * sizeof(int)); 12834 if (!tinyexr::DecompressZip( 12835 reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)), 12836 &dstLen, data_ptr + 28, 12837 static_cast<unsigned long>(packedOffsetTableSize))) { 12838 return false; 12839 } 12840 12841 TEXR_ASSERT(dstLen == pixelOffsetTable.size() * sizeof(int)); 12842 for (size_t i = 0; i < static_cast<size_t>(data_width); i++) { 12843 deep_image->offset_table[y][i] = pixelOffsetTable[i]; 12844 } 12845 } 12846 12847 std::vector<unsigned char> sample_data( 12848 static_cast<size_t>(unpackedSampleDataSize)); 12849 12850 // decode sample data. 12851 { 12852 unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize); 12853 if (dstLen) { 12854 if (!tinyexr::DecompressZip( 12855 reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen, 12856 data_ptr + 28 + packedOffsetTableSize, 12857 static_cast<unsigned long>(packedSampleDataSize))) { 12858 return false; 12859 } 12860 TEXR_ASSERT(dstLen == static_cast<unsigned long>(unpackedSampleDataSize)); 12861 } 12862 } 12863 12864 // decode sample 12865 int sampleSize = -1; 12866 std::vector<int> channel_offset_list(static_cast<size_t>(num_channels)); 12867 { 12868 int channel_offset = 0; 12869 for (size_t i = 0; i < static_cast<size_t>(num_channels); i++) { 12870 channel_offset_list[i] = channel_offset; 12871 if (channels[i].pixel_type == TINYEXR_PIXELTYPE_UINT) { // UINT 12872 channel_offset += 4; 12873 } else if (channels[i].pixel_type == TINYEXR_PIXELTYPE_HALF) { // half 12874 channel_offset += 2; 12875 } else if (channels[i].pixel_type == 12876 TINYEXR_PIXELTYPE_FLOAT) { // float 12877 channel_offset += 4; 12878 } else { 12879 TEXR_ASSERT(0); 12880 } 12881 } 12882 sampleSize = channel_offset; 12883 } 12884 TEXR_ASSERT(sampleSize >= 2); 12885 12886 TEXR_ASSERT(static_cast<size_t>( 12887 pixelOffsetTable[static_cast<size_t>(data_width - 1)] * 12888 sampleSize) == sample_data.size()); 12889 int samples_per_line = static_cast<int>(sample_data.size()) / sampleSize; 12890 12891 // 12892 // Alloc memory 12893 // 12894 12895 // 12896 // pixel data is stored as image[channels][pixel_samples] 12897 // 12898 { 12899 tinyexr::tinyexr_uint64 data_offset = 0; 12900 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) { 12901 deep_image->image[c][y] = static_cast<float *>( 12902 malloc(sizeof(float) * static_cast<size_t>(samples_per_line))); 12903 12904 if (channels[c].pixel_type == 0) { // UINT 12905 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { 12906 unsigned int ui; 12907 unsigned int *src_ptr = reinterpret_cast<unsigned int *>( 12908 &sample_data.at(size_t(data_offset) + x * sizeof(int))); 12909 tinyexr::cpy4(&ui, src_ptr); 12910 deep_image->image[c][y][x] = static_cast<float>(ui); // @fixme 12911 } 12912 data_offset += 12913 sizeof(unsigned int) * static_cast<size_t>(samples_per_line); 12914 } else if (channels[c].pixel_type == 1) { // half 12915 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { 12916 tinyexr::FP16 f16; 12917 const unsigned short *src_ptr = reinterpret_cast<unsigned short *>( 12918 &sample_data.at(size_t(data_offset) + x * sizeof(short))); 12919 tinyexr::cpy2(&(f16.u), src_ptr); 12920 tinyexr::FP32 f32 = half_to_float(f16); 12921 deep_image->image[c][y][x] = f32.f; 12922 } 12923 data_offset += sizeof(short) * static_cast<size_t>(samples_per_line); 12924 } else { // float 12925 for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) { 12926 float f; 12927 const float *src_ptr = reinterpret_cast<float *>( 12928 &sample_data.at(size_t(data_offset) + x * sizeof(float))); 12929 tinyexr::cpy4(&f, src_ptr); 12930 deep_image->image[c][y][x] = f; 12931 } 12932 data_offset += sizeof(float) * static_cast<size_t>(samples_per_line); 12933 } 12934 } 12935 } 12936 } // y 12937 12938 deep_image->width = data_width; 12939 deep_image->height = data_height; 12940 12941 deep_image->channel_names = static_cast<const char **>( 12942 malloc(sizeof(const char *) * static_cast<size_t>(num_channels))); 12943 for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) { 12944#ifdef _WIN32 12945 deep_image->channel_names[c] = _strdup(channels[c].name.c_str()); 12946#else 12947 deep_image->channel_names[c] = strdup(channels[c].name.c_str()); 12948#endif 12949 } 12950 deep_image->num_channels = num_channels; 12951 12952 return TINYEXR_SUCCESS; 12953} 12954 12955void InitEXRImage(EXRImage *exr_image) { 12956 if (exr_image == NULL) { 12957 return; 12958 } 12959 12960 exr_image->width = 0; 12961 exr_image->height = 0; 12962 exr_image->num_channels = 0; 12963 12964 exr_image->images = NULL; 12965 exr_image->tiles = NULL; 12966 12967 exr_image->num_tiles = 0; 12968} 12969 12970void FreeEXRErrorMessage(const char *msg) { 12971 if (msg) { 12972 free(reinterpret_cast<void *>(const_cast<char *>(msg))); 12973 } 12974 return; 12975} 12976 12977void InitEXRHeader(EXRHeader *exr_header) { 12978 if (exr_header == NULL) { 12979 return; 12980 } 12981 12982 memset(exr_header, 0, sizeof(EXRHeader)); 12983} 12984 12985int FreeEXRHeader(EXRHeader *exr_header) { 12986 if (exr_header == NULL) { 12987 return TINYEXR_ERROR_INVALID_ARGUMENT; 12988 } 12989 12990 if (exr_header->channels) { 12991 free(exr_header->channels); 12992 } 12993 12994 if (exr_header->pixel_types) { 12995 free(exr_header->pixel_types); 12996 } 12997 12998 if (exr_header->requested_pixel_types) { 12999 free(exr_header->requested_pixel_types); 13000 } 13001 13002 for (int i = 0; i < exr_header->num_custom_attributes; i++) { 13003 if (exr_header->custom_attributes[i].value) { 13004 free(exr_header->custom_attributes[i].value); 13005 } 13006 } 13007 13008 if (exr_header->custom_attributes) { 13009 free(exr_header->custom_attributes); 13010 } 13011 13012 return TINYEXR_SUCCESS; 13013} 13014 13015int FreeEXRImage(EXRImage *exr_image) { 13016 if (exr_image == NULL) { 13017 return TINYEXR_ERROR_INVALID_ARGUMENT; 13018 } 13019 13020 for (int i = 0; i < exr_image->num_channels; i++) { 13021 if (exr_image->images && exr_image->images[i]) { 13022 free(exr_image->images[i]); 13023 } 13024 } 13025 13026 if (exr_image->images) { 13027 free(exr_image->images); 13028 } 13029 13030 if (exr_image->tiles) { 13031 for (int tid = 0; tid < exr_image->num_tiles; tid++) { 13032 for (int i = 0; i < exr_image->num_channels; i++) { 13033 if (exr_image->tiles[tid].images && exr_image->tiles[tid].images[i]) { 13034 free(exr_image->tiles[tid].images[i]); 13035 } 13036 } 13037 if (exr_image->tiles[tid].images) { 13038 free(exr_image->tiles[tid].images); 13039 } 13040 } 13041 free(exr_image->tiles); 13042 } 13043 13044 return TINYEXR_SUCCESS; 13045} 13046 13047int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version, 13048 const char *filename, const char **err) { 13049 if (exr_header == NULL || exr_version == NULL || filename == NULL) { 13050 tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile", 13051 err); 13052 return TINYEXR_ERROR_INVALID_ARGUMENT; 13053 } 13054 13055#ifdef _WIN32 13056 FILE *fp = NULL; 13057 fopen_s(&fp, filename, "rb"); 13058#else 13059 FILE *fp = fopen(filename, "rb"); 13060#endif 13061 if (!fp) { 13062 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); 13063 return TINYEXR_ERROR_CANT_OPEN_FILE; 13064 } 13065 13066 size_t filesize; 13067 // Compute size 13068 fseek(fp, 0, SEEK_END); 13069 filesize = static_cast<size_t>(ftell(fp)); 13070 fseek(fp, 0, SEEK_SET); 13071 13072 std::vector<unsigned char> buf(filesize); // @todo { use mmap } 13073 { 13074 size_t ret; 13075 ret = fread(&buf[0], 1, filesize, fp); 13076 TEXR_ASSERT(ret == filesize); 13077 fclose(fp); 13078 13079 if (ret != filesize) { 13080 tinyexr::SetErrorMessage("fread() error on " + std::string(filename), 13081 err); 13082 return TINYEXR_ERROR_INVALID_FILE; 13083 } 13084 } 13085 13086 return ParseEXRHeaderFromMemory(exr_header, exr_version, &buf.at(0), filesize, 13087 err); 13088} 13089 13090int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers, 13091 int *num_headers, 13092 const EXRVersion *exr_version, 13093 const unsigned char *memory, size_t size, 13094 const char **err) { 13095 if (memory == NULL || exr_headers == NULL || num_headers == NULL || 13096 exr_version == NULL) { 13097 // Invalid argument 13098 tinyexr::SetErrorMessage( 13099 "Invalid argument for ParseEXRMultipartHeaderFromMemory", err); 13100 return TINYEXR_ERROR_INVALID_ARGUMENT; 13101 } 13102 13103 if (size < tinyexr::kEXRVersionSize) { 13104 tinyexr::SetErrorMessage("Data size too short", err); 13105 return TINYEXR_ERROR_INVALID_DATA; 13106 } 13107 13108 const unsigned char *marker = memory + tinyexr::kEXRVersionSize; 13109 size_t marker_size = size - tinyexr::kEXRVersionSize; 13110 13111 std::vector<tinyexr::HeaderInfo> infos; 13112 13113 for (;;) { 13114 tinyexr::HeaderInfo info; 13115 info.clear(); 13116 13117 std::string err_str; 13118 bool empty_header = false; 13119 int ret = ParseEXRHeader(&info, &empty_header, exr_version, &err_str, 13120 marker, marker_size); 13121 13122 if (ret != TINYEXR_SUCCESS) { 13123 tinyexr::SetErrorMessage(err_str, err); 13124 return ret; 13125 } 13126 13127 if (empty_header) { 13128 marker += 1; // skip '\0' 13129 break; 13130 } 13131 13132 // `chunkCount` must exist in the header. 13133 if (info.chunk_count == 0) { 13134 tinyexr::SetErrorMessage( 13135 "`chunkCount' attribute is not found in the header.", err); 13136 return TINYEXR_ERROR_INVALID_DATA; 13137 } 13138 13139 infos.push_back(info); 13140 13141 // move to next header. 13142 marker += info.header_len; 13143 size -= info.header_len; 13144 } 13145 13146 // allocate memory for EXRHeader and create array of EXRHeader pointers. 13147 (*exr_headers) = 13148 static_cast<EXRHeader **>(malloc(sizeof(EXRHeader *) * infos.size())); 13149 for (size_t i = 0; i < infos.size(); i++) { 13150 EXRHeader *exr_header = static_cast<EXRHeader *>(malloc(sizeof(EXRHeader))); 13151 13152 ConvertHeader(exr_header, infos[i]); 13153 13154 // transfoer `tiled` from version. 13155 exr_header->tiled = exr_version->tiled; 13156 13157 (*exr_headers)[i] = exr_header; 13158 } 13159 13160 (*num_headers) = static_cast<int>(infos.size()); 13161 13162 return TINYEXR_SUCCESS; 13163} 13164 13165int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers, 13166 const EXRVersion *exr_version, 13167 const char *filename, const char **err) { 13168 if (exr_headers == NULL || num_headers == NULL || exr_version == NULL || 13169 filename == NULL) { 13170 tinyexr::SetErrorMessage( 13171 "Invalid argument for ParseEXRMultipartHeaderFromFile()", err); 13172 return TINYEXR_ERROR_INVALID_ARGUMENT; 13173 } 13174 13175#ifdef _WIN32 13176 FILE *fp = NULL; 13177 fopen_s(&fp, filename, "rb"); 13178#else 13179 FILE *fp = fopen(filename, "rb"); 13180#endif 13181 if (!fp) { 13182 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); 13183 return TINYEXR_ERROR_CANT_OPEN_FILE; 13184 } 13185 13186 size_t filesize; 13187 // Compute size 13188 fseek(fp, 0, SEEK_END); 13189 filesize = static_cast<size_t>(ftell(fp)); 13190 fseek(fp, 0, SEEK_SET); 13191 13192 std::vector<unsigned char> buf(filesize); // @todo { use mmap } 13193 { 13194 size_t ret; 13195 ret = fread(&buf[0], 1, filesize, fp); 13196 TEXR_ASSERT(ret == filesize); 13197 fclose(fp); 13198 13199 if (ret != filesize) { 13200 tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err); 13201 return TINYEXR_ERROR_INVALID_FILE; 13202 } 13203 } 13204 13205 return ParseEXRMultipartHeaderFromMemory( 13206 exr_headers, num_headers, exr_version, &buf.at(0), filesize, err); 13207} 13208 13209int ParseEXRVersionFromMemory(EXRVersion *version, const unsigned char *memory, 13210 size_t size) { 13211 if (version == NULL || memory == NULL) { 13212 return TINYEXR_ERROR_INVALID_ARGUMENT; 13213 } 13214 13215 if (size < tinyexr::kEXRVersionSize) { 13216 return TINYEXR_ERROR_INVALID_DATA; 13217 } 13218 13219 const unsigned char *marker = memory; 13220 13221 // Header check. 13222 { 13223 const char header[] = {0x76, 0x2f, 0x31, 0x01}; 13224 13225 if (memcmp(marker, header, 4) != 0) { 13226 return TINYEXR_ERROR_INVALID_MAGIC_NUMBER; 13227 } 13228 marker += 4; 13229 } 13230 13231 version->tiled = false; 13232 version->long_name = false; 13233 version->non_image = false; 13234 version->multipart = false; 13235 13236 // Parse version header. 13237 { 13238 // must be 2 13239 if (marker[0] != 2) { 13240 return TINYEXR_ERROR_INVALID_EXR_VERSION; 13241 } 13242 13243 version->version = 2; 13244 13245 if (marker[1] & 0x2) { // 9th bit 13246 version->tiled = true; 13247 } 13248 if (marker[1] & 0x4) { // 10th bit 13249 version->long_name = true; 13250 } 13251 if (marker[1] & 0x8) { // 11th bit 13252 version->non_image = true; // (deep image) 13253 } 13254 if (marker[1] & 0x10) { // 12th bit 13255 version->multipart = true; 13256 } 13257 } 13258 13259 return TINYEXR_SUCCESS; 13260} 13261 13262int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) { 13263 if (filename == NULL) { 13264 return TINYEXR_ERROR_INVALID_ARGUMENT; 13265 } 13266 13267#ifdef _WIN32 13268 FILE *fp = NULL; 13269 fopen_s(&fp, filename, "rb"); 13270#else 13271 FILE *fp = fopen(filename, "rb"); 13272#endif 13273 if (!fp) { 13274 return TINYEXR_ERROR_CANT_OPEN_FILE; 13275 } 13276 13277 size_t file_size; 13278 // Compute size 13279 fseek(fp, 0, SEEK_END); 13280 file_size = static_cast<size_t>(ftell(fp)); 13281 fseek(fp, 0, SEEK_SET); 13282 13283 if (file_size < tinyexr::kEXRVersionSize) { 13284 fclose(fp); 13285 return TINYEXR_ERROR_INVALID_FILE; 13286 } 13287 13288 unsigned char buf[tinyexr::kEXRVersionSize]; 13289 size_t ret = fread(&buf[0], 1, tinyexr::kEXRVersionSize, fp); 13290 fclose(fp); 13291 13292 if (ret != tinyexr::kEXRVersionSize) { 13293 return TINYEXR_ERROR_INVALID_FILE; 13294 } 13295 13296 return ParseEXRVersionFromMemory(version, buf, tinyexr::kEXRVersionSize); 13297} 13298 13299int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, 13300 const EXRHeader **exr_headers, 13301 unsigned int num_parts, 13302 const unsigned char *memory, 13303 const size_t size, const char **err) { 13304 if (exr_images == NULL || exr_headers == NULL || num_parts == 0 || 13305 memory == NULL || (size <= tinyexr::kEXRVersionSize)) { 13306 tinyexr::SetErrorMessage( 13307 "Invalid argument for LoadEXRMultipartImageFromMemory()", err); 13308 return TINYEXR_ERROR_INVALID_ARGUMENT; 13309 } 13310 13311 // compute total header size. 13312 size_t total_header_size = 0; 13313 for (unsigned int i = 0; i < num_parts; i++) { 13314 if (exr_headers[i]->header_len == 0) { 13315 tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); 13316 return TINYEXR_ERROR_INVALID_ARGUMENT; 13317 } 13318 13319 total_header_size += exr_headers[i]->header_len; 13320 } 13321 13322 const char *marker = reinterpret_cast<const char *>( 13323 memory + total_header_size + 4 + 13324 4); // +8 for magic number and version header. 13325 13326 marker += 1; // Skip empty header. 13327 13328 // NOTE 1: 13329 // In multipart image, There is 'part number' before chunk data. 13330 // 4 byte : part number 13331 // 4+ : chunk 13332 // 13333 // NOTE 2: 13334 // EXR spec says 'part number' is 'unsigned long' but actually this is 13335 // 'unsigned int(4 bytes)' in OpenEXR implementation... 13336 // http://www.openexr.com/openexrfilelayout.pdf 13337 13338 // Load chunk offset table. 13339 std::vector<std::vector<tinyexr::tinyexr_uint64> > chunk_offset_table_list; 13340 for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) { 13341 std::vector<tinyexr::tinyexr_uint64> offset_table( 13342 static_cast<size_t>(exr_headers[i]->chunk_count)); 13343 13344 for (size_t c = 0; c < offset_table.size(); c++) { 13345 tinyexr::tinyexr_uint64 offset; 13346 memcpy(&offset, marker, 8); 13347 tinyexr::swap8(&offset); 13348 13349 if (offset >= size) { 13350 tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", 13351 err); 13352 return TINYEXR_ERROR_INVALID_DATA; 13353 } 13354 13355 offset_table[c] = offset + 4; // +4 to skip 'part number' 13356 marker += 8; 13357 } 13358 13359 chunk_offset_table_list.push_back(offset_table); 13360 } 13361 13362 // Decode image. 13363 for (size_t i = 0; i < static_cast<size_t>(num_parts); i++) { 13364 std::vector<tinyexr::tinyexr_uint64> &offset_table = 13365 chunk_offset_table_list[i]; 13366 13367 // First check 'part number' is identitical to 'i' 13368 for (size_t c = 0; c < offset_table.size(); c++) { 13369 const unsigned char *part_number_addr = 13370 memory + offset_table[c] - 4; // -4 to move to 'part number' field. 13371 unsigned int part_no; 13372 memcpy(&part_no, part_number_addr, sizeof(unsigned int)); // 4 13373 tinyexr::swap4(&part_no); 13374 13375 if (part_no != i) { 13376 tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.", 13377 err); 13378 return TINYEXR_ERROR_INVALID_DATA; 13379 } 13380 } 13381 13382 std::string e; 13383 int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table, 13384 memory, size, &e); 13385 if (ret != TINYEXR_SUCCESS) { 13386 if (!e.empty()) { 13387 tinyexr::SetErrorMessage(e, err); 13388 } 13389 return ret; 13390 } 13391 } 13392 13393 return TINYEXR_SUCCESS; 13394} 13395 13396int LoadEXRMultipartImageFromFile(EXRImage *exr_images, 13397 const EXRHeader **exr_headers, 13398 unsigned int num_parts, const char *filename, 13399 const char **err) { 13400 if (exr_images == NULL || exr_headers == NULL || num_parts == 0) { 13401 tinyexr::SetErrorMessage( 13402 "Invalid argument for LoadEXRMultipartImageFromFile", err); 13403 return TINYEXR_ERROR_INVALID_ARGUMENT; 13404 } 13405 13406#ifdef _WIN32 13407 FILE *fp = NULL; 13408 fopen_s(&fp, filename, "rb"); 13409#else 13410 FILE *fp = fopen(filename, "rb"); 13411#endif 13412 if (!fp) { 13413 tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); 13414 return TINYEXR_ERROR_CANT_OPEN_FILE; 13415 } 13416 13417 size_t filesize; 13418 // Compute size 13419 fseek(fp, 0, SEEK_END); 13420 filesize = static_cast<size_t>(ftell(fp)); 13421 fseek(fp, 0, SEEK_SET); 13422 13423 std::vector<unsigned char> buf(filesize); // @todo { use mmap } 13424 { 13425 size_t ret; 13426 ret = fread(&buf[0], 1, filesize, fp); 13427 TEXR_ASSERT(ret == filesize); 13428 fclose(fp); 13429 (void)ret; 13430 } 13431 13432 return LoadEXRMultipartImageFromMemory(exr_images, exr_headers, num_parts, 13433 &buf.at(0), filesize, err); 13434} 13435 13436int SaveEXR(const float *data, int width, int height, int components, 13437 const int save_as_fp16, const char *outfilename, const char **err) { 13438 if ((components == 1) || components == 3 || components == 4) { 13439 // OK 13440 } else { 13441 std::stringstream ss; 13442 ss << "Unsupported component value : " << components << std::endl; 13443 13444 tinyexr::SetErrorMessage(ss.str(), err); 13445 return TINYEXR_ERROR_INVALID_ARGUMENT; 13446 } 13447 13448 EXRHeader header; 13449 InitEXRHeader(&header); 13450 13451 if ((width < 16) && (height < 16)) { 13452 // No compression for small image. 13453 header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE; 13454 } else { 13455 header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP; 13456 } 13457 13458 EXRImage image; 13459 InitEXRImage(&image); 13460 13461 image.num_channels = components; 13462 13463 std::vector<float> images[4]; 13464 13465 if (components == 1) { 13466 images[0].resize(static_cast<size_t>(width * height)); 13467 memcpy(images[0].data(), data, sizeof(float) * size_t(width * height)); 13468 } else { 13469 images[0].resize(static_cast<size_t>(width * height)); 13470 images[1].resize(static_cast<size_t>(width * height)); 13471 images[2].resize(static_cast<size_t>(width * height)); 13472 images[3].resize(static_cast<size_t>(width * height)); 13473 13474 // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers 13475 for (size_t i = 0; i < static_cast<size_t>(width * height); i++) { 13476 images[0][i] = data[static_cast<size_t>(components) * i + 0]; 13477 images[1][i] = data[static_cast<size_t>(components) * i + 1]; 13478 images[2][i] = data[static_cast<size_t>(components) * i + 2]; 13479 if (components == 4) { 13480 images[3][i] = data[static_cast<size_t>(components) * i + 3]; 13481 } 13482 } 13483 } 13484 13485 float *image_ptr[4] = {0, 0, 0, 0}; 13486 if (components == 4) { 13487 image_ptr[0] = &(images[3].at(0)); // A 13488 image_ptr[1] = &(images[2].at(0)); // B 13489 image_ptr[2] = &(images[1].at(0)); // G 13490 image_ptr[3] = &(images[0].at(0)); // R 13491 } else if (components == 3) { 13492 image_ptr[0] = &(images[2].at(0)); // B 13493 image_ptr[1] = &(images[1].at(0)); // G 13494 image_ptr[2] = &(images[0].at(0)); // R 13495 } else if (components == 1) { 13496 image_ptr[0] = &(images[0].at(0)); // A 13497 } 13498 13499 image.images = reinterpret_cast<unsigned char **>(image_ptr); 13500 image.width = width; 13501 image.height = height; 13502 13503 header.num_channels = components; 13504 header.channels = static_cast<EXRChannelInfo *>(malloc( 13505 sizeof(EXRChannelInfo) * static_cast<size_t>(header.num_channels))); 13506 // Must be (A)BGR order, since most of EXR viewers expect this channel order. 13507 if (components == 4) { 13508#ifdef _MSC_VER 13509 strncpy_s(header.channels[0].name, "A", 255); 13510 strncpy_s(header.channels[1].name, "B", 255); 13511 strncpy_s(header.channels[2].name, "G", 255); 13512 strncpy_s(header.channels[3].name, "R", 255); 13513#else 13514 strncpy(header.channels[0].name, "A", 255); 13515 strncpy(header.channels[1].name, "B", 255); 13516 strncpy(header.channels[2].name, "G", 255); 13517 strncpy(header.channels[3].name, "R", 255); 13518#endif 13519 header.channels[0].name[strlen("A")] = '\0'; 13520 header.channels[1].name[strlen("B")] = '\0'; 13521 header.channels[2].name[strlen("G")] = '\0'; 13522 header.channels[3].name[strlen("R")] = '\0'; 13523 } else if (components == 3) { 13524#ifdef _MSC_VER 13525 strncpy_s(header.channels[0].name, "B", 255); 13526 strncpy_s(header.channels[1].name, "G", 255); 13527 strncpy_s(header.channels[2].name, "R", 255); 13528#else 13529 strncpy(header.channels[0].name, "B", 255); 13530 strncpy(header.channels[1].name, "G", 255); 13531 strncpy(header.channels[2].name, "R", 255); 13532#endif 13533 header.channels[0].name[strlen("B")] = '\0'; 13534 header.channels[1].name[strlen("G")] = '\0'; 13535 header.channels[2].name[strlen("R")] = '\0'; 13536 } else { 13537#ifdef _MSC_VER 13538 strncpy_s(header.channels[0].name, "A", 255); 13539#else 13540 strncpy(header.channels[0].name, "A", 255); 13541#endif 13542 header.channels[0].name[strlen("A")] = '\0'; 13543 } 13544 13545 header.pixel_types = static_cast<int *>( 13546 malloc(sizeof(int) * static_cast<size_t>(header.num_channels))); 13547 header.requested_pixel_types = static_cast<int *>( 13548 malloc(sizeof(int) * static_cast<size_t>(header.num_channels))); 13549 for (int i = 0; i < header.num_channels; i++) { 13550 header.pixel_types[i] = 13551 TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image 13552 13553 if (save_as_fp16 > 0) { 13554 header.requested_pixel_types[i] = 13555 TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format 13556 } else { 13557 header.requested_pixel_types[i] = 13558 TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e. 13559 // no precision reduction) 13560 } 13561 } 13562 13563 int ret = SaveEXRImageToFile(&image, &header, outfilename, err); 13564 if (ret != TINYEXR_SUCCESS) { 13565 return ret; 13566 } 13567 13568 free(header.channels); 13569 free(header.pixel_types); 13570 free(header.requested_pixel_types); 13571 13572 return ret; 13573} 13574 13575#ifdef __clang__ 13576// zero-as-null-ppinter-constant 13577#pragma clang diagnostic pop 13578#endif 13579 13580#endif // TINYEXR_IMPLEMENTATION_DEIFNED 13581#endif // TINYEXR_IMPLEMENTATION 13582